Graph Theory
Release 10.4

The Sage Development TeamJul 23, 2024

CONTENTS

1Graph objects and methods

1

2

Constructors and databases

773

3

Low-level implementation

1373

4

Hypergraphs

1505

5

Libraries of algorithms

1539

6

Indices and Tables

1959

Bibliography

1961

Python Module Index

1963

Index

1965

i

ii

CHAPTERONE

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()igraph_graph()
to_dictionary()
copy()
export_to_file()
adjacency_matrix()
incidence_matrix()
distance_matrix()
weighted_adjacency_matrix()
kirchhoff_matrix()
has_loops()
allows_loops()
allow_loops()
loops()
loop_edges()
number_of_loops()
loop_vertices()
remove_loops()
has_multiple_edges()allows_multiple_edges()allow_multiple_edges()
multiple_edges()name()
is_immutable()weighted()
antisymmetric()
density()order()
size()

Return a new NetworkX graph from the Sage graph
Return an igraph graph from the Sage graph
Create a dictionary encoding the graph.
Return a copy of the graph.
Export the graph to a file.
Return the adjacency matrix of the (di)graph.
Return an incidence matrix of the (di)graph
Return the distance matrix of the (strongly) connected (di)graph
Return the weighted adjacency matrix of the graph
Return the Kirchhoff matrix (a.k.a. the Laplacian) of the graph.
Return whether there are loops in the (di)graph
Return whether loops are permitted in the (di)graph
Change whether loops are permitted in the (di)graph
Return a list of all loops in the (di)graph
Return a list of all loops in the (di)graph
Return the number of edges that are loops
Return a list of vertices with loops
Remove loops on vertices in vertices.
Return whether there are multiple edges in the (di)graph.
Return whether multiple edges are permitted in the (di)graph.
Change whether multiple edges are permitted in the (di)graph.
Return any multiple edges in the (di)graph.
Return or set the graph’s name.
Return whether the graph is immutable.
Whether the (di)graph is to be considered as a weighted (di)graph.
Test whether the graph is antisymmetric
Return the density
Return the number of vertices.
Return the number of edges.
continues on next page1

Graph Theory, Release 10.4

Table 1 – continued from previous page
add_vertex()
add_vertices()delete_vertex()
delete_vertices()
has_vertex()
random_vertex()
random_vertex_iterator()
random_edge()
random_edge_iterator()vertex_boundary()
set_vertices()
set_vertex()
get_vertex()
get_vertices()vertex_iterator()neighbor_iterator()vertices()neighbors()
merge_vertices()
add_edge()
add_edges()
subdivide_edge()
subdivide_edges()delete_edge()
delete_edges()
contract_edge()
contract_edges()delete_multiedge()
set_edge_label()
has_edge()edges()
edge_boundary()
edge_iterator()edges_incident()
edge_label()
edge_labels()
remove_multiple_edges()
clear()
degree()average_degree()degree_histogram()degree_iterator()
degree_sequence()
random_subgraph()
add_clique()
add_cycle()
add_path()2

Create an isolated vertex.
Add vertices to the (di)graph from an iterable container of vertices
Delete vertex, removing all incident edges.
Delete vertices from the (di)graph taken from an iterable container of vertices.
Check if vertex is one of the vertices of this graph.
Return a random vertex of self.
Return an iterator over random vertices of self.
Return a random edge of self.
Return an iterator over random edges of self.
Return a list of all vertices in the external boundary of vertices1, intersectedwith vertices2.
Associate arbitrary objects with each vertex
Associate an arbitrary object with a vertex.
Retrieve the object associated with a given vertex.
Return a dictionary of the objects associated to each vertex.
Return an iterator over the given vertices.
Return an iterator over neighbors of vertex.
Return a list of the vertices.
Return a list of neighbors (in and out if directed) of vertex.
Merge vertices.
Add an edge from u to v.
Add edges from an iterable container.
Subdivide an edge 𝑘 times.
Subdivide 𝑘 times edges from an iterable container.
Delete the edge from u to v
Delete edges from an iterable container.
Contract an edge from u to v.
Contract edges from an iterable container.
Delete all edges from u to v.
Set the edge label of a given edge.
Check whether (u, v) is an edge of the (di)graph.
Return a EdgesView of edges.
Return a list of edges (u,v,l) with u in vertices1
Return an iterator over edges.
Return incident edges to some vertices.
Return the label of an edge.
Return a list of the labels of all edges in self.
Remove all multiple edges, retaining one edge for each.
Empty the graph of vertices and edges and removes name, associated objects, andposition information.
Return the degree (in + out for digraphs) of a vertex or of vertices.
Return the average degree of the graph.
Return a list, whose ith entry is the frequency of degree i.
Return an iterator over the degrees of the (di)graph.
Return the degree sequence of this (di)graph.
Return a random subgraph containing each vertex with probability p.
Add a clique to the graph with the given vertices.
Add a cycle to the graph with the given vertices.
Add a path to the graph with the given vertices.
continues on next page
Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Table 1 – continued from previous pagecomplement()
line_graph()
to_simple()disjoint_union()
union()
relabel()degree_to_cell()subgraph()
is_subgraph()

Return the complement of the (di)graph.
Return the line graph of the (di)graph.
Return a simple version of itself (i.e., undirected and loops and multiple edges are
removed).
Return the disjoint union of self and other.
Return the union of self and other.
Relabel the vertices of self
Return the number of edges from vertex to an edge in cell.
Return the subgraph containing the given vertices and edges.
Check whether self is a subgraph of other.

Graph products:
cartesian_product()tensor_product()
lexicographic_product()
strong_product()disjunctive_product()

Return the Cartesian product of self and other.
Return the tensor product, also called the categorical product, of self and other.
Return the lexicographic product of self and other.
Return the strong product of self and other.
Return the disjunctive product of self and other.

Paths and cycles:
eulerian_orientation()
eulerian_circuit()
minimum_cycle_basis()
cycle_basis()all_paths()
all_paths_iterator()
all_simple_paths()
triangles_count()
shortest_simple_paths()

Return a DiGraph which is an Eulerian orientation of the current graph.
Return a list of edges forming an Eulerian circuit if one exists.
Return a minimum weight cycle basis of the graph.
Return a list of cycles which form a basis of the cycle space of self.
Return a list of all paths (also lists) between a pair of vertices in the (di)graph.
Return an iterator over the paths of self.
Return a list of all the simple paths of self starting with one of the given vertices.
Return the number of triangles in the (di)graph.
Return an iterator over the simple paths between a pair of vertices.

Linear algebra:
spectrum()eigenvectors()
eigenspaces()

Return a list of the eigenvalues of the adjacency matrix.
Return the right eigenvectors of the adjacency matrix of the graph.
Return the right eigenspaces of the adjacency matrix of the graph.

Some metrics:

1.1. Generic graphs (common to directed/undirected)

3Graph Theory, Release 10.4

cluster_triangles()clustering_average()clustering_coeff()cluster_transitivity()szeged_index()
katz_centrality()
katz_matrix()
pagerank()

Return the number of triangles for the set nbunch of vertices as a dictionary keyedby vertex.
Return the average clustering coefficient.
Return the clustering coefficient for each vertex in nbunch
Return the transitivity (fraction of transitive triangles) of the graph.
Return the Szeged index of the graph.
Return the katz centrality of the vertex u of the graph.
Return the katz matrix of the graph.
Return the PageRank of the vertices of self.

Automorphism group:coarsest_equitable_refinement()
automorphism_group()
is_vertex_transitive()
is_isomorphic()
canonical_label()
is_cayley()

Return the coarsest partition which is finer than the input partition, and equitablewith respect to self.
Return the largest subgroup of the automorphism group of the (di)graph whose
orbit partition is finer than the partition given.
Return whether the automorphism group of self is transitive within the partition
provided
Test for isomorphism between self and other.
Return the canonical graph.
Check whether the graph is a Cayley graph.

Graph properties:
is_eulerian()
is_planar()
is_circular_planar()
is_regular()is_chordal()
is_bipartite()
is_circulant()
is_interval()
is_gallai_tree()is_clique()is_cycle()
is_geodetic()
is_independent_set()
is_transitively_reduced()
is_equitable()is_self_complementary()

Return True if the graph has a (closed) tour that visits each edge exactly once.
Check whether the graph is planar.
Check whether the graph is circular planar (outerplanar)
Return True if this graph is (𝑘-)regular.
Check whether the given graph is chordal.
Test whether the given graph is bipartite.
Check whether the graph is a circulant graph.
Check whether the graph is an interval graph.
Return whether the current graph is a Gallai tree.
Check whether a set of vertices is a clique
Check whether self is a (directed) cycle graph.
Check whether the input (di)graph is geodetic.
Check whether vertices is an independent set of self
Test whether the digraph is transitively reduced.
Check whether the given partition is equitable with respect to self.
Check whether the graph is self-complementary.

Traversals:

4

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

breadth_first_search()
depth_first_search()
lex_BFS()
lex_UP()
lex_DFS()
lex_DOWN()

Return an iterator over the vertices in a breadth-first ordering.
Return an iterator over the vertices in a depth-first ordering.
Perform a lexicographic breadth first search (LexBFS) on the graph.
Perform a lexicographic UP search (LexUP) on the graph.
Perform a lexicographic depth first search (LexDFS) on the graph.
Perform a lexicographic DOWN search (LexDOWN) on the graph.

Distances:
centrality_betweenness()
centrality_closeness()distance()
distance_all_pairs()
distances_distribution()girth()
odd_girth()shortest_path()shortest_path_length()
shortest_paths()
shortest_path_lengths()
shortest_path_all_pairs()
wiener_index()
average_distance()

Return the betweenness centrality
Returns the closeness centrality (1/average distance to all vertices)
Return the (directed) distance from u to v in the (di)graph
Return the distances between all pairs of vertices.
Return the distances distribution of the (di)graph in a dictionary.
Return the girth of the graph.
Return the odd girth of the graph.
Return a list of vertices representing some shortest path from 𝑢 to 𝑣
Return the minimal length of paths from u to v
Return a dictionary associating to each vertex v a shortest path from u to v, if itexists.
Return a dictionary of shortest path lengths keyed by targets that are connected bya path from u.
Compute a shortest path between each pair of vertices.
Return the Wiener index of the graph.
Return the average distance between vertices of the graph.

Flows, connectivity, trees:1.1. Generic graphs (common to directed/undirected)

5Graph Theory, Release 10.4

is_connected()connected_components()
connected_components_number()connected_components_subgraphs()
connected_component_containing_vertex()
connected_components_sizes()
blocks_and_cut_vertices()
blocks_and_cuts_tree()is_cut_edge()
is_cut_vertex()
edge_cut()vertex_cut()flow()
nowhere_zero_flow()
edge_disjoint_paths()
vertex_disjoint_paths()
edge_connectivity()vertex_connectivity()transitive_closure()transitive_reduction()min_spanning_tree()spanning_trees_count()
dominator_tree()connected_subgraph_iterator()

Test whether the (di)graph is connected.
Return the list of connected components
Return the number of connected components.
Return a list of connected components as graph objects.
Return a list of the vertices connected to vertex.

Return the sizes of the connected components as a list.
Compute the blocks and cut vertices of the graph.
Compute the blocks-and-cuts tree of the graph.
Return True if the input edge is a cut-edge or a bridge.
Return True if the input vertex is a cut-vertex.
Return a minimum edge cut between vertices 𝑠 and 𝑡
Return a minimum vertex cut between non-adjacent vertices 𝑠 and 𝑡
Return a maximum flow in the graph from x to y
Return a 𝑘-nowhere zero flow of the (di)graph.
Return a list of edge-disjoint paths between two vertices
Return a list of vertex-disjoint paths between two vertices
Return the edge connectivity of the graph.
Return the vertex connectivity of the graph.
Compute the transitive closure of a graph and returns it.
Return a transitive reduction of a graph.
Return the edges of a minimum spanning tree.
Return the number of spanning trees in a graph.
Returns a dominator tree of the graph.
Iterator over the induced connected subgraphs of order at most 𝑘

Plot/embedding-related methods:

6

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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.
genus()
Return the number of 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.
layout_planar()Compute a planar layout of the graph using Schnyder’s algorithm.
is_drawn_free_of_edge_crossCheck whether the position dictionary gives a planar embedding.
ings()
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()
Return a spring layout for this graphlayout_ranked()
Return a ranked layout for this graphlayout_extend_ranExtend randomly a partial layout
domly()
layout_circular()
Return a circular layout for this graphlayout_tree()Return an ordered tree layout for this graphlayout_forest()
Return an ordered forest layout for this graphlayout_graphviz()Call graphviz to compute a layout of the vertices of this graph.
_circle_embedding()
Set some vertices on a circle in the embedding of this graph.
_line_embedding()
Set 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 language in a file.
Algorithmically hard stuff:

1.1. Generic graphs (common to directed/undirected)

7Graph Theory, Release 10.4

steiner_tree()edge_disjoint_spanning_trees()
feedback_vertex_set()
multiway_cut()
max_cut()
longest_cycle()
longest_path()
traveling_salesman_problem()is_hamiltonian()
hamiltonian_cycle()hamiltonian_path()
multicommodity_flow()
disjoint_routed_paths()
dominating_set()
greedy_dominating_set()
maximum_leaf_number()subgraph_search()
subgraph_search_count()
subgraph_search_iterator()characteristic_polynomial()
genus()
crossing_number()

Return a tree of minimum weight connecting the given set of vertices.
Return the desired number of edge-disjoint spanning trees/arborescences.
Compute the minimum feedback vertex set of a (di)graph.
Return a minimum edge multiway cut
Return a maximum edge cut of the graph.
Return the longest (induced) cycle of self.
Return a longest path of self.
Solve the traveling salesman problem (TSP)
Test whether the current graph is Hamiltonian.
Return a Hamiltonian cycle/circuit of the current graph/digraph
Return a Hamiltonian path of the current graph/digraph
Solve a multicommodity flow problem.
Return a set of disjoint routed paths.
Return a minimum dominating set of the graph
Return a greedy distance-𝑘 dominating set of the graph.
Return the maximum leaf number of the graph.
Return a copy of G in self.
Return the number of labelled occurrences of G in self.
Return an iterator over the labelled copies of G in self.
Return the characteristic polynomial of the adjacency matrix of the (di)graph.
Return the minimal genus of the graph.
Return the crossing number of the graph.

Miscellaneousedge_polytope()
symmetric_edge_polytope()

Return the edge polytope of self.
Return the symmetric edge polytope of self.

1.1.1 Methods
class sage.graphs.generic_graph.GenericGraph
Bases: 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;
8

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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()Truesage: G = graphs.RandomGNP(8, .9999)
sage: H = graphs.CompleteGraph(8)sage: G == H # random - most often true
True
sage: G = Graph({0: [1, 2, 3, 4, 5, 6, 7]} )sage: H = Graph({1: [0], 2: [0], 3: [0], 4: [0], 5: [0], 6: [0], 7: [0]} )sage: G == H
True
sage: G.allow_loops(True)
sage: G == H
False
sage: G = graphs.RandomGNP(9, .3).to_directed()sage: H = graphs.RandomGNP(9, .3).to_directed()sage: G == H # most often false
False
sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edge(0, 1)
sage: H = copy(G)sage: H.add_edge(0, 1)
sage: G == H
False>>> from sage.all import *>>> G = graphs.EmptyGraph()>>> H = Graph()>>> G == H
True>>> G.to_directed() == H.to_directed()
True>>> G = graphs.RandomGNP(Integer(8), RealNumber( .9999 ))>>> H = graphs.CompleteGraph(Integer(8))>>> G == H # random - most often true
True>>> G = Graph({Integer(0): [Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5), Integer(6), Integer(7)]} )>>> H = Graph({Integer(1): [Integer(0)], Integer(2): [Integer(0)],␣
˓→Integer(3): [Integer(0)], Integer(4): [Integer(0)], Integer(5):␣
˓→[Integer(0)], Integer(6): [Integer(0)], Integer(7): [Integer(0)]} )>>> G == H
True>>> G.allow_loops(True)>>> G == H
False>>> G = graphs.RandomGNP(Integer(9), RealNumber( .3 )).to_directed()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

9Graph Theory, Release 10.4

(continued from previous page)>>> H = graphs.RandomGNP(Integer(9), RealNumber( .3 )).to_directed()>>> G == H # most often false
False>>> G = Graph(multiedges=True, sparse=True)>>> G.add_edge(Integer(0), Integer(1))>>> H = copy(G)>>> H.add_edge(Integer(0), Integer(1))>>> 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)
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>>> from sage.all import *>>> foo = Graph(sparse=True)>>> foo.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(0),␣
˓→Integer(2), Integer(2))])>>> bar = Graph(sparse=True)>>> bar.add_edges([(Integer(0), Integer(1), Integer(2)), (Integer(0),␣
˓→Integer(2), Integer(1))])>>> foo == bar
True>>> foo.weighted(True)>>> foo == bar
False>>> bar.weighted(True)>>> 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 container of vertices for the clique to be added, e.g. a list, set, graph, etc.
• loops – boolean (default: False); whether to add edges from every given vertex to itself. This isallowed only if the (di)graph allows loops.
EXAMPLES:
sage: G = Graph()
sage: G.add_clique(range(4))(continues on next page)10

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.is_isomorphic(graphs.CompleteGraph(4))
Truesage: 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))Truesage: 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>>> from sage.all import *>>> G = Graph()>>> G.add_clique(range(Integer(4)))>>> G.is_isomorphic(graphs.CompleteGraph(Integer(4)))
True>>> D = DiGraph()>>> D.add_clique(range(Integer(4)))>>> D.is_isomorphic(digraphs.Complete(Integer(4)))
True>>> D = DiGraph(loops=True)>>> D.add_clique(range(Integer(4)), loops=True)>>> D.is_isomorphic(digraphs.Complete(Integer(4), loops=True))
True>>> D = DiGraph(loops=False)>>> D.add_clique(range(Integer(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(sort=True)[(1, 1, None)]>>> from sage.all import *>>> G = Graph(loops=True)>>> G.add_clique([Integer(1), Integer(1)])>>> G.edges(sort=True)[(1, 1, None)]

This is equivalent to:
sage: G = Graph(loops=True)
sage: G.add_clique([1], loops=True)
sage: G.edges(sort=True)[(1, 1, None)]

1.1. Generic graphs (common to directed/undirected)

11Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph(loops=True)>>> G.add_clique([Integer(1)], loops=True)>>> G.edges(sort=True)[(1, 1, None)]

add_cycle(vertices)
Add a cycle to the graph with the given vertices.
If the vertices are already present, only the edges are added.
For digraphs, adds the directed cycle, whose orientation is determined by the list.
(vertices[u], vertices[u+1]) and (vertices[-1], vertices[0]).

Adds edges

INPUT:• vertices – an ordered list of the vertices of the cycle to be added
EXAMPLES:
sage: G = Graph()
sage: G.add_vertices(range(10)); G
Graph on 10 vertices
sage: show(G)˓→needs sage.plot
sage: G.add_cycle(list(range(10, 20)))
sage: show(G)˓→needs sage.plot
sage: G.add_cycle(list(range(10)))sage: show(G)˓→needs sage.plot

#␣

#␣

#␣

>>> from sage.all import *>>> G = Graph()>>> G.add_vertices(range(Integer(10))); G
Graph on 10 vertices>>> show(G)˓→needs sage.plot>>> G.add_cycle(list(range(Integer(10), Integer(20))))>>> show(G)˓→needs sage.plot>>> G.add_cycle(list(range(Integer(10))))>>> show(G)˓→needs sage.plot

#␣

#␣

#␣

sage: D = DiGraph()
sage: D.add_cycle(list(range(4)))
sage: D.edges(sort=True)[(0, 1, None), (1, 2, None), (2, 3, None), (3, 0, None)]>>> from sage.all import *>>> D = DiGraph()>>> D.add_cycle(list(range(Integer(4))))>>> D.edges(sort=True)[(0, 1, None), (1, 2, None), (2, 3, None), (3, 0, None)]

add_edge(u, v=None, label=None)
Add an edge from u to v.
12

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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.edges(sort=False)[( label , (1, 2), None)]>>> from sage.all import *>>> G = Graph()>>> G.add_edge((Integer(1), Integer(2)),>>> G.edges(sort=False)[( label , (1, 2), None)]label )You must either use the label keyword:
sage: G = Graph()
sage: G.add_edge((1, 2), label="label")
sage: G.edges(sort=False)[(1, 2, label )]>>> from sage.all import *>>> G = Graph()>>> G.add_edge((Integer(1), Integer(2)), label="label")>>> G.edges(sort=False)[(1, 2, label )]Or use one of these:
sage: G = Graph()
sage: G.add_edge(1, 2, label )sage: G.edges(sort=False)[(1, 2, label )]sage: G = Graph()
sage: G.add_edge((1, 2, label ))sage: G.edges(sort=False)[(1, 2, label )]>>> from sage.all import *>>> G = Graph()>>> G.add_edge(Integer(1), Integer(2), label )>>> G.edges(sort=False)[(1, 2, label )]>>> G = Graph()>>> G.add_edge((Integer(1), Integer(2), label ))>>> G.edges(sort=False)[(1, 2, label )]1.1. Generic graphs (common to directed/undirected)

13

Graph Theory, Release 10.4

Vertex name cannot be None, so:sage: G = Graph()
sage: G.add_edge(None, 4)
sage: G.vertices(sort=True)[0, 4]>>> from sage.all import *>>> G = Graph()>>> G.add_edge(None, Integer(4))>>> G.vertices(sort=True)[0, 4]

add_edges(edges, loops=True)
Add edges from an iterable container.
INPUT:• edges – an iterable of edges, given either as (u, v) or (u, v, label).
• loops – boolean (default: True); if False, remove all loops (v, v) from the input iterator. If
None, remove loops unless the graph allows loops.
EXAMPLES:
sage: G = graphs.DodecahedralGraph()
sage: H = Graph()
sage: H.add_edges(G.edge_iterator()); H
Graph on 20 vertices
sage: G = graphs.DodecahedralGraph().to_directed()sage: H = DiGraph()
sage: H.add_edges(G.edge_iterator()); H
Digraph on 20 vertices
sage: H.add_edges(iter([]))
sage: H = Graph()
sage: H.add_edges([(0, 1), (0, 2, "label")])sage: H.edges(sort=True)[(0, 1, None), (0, 2, label )]>>> from sage.all import *>>> G = graphs.DodecahedralGraph()>>> H = Graph()>>> H.add_edges(G.edge_iterator()); H
Graph on 20 vertices>>> G = graphs.DodecahedralGraph().to_directed()>>> H = DiGraph()>>> H.add_edges(G.edge_iterator()); H
Digraph on 20 vertices>>> H.add_edges(iter([]))>>> H = Graph()>>> H.add_edges([(Integer(0), Integer(1)), (Integer(0), Integer(2), "label")])>>> H.edges(sort=True)[(0, 1, None), (0, 2, label )]We demonstrate the loops argument:

14

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: H = Graph()
sage: H.add_edges([(0, 0)], loops=False); H.edges(sort=True)[]
sage: H.add_edges([(0, 0)], loops=None); H.edges(sort=True)[]
sage: H.add_edges([(0, 0)]); H.edges(sort=True)
Traceback (most recent call last):...
ValueError: cannot add edge from 0 to 0 in graph without loops
sage: H = Graph(loops=True)
sage: H.add_edges([(0, 0)], loops=False); H.edges(sort=True)[]
sage: H.add_edges([(0, 0)], loops=None); H.edges(sort=True)[(0, 0, None)]sage: H.add_edges([(0, 0)]); H.edges(sort=True)[(0, 0, None)]>>> from sage.all import *>>> H = Graph()>>> H.add_edges([(Integer(0), Integer(0))], loops=False); H.edges(sort=True)[]>>> H.add_edges([(Integer(0), Integer(0))], loops=None); H.edges(sort=True)[]>>> H.add_edges([(Integer(0), Integer(0))]); H.edges(sort=True)
Traceback (most recent call last):...
ValueError: cannot add edge from 0 to 0 in graph without loops>>> H = Graph(loops=True)>>> H.add_edges([(Integer(0), Integer(0))], loops=False); H.edges(sort=True)[]>>> H.add_edges([(Integer(0), Integer(0))], loops=None); H.edges(sort=True)[(0, 0, None)]>>> H.add_edges([(Integer(0), Integer(0))]); H.edges(sort=True)[(0, 0, None)]

add_path(vertices)
Add a path to the graph with the given vertices.
If the vertices are already present, only the edges are added.
For digraphs, adds the directed path vertices[0], ..., vertices[-1].
INPUT:• vertices – an ordered list of the vertices of the path to be added
EXAMPLES:
sage: G = Graph()
sage: G.add_vertices(range(10)); G
Graph on 10 vertices
sage: show(G)˓→needs sage.plot
sage: G.add_path(list(range(10, 20)))
sage: show(G)˓→needs sage.plot
sage: G.add_path(list(range(10)))sage: show(G)˓→needs sage.plot

1.1. Generic graphs (common to directed/undirected)

#␣

#␣

#␣

15

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph()>>> G.add_vertices(range(Integer(10))); G
Graph on 10 vertices>>> show(G)˓→needs sage.plot>>> G.add_path(list(range(Integer(10), Integer(20))))>>> show(G)˓→needs sage.plot>>> G.add_path(list(range(Integer(10))))>>> show(G)˓→needs sage.plot

#␣

#␣

#␣

sage: D = DiGraph()
sage: D.add_path(list(range(4)))
sage: D.edges(sort=True)[(0, 1, None), (1, 2, None), (2, 3, None)]>>> from sage.all import *>>> D = DiGraph()>>> D.add_path(list(range(Integer(4))))>>> D.edges(sort=True)[(0, 1, None), (1, 2, None), (2, 3, None)]

add_vertex(name=None)
Create an isolated vertex.
If the vertex already exists, then nothing is done.
INPUT:• name – an immutable object (default: None); when no name is specified (default), then the new vertex
will be represented by the least integer not already representing a vertex. name must be an immutableobject (e.g., an integer, a tuple, etc.).
As it is implemented now, if a graph 𝐺 has a large number of vertices with numeric labels, then G.
add_vertex() could potentially be slow, if name=None.
OUTPUT:
If name=None, the new vertex name is returned. None otherwise.
EXAMPLES:
sage: G = Graph(); G.add_vertex(); G
0Graph on 1 vertex>>> from sage.all import *>>> G = Graph(); G.add_vertex(); G
0Graph on 1 vertex
sage: D = DiGraph(); D.add_vertex(); D
0Digraph on 1 vertex

16

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> D = DiGraph(); D.add_vertex(); D
0Digraph 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.
INPUT:• vertices – iterator container of vertex labels. A new label is created, used and returned in the output
list for all None values in vertices.
OUTPUT:
Generated names of new vertices if there is at least one None value present in vertices. None otherwise.
EXAMPLES:
sage: 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(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: G.add_vertices(graphs.CycleGraph(25).vertex_iterator())
sage: G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
˓→ 22, 23, 24]>>> from sage.all import *>>> d = {Integer(0): [Integer(1),Integer(4),Integer(5)], Integer(1):␣
˓→[Integer(2),Integer(6)], Integer(2): [Integer(3),Integer(7)], Integer(3):␣
˓→[Integer(4),Integer(8)], Integer(4): [Integer(9)], Integer(5): [Integer(7),˓→Integer(8)], Integer(6): [Integer(8),Integer(9)], Integer(7): [Integer(9)]}>>> G = Graph(d)>>> G.add_vertices([Integer(10),Integer(11),Integer(12)])>>> G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]>>> G.add_vertices(graphs.CycleGraph(Integer(25)).vertex_iterator())>>> G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
˓→ 22, 23, 24]
sage: G = Graph()
sage: G.add_vertices([1, 2, 3])
sage: G.add_vertices([4, None, None, 5])[0, 6]>>> from sage.all import *>>> G = Graph()>>> G.add_vertices([Integer(1), Integer(2), Integer(3)])>>> G.add_vertices([Integer(4), None, None, Integer(5)])[0, 6]

1.1. Generic graphs (common to directed/undirected)

17

Graph Theory, Release 10.4

adjacency_matrix(sparse, vertices=None, base_ring=None, **kwds)
Return the adjacency matrix of the (di)graph.
By default, the matrix returned is over the integers.
INPUT:• sparse – boolean (default: None); whether to represent with a sparse matrix• vertices – list, None, or True (default: None);– when a list, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering ofvertices,– when None, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering
given by GenericGraph.vertices() with sort=True.
– when True, construct an endomorphism of a free module instead of a matrix, where the module’sbasis is indexed by the vertices.
If the vertices are not comparable, the keyword vertices must be used to specify an ordering, or a
TypeError exception will be raised.
• base_ring – a ring (default: ZZ); the base ring of the matrix space to use.
• **kwds – other keywords to pass to matrix().
EXAMPLES:
sage: G = graphs.CubeGraph(4)sage: G.adjacency_matrix()
˓→needs sage.modules[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]>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(4))>>> G.adjacency_matrix()
˓→needs sage.modules[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]#␣#␣(continues on next page)

18

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[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)˓→needs sage.modules sage.rings.finite_rings[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]>>> from sage.all import *>>> matrix(GF(Integer(2)), G) # matrix over GF(2)˓→# needs sage.modules sage.rings.finite_rings[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()
˓→needs sage.modules[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.1. Generic graphs (common to directed/undirected)

#␣

␣

#␣

(continues on next page)19

Graph Theory, Release 10.4

(continued from previous page)[1 0 0 0 0 1]
[0 1 0 0 0 0]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(0), Integer(2)], Integer(2): [Integer(3)],...
Integer(3): [Integer(4)], Integer(4): [Integer(0),␣
˓→Integer(5)], Integer(5): [Integer(1)]})>>> D.adjacency_matrix()
˓→needs sage.modules[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])
˓→needs sage.modules[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]

#␣>>> from sage.all import *>>> graphs.PathGraph(Integer(5)).adjacency_matrix(vertices=[Integer(2),␣
˓→Integer(4), Integer(1), Integer(3), Integer(0)])# needs sage.modules[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]

A different base ring:sage: graphs.PathGraph(5).adjacency_matrix(base_ring=RDF)
˓→needs sage.modules[0.0 1.0 0.0 0.0 0.0]
[1.0 0.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0]
[0.0 0.0 1.0 0.0 1.0]
[0.0 0.0 0.0 1.0 0.0]
sage: type(_)˓→needs sage.modules<class sage.matrix.matrix_real_double_dense.Matrix_real_double_dense >>>> from sage.all import *>>> graphs.PathGraph(Integer(5)).adjacency_matrix(base_ring=RDF)˓→# needs sage.modules[0.0 1.0 0.0 0.0 0.0]
[1.0 0.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0]

#␣

#␣

␣

(continues on next page)

20

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[0.0 0.0 1.0 0.0 1.0]
[0.0 0.0 0.0 1.0 0.0]>>> type(_)˓→needs sage.modules<class sage.matrix.matrix_real_double_dense.Matrix_real_double_dense >#␣A different matrix implementation:
sage: graphs.PathGraph(5).adjacency_matrix(sparse=False,#␣˓→needs numpy sage.modules....:
implementation= numpy )[0 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[0 0 1 0 1]
[0 0 0 1 0]
sage: type(_)<class sage.matrix.matrix_numpy_integer_dense.Matrix_numpy_integer_dense >>>> from sage.all import *>>> graphs.PathGraph(Integer(5)).adjacency_matrix(sparse=False,˓→# needs numpy sage.modules...
implementation= numpy )[0 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[0 0 1 0 1]
[0 0 0 1 0]>>> type(_)<class sage.matrix.matrix_numpy_integer_dense.Matrix_numpy_integer_dense >␣As an immutable matrix:
sage: M = graphs.PathGraph(5).adjacency_matrix(sparse=False,
˓→needs sage.modules....:
immutable=True); M[0 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[0 0 1 0 1]
[0 0 0 1 0]
sage: M[2, 2] = 1
˓→needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).
>>> from sage.all import *>>> M = graphs.PathGraph(Integer(5)).adjacency_matrix(sparse=False,˓→# needs sage.modules...
immutable=True); M[0 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[0 0 1 0 1]

#␣

#␣

␣

(continues on next page)

1.1. Generic graphs (common to directed/undirected)

21

Graph Theory, Release 10.4

(continued from previous page)[0 0 0 1 0]>>> M[Integer(2), Integer(2)] = Integer(1)˓→# needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).

␣Creating a module endomorphism:
sage: # needs sage.modules
sage: D12 = posets.DivisorLattice(12).hasse_diagram()
sage: phi = D12.adjacency_matrix(vertices=True); phi
Generic endomorphism ofFree module generated by {1, 2, 3, 4, 6, 12} over Integer Ringsage: print(phi._unicode_art_matrix())
1 2 3 4 6 121⎛ 0 1 1 0 0 0⎞
2⎜ 0 0 0 1 1 0⎟
3⎜ 0 0 0 0 1 0⎟
4⎜ 0 0 0 0 0 1⎟
6⎜ 0 0 0 0 0 1⎟
12⎝ 0 0 0 0 0 0⎠>>> from sage.all import *>>> # needs sage.modules>>> D12 = posets.DivisorLattice(Integer(12)).hasse_diagram()>>> phi = D12.adjacency_matrix(vertices=True); phi
Generic endomorphism ofFree module generated by {1, 2, 3, 4, 6, 12} over Integer Ring>>> print(phi._unicode_art_matrix())
1 2 3 4 6 121⎛ 0 1 1 0 0 0⎞
2⎜ 0 0 0 1 1 0⎟
3⎜ 0 0 0 0 1 0⎟
4⎜ 0 0 0 0 0 1⎟
6⎜ 0 0 0 0 0 1⎟
12⎝ 0 0 0 0 0 0⎠

all_paths(G, start, end, use_multiedges=False, report_edges=False, labels=False)
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”.
If G has multiple edges, a path will be returned as many times as the product of the multiplicity of the edges
along that path depending on the value of the flag use_multiedges.
INPUT:• start – a vertex of a graph, where to start• end – a vertex of a graph, where to end• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple
edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected for

22

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

each edge as in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges is True
– If True, a path will be reported as many times as the edges multiplicities along that path (whenreport_edges = False or labels = False), or with all possible combinations of edge
labels (when report_edges = True and labels = True)• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or listof edges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices.
Otherwise a list of edges along with its edge labels are used to represent the path.
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],[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]]
sage: g = Graph([(0, 1), (0, 1), (1, 2), (1, 2)], multiedges=True)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

23

Graph Theory, Release 10.4

(continued from previous page)

sage: g.all_paths(0, 2, use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: dg = DiGraph({0:[1, 2, 1], 3:[0, 0]}, multiedges=True)
sage: dg.all_paths(3, 1, use_multiedges=True)[[3, 0, 1], [3, 0, 1], [3, 0, 1], [3, 0, 1]]
sage: g = Graph([(0, 1, a ), (0, 1, b ), (1, 2, c ), (1, 2, d )],␣˓→multiedges=True)
sage: g.all_paths(0, 2, use_multiedges=False)[[0, 1, 2]]
sage: g.all_paths(0, 2, use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: g.all_paths(0, 2, use_multiedges=True, report_edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]sage: g.all_paths(0, 2, use_multiedges=True, report_edges=True, labels=True)[((0, 1, b ), (1, 2, d )),((0, 1, b ), (1, 2, c )),((0, 1, a ), (1, 2, d )),((0, 1, a ), (1, 2, c ))]sage: g.all_paths(0, 2, use_multiedges=False, report_edges=True, labels=True)[((0, 1, b ), (1, 2, d ))]sage: g.all_paths(0, 2, use_multiedges=False, report_edges=False, labels=True)[[0, 1, 2]]
sage: g.all_paths(0, 2, use_multiedges=True, report_edges=False, labels=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> from sage.all import *>>> eg1 = Graph({Integer(0):[Integer(1), Integer(2)], Integer(1):[Integer(4)],
˓→ Integer(2):[Integer(3), Integer(4)], Integer(4):[Integer(5)],␣
˓→Integer(5):[Integer(6)]})>>> eg1.all_paths(Integer(0), Integer(6))[[0, 1, 4, 5, 6], [0, 2, 4, 5, 6]]>>> eg2 = graphs.PetersenGraph()>>> sorted(eg2.all_paths(Integer(1), Integer(4)))[[1, 0, 4],[1, 0, 5, 7, 2, 3, 4],[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],(continues on next page)

24

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[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]]>>> dg = DiGraph({Integer(0):[Integer(1), Integer(3)],␣
˓→Integer(1):[Integer(3)], Integer(2):[Integer(0), Integer(3)]})>>> sorted(dg.all_paths(Integer(0), Integer(3)))[[0, 1, 3], [0, 3]]>>> ug = dg.to_undirected()>>> sorted(ug.all_paths(Integer(0), Integer(3)))[[0, 1, 3], [0, 2, 3], [0, 3]]>>> g = Graph([(Integer(0), Integer(1)), (Integer(0), Integer(1)),␣
˓→(Integer(1), Integer(2)), (Integer(1), Integer(2))], multiedges=True)>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> dg = DiGraph({Integer(0):[Integer(1), Integer(2), Integer(1)],␣
˓→Integer(3):[Integer(0), Integer(0)]}, multiedges=True)>>> dg.all_paths(Integer(3), Integer(1), use_multiedges=True)[[3, 0, 1], [3, 0, 1], [3, 0, 1], [3, 0, 1]]>>> g = Graph([(Integer(0), Integer(1), a ), (Integer(0), Integer(1), b ),␣
˓→(Integer(1), Integer(2),c ), (Integer(1), Integer(2), d )],␣˓→multiedges=True)>>> g.all_paths(Integer(0), Integer(2), use_multiedges=False)[[0, 1, 2]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_
˓→edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_
˓→edges=True, labels=True)[((0, 1, b ), (1, 2, d )),((0, 1, b ), (1, 2, c )),((0, 1, a ), (1, 2, d )),((0, 1, a ), (1, 2, c ))]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=False, report_
˓→edges=True, labels=True)[((0, 1, b ), (1, 2, d ))]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=False, report_
˓→edges=False, labels=True)[[0, 1, 2]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_
˓→edges=False, labels=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]

all_paths_iterator(starting_vertices=None, ending_vertices=None, simple=False, max_length=None,trivial=False, use_multiedges=False, report_edges=False, labels=False)
Return an iterator over the paths of self.
1.1. Generic graphs (common to directed/undirected)

25

Graph Theory, Release 10.4

The paths are enumerated in increasing length order.
INPUT:• starting_vertices – iterable (default: None); vertices from which the paths must start. If None,then all vertices of the graph can be starting points.
• ending_vertices – iterable (default: None); allowed ending vertices of the paths. If None, thenall vertices are allowed.
• simple – boolean (default: False); if set to True, then only simple paths are considered. Simple
paths are paths in which no two arcs share a head or share a tail, i.e. every vertex in the path is enteredat 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.
• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple
edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected foreach edge as in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges is True
– If True, a path will be reported as many times as the edges multiplicities along that path (whenreport_edges = False or labels = False), or with all possible combinations of edge
labels (when report_edges = True and labels = True)• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or listof edges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices.
Otherwise a list of edges along with its edge labels are used to represent the path.
OUTPUT:
iterator
AUTHOR:
Alexandre Blondin Masse
EXAMPLES:
sage: G = graphs.CompleteGraph(4)sage: list(G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3],␣
˓→simple=True))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]
sage: list(G.shortest_simple_paths(1, 3))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]
sage: pi = G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3])sage: for _ in range(6):....:print(next(pi))[1, 3][1, 0, 3][1, 2, 3][1, 0, 1, 3][1, 0, 2, 3][1, 2, 0, 3]
sage: g = DiGraph({ a : [ a ,b ],b : [ c ],c : [ d ],d : [ c ]},␣(continues on next page)

26

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)loops=True)
sage: pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ d˓→ ], report_edges=True, simple=True)
sage: list(pi)[[( a , b ), ( b , c ), ( c , d )]]˓→sage: g = DiGraph([(0, 1, a ), (0, 1, b ), (1, 2, c ), (1, 2, d )],␣˓→multiedges=True)
sage: pi = g.all_paths_iterator(starting_vertices=[0], use_multiedges=True)
sage: for _ in range(6):....:print(next(pi))[0, 1][0, 1][0, 1, 2][0, 1, 2][0, 1, 2][0, 1, 2]
sage: pi = g.all_paths_iterator(starting_vertices=[0], use_multiedges=True,␣
˓→report_edges=True, labels=True)
sage: for _ in range(6):....:print(next(pi))[(0, 1, b )][(0, 1, a )][(0, 1, b ), (1, 2, d )][(0, 1, b ), (1, 2, c )][(0, 1, a ), (1, 2, d )][(0, 1, a ), (1, 2, c )]sage: list(g.all_paths_iterator(starting_vertices=[0, 1], ending_vertices=[2],˓→ use_multiedges=False, report_edges=True, labels=True, simple=True))[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]sage: list(g.all_paths_iterator(starting_vertices=[0, 1], ending_vertices=[2],˓→ use_multiedges=False, report_edges=False, labels=True))[[1, 2], [0, 1, 2]]
sage: list(g.all_paths_iterator(use_multiedges=True, report_edges=False,␣
˓→labels=True, max_length=1))[[1, 2], [1, 2], [0, 1], [0, 1]]
sage: list(g.all_paths_iterator(use_multiedges=True, report_edges=True,␣
˓→labels=True, max_length=1))[[(1, 2, d )], [(1, 2, c )], [(0, 1, b )], [(0, 1, a )]]sage: g = DiGraph({ a : [ a , b ], b : [ c ],˓→loops=True)
sage: pi = g.all_paths_iterator()sage: [len(next(pi)) - 1 for _ in range(7)][1, 1, 1, 1, 1, 2, 2]

c : [ d ],d : [ c ]},␣>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> list(G.all_paths_iterator(starting_vertices=[Integer(1)], ending_˓→vertices=[Integer(3)], simple=True))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]>>> list(G.shortest_simple_paths(Integer(1), Integer(3)))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]>>> pi = G.all_paths_iterator(starting_vertices=[Integer(1)], ending_˓→vertices=[Integer(3)])>>> for _ in range(Integer(6)):(continues on next page)

1.1. Generic graphs (common to directed/undirected)

27

Graph Theory, Release 10.4

(continued from previous page)...
print(next(pi))[1, 3][1, 0, 3][1, 2, 3][1, 0, 1, 3][1, 0, 2, 3][1, 2, 0, 3]>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ d ],␣
˓→report_edges=True, simple=True)>>> list(pi)[[( a , b ), ( b , c ), ( c , d )]]>>> g = DiGraph([(Integer(0), Integer(1), a ), (Integer(0), Integer(1), b ),˓→ (Integer(1), Integer(2), c ), (Integer(1), Integer(2), d )],␣˓→multiedges=True)>>> pi = g.all_paths_iterator(starting_vertices=[Integer(0)], use_
˓→multiedges=True)>>> for _ in range(Integer(6)):...
print(next(pi))[0, 1][0, 1][0, 1, 2][0, 1, 2][0, 1, 2][0, 1, 2]>>> pi = g.all_paths_iterator(starting_vertices=[Integer(0)], use_
˓→multiedges=True, report_edges=True, labels=True)>>> for _ in range(Integer(6)):...
print(next(pi))[(0, 1, b )][(0, 1, a )][(0, 1, b ), (1, 2, d )][(0, 1, b ), (1, 2, c )][(0, 1, a ), (1, 2, d )][(0, 1, a ), (1, 2, c )]>>> list(g.all_paths_iterator(starting_vertices=[Integer(0), Integer(1)],␣
˓→ending_vertices=[Integer(2)], use_multiedges=False, report_edges=True,␣
˓→labels=True, simple=True))[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]>>> list(g.all_paths_iterator(starting_vertices=[Integer(0), Integer(1)],␣
˓→ending_vertices=[Integer(2)], use_multiedges=False, report_edges=False,␣
˓→labels=True))[[1, 2], [0, 1, 2]]>>> list(g.all_paths_iterator(use_multiedges=True, report_edges=False,␣
˓→labels=True, max_length=Integer(1)))[[1, 2], [1, 2], [0, 1], [0, 1]]>>> list(g.all_paths_iterator(use_multiedges=True, report_edges=True,␣
˓→labels=True, max_length=Integer(1)))[[(1, 2, d )], [(1, 2, c )], [(0, 1, b )], [(0, 1, a )]]>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)>>> pi = g.all_paths_iterator()>>> [len(next(pi)) - Integer(1) for _ in range(Integer(7))](continues on next page)

28

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[1, 1, 1, 1, 1, 2, 2]

It is possible to precise the allowed starting and/or ending vertices:sage: pi = g.all_paths_iterator(starting_vertices=[ a ])sage: [len(next(pi)) - 1 for _ in range(5)][1, 1, 2, 2, 2]
sage: pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b˓→ ])sage: for _ in range(5):....:print(next(pi))[ a , b ][ a , a , b ][ a , a , a , b ][ a , a , a , a , b ][ a , a , a , a , a , b ]>>> from sage.all import *>>> pi = g.all_paths_iterator(starting_vertices=[ a ])>>> [len(next(pi)) - Integer(1) for _ in range(Integer(5))][1, 1, 2, 2, 2]>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ])>>> for _ in range(Integer(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: sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d ,[ a , b , c , d ]]sage: pi = g.all_paths_iterator(simple=True)
sage: [len(p) - 1 for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]>>> from sage.all import *>>> pi = g.all_paths_iterator(simple=True)>>> sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d ,[ a , b , c , d ]]>>> pi = g.all_paths_iterator(simple=True)>>> [len(p) - Integer(1) for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]

c ,

d ],

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: sorted(list(pi), key=lambda x:(len(x), x))(continues on next page)

1.1. Generic graphs (common to directed/undirected)

29

Graph Theory, Release 10.4

(continued from previous page)[[ 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 ]]sage: pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ,˓→c ], max_length=6)
sage: [len(p) - 1 for p in pi][1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6]>>> from sage.all import *>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ,˓→ c ], max_length=Integer(6))>>> sorted(list(pi), key=lambda x:(len(x), x))[[ 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 ]]>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ,˓→ c ], max_length=Integer(6))>>> [len(p) - Integer(1) for p in pi][1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6]

By default, empty paths are not enumerated, but it may be parametrized:
sage: pi = g.all_paths_iterator(simple=True, trivial=True)
sage: sorted(list(pi), key=lambda x:(len(x), x))[[ 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=True)
sage: [len(p) - 1 for p in pi][0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3]
sage: pi = g.all_paths_iterator(simple=True, trivial=False)
sage: sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d , c ,[ a , b , c , d ]]sage: pi = g.all_paths_iterator(simple=True, trivial=False)
sage: [len(p) - 1 for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]

d ],>>> from sage.all import *>>> pi = g.all_paths_iterator(simple=True, trivial=True)>>> sorted(list(pi), key=lambda x:(len(x), x))[[ a ], [ b ], [ c ], [ d ], [ a , a ], [ a , b ], [ b , c ],[ c , d ], [ d , c ], [ a , b , c ], [ b , c , d ],(continues on next page)

30

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[ c , d , c ], [ d , c , d ], [ a , b , c , d ]]>>> pi = g.all_paths_iterator(simple=True, trivial=True)>>> [len(p) - Integer(1) for p in pi][0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3]>>> pi = g.all_paths_iterator(simple=True, trivial=False)>>> sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d ,[ a , b , c , d ]]>>> pi = g.all_paths_iterator(simple=True, trivial=False)>>> [len(p) - Integer(1) for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]

c ,

d ],

all_simple_paths(starting_vertices=None, ending_vertices=None, max_length=None, trivial=False,
use_multiedges=False, report_edges=False, labels=False)
Return 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 enteredat most once and exited at most once.
INPUT:• starting_vertices – list (default: None); vertices from which the paths must start. If None,then all vertices of the graph can be starting points.
• ending_vertices – iterable (default: None); allowed ending vertices of the paths. If None, thenall 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.
• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple
edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected foreach edge as in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges is True
– If True, a path will be reported as many times as the edges multiplicities along that path (whenreport_edges = False or labels = False), or with all possible combinations of edge
labels (when report_edges = True and labels = True)• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or listof edges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices.
Otherwise a list of edges along with its edge labels are used to represent the path.
OUTPUT:
list
Note: Although the number of simple paths of a finite graph is always finite, computing all its paths may
take a very long time.
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

31Graph Theory, Release 10.4

sage: G = graphs.CompleteGraph(4)sage: G.all_simple_paths([1], [3])[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]
sage: list(G.shortest_simple_paths(1, 3))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]
sage: G.all_simple_paths([0, 1], [2, 3])[[1, 2],[1, 3],[0, 2],[0, 3],[0, 1, 2],[0, 1, 3],[0, 2, 3],[0, 3, 2],[1, 0, 2],[1, 0, 3],[1, 2, 3],[1, 3, 2],[1, 0, 2, 3],[1, 0, 3, 2],[1, 2, 0, 3],[1, 3, 0, 2],[0, 1, 2, 3],[0, 1, 3, 2],[0, 2, 1, 3],[0, 3, 1, 2]]
sage: g = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True)
sage: g.all_simple_paths()[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3],[0, 1, 2, 3]]
sage: g = DiGraph([(0, 1, a ), (0, 1, b ), (1, 2, c ), (1, 2, d )],␣˓→multiedges=True)
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=False)[[0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True, report_edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True, report_edges=True, labels=True)[[(0, 1, b ), (1, 2, d )],[(0, 1, b ), (1, 2, c )],[(0, 1, a ), (1, 2, d )],[(0, 1, a ), (1, 2, c )]](continues on next page)

32

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_
˓→multiedges=False, report_edges=True, labels=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_
˓→multiedges=False, report_edges=False, labels=True)[[1, 2], [0, 1, 2]]
sage: g.all_simple_paths(use_multiedges=True, report_edges=False, labels=True)[[1, 2], [1, 2], [0, 1], [0, 1], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_
˓→multiedges=False, report_edges=True, labels=True, trivial=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> G.all_simple_paths([Integer(1)], [Integer(3)])[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]>>> list(G.shortest_simple_paths(Integer(1), Integer(3)))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]>>> G.all_simple_paths([Integer(0), Integer(1)], [Integer(2), Integer(3)])[[1, 2],[1, 3],[0, 2],[0, 3],[0, 1, 2],[0, 1, 3],[0, 2, 3],[0, 3, 2],[1, 0, 2],[1, 0, 3],[1, 2, 3],[1, 3, 2],[1, 0, 2, 3],[1, 0, 3, 2],[1, 2, 0, 3],[1, 3, 0, 2],[0, 1, 2, 3],[0, 1, 3, 2],[0, 2, 1, 3],[0, 3, 1, 2]]>>> g = DiGraph({Integer(0): [Integer(0), Integer(1)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(2)]},␣
˓→loops=True)>>> g.all_simple_paths()[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3],[0, 1, 2, 3]]>>> g = DiGraph([(Integer(0), Integer(1),a ), (Integer(0), Integer(1),b ),(continues on next page)

1.1. Generic graphs (common to directed/undirected)

33

Graph Theory, Release 10.4

(continued from previous page)(Integer(1), Integer(2), c ), (Integer(1), Integer(2), d )],␣˓→multiedges=True)>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=False)[[0, 1, 2]]>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=True, report_edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=True, report_edges=True, labels=True)[[(0, 1, b ), (1, 2, d )],[(0, 1, b ), (1, 2, c )],[(0, 1, a ), (1, 2, d )],[(0, 1, a ), (1, 2, c )]]>>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]>>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=False,␣
˓→labels=True)[[1, 2], [0, 1, 2]]>>> g.all_simple_paths(use_multiedges=True, report_edges=False, labels=True)[[1, 2], [1, 2], [0, 1], [0, 1], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True,
˓→ trivial=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]˓→One may compute all paths having specific starting and/or ending vertices:sage: g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)
sage: g.all_simple_paths(starting_vertices=[ a ])[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]sage: g.all_simple_paths(starting_vertices=[ a ], ending_vertices=[ c ])[[ a , b , c ]]sage: g.all_simple_paths(starting_vertices=[ a ], ending_vertices=[ b , c ])[[ a , b ], [ a , b , c ]]>>> from sage.all import *>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)>>> g.all_simple_paths(starting_vertices=[ a ])[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]>>> g.all_simple_paths(starting_vertices=[ a ], ending_vertices=[ c ])[[ a , b , c ]]>>> 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 = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True)
sage: g.all_simple_paths(max_length=2)(continues on next page)

34

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3]]>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(0), Integer(1)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(2)]},␣
˓→loops=True)>>> g.all_simple_paths(max_length=Integer(2))[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3]]

By default, empty paths are not enumerated, but this can be parametrized:
sage: g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)
sage: g.all_simple_paths(starting_vertices=[ a ], trivial=True)[[ a ], [ a , a ], [ a , b ], [ a , b , c ],[ a , b , c , d ]]sage: g.all_simple_paths(starting_vertices=[ a ], trivial=False)[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]>>> from sage.all import *>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)>>> g.all_simple_paths(starting_vertices=[ a ], trivial=True)[[ a ], [ a , a ], [ a , b ], [ a , b , c ],[ a , b , c , d ]]>>> g.all_simple_paths(starting_vertices=[ a ], trivial=False)[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]allow_loops(new, check=True)
Change whether loops are permitted in the (di)graph
INPUT:• new – boolean• check – boolean (default: True); whether to remove existing loops from the (di)graph when the new
status is False
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

35

Graph Theory, Release 10.4

sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edge((0, 0))
sage: G.has_loops()
True
sage: G.loops()[(0, 0, None)]sage: G.allow_loops(False); G
Graph on 1 vertex
sage: G.has_loops()
False
sage: G.edges(sort=True)[]
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()[(0, 0, None)]sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)[]>>> from sage.all import *>>> G = Graph(loops=True); G
Looped graph on 0 vertices>>> G.has_loops()
False>>> G.allows_loops()
True>>> G.add_edge((Integer(0), Integer(0)))>>> G.has_loops()
True>>> G.loops()[(0, 0, None)]>>> G.allow_loops(False); G
Graph on 1 vertex>>> G.has_loops()
False>>> G.edges(sort=True)[]>>> D = DiGraph(loops=True); D
Looped digraph on 0 vertices(continues on next page)

36

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> D.has_loops()
False>>> D.allows_loops()
True>>> D.add_edge((Integer(0), Integer(0)))>>> D.has_loops()
True>>> D.loops()[(0, 0, None)]>>> D.allow_loops(False); D
Digraph on 1 vertex>>> D.has_loops()
False>>> D.edges(sort=True)[]

allow_multiple_edges(new, check=True, keep_label='any')
Change whether multiple edges are permitted in the (di)graph.
INPUT:• new – boolean; if True, the new graph will allow multiple edges• check – boolean (default: True); if True and new is False, we remove all multiple edges from thegraph• keep_label – string (default: any ); 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 – any label–

min – the smallest label–

max – the largest label

Warning:
min and max only works if the labels can be compared. A TypeError might beraised when working with non-comparable objects.
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(continues on next page)

1.1. Generic graphs (common to directed/undirected)

37

Graph Theory, Release 10.4

(continued from previous page)

sage: G.edges(sort=True)[(0, 1, 3)]>>> from sage.all import *>>> G = Graph(multiedges=True, sparse=True); G
Multi-graph on 0 vertices>>> G.has_multiple_edges()
False>>> G.allows_multiple_edges()
True>>> G.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(0),␣
˓→Integer(1), Integer(2)), (Integer(0), Integer(1), Integer(3))])>>> G.has_multiple_edges()
True>>> G.multiple_edges(sort=True)[(0, 1, 1), (0, 1, 2), (0, 1, 3)]>>> G.allow_multiple_edges(False); G
Graph on 2 vertices>>> G.has_multiple_edges()
False>>> G.edges(sort=True)[(0, 1, 3)]

If we ask for the minimum 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= min )sage: G.edges(sort=True)[(0, 1, 1)]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1), Integer(1)), (Integer(0), Integer(1),␣
˓→Integer(2)), (Integer(0), Integer(1), Integer(3))], multiedges=True,␣
˓→sparse=True)>>> G.allow_multiple_edges(False, keep_label= min )>>> G.edges(sort=True)[(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(sort=True)[(0, 1, 3)]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1), Integer(1)), (Integer(0), Integer(1),␣
˓→Integer(2)), (Integer(0), Integer(1), Integer(3))], multiedges=True,␣
˓→sparse=True)>>> G.allow_multiple_edges(False, keep_label= max )>>> G.edges(sort=True)[(0, 1, 3)]

The standard behavior with digraphs:
38

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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(sort=True)[(0, 1, None)]>>> from sage.all import *>>> D = DiGraph(multiedges=True, sparse=True); D
Multi-digraph on 0 vertices>>> D.has_multiple_edges()
False>>> D.allows_multiple_edges()
True>>> D.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> D.has_multiple_edges()
True>>> D.multiple_edges()[(0, 1, None), (0, 1, None), (0, 1, None)]>>> D.allow_multiple_edges(False); D
Digraph on 2 vertices>>> D.has_multiple_edges()
False>>> D.edges(sort=True)[(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(continues on next page)

1.1. Generic graphs (common to directed/undirected)

39

Graph Theory, Release 10.4

(continued from previous page)

sage: G.edges(sort=True)[]
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()[(0, 0, None)]sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)[]>>> from sage.all import *>>> G = Graph(loops=True); G
Looped graph on 0 vertices>>> G.has_loops()
False>>> G.allows_loops()
True>>> G.add_edge((Integer(0), Integer(0)))>>> G.has_loops()
True>>> G.loops()[(0, 0, None)]>>> G.allow_loops(False); G
Graph on 1 vertex>>> G.has_loops()
False>>> G.edges(sort=True)[]>>> D = DiGraph(loops=True); D
Looped digraph on 0 vertices>>> D.has_loops()
False>>> D.allows_loops()
True>>> D.add_edge((Integer(0), Integer(0)))>>> D.has_loops()
True>>> D.loops()[(0, 0, None)]>>> D.allow_loops(False); D
Digraph on 1 vertex>>> D.has_loops()
False>>> D.edges(sort=True)[]

40

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

allows_multiple_edges()
Return 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(sort=True)[(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(sort=True)[(0, 1, None)]>>> from sage.all import *>>> G = Graph(multiedges=True, sparse=True); G
Multi-graph on 0 vertices>>> G.has_multiple_edges()
False>>> G.allows_multiple_edges()
True>>> G.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> G.has_multiple_edges()
True>>> G.multiple_edges()[(0, 1, None), (0, 1, None), (0, 1, None)]>>> G.allow_multiple_edges(False); G
Graph on 2 vertices>>> G.has_multiple_edges()
False>>> G.edges(sort=True)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

41

Graph Theory, Release 10.4

(continued from previous page)[(0, 1, None)]>>> D = DiGraph(multiedges=True, sparse=True); D
Multi-digraph on 0 vertices>>> D.has_multiple_edges()
False>>> D.allows_multiple_edges()
True>>> D.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> D.has_multiple_edges()
True>>> D.multiple_edges()[(0, 1, None), (0, 1, None), (0, 1, None)]>>> D.allow_multiple_edges(False); D
Digraph on 2 vertices>>> D.has_multiple_edges()
False>>> D.edges(sort=True)[(0, 1, None)]am(sparse, vertices=None, base_ring=None, **kwds)
Return the adjacency matrix of the (di)graph.
By default, the matrix returned is over the integers.
INPUT:• sparse – boolean (default: None); whether to represent with a sparse matrix• vertices – list, None, or True (default: None);– when a list, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering ofvertices,– when None, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering
given by GenericGraph.vertices() with sort=True.
– when True, construct an endomorphism of a free module instead of a matrix, where the module’sbasis is indexed by the vertices.
If the vertices are not comparable, the keyword vertices must be used to specify an ordering, or a
TypeError exception will be raised.
• base_ring – a ring (default: ZZ); the base ring of the matrix space to use.
• **kwds – other keywords to pass to matrix().
EXAMPLES:
sage: G = graphs.CubeGraph(4)sage: G.adjacency_matrix()
˓→needs sage.modules[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]

#␣(continues on next page)

42

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[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]>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(4))>>> G.adjacency_matrix()
˓→needs sage.modules[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)˓→needs sage.modules sage.rings.finite_rings[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]>>> from sage.all import *>>> matrix(GF(Integer(2)), G) # matrix over GF(2)˓→# needs sage.modules sage.rings.finite_rings[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.1. Generic graphs (common to directed/undirected)

#␣

#␣

␣

(continues on next page)43

Graph Theory, Release 10.4

(continued from previous page)[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()
˓→needs sage.modules[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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(0), Integer(2)], Integer(2): [Integer(3)],...
Integer(3): [Integer(4)], Integer(4): [Integer(0),␣
˓→Integer(5)], Integer(5): [Integer(1)]})>>> D.adjacency_matrix()
˓→needs sage.modules[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])
˓→needs sage.modules[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]

#␣>>> from sage.all import *>>> graphs.PathGraph(Integer(5)).adjacency_matrix(vertices=[Integer(2),␣
˓→Integer(4), Integer(1), Integer(3), Integer(0)])# needs sage.modules[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]44

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

A different base ring:sage: graphs.PathGraph(5).adjacency_matrix(base_ring=RDF)
˓→needs sage.modules[0.0 1.0 0.0 0.0 0.0]
[1.0 0.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0]
[0.0 0.0 1.0 0.0 1.0]
[0.0 0.0 0.0 1.0 0.0]
sage: type(_)˓→needs sage.modules<class sage.matrix.matrix_real_double_dense.Matrix_real_double_dense >>>> from sage.all import *>>> graphs.PathGraph(Integer(5)).adjacency_matrix(base_ring=RDF)˓→# needs sage.modules[0.0 1.0 0.0 0.0 0.0]
[1.0 0.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0]
[0.0 0.0 1.0 0.0 1.0]
[0.0 0.0 0.0 1.0 0.0]>>> type(_)˓→needs sage.modules<class sage.matrix.matrix_real_double_dense.Matrix_real_double_dense >

#␣

#␣

␣

#␣

A different matrix implementation:
sage: graphs.PathGraph(5).adjacency_matrix(sparse=False,#␣˓→needs numpy sage.modules....:
implementation= numpy )[0 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[0 0 1 0 1]
[0 0 0 1 0]
sage: type(_)<class sage.matrix.matrix_numpy_integer_dense.Matrix_numpy_integer_dense >>>> from sage.all import *>>> graphs.PathGraph(Integer(5)).adjacency_matrix(sparse=False,˓→# needs numpy sage.modules...
implementation= numpy )[0 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[0 0 1 0 1]
[0 0 0 1 0]>>> type(_)<class sage.matrix.matrix_numpy_integer_dense.Matrix_numpy_integer_dense >␣As an immutable matrix:
sage: M = graphs.PathGraph(5).adjacency_matrix(sparse=False,
˓→needs sage.modules....:
immutable=True); M[0 1 0 0 0]
[1 0 1 0 0]#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

45

Graph Theory, Release 10.4

(continued from previous page)[0 1 0 1 0]
[0 0 1 0 1]
[0 0 0 1 0]
sage: M[2, 2] = 1
˓→needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).
>>> from sage.all import *>>> M = graphs.PathGraph(Integer(5)).adjacency_matrix(sparse=False,˓→# needs sage.modules...
immutable=True); M[0 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[0 0 1 0 1]
[0 0 0 1 0]>>> M[Integer(2), Integer(2)] = Integer(1)˓→# needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).

#␣

␣

␣

Creating a module endomorphism:
sage: # needs sage.modules
sage: D12 = posets.DivisorLattice(12).hasse_diagram()
sage: phi = D12.adjacency_matrix(vertices=True); phi
Generic endomorphism ofFree module generated by {1, 2, 3, 4, 6, 12} over Integer Ringsage: print(phi._unicode_art_matrix())
1 2 3 4 6 121⎛ 0 1 1 0 0 0⎞
2⎜ 0 0 0 1 1 0⎟
3⎜ 0 0 0 0 1 0⎟
4⎜ 0 0 0 0 0 1⎟
6⎜ 0 0 0 0 0 1⎟
12⎝ 0 0 0 0 0 0⎠>>> from sage.all import *>>> # needs sage.modules>>> D12 = posets.DivisorLattice(Integer(12)).hasse_diagram()>>> phi = D12.adjacency_matrix(vertices=True); phi
Generic endomorphism ofFree module generated by {1, 2, 3, 4, 6, 12} over Integer Ring>>> print(phi._unicode_art_matrix())
1 2 3 4 6 121⎛ 0 1 1 0 0 0⎞
2⎜ 0 0 0 1 1 0⎟
3⎜ 0 0 0 0 1 0⎟
4⎜ 0 0 0 0 0 1⎟
6⎜ 0 0 0 0 0 1⎟
12⎝ 0 0 0 0 0 0⎠46

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

antisymmetric()
Check whether the graph is antisymmetric.
A graph represents an antisymmetric relation if the existence of a path from a vertex 𝑥 to a vertex 𝑦 implies
that there is not a path from 𝑦 to 𝑥 unless 𝑥 = 𝑦.
EXAMPLES:
A directed acyclic graph is antisymmetric:
sage: G = digraphs.RandomDirectedGNR(20, 0.5)
˓→needs networkx
sage: G.antisymmetric()
˓→needs networkx
True

#␣
#␣

>>> from sage.all import *>>> G = digraphs.RandomDirectedGNR(Integer(20), RealNumber( 0.5 ))˓→# needs networkx>>> G.antisymmetric()
˓→needs networkx
True

␣
#␣

Loops are allowed:
sage: G.allow_loops(True)
˓→needs networkx
sage: G.add_edge(0, 0)
˓→needs networkx
sage: G.antisymmetric()
˓→needs networkx
True

#␣
#␣
#␣

>>> from sage.all import *>>> G.allow_loops(True)
˓→needs networkx>>> G.add_edge(Integer(0), Integer(0))˓→# needs networkx>>> G.antisymmetric()
˓→needs networkx
True

#␣
␣
#␣

An undirected graph is never antisymmetric unless it is just a union of isolated vertices (with possible loops):
sage: graphs.RandomGNP(20, 0.5).antisymmetric()
˓→needs networkx
False
sage: Graph(3).antisymmetric()True
sage: Graph([(i, i) for i in range(3)], loops=True).antisymmetric()True
sage: DiGraph([(i, i) for i in range(3)], loops=True).antisymmetric()
True>>> from sage.all import *>>> graphs.RandomGNP(Integer(20), RealNumber( 0.5 )).antisymmetric()˓→# needs networkx#␣␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

47

Graph Theory, Release 10.4

(continued from previous page)

False>>> Graph(Integer(3)).antisymmetric()
True>>> Graph([(i, i) for i in range(Integer(3))], loops=True).antisymmetric()
True>>> DiGraph([(i, i) for i in range(Integer(3))], loops=True).antisymmetric()
Trueautomorphism_group(partition=None, verbosity=0, edge_labels=False, order=False, return_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)graphwhose orbit partition is finer than the partition given.
INPUT:• partition – default is the unit partition, otherwise computes the subgroup of the full automorphismgroup 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 optional
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 theseon or off.
EXAMPLES:
Graphs:sage: # needs sage.groups
sage: graphs_query = GraphQuery(display_cols=[ graph6 ],num_vertices=4)
sage: L = graphs_query.get_graphs_list()
sage: graphs_list.show_graphs(L)˓→needs sage.plot
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()#␣(continues on next page)48

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: M = G.character_table() # random order of rows, thus abs() below
sage: QQ(M.determinant()).abs()
712483534798848
sage: G.order()384>>> from sage.all import *>>> # needs sage.groups>>> graphs_query = GraphQuery(display_cols=[ graph6 ],num_vertices=Integer(4))>>> L = graphs_query.get_graphs_list()>>> graphs_list.show_graphs(L)#␣˓→needs sage.plot>>> 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)))>>> C = graphs.CubeGraph(Integer(4))>>> G = C.automorphism_group()>>> M = G.character_table() # random order of rows, thus abs() below>>> QQ(M.determinant()).abs()
712483534798848>>> G.order()384
sage: # needs sage.groups
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>>> from sage.all import *>>> # needs sage.groups>>> D = graphs.DodecahedralGraph()>>> G = D.automorphism_group()>>> A5 = AlternatingGroup(Integer(5))>>> Z2 = CyclicPermutationGroup(Integer(2))>>> H = A5.direct_product(Z2)[Integer(0)] #see documentation for direct_
˓→product to explain the [0]>>> G.is_isomorphic(H)
True

Multigraphs:
1.1. Generic graphs (common to directed/undirected)

49

Graph Theory, Release 10.4

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()
˓→needs sage.groups
Permutation Group with generators [( a , b )]#␣>>> from sage.all import *>>> G = Graph(multiedges=True,sparse=True)>>> G.add_edge(( a , b ))>>> G.add_edge(( a , b ))>>> G.add_edge(( a , b ))>>> G.automorphism_group()
˓→needs sage.groups
Permutation Group with generators [( a , b )]#␣Digraphs:sage: D = DiGraph( { 0:[1], 1:[2], 2:[3], 3:[4], 4:[0] } )sage: D.automorphism_group()
˓→needs sage.groups
Permutation Group with generators [(0,1,2,3,4)]#␣>>> from sage.all import *>>> D = DiGraph( { Integer(0):[Integer(1)], Integer(1):[Integer(2)],␣
˓→Integer(2):[Integer(3)], Integer(3):[Integer(4)], Integer(4):[Integer(0)] }␣
˓→)>>> D.automorphism_group()#␣˓→needs sage.groups
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)
˓→needs sage.groups
Permutation Group with generators [(1,4)(2,3)]#␣

sage: G.automorphism_group(edge_labels=True, algorithm="bliss")
˓→bliss
Permutation Group with generators [(1,4)(2,3)]# optional -␣

sage: G.automorphism_group(edge_labels=True, algorithm="sage")˓→needs sage.groups
Permutation Group with generators [(1,4)(2,3)]#␣>>> from sage.all import *>>> G = Graph(sparse=True)>>> G.add_edges( [(Integer(0),Integer(1), a ),(Integer(1),Integer(2), b ),˓→(Integer(2),Integer(3), c ),(Integer(3),Integer(4), b ),(Integer(4),˓→Integer(0), a )] )>>> G.automorphism_group(edge_labels=True)#␣˓→needs sage.groups
Permutation Group with generators [(1,4)(2,3)](continues on next page)

50

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G.automorphism_group(edge_labels=True, algorithm="bliss")
˓→bliss
Permutation Group with generators [(1,4)(2,3)]# optional -␣>>> G.automorphism_group(edge_labels=True, algorithm="sage")˓→needs sage.groups
Permutation Group with generators [(1,4)(2,3)]#␣

sage: G = Graph({0 : {1 : 7}})sage: G.automorphism_group(edge_labels=True)
˓→needs sage.groups
Permutation Group with generators [(0,1)]#␣

sage: # needs sage.groups
sage: foo = Graph(sparse=True)
sage: bar = 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 [()]>>> from sage.all import *>>> G = Graph({Integer(0) : {Integer(1) : Integer(7)}})>>> G.automorphism_group(edge_labels=True)
˓→needs sage.groups
Permutation Group with generators [(0,1)]#␣>>> # needs sage.groups>>> foo = Graph(sparse=True)>>> bar = Graph(sparse=True)>>> foo.add_edges([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)), (Integer(2),Integer(3),Integer(3))])>>> bar.add_edges([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)), (Integer(2),Integer(3),Integer(3))])>>> foo.automorphism_group(edge_labels=True)
Permutation Group with generators [()]>>> foo.automorphism_group()
Permutation Group with generators [(0,3)(1,2)]>>> 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)
˓→needs sage.groups120>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.automorphism_group(return_group=False, order=True)

1.1. Generic graphs (common to directed/undirected)#␣#␣(continues on next page)51

Graph Theory, Release 10.4

(continued from previous page)needs sage.groups120˓→Or, just the orbits (note that each graph here is vertex transitive)
sage: # needs sage.groups
sage: G = graphs.PetersenGraph()
sage: G.automorphism_group(return_group=False, orbits=True, algorithm= sage )[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))],....:
return_group=False, orbits=True, algorithm=
˓→ sage )sage: sorted([sorted(o) for o in orb], key=len)[[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]]
sage: C = graphs.CubeGraph(3)sage: orb = C.automorphism_group(orbits=True, return_group=False, algorithm=
˓→ sage )sage: [sorted(o) for o in orb][[ 000 , 001 , 010 , 011 , 100 , 101 , 110 , 111 ]]>>> from sage.all import *>>> # needs sage.groups>>> G = graphs.PetersenGraph()>>> G.automorphism_group(return_group=False, orbits=True, algorithm= sage )[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]>>> orb = G.automorphism_group(partition=[[Integer(0)],list(range(Integer(1),˓→Integer(10)))],...
return_group=False, orbits=True, algorithm=
˓→ sage )>>> sorted([sorted(o) for o in orb], key=len)[[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]]>>> C = graphs.CubeGraph(Integer(3))>>> orb = C.automorphism_group(orbits=True, return_group=False, algorithm=
˓→ sage )>>> [sorted(o) for o in orb][[ 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: # optional - bliss
sage: G = graphs.HallJankoGraph()
sage: A1 = G.automorphism_group()
˓→needs sage.groups
sage: A2 = G.automorphism_group(algorithm= bliss )sage: A1.is_isomorphic(A2)˓→needs sage.groups
True>>> from sage.all import *>>> # optional - bliss>>> G = graphs.HallJankoGraph()>>> A1 = G.automorphism_group()
˓→needs sage.groups>>> A2 = G.automorphism_group(algorithm= bliss )>>> A1.is_isomorphic(A2)˓→needs sage.groups

#␣

#␣

#␣

#␣
(continues on next page)

52

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True

average_degree()Return the average degree of the graph.
The average degree of a graph 𝐺 = (𝑉, 𝐸) is equal to 2|𝐸|
|𝑉 | .
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>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> g.average_degree() == Integer(4)True

The average degree of a tree is always strictly less than 2:
sage: tree = graphs.RandomTree(20)sage: tree.average_degree() < 2
True>>> from sage.all import *>>> tree = graphs.RandomTree(Integer(20))>>> tree.average_degree() < Integer(2)True

For any graph, it is equal to 2|𝐸|
|𝑉 | :
sage: g = graphs.RandomGNP(20, .4)
sage: g.average_degree() == 2 * g.size() / g.order()True>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(20), RealNumber( .4 ))>>> g.average_degree() == Integer(2) * g.size() / g.order()Trueaverage_distance(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return 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() andshortest_path_all_pairs(), which have very similar input variables.
INPUT:• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• algorithm – string (default: None); one of the algorithms available for method wiener_index()

1.1. Generic graphs (common to directed/undirected)

53

Graph Theory, Release 10.4

• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
EXAMPLES:
From [GYLL1993]:
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>>> from sage.all import *>>> g=graphs.PathGraph(Integer(10))>>> w=lambda x: (x*(x*x -Integer(1))/Integer(6))/(x*(x-Integer(1))/Integer(2))>>> g.average_distance()==w(Integer(10))
True

Average distance of a circuit:sage: g = digraphs.Circuit(6)sage: g.average_distance()3>>> from sage.all import *>>> g = digraphs.Circuit(Integer(6))>>> g.average_distance()3

blocks_and_cut_vertices(G, algorithm='Tarjan_Boost', sort=False, key=None)
Return 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 – string (default: "Tarjan_Boost"); the algorithm to use among:– "Tarjan_Boost" (default) – Tarjan’s algorithm (Boost implementation)– "Tarjan_Sage" – Tarjan’s algorithm (Sage implementation)• sort – boolean (default: False); whether to sort vertices inside the components and the list of cut
vertices currently only available for ``”Tarjan_Sage”``• key – a function (default: None); a function that takes a vertex as its one argument and returns a valuethat can be used for comparisons in the sorting algorithm (we must have sort=True)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:

54

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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: B, C = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage",␣
˓→sort=True)
sage: B, C([[0, 1, 2, 3, 4], [0, 6, 7, 8, 9]], [0])sage: B2, C2 = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage",␣
˓→sort=False)
sage: Set(map(Set, B)) == Set(map(Set, B2)) and set(C) == set(C2)True>>> from sage.all import *>>> from sage.graphs.connectivity import blocks_and_cut_vertices>>> rings = graphs.CycleGraph(Integer(10))>>> rings.merge_vertices([Integer(0), Integer(5)])>>> blocks_and_cut_vertices(rings)([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])>>> rings.blocks_and_cut_vertices()([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])>>> B, C = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=True)>>> B, C([[0, 1, 2, 3, 4], [0, 6, 7, 8, 9]], [0])>>> B2, C2 = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage",␣
˓→sort=False)>>> Set(map(Set, B)) == Set(map(Set, B2)) and set(C) == set(C2)True

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]], [])>>> from sage.all import *>>> blocks_and_cut_vertices(graphs.PetersenGraph())([[0, 1, 4, 5, 2, 6, 3, 7, 8, 9]], [])Decomposing paths to pairs:

1.1. Generic graphs (common to directed/undirected)

55

Graph Theory, Release 10.4

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])>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4)) + graphs.PathGraph(Integer(5))>>> 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])>>> from sage.all import *>>> g = Graph({Integer(1): {Integer(2): Integer(28), Integer(3): Integer(10)},
˓→ Integer(2): {Integer(1): Integer(10), Integer(3): Integer(16)},␣
˓→Integer(4): {}, Integer(5): {Integer(6): Integer(3), Integer(7):␣
˓→Integer(10), Integer(8): Integer(4)}})>>> blocks_and_cut_vertices(g)([[1, 2, 3], [5, 6], [5, 7], [5, 8], [4]], [5])A directed graph with Boost’s algorithm (Issue #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])>>> from sage.all import *>>> rings = graphs.CycleGraph(Integer(10))>>> rings.merge_vertices([Integer(0), Integer(5)])>>> rings = rings.to_directed()>>> blocks_and_cut_vertices(rings, algorithm="Tarjan_Boost")([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])blocks_and_cuts_tree(G)Return the blocks-and-cuts tree of self.
This new graph has two different kinds of vertices, some representing the blocks (type B) and some other the
cut vertices of the graph (type C).
There is an edge between a vertex 𝑢 of type B and a vertex 𝑣 of type C if the cut-vertex corresponding to 𝑣
is in the block corresponding to 𝑢.
The resulting graph is a tree, with the additional characteristic property that the distance between two leaves
is even. When self is not connected, the resulting graph is a forest.
When self is biconnected, the tree is reduced to a single node of type 𝐵.
We referred to [HarPri] and [Gallai] for blocks and cuts tree.
See also:• blocks_and_cut_vertices()
56

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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))
Truesage: from sage.graphs.connectivity import blocks_and_cuts_tree
sage: T = graphs.KrackhardtKiteGraph().blocks_and_cuts_tree(); T
Graph on 5 vertices>>> from sage.all import *>>> from sage.graphs.connectivity import blocks_and_cuts_tree>>> T = blocks_and_cuts_tree(graphs.KrackhardtKiteGraph()); T
Graph on 5 vertices>>> T.is_isomorphic(graphs.PathGraph(Integer(5)))
True>>> from sage.graphs.connectivity import blocks_and_cuts_tree>>> 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>>> from sage.all import *>>> T = blocks_and_cuts_tree(graphs.RandomTree(Integer(40)))>>> T.is_tree()True>>> leaves = [v for v in T if T.degree(v) == Integer(1)]>>> all(T.distance(u,v) % Integer(2) == Integer(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(sort=True)[( B , (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]>>> from sage.all import *>>> T = blocks_and_cuts_tree(graphs.PetersenGraph())>>> T.vertices(sort=True)[( B , (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]breadth_first_search(start, ignore_direction=False, distance=None, neighbors=None,
report_distance=False, edges=False)
Return an iterator over the vertices in a breadth-first ordering.
INPUT:
1.1. Generic graphs (common to directed/undirected)

57

Graph Theory, Release 10.4

• start – vertex or list of vertices from which to start the traversal• ignore_direction – boolean (default: False); only applies to directed graphs. If True, searches
across edges in either direction.
• distance – integer (default: None); the maximum distance from the start nodes to traverse. The
start nodes are at distance zero from themselves.
• neighbors – function (default: None); a function that inputs a vertex and return a list of vertices.
For an undirected graph, neighbors is by default the neighbors() function. For a digraph, theneighbors function defaults to the neighbor_out_iterator() function of the graph.
• report_distance – boolean (default: False); if True, reports pairs (vertex, distance)
where distance is the distance from the start nodes. If False only the vertices are reported.
• edges – boolean (default: False); whether to return the edges of the BFS tree in the order of visit or
the vertices (default). Edges are directed in root to leaf orientation of the tree.
Note that parameters edges and report_distance cannot be True simultaneously.
See also:• 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]>>> from sage.all import *>>> G = Graph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(3): [Integer(4)], Integer(4):␣
˓→[Integer(0)]})>>> list(G.breadth_first_search(Integer(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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(4), Integer(5)], Integer(2): [Integer(5)], Integer(3):␣
˓→[Integer(6)], Integer(5): [Integer(7)], Integer(6): [Integer(7)],␣
˓→Integer(7): [Integer(0)]})>>> list(D.breadth_first_search(Integer(0)))[0, 1, 2, 3, 4, 5, 6, 7]>>> list(D.breadth_first_search(Integer(0), ignore_direction=True))[0, 1, 2, 3, 7, 4, 5, 6]

58

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

You can specify a maximum distance in which to search. A distance of zero returns the start vertices:sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7],␣
˓→7: [0]})sage: list(D.breadth_first_search(0, distance=0))[0]sage: list(D.breadth_first_search(0, distance=1))[0, 1, 2, 3]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(4), Integer(5)], Integer(2): [Integer(5)], Integer(3):␣
˓→[Integer(6)], Integer(5): [Integer(7)], Integer(6): [Integer(7)],␣
˓→Integer(7): [Integer(0)]})>>> list(D.breadth_first_search(Integer(0), distance=Integer(0)))[0]>>> list(D.breadth_first_search(Integer(0), distance=Integer(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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(4), Integer(5)], Integer(2): [Integer(5)], Integer(3):␣
˓→[Integer(6)], Integer(5): [Integer(7)], Integer(6): [Integer(7)],␣
˓→Integer(7): [Integer(0)]})>>> list(D.breadth_first_search([Integer(0)]))[0, 1, 2, 3, 4, 5, 6, 7]>>> list(D.breadth_first_search([Integer(0), Integer(6)]))[0, 6, 1, 2, 3, 7, 4, 5]>>> list(D.breadth_first_search([Integer(0), Integer(6)],␣
˓→distance=Integer(0)))[0, 6]>>> list(D.breadth_first_search([Integer(0), Integer(6)],␣
˓→distance=Integer(1)))[0, 6, 1, 2, 3, 7]>>> list(D.breadth_first_search(Integer(6), ignore_direction=True,␣
˓→distance=Integer(2)))[6, 3, 7, 0, 5]More generally, you can specify a neighbors function. For example, you can traverse the graph backwards
by setting neighbors to be the neighbors_in() function of the graph:
sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7],␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

59

Graph Theory, Release 10.4

(continued from previous page)

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]
˓→>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(4), Integer(5)], Integer(2): [Integer(5)], Integer(3):␣
˓→[Integer(6)], Integer(5): [Integer(7)], Integer(6): [Integer(7)],␣
˓→Integer(7): [Integer(0)]})>>> list(D.breadth_first_search(Integer(5), neighbors=D.neighbors_in,␣
˓→distance=Integer(2)))[5, 1, 2, 0]>>> list(D.breadth_first_search(Integer(5), neighbors=D.neighbors_out,␣
˓→distance=Integer(2)))[5, 7, 0]>>> list(D.breadth_first_search(Integer(5) ,neighbors=D.neighbors,␣
˓→distance=Integer(2)))[5, 1, 2, 7, 0, 4, 6]

It is possible (Issue #16470) using the keyword report_distance to get pairs (vertex, distance)
encoding the distance from the starting vertices:sage: G = graphs.PetersenGraph()
sage: list(G.breadth_first_search(0, report_distance=True))[(0, 0), (1, 1), (4, 1), (5, 1), (2, 2), (6, 2), (3, 2), (9, 2),(7, 2), (8, 2)]
sage: list(G.breadth_first_search(0, report_distance=False))[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
sage: D = DiGraph({0: [1, 3], 1: [0, 2], 2: [0, 3], 3: [4]})sage: D.show()˓→needs sage.plot
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)]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> list(G.breadth_first_search(Integer(0), report_distance=True))[(0, 0), (1, 1), (4, 1), (5, 1), (2, 2), (6, 2), (3, 2), (9, 2),(7, 2), (8, 2)]>>> list(G.breadth_first_search(Integer(0), report_distance=False))[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1):␣
˓→[Integer(0), Integer(2)], Integer(2): [Integer(0), Integer(3)], Integer(3):␣
˓→[Integer(4)]})>>> D.show()#␣(continues on next page)

60

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.plot>>> list(D.breadth_first_search(Integer(4), neighbors=D.neighbor_in_iterator,...
report_distance=True))[(4, 0), (3, 1), (0, 2), (2, 2), (1, 3)]
˓→>>> C = graphs.CycleGraph(Integer(4))>>> list(C.breadth_first_search([Integer(0), Integer(1)], report_
˓→distance=True))[(0, 0), (1, 0), (3, 1), (2, 1)]

You can get edges of the BFS tree instead of the vertices using the edges parameter:
sage: D = DiGraph({1:[2,3],2:[4],3:[4],4:[1],5:[2,6]})
sage: list(D.breadth_first_search(1, edges=True))[(1, 2), (1, 3), (2, 4)]>>> from sage.all import *>>> D = DiGraph({Integer(1):[Integer(2),Integer(3)],Integer(2):[Integer(4)],
˓→Integer(3):[Integer(4)],Integer(4):[Integer(1)],Integer(5):[Integer(2),˓→Integer(6)]})>>> list(D.breadth_first_search(Integer(1), edges=True))[(1, 2), (1, 3), (2, 4)]canonical_label(partition=None, certificate=False, edge_labels=False, algorithm=None,
return_graph=True)
Return the canonical graph.
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 verticesof the (di)graph to its canonical label will also be returned.
• edge_labels – boolean (default: False). When set to True, allows only permutations respectingedge 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 thecanonical graph instead of the canonical graph; only available when bliss is explicitly set as algorithm.
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

61

Graph Theory, Release 10.4

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>>> from sage.all import *>>> g1 = graphs.GridGraph([Integer(2),Integer(3)])>>> g2 = Graph({Integer(1): [Integer(2), Integer(4)], Integer(3): [Integer(2),˓→ Integer(6)], Integer(5): [Integer(4), Integer(2), Integer(6)]})>>> g1 == g2
False>>> g1.is_isomorphic(g2)True>>> 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: gGrid 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}>>> from sage.all import *>>> g, c = g1.canonical_label(algorithm= sage , certificate=True)>>> g
Grid Graph for [2, 3]: Graph on 6 vertices>>> 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()Multi-graph on 2 vertices
sage: Graph( A? ).canonical_label()Graph on 2 vertices
sage: P = graphs.PetersenGraph()
sage: DP = P.to_directed()sage: DP.canonical_label(algorithm= sage ).adjacency_matrix()
˓→needs sage.modules[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]#␣(continues on next page)

62

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[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]>>> from sage.all import *>>> G = Graph(multiedges=True,sparse=True)>>> G.add_edge((Integer(0),Integer(1)))>>> G.add_edge((Integer(0),Integer(1)))>>> G.add_edge((Integer(0),Integer(1)))>>> G.canonical_label()Multi-graph on 2 vertices>>> Graph( A? ).canonical_label()Graph on 2 vertices>>> P = graphs.PetersenGraph()>>> DP = P.to_directed()>>> DP.canonical_label(algorithm= sage ).adjacency_matrix()
˓→needs sage.modules[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",#␣˓→optional - bliss....:certificate=True)(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})>>> from sage.all import *>>> G = Graph(sparse=True)>>> G.add_edges( [(Integer(0),Integer(1), a ),(Integer(1),Integer(2), b ),˓→(Integer(2),Integer(3), c ),(Integer(3),Integer(4), b ),(Integer(4),˓→Integer(0), a )] )>>> G.canonical_label(edge_labels=True)
Graph on 5 vertices>>> G.canonical_label(edge_labels=True, algorithm="bliss",# optional ˓→ bliss...
certificate=True)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

63Graph Theory, Release 10.4

(continued from previous page)(Graph on 5 vertices, {0: 4, 1: 3, 2: 1, 3: 0, 4: 2})>>> 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(sort=True, labels=False)[(0, 3), (1, 2)]
sage: g_bliss.edges(sort=True, labels=False)
˓→optional - bliss[(0, 1), (2, 3)]>>> from sage.all import *>>> g = Graph({ a : [ b ], c : [ d ]})>>> g_sage = g.canonical_label(algorithm= sage )>>> g_bliss = g.canonical_label(algorithm= bliss )˓→ bliss>>> g_sage.edges(sort=True, labels=False)[(0, 3), (1, 2)]>>> g_bliss.edges(sort=True, labels=False)
˓→ bliss[(0, 1), (2, 3)]#␣#␣# optional -# optional -cartesian_product(other)
Return the Cartesian product of self and other.
The Cartesian product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of thevertices 𝑉 (𝐺) 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)
Return the tensor product of self and other.
The tensor product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of thevertices 𝑉 (𝐺) and 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff - (𝑢, 𝑤) is an edge of self, and - (𝑣, 𝑥) is an edgeof other.
The tensor product is also known as the categorical product and the Kronecker product (referring to the
Kronecker matrix product). See the Wikipedia article Kronecker_product.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)sage: C = graphs.CycleGraph(5)sage: T = C.tensor_product(Z); T(continues on next page)

64

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Graph on 10 vertices
sage: T.size()
10
sage: T.plot()# long time
˓→needs sage.plot
Graphics object consisting of 21 graphics primitives>>> from sage.all import *>>> Z = graphs.CompleteGraph(Integer(2))>>> C = graphs.CycleGraph(Integer(5))>>> T = C.tensor_product(Z); T
Graph on 10 vertices>>> T.size()
10>>> T.plot()# long time
˓→needs sage.plot
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
˓→needs sage.plot
Graphics object consisting of 1101 graphics primitives>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> P = graphs.PetersenGraph()>>> T = D.tensor_product(P); T
Graph on 200 vertices>>> T.size()
900>>> T.plot()# long time
˓→needs sage.plot
Graphics object consisting of 1101 graphics primitives

#␣

#␣

#␣

#␣

centrality_betweenness(k=None, normalized=True, weight=None, endpoints=False, seed=None,exact=False, algorithm=None)
Return the betweenness centrality.
The betweenness centrality of a vertex is the fraction of number of shortest paths that go through each vertex.
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 toits graph. Vertices that occur on more shortest paths between other vertices have higher betweenness thanvertices that occur on less.
INPUT:• normalized – boolean (default: True); if set to False, result is not normalized.
• k – integer (default: None); if set to an integer, use k node samples to estimate betweenness. Higher
values give better approximations. Not available when algorithm="Sage".

1.1. Generic graphs (common to directed/undirected)

65Graph Theory, Release 10.4

• weight – string (default: None); 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 (default: False); 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 – string (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:
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])
˓→needs sage.plot
sage: D = D.to_undirected()sage: D.show(figsize=[2,2])
˓→needs sage.plot
sage: D.centrality_betweenness() # abs tol abs 1e-10{0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0}

#␣#␣>>> from sage.all import *>>> g = graphs.ChvatalGraph()>>> 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}>>> 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}>>> D = DiGraph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
(continues on next page)

66

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> D.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> D = D.to_undirected()>>> D.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> 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)
Return the closeness centrality of all vertices in 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 multipliedby the fraction of reachable vertices in the graph: this way, central vertices should also reach several othervertices in the graph [OLJ2014]. 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 othervertices… Closeness is an inverse measure of centrality in that a larger value indicates a less central actor
while a smaller value indicates a more central actor,’ [Bor1995].
For more information, see the Wikipedia article Centrality.
INPUT:• vert – the vertex or the list of vertices we want to analyze. If None (default), all vertices are considered.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, and otherwise
all edges have weight 1• algorithm – string (default: None); one of the following algorithms:–

BFS : performs a BFS from each vertex that has to be analyzed. Does not work with edge weights.

–

NetworkX : the NetworkX algorithm (works only with positive weights).

–

Dijkstra_Boost : the Dijkstra algorithm, implemented in Boost (works only with positive
weights).

–

Floyd-Warshall-Cython : the Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False and all centralities are needed.

–

Floyd-Warshall-Python : the Python implementation of the Floyd-Warshall algorithm.
Works only if all centralities are needed, but it can deal with weighted graphs, even with 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 (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
1.1. Generic graphs (common to directed/undirected)

67Graph Theory, Release 10.4

• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge.
OUTPUT:If vert is a vertex, the closeness centrality of that vertex. Otherwise, a dictionary associating to each vertex
in vert its closeness centrality. If a vertex has (out)degree 0, its closeness centrality is not defined, and thevertex is not included in the output.
See also:• centrality_closeness_top_k()• centrality_degree()• centrality_betweenness()
EXAMPLES:
Standard examples:sage: (graphs.ChvatalGraph()).centrality_closeness(){0: 0.61111111111111..., 1: 0.61111111111111...,
2: 0.61111111111111..., 3: 0.61111111111111...,
4: 0.61111111111111..., 5: 0.61111111111111...,
6: 0.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])
˓→needs sage.plot
sage: D.centrality_closeness(vert=[0,1]){0: 1.0, 1: 0.3333333333333333}
sage: D = D.to_undirected()sage: D.show(figsize=[2,2])
˓→needs sage.plot
sage: D.centrality_closeness(){0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75}>>> from sage.all import *>>> (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...}>>> D = DiGraph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> D.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> D.centrality_closeness(vert=[Integer(0),Integer(1)]){0: 1.0, 1: 0.3333333333333333}>>> D = D.to_undirected()>>> D.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> D.centrality_closeness(){0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75}

68

#␣

#␣

␣

␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

In a (strongly) connected (di)graph, the closeness centrality of 𝑣 is inverse of the average distance between 𝑣
and all other vertices:sage: g = graphs.PathGraph(5)sage: g.centrality_closeness(0)0.4
sage: dist = g.shortest_path_lengths(0).values()
sage: float(len(dist)-1) / sum(dist)0.4
sage: d = g.to_directed()sage: d.centrality_closeness(0)0.4
sage: dist = d.shortest_path_lengths(0).values()
sage: float(len(dist)-1) / sum(dist)
0.4>>> from sage.all import *>>> g = graphs.PathGraph(Integer(5))>>> g.centrality_closeness(Integer(0))
0.4>>> dist = g.shortest_path_lengths(Integer(0)).values()>>> float(len(dist)-Integer(1)) / sum(dist)
0.4>>> d = g.to_directed()>>> d.centrality_closeness(Integer(0))
0.4>>> dist = d.shortest_path_lengths(Integer(0)).values()>>> float(len(dist)-Integer(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>>> from sage.all import *>>> g = Graph(Integer(5))>>> g.centrality_closeness(){}>>> print(g.centrality_closeness(Integer(0)))
NoneWeighted 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

1.1. Generic graphs (common to directed/undirected)

69Graph Theory, Release 10.4>>> from sage.all import *>>> D = graphs.GridGraph([Integer(2),Integer(2)])>>> weight_function = lambda e:Integer(10)>>> D.centrality_closeness([(Integer(0),Integer(0)),(Integer(0),Integer(1))])␣
˓→# tol abs 1e-12{(0, 0): 0.75, (0, 1): 0.75}>>> D.centrality_closeness((Integer(0),Integer(0)), weight_function=weight_
˓→function) # tol abs 1e-12
0.075

characteristic_polynomial(var='x', laplacian=False)
Return the characteristic polynomial of the adjacency matrix of the (di)graph.
Let 𝐺 be a (simple) graph with adjacency matrix 𝐴. Let 𝐼 be the identity matrix of dimensions the same as
𝐴. The characteristic polynomial of 𝐺 is defined as the determinant det(𝑥𝐼 − 𝐴).
Note: characteristic_polynomial and charpoly are aliases and thus provide exactly the same
method.
INPUT:• x – (default: x ); the variable of the characteristic polynomial• laplacian – boolean (default: False); if True, use the Laplacian matrix
See also:• kirchhoff_matrix()• laplacian_matrix()
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.characteristic_polynomial()
˓→needs sage.modulesx^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()
˓→needs sage.modulesx^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)
˓→needs sage.modulesx^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

#␣

#␣

#␣

>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.characteristic_polynomial()#␣˓→needs sage.modulesx^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48>>> P.charpoly()#␣˓→needs sage.modulesx^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48>>> P.characteristic_polynomial(laplacian=True)#␣˓→needs sage.modulesx^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*x70

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

charpoly(var='x', laplacian=False)
Return the characteristic polynomial of the adjacency matrix of the (di)graph.
Let 𝐺 be a (simple) graph with adjacency matrix 𝐴. Let 𝐼 be the identity matrix of dimensions the same as
𝐴. The characteristic polynomial of 𝐺 is defined as the determinant det(𝑥𝐼 − 𝐴).
Note: characteristic_polynomial and charpoly are aliases and thus provide exactly the same
method.
INPUT:• x – (default: x ); the variable of the characteristic polynomial• laplacian – boolean (default: False); if True, use the Laplacian matrix
See also:• kirchhoff_matrix()• laplacian_matrix()
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.characteristic_polynomial()
˓→needs sage.modulesx^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()
˓→needs sage.modulesx^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)
˓→needs sage.modulesx^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

#␣

#␣

#␣

>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.characteristic_polynomial()#␣˓→needs sage.modulesx^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48>>> P.charpoly()#␣˓→needs sage.modulesx^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48>>> P.characteristic_polynomial(laplacian=True)#␣˓→needs sage.modulesx^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x

clear()
Empties the graph of vertices and edges and removes name, associated objects, and position information.
EXAMPLES:
sage: G = graphs.CycleGraph(4)sage: G.set_vertices({0: vertex0 })sage: print(G.order(), G.size())
4 4(continues on next page)

1.1. Generic graphs (common to directed/undirected)

71Graph Theory, Release 10.4

(continued from previous page)

sage: G.name()
Cycle graphsage: G.get_vertex(0)vertex0
sage: H = G.copy(sparse=True)
sage: H.clear()sage: print(H.order(), H.size())
0 0
sage: H.name()
sage: H.get_vertex(0)sage: H = G.copy(sparse=False)
sage: H.clear()sage: print(H.order(), H.size())
0 0
sage: H.name()
sage: H.get_vertex(0)>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> G.set_vertices({Integer(0): vertex0 })>>> print(G.order(), G.size())
4 4>>> G.name()
Cycle graph>>> G.get_vertex(Integer(0))
vertex0>>> H = G.copy(sparse=True)>>> H.clear()>>> print(H.order(), H.size())
0 0>>> H.name()>>> H.get_vertex(Integer(0))>>> H = G.copy(sparse=False)>>> H.clear()>>> print(H.order(), H.size())
0 0>>> H.name()>>> H.get_vertex(Integer(0))

cluster_transitivity()
Return the transitivity (fraction of transitive triangles) of the graph.
Transitivity is the fraction of all existing triangles over all connected triples (triads), 𝑇 = 3 × triangles
triads .
See also section “Clustering” in chapter “Algorithms” of [HSS].
EXAMPLES:
sage: graphs.FruchtGraph().cluster_transitivity()
˓→needs networkx
0.25

72

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.FruchtGraph().cluster_transitivity()
˓→needs networkx
0.25

#␣

cluster_triangles(nbunch=None, implementation=None)
Return the number of triangles for the set 𝑛𝑏𝑢𝑛𝑐ℎ of vertices as a dictionary keyed by vertex.
See also section “Clustering” in chapter “Algorithms” of [HSS].
INPUT:• nbunch – a list of vertices (default: None); the vertices
nbunch=None, returns data for all vertices in the graph.

toinspect.

If• implementation – string (default: None); one of sparse_copy , dense_copy ,networkx or None (default). In the latter case, the best algorithm available is used. Note that
networkx does not support directed graphs.
EXAMPLES:
sage: F = graphs.FruchtGraph()
sage: list(F.cluster_triangles().values())[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0]
sage: F.cluster_triangles(){0: 1, 1: 1, 2: 0, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 0, 9: 1, 10: 1, 11: 0}
sage: F.cluster_triangles(nbunch=[0, 1, 2]){0: 1, 1: 1, 2: 0}>>> from sage.all import *>>> F = graphs.FruchtGraph()>>> list(F.cluster_triangles().values())[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0]>>> F.cluster_triangles(){0: 1, 1: 1, 2: 0, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 0, 9: 1, 10: 1, 11: 0}>>> F.cluster_triangles(nbunch=[Integer(0), Integer(1), Integer(2)]){0: 1, 1: 1, 2: 0}
sage: G = graphs.RandomGNP(20, .3)
sage: d1 = G.cluster_triangles(implementation="networkx")
˓→needs networkx
sage: d2 = G.cluster_triangles(implementation="dense_copy")
sage: d3 = G.cluster_triangles(implementation="sparse_copy")
sage: d1 == d2 and d1 == d3
˓→needs networkx
True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(20), RealNumber( .3 ))>>> d1 = G.cluster_triangles(implementation="networkx")
˓→needs networkx>>> d2 = G.cluster_triangles(implementation="dense_copy")>>> d3 = G.cluster_triangles(implementation="sparse_copy")>>> d1 == d2 and d1 == d3
˓→needs networkx
True

1.1. Generic graphs (common to directed/undirected)

#␣

#␣

#␣

#␣

73

Graph Theory, Release 10.4

clustering_average(implementation=None)
Return the average clustering coefficient.
The clustering coefficient of a node(︀ 𝑖)︀is the fraction of existing triangles containing node 𝑖 over all possible
triangles containing 𝑖: 𝑐𝑖 = 𝑇 (𝑖)/ 𝑘2𝑖 where 𝑇 (𝑖) is the number of existing triangles through 𝑖, and 𝑘𝑖 is thedegree of vertex 𝑖.
A coefficient for the whole graph is the average of the 𝑐𝑖 .
See also section “Clustering” in chapter “Algorithms” of [HSS].
INPUT:• implementation – string (default:None); one of boost ,sparse_copy ,dense_copy , networkx or None (default). In the latter case, the best algorithm available isused. Note that only networkx supports directed graphs.
EXAMPLES:
sage: (graphs.FruchtGraph()).clustering_average()
1/4
sage: (graphs.FruchtGraph()).clustering_average(implementation= networkx )˓→needs networkx
0.25>>> from sage.all import *>>> (graphs.FruchtGraph()).clustering_average()
1/4>>> (graphs.FruchtGraph()).clustering_average(implementation= networkx )˓→needs networkx
0.25

#␣

#␣

clustering_coeff(nodes=None, weight=False, implementation=None)
Return 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 containing
node 𝑖 over 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 [HSS].
INPUT:• nodes – an iterable container of vertices (default: None); the vertices to inspect. By default, returns
data on all vertices in graph• weight – string or boolean (default: False); if it is a string it uses the indicated edge property as
weight. weight = True is equivalent to weight = weight• implementation – string (default:None); one of boost ,sparse_copy ,dense_copy , networkx or None (default). In the latter case, the best algorithm available isused. Note that only networkx supports directed or weighted graphs, and that sparse_copy
and dense_copy do not support node different from None
EXAMPLES:

74

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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)
˓→needs networkx{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],
˓→needs networkx....:
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}>>> from sage.all import *>>> 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}>>> (graphs.FruchtGraph()).clustering_coeff(weight=True)
˓→needs networkx{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}#␣>>> (graphs.FruchtGraph()).clustering_coeff(nodes=[Integer(0),Integer(1),˓→Integer(2)]){0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0.0}>>> (graphs.FruchtGraph()).clustering_coeff(nodes=[Integer(0),Integer(1),˓→Integer(2)],# needs networkx...
weight=True){0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0}>>> (graphs.GridGraph([Integer(5),Integer(5)])).clustering_˓→coeff(nodes=[(Integer(0),Integer(0)),(Integer(0),Integer(1)),(Integer(2),˓→Integer(2))]){(0, 0): 0.0, (0, 1): 0.0, (2, 2): 0.0}

coarsest_equitable_refinement(partition, sparse=True)
Return the coarsest partition which is finer than the input partition, and equitable with respect to self.
A partition is equitable with respect to a graph if for every pair of cells 𝐶1 , 𝐶2 of the partition, the numberof edges from a vertex of 𝐶1 to 𝐶2 is the same, over all vertices in 𝐶1 .
A partition 𝑃1 is finer than 𝑃2 (𝑃2 is coarser than 𝑃1 ) if every cell of 𝑃1 is a subset of a cell of 𝑃2 .

1.1. Generic graphs (common to directed/undirected)

75Graph Theory, Release 10.4

INPUT:• partition – a list of lists• sparse – boolean (default: False); whether to use sparse ordense representation - for small graphs, use dense for speed
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.coarsest_equitable_refinement([[0],list(range(1,10))])[[0], [2, 3, 6, 7, 8, 9], [1, 4, 5]]
sage: G = graphs.CubeGraph(3)sage: verts = G.vertices(sort=True)
sage: Pi = [verts[:1], verts[1:]]sage: Pi[[ 000 ], [ 001 , 010 , 011 , 100 , 101 , 110 , 111 ]]sage: [sorted(cell) for cell in G.coarsest_equitable_refinement(Pi)][[ 000 ], [ 011 , 101 , 110 ], [ 111 ], [ 001 , 010 , 100 ]]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.coarsest_equitable_refinement([[Integer(0)],list(range(Integer(1),˓→Integer(10)))])[[0], [2, 3, 6, 7, 8, 9], [1, 4, 5]]>>> G = graphs.CubeGraph(Integer(3))>>> verts = G.vertices(sort=True)>>> Pi = [verts[:Integer(1)], verts[Integer(1):]]>>> Pi[[ 000 ], [ 001 , 010 , 011 , 100 , 101 , 110 , 111 ]]>>> [sorted(cell) for cell in G.coarsest_equitable_refinement(Pi)][[ 000 ], [ 011 , 101 , 110 ], [ 111 ], [ 001 , 010 , 100 ]]Note that given an equitable partition, this function returns that partition:
sage: P = graphs.PetersenGraph()
sage: prt = [[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]]
sage: P.coarsest_equitable_refinement(prt)[[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]]>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> prt = [[Integer(0)], [Integer(1), Integer(4), Integer(5)], [Integer(2),␣
˓→Integer(3), Integer(6), Integer(7), Integer(8), Integer(9)]]>>> 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>>> from sage.all import *>>> ss = (graphs.WheelGraph(Integer(6))).line_graph(labels=False)(continues on next page)

76

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> prt = [[(Integer(0), Integer(1))], [(Integer(0), Integer(2)), (Integer(0),˓→ Integer(3)), (Integer(0), Integer(4)), (Integer(1), Integer(2)),␣
˓→(Integer(1), Integer(4))], [(Integer(2), Integer(3)), (Integer(3),␣
˓→Integer(4))]]>>> ss.coarsest_equitable_refinement(prt)Traceback (most recent call last):...
TypeError: partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)],[(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect
sage: ss = (graphs.WheelGraph(5)).line_graph(labels=False)
sage: ss.coarsest_equitable_refinement(prt)[[(0, 1)], [(1, 2), (1, 4)], [(0, 3)], [(0, 4), (0, 2)], [(2, 3), (3, 4)]]>>> from sage.all import *>>> ss = (graphs.WheelGraph(Integer(5))).line_graph(labels=False)>>> ss.coarsest_equitable_refinement(prt)[[(0, 1)], [(1, 2), (1, 4)], [(0, 3)], [(0, 4), (0, 2)], [(2, 3), (3, 4)]]

ALGORITHM: Brendan D. McKay’s Master’s Thesis, University of Melbourne, 1976.
complement()
Return 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
˓→needs sage.plot
Graphics object consisting of 26 graphics primitives
sage: PC = P.complement()
sage: PC.plot()# long time
˓→needs sage.plot
Graphics object consisting of 41 graphics primitives>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.plot()# long time
˓→needs sage.plot
Graphics object consisting of 26 graphics primitives>>> PC = P.complement()>>> PC.plot()# long time
˓→needs sage.plot
Graphics object consisting of 41 graphics primitives

#␣

#␣

#␣

#␣

sage: graphs.TetrahedralGraph().complement().size()0sage: graphs.CycleGraph(4).complement().edges(sort=True)[(0, 2, None), (1, 3, None)]sage: graphs.CycleGraph(4).complement()
complement(Cycle graph): Graph on 4 vertices
sage: G = Graph(multiedges=True, sparse=True)
sage: G.add_edges([(0, 1)] * 3)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

77Graph Theory, Release 10.4

(continued from previous page)

sage: G.complement()
Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withmultiedges. 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().
>>> from sage.all import *>>> graphs.TetrahedralGraph().complement().size()0>>> graphs.CycleGraph(Integer(4)).complement().edges(sort=True)[(0, 2, None), (1, 3, None)]>>> graphs.CycleGraph(Integer(4)).complement()
complement(Cycle graph): Graph on 4 vertices>>> G = Graph(multiedges=True, sparse=True)>>> G.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> G.complement()
Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withmultiedges. 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=None, key=None)
Return a list of the vertices connected to vertex.
INPUT:• G – the input graph• v – the vertex to search for• sort – boolean (default: None); if True, vertices inside the component are sorted according to thedefault ordering
As of Issue #35889, this argument must be explicitly specified (unless a key is given); otherwise awarning is printed and sort=True is used. The default will eventually be changed to False.
• key – a function (default: None); a function that takes a vertex as its one argument and returns a valuethat can be used for comparisons in the sorting algorithm (we must have sort=True)
EXAMPLES:
sage: from sage.graphs.connectivity import connected_component_containing_˓→vertexsage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]})sage: connected_component_containing_vertex(G, 0, sort=True)[0, 1, 2, 3]
sage: G.connected_component_containing_vertex(0, sort=True)[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, sort=True)[0, 1, 2, 3]
sage: connected_component_containing_vertex(D, 0, sort=True, key=lambda x: -x)[3, 2, 1, 0]

78

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.connectivity import connected_component_containing_vertex>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],
˓→ Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)],␣
˓→Integer(5): [Integer(6)]})>>> connected_component_containing_vertex(G, Integer(0), sort=True)[0, 1, 2, 3]>>> G.connected_component_containing_vertex(Integer(0), sort=True)[0, 1, 2, 3]>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)], Integer(4): [Integer(5),␣
˓→Integer(6)], Integer(5): [Integer(6)]})>>> connected_component_containing_vertex(D, Integer(0), sort=True)[0, 1, 2, 3]>>> connected_component_containing_vertex(D, Integer(0), sort=True,␣
˓→key=lambda x: -x)[3, 2, 1, 0]

connected_components(G, sort=None, key=None)
Return the list of connected components.
This returns a list of lists of vertices, each list representing a connected component. The list is ordered fromlargest to smallest component.
INPUT:• G – the input graph• sort – boolean (default: None); if True, vertices inside each component are sorted according to thedefault ordering
As of Issue #35889, this argument must be explicitly specified (unless a key is given); otherwise awarning is printed and sort=True is used. The default will eventually be changed to False.
• key – a function (default: None); a function that takes a vertex as its one argument and returns a valuethat can be used for comparisons in the sorting algorithm (we must have sort=True)
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, sort=True)[[0, 1, 2, 3], [4, 5, 6]]
sage: G.connected_components(sort=True)[[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, sort=True)[[0, 1, 2, 3], [4, 5, 6]]
sage: connected_components(D, sort=True, key=lambda x: -x)[[3, 2, 1, 0], [6, 5, 4]]>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],
˓→ Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)],␣
˓→Integer(5): [Integer(6)]})>>> connected_components(G, sort=True)[[0, 1, 2, 3], [4, 5, 6]]>>> G.connected_components(sort=True)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

79Graph Theory, Release 10.4

(continued from previous page)[[0, 1, 2, 3], [4, 5, 6]]>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)], Integer(4): [Integer(5),␣
˓→Integer(6)], Integer(5): [Integer(6)]})>>> connected_components(D, sort=True)[[0, 1, 2, 3], [4, 5, 6]]>>> connected_components(D, sort=True, key=lambda x: -x)[[3, 2, 1, 0], [6, 5, 4]]connected_components_number(G)Return the number of connected components.
INPUT:• G – 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)2sage: 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>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components_number>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],
˓→ Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)],␣
˓→Integer(5): [Integer(6)]})>>> connected_components_number(G)2>>> G.connected_components_number()2>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)], Integer(4): [Integer(5),␣
˓→Integer(6)], Integer(5): [Integer(6)]})>>> connected_components_number(D)2connected_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](continues on next page)

80

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: for x in graphs(3):....:print(x.connected_components_sizes())[1, 1, 1][2, 1][3][3]>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components_sizes>>> for x in graphs(Integer(3)):...
print(connected_components_sizes(x))[1, 1, 1][2, 1][3][3]>>> for x in graphs(Integer(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)˓→# needs sage.plot
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)˓→# needs sage.plot
sage: L = D.connected_components_subgraphs()sage: graphs_list.show_graphs(L)˓→# needs sage.plot

␣

␣

␣

>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components_subgraphs>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],
˓→ Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)],␣
˓→Integer(5): [Integer(6)]})>>> L = connected_components_subgraphs(G)>>> graphs_list.show_graphs(L)˓→# needs sage.plot>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)], Integer(4): [Integer(5),␣
˓→Integer(6)], Integer(5): [Integer(6)]})>>> L = connected_components_subgraphs(D)>>> graphs_list.show_graphs(L)˓→# needs sage.plot>>> L = D.connected_components_subgraphs()>>> graphs_list.show_graphs(L)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

81Graph Theory, Release 10.4

(continued from previous page)# needs sage.plot

˓→connected_subgraph_iterator(G, k=None, vertices_only=False, edges_only=False, labels=False,
induced=True, exactly_k=False)
Return an terator over the induced connected subgraphs of order at most 𝑘.
This method implements a iterator over the induced connected subgraphs of the input (di)graph. An induced
subgraph of a graph is another graph, formed from a subset of the vertices of the graph and all of the edges
connecting pairs of vertices in that subset (Wikipedia article Induced_subgraph).
As for method sage.graphs.generic_graph.connected_components(), edge orientation is
ignored. Hence, the directed graph with a single arc 0 → 1 is considered connected.
INPUT:• G – a Graph or a DiGraph; loops and multiple edges are allowed• k – (optional) integer; maximum order of the connected subgraphs to report; by default, the method
iterates over all connected subgraphs (equivalent to k == n)• vertices_only – boolean (default: False); whether to return (Di)Graph or list of vertices. Thisparameter is ignored when induced is True.
• edges_only – boolean (default: False); whether to return (Di)Graph or list of edges. When vertices_only is True, this parameter is ignored.
• labels – boolean (default: False); whether to return labelled edges or not. This parameter is used
only when vertices_only is False and edges_only is True.
• induced – boolean (default: True); whether to return induced connected sub(di)graph only or also
non-induced sub(di)graphs. This parameter can be set to False for simple (di)graphs only.
• exactly_k – boolean (default: False); True if we only return graphs of order 𝑘, False if we
return graphs of order at most 𝑘.
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)

82

Chapter 1. Graph objects and methods

Graph Theory, Release 10.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=3, vertices_only=True, exactly_
˓→k=True))[[1, 2, 3], [1, 2, 4], [2, 3, 4]]
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: G = graphs.CompleteGraph(3)sage: len(list(G.connected_subgraph_iterator()))
7
sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))7
sage: len(list(G.connected_subgraph_iterator(edges_only=True)))7
sage: len(list(G.connected_subgraph_iterator(induced=False)))10
sage: G = DiGraph([(0, 1), (1, 0), (1, 2), (2, 1)])
sage: len(list(G.connected_subgraph_iterator()))
6
sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))6sage: len(list(G.connected_subgraph_iterator(edges_only=True)))6sage: len(list(G.connected_subgraph_iterator(induced=False)))18>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(3), Integer(4)), (Integer(4), Integer(2))])>>> 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]>>> list(G.connected_subgraph_iterator(vertices_only=True))[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 4],(continues on next page)

1.1. Generic graphs (common to directed/undirected)

83Graph Theory, Release 10.4

(continued from previous page)[2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]]>>> list(G.connected_subgraph_iterator(k=Integer(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]>>> list(G.connected_subgraph_iterator(k=Integer(3), vertices_only=True,␣
˓→exactly_k=True))[[1, 2, 3], [1, 2, 4], [2, 3, 4]]>>> list(G.connected_subgraph_iterator(k=Integer(2), vertices_only=True))[[1], [1, 2], [2], [2, 3], [2, 4], [3], [3, 4], [4]]>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(1))])>>> list(G.connected_subgraph_iterator())[Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,
Subgraph of (): Digraph on 1 vertex]>>> list(G.connected_subgraph_iterator(vertices_only=True))[[1], [1, 2], [2]]>>> G = graphs.CompleteGraph(Integer(3))>>> len(list(G.connected_subgraph_iterator()))
7>>> len(list(G.connected_subgraph_iterator(vertices_only=True)))7>>> len(list(G.connected_subgraph_iterator(edges_only=True)))7>>> len(list(G.connected_subgraph_iterator(induced=False)))10>>> G = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(0)),␣
˓→(Integer(1), Integer(2)), (Integer(2), Integer(1))])>>> len(list(G.connected_subgraph_iterator()))
6>>> len(list(G.connected_subgraph_iterator(vertices_only=True)))
6>>> len(list(G.connected_subgraph_iterator(edges_only=True)))
6>>> len(list(G.connected_subgraph_iterator(induced=False)))18

contract_edge(u, v=None, label=None)
Contract an edge from u to v.
This method returns silently if the edge does not exist.
INPUT: The following forms are all accepted:• G.contract_edge( 1, 2 )• G.contract_edge( (1, 2) )• G.contract_edge( [ (1, 2) ] )• G.contract_edge( 1, 2, ‘label’ )84

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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(sort=True)[(0, 2, None), (0, 3, None), (2, 3, None)]sage: G = graphs.CompleteGraph(4)sage: G.allow_loops(True); G.allow_multiple_edges(True)
sage: G.contract_edge((0, 1)); G.edges(sort=True)[(0, 2, None), (0, 2, None), (0, 3, None), (0, 3, None), (2, 3, None)]sage: G.contract_edge((0, 2)); G.edges(sort=True)[(0, 0, None), (0, 3, None), (0, 3, None), (0, 3, None)]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> G.contract_edge((Integer(0), Integer(1))); G.edges(sort=True)[(0, 2, None), (0, 3, None), (2, 3, None)]>>> G = graphs.CompleteGraph(Integer(4))>>> G.allow_loops(True); G.allow_multiple_edges(True)>>> G.contract_edge((Integer(0), Integer(1))); G.edges(sort=True)[(0, 2, None), (0, 2, None), (0, 3, None), (0, 3, None), (2, 3, None)]>>> G.contract_edge((Integer(0), Integer(2))); G.edges(sort=True)[(0, 0, None), (0, 3, None), (0, 3, None), (0, 3, None)]sage: G = graphs.CompleteGraph(4).to_directed()sage: G.allow_loops(True)
sage: G.contract_edge(0, 1); G.edges(sort=True)[(0, 0, None),(0, 2, None),(0, 3, None),(2, 0, None),(2, 3, None),(3, 0, None),(3, 2, None)]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4)).to_directed()>>> G.allow_loops(True)>>> G.contract_edge(Integer(0), Integer(1)); G.edges(sort=True)[(0, 0, None),(0, 2, None),(0, 3, None),(2, 0, None),(2, 3, None),(3, 0, None),(3, 2, None)]

contract_edges(edges)
Contract edges from an iterable container.
If 𝑒 is an edge that is not contracted but the vertices of 𝑒 are merged by contraction of other edges, then 𝑒will become a loop.
INPUT:• edges – a list containing 2-tuples or 3-tuples that represent edges
1.1. Generic graphs (common to directed/undirected)

85

Graph Theory, Release 10.4

EXAMPLES:
sage: G = graphs.CompleteGraph(4)sage: G.allow_loops(True); G.allow_multiple_edges(True)
sage: G.contract_edges([(0, 1), (1, 2), (0, 2)]); G.edges(sort=True)[(0, 3, None), (0, 3, None), (0, 3, None)]sage: G.contract_edges([(1, 3), (2, 3)]); G.edges(sort=True)[(0, 3, None), (0, 3, None), (0, 3, None)]sage: G = graphs.CompleteGraph(4)sage: G.allow_loops(True); G.allow_multiple_edges(True)
sage: G.contract_edges([(0, 1), (1, 2), (0, 2), (1, 3), (2, 3)]); G.
˓→edges(sort=True)[(0, 0, None)]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> G.allow_loops(True); G.allow_multiple_edges(True)>>> G.contract_edges([(Integer(0), Integer(1)), (Integer(1), Integer(2)),␣
˓→(Integer(0), Integer(2))]); G.edges(sort=True)[(0, 3, None), (0, 3, None), (0, 3, None)]>>> G.contract_edges([(Integer(1), Integer(3)), (Integer(2), Integer(3))]); G.
˓→edges(sort=True)[(0, 3, None), (0, 3, None), (0, 3, None)]>>> G = graphs.CompleteGraph(Integer(4))>>> G.allow_loops(True); G.allow_multiple_edges(True)>>> G.contract_edges([(Integer(0), Integer(1)), (Integer(1), Integer(2)),␣
˓→(Integer(0), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3))]); G.edges(sort=True)[(0, 0, None)]sage: D = digraphs.Complete(4)sage: D.allow_loops(True); D.allow_multiple_edges(True)
sage: D.contract_edges([(0, 1), (1, 0), (0, 2)]); D.edges(sort=True)[(0, 0, None),(0, 0, None),(0, 0, None),(0, 3, None),(0, 3, None),(0, 3, None),(3, 0, None),(3, 0, None),(3, 0, None)]>>> from sage.all import *>>> D = digraphs.Complete(Integer(4))>>> D.allow_loops(True); D.allow_multiple_edges(True)>>> D.contract_edges([(Integer(0), Integer(1)), (Integer(1), Integer(0)),␣
˓→(Integer(0), Integer(2))]); D.edges(sort=True)[(0, 0, None),(0, 0, None),(0, 0, None),(0, 3, None),(0, 3, None),(0, 3, None),(3, 0, None),(3, 0, None),(3, 0, None)]86

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

copy(weighted=None, data_structure=None, sparse=None, immutable=None, hash_labels=None)
Change the graph implementation
INPUT:• weighted – boolean (default: None); weightedness for the copy. Might change the equality class if
not None.
• sparse – boolean (default: None); sparse=True is an alias for data_structure="sparse",
and sparse=False is an alias for data_structure="dense".
Only used when
data_structure=None.
• data_structure – string (default: None); one of "sparse", "static_sparse", or"dense". See the documentation of Graph or DiGraph.
• immutable – boolean (default: None); whether to create a mutable/immutable copy. Only used when
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– immutable=False means that the created graph is mutable. When used to copy an immutablegraph, the data structure used is "sparse" unless anything else is specified.
• hash_labels – boolean (default: None); whether to include edge labels during hashing of the copy.
This parameter defaults to True if the graph is weighted. This parameter is ignored when parameter
immutable is not True. Beware that trying to hash unhashable labels will raise an error.
Note: If the graph uses StaticSparseBackend and the _immutable flag, then self is returned
rather than a copy (unless one of the optional arguments is used).
OUTPUT:
A Graph object.
Warning: Please use this method only if you need to copy but change the underlying data structure or
weightedness. Otherwise simply do copy(g) instead of g.copy().

Warning: If weighted is passed and is not the weightedness of the original, then the copy will not
equal the original.
EXAMPLES:
sage: g = Graph({0: [0, 1, 1, 2]}, loops=True, multiedges=True, sparse=True)
sage: g == copy(g)Truesage: g = DiGraph({0: [0, 1, 1, 2], 1: [0, 1]}, loops=True, multiedges=True,␣
˓→sparse=True)
sage: g == copy(g)True>>> from sage.all import *>>> g = Graph({Integer(0): [Integer(0), Integer(1), Integer(1), Integer(2)]},␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

87Graph Theory, Release 10.4

(continued from previous page)loops=True, multiedges=True, sparse=True)>>> g == copy(g)True>>> g = DiGraph({Integer(0): [Integer(0), Integer(1), Integer(1), Integer(2)],
˓→ Integer(1): [Integer(0), Integer(1)]}, loops=True, multiedges=True,␣
˓→sparse=True)>>> 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>>> from sage.all import *>>> d = {Integer(0): graphs.DodecahedralGraph(), Integer(1): graphs.
˓→FlowerSnark(), Integer(2): graphs.MoebiusKantorGraph(), Integer(3): graphs.
˓→PetersenGraph()}>>> T = graphs.TetrahedralGraph()>>> T.set_vertices(d)>>> T2 = copy(T)>>> T2.get_vertex(Integer(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>>> from sage.all import *>>> T2.get_vertex(Integer(0)) is T.get_vertex(Integer(0))
False

Examples of the keywords in use:
sage: G = graphs.CompleteGraph(9)sage: H = G.copy()
sage: H == G; H is G
True
False
sage: G1 = G.copy(sparse=True)
sage: G1 == G
True
sage: G1 is G
False
sage: G2 = copy(G)sage: G2 is G
False>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(9))

88(continues on next page)

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> H = G.copy()>>> H == G; H is G
True
False
>>> G1 = G.copy(sparse=True)>>> G1 == G
True>>> G1 is G
False>>> G2 = copy(G)>>> G2 is G
False

Argument weighted affects the equality class:sage: G = graphs.CompleteGraph(5)sage: H1 = G.copy(weighted=False)
sage: H2 = G.copy(weighted=True)
sage: [G.weighted(), H1.weighted(), H2.weighted()][False, False, True]
sage: [G == H1, G == H2, H1 == H2][True, False, False]
sage: G.weighted(True)
sage: [G == H1, G == H2, H1 == H2][False, True, False]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> H1 = G.copy(weighted=False)>>> H2 = G.copy(weighted=True)>>> [G.weighted(), H1.weighted(), H2.weighted()][False, False, True]>>> [G == H1, G == H2, H1 == H2][True, False, False]>>> G.weighted(True)>>> [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 aplane. 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>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.crossing_number()2

1.1. Generic graphs (common to directed/undirected)

89Graph Theory, Release 10.4

ALGORITHM:
This is slow brute force implementation: for every 𝑘 pairs of edges try adding a new vertex for a crossing
point for them. If the result is not planar in any of those, try 𝑘 + 1 pairs.
Computing the crossing number is NP-hard problem.
cycle_basis(output='vertex')
Return a list of cycles which form a basis of the cycle space of self.
A basis of cycles of a graph is a minimal collection of cycles (considered as sets of edges) such that the edge
set of any cycle in the graph can be written as a 𝑍/2𝑍 sum of the cycles in the basis.
See the Wikipedia article Cycle_basis for more information.
INPUT:• output – string (default: vertex ); whether every cycle is given as a list of vertices (output ==vertex ) or a list of edges (output == edge )OUTPUT:
A list of lists, each of them representing the vertices (or the edges) of a cycle in a basis.
ALGORITHM:
Uses the NetworkX library for graphs without multiple edges.
Otherwise, by the standard algorithm using a spanning tree.
EXAMPLES:
A cycle basis in Petersen’s Graphsage: g = graphs.PetersenGraph()
sage: g.cycle_basis()
˓→needs networkx, random (changes in networkx 3.2)[[1, 6, 8, 5, 0], [4, 9, 6, 8, 5, 0], [7, 9, 6, 8, 5],[4, 3, 8, 5, 0], [1, 2, 3, 8, 5, 0], [7, 2, 3, 8, 5]]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.cycle_basis()
˓→needs networkx, random (changes in networkx 3.2)[[1, 6, 8, 5, 0], [4, 9, 6, 8, 5, 0], [7, 9, 6, 8, 5],[4, 3, 8, 5, 0], [1, 2, 3, 8, 5, 0], [7, 2, 3, 8, 5]]#␣#␣One can also get the result as a list of lists of edges:
sage: g.cycle_basis(output= edge )˓→needs networkx, random (changes in networkx 3.2)[[(1, 6, None), (6, 8, None), (8, 5, None), (5, 0, None),(0, 1, None)], [(4, 9, None), (9, 6, None), (6, 8, None),(8, 5, None), (5, 0, None), (0, 4, None)], [(7, 9, None),(9, 6, None), (6, 8, None), (8, 5, None), (5, 7, None)],[(4, 3, None), (3, 8, None), (8, 5, None), (5, 0, None),(0, 4, None)], [(1, 2, None), (2, 3, None), (3, 8, None),(8, 5, None), (5, 0, None), (0, 1, None)], [(7, 2, None),(2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None)]]90#␣Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g.cycle_basis(output= edge )˓→needs networkx, random (changes in networkx 3.2)[[(1, 6, None), (6, 8, None), (8, 5, None), (5, 0, None),(0, 1, None)], [(4, 9, None), (9, 6, None), (6, 8, None),(8, 5, None), (5, 0, None), (0, 4, None)], [(7, 9, None),(9, 6, None), (6, 8, None), (8, 5, None), (5, 7, None)],[(4, 3, None), (3, 8, None), (8, 5, None), (5, 0, None),(0, 4, None)], [(1, 2, None), (2, 3, None), (3, 8, None),(8, 5, None), (5, 0, None), (0, 1, None)], [(7, 2, None),(2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None)]]#␣Checking the given cycles are algebraically free:
sage: g = graphs.RandomGNP(30, .4)
˓→needs networkx
sage: basis = g.cycle_basis()
˓→needs networkx>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(30), RealNumber( .4 ))˓→# needs networkx>>> basis = g.cycle_basis()
˓→needs networkx

#␣
#␣

␣
#␣

Building the space of (directed) edges over 𝑍/2𝑍. On the way, building a dictionary associating a uniquevector to each undirected edge:
sage: m = g.size()
sage: edge_space = VectorSpace(FiniteField(2), m)
˓→needs sage.modules sage.rings.finite_rings
sage: edge_vector = dict(zip(g.edges(labels=False, sort=False),
˓→needs sage.modules sage.rings.finite_rings....:
edge_space.basis()))
sage: for (u, v), vec in list(edge_vector.items()):˓→needs sage.modules sage.rings.finite_rings....:
edge_vector[(v, u)] = vec>>> from sage.all import *>>> m = g.size()>>> edge_space = VectorSpace(FiniteField(Integer(2)), m)˓→# needs sage.modules sage.rings.finite_rings>>> edge_vector = dict(zip(g.edges(labels=False, sort=False),
˓→needs sage.modules sage.rings.finite_rings...
edge_space.basis()))>>> for (u, v), vec in list(edge_vector.items()):˓→needs sage.modules sage.rings.finite_rings...
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))

1.1. Generic graphs (common to directed/undirected)

91Graph Theory, Release 10.4>>> from sage.all import *>>> vertices_to_edges = lambda x: zip(x, x[Integer(1):] + [x[Integer(0)]])>>> 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]
˓→needs networkx sage.modules sage.rings.finite_rings
sage: edge_space.span(basis_as_vectors).rank() == len(basis)
˓→needs networkx sage.modules sage.rings.finite_rings
True

#␣
#␣

>>> from sage.all import *>>> basis_as_vectors = [cycle_to_vector(_) for _ in basis]
˓→needs networkx sage.modules sage.rings.finite_rings>>> edge_space.span(basis_as_vectors).rank() == len(basis)
˓→needs networkx sage.modules sage.rings.finite_rings
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()[[2, 0], [2, 0, 1]]
sage: G.cycle_basis(output= edge )[[(0, 2, b ), (2, 0, a )], [(1, 2, d ), (2, 0, a ), (0, 1, c )]]sage: H = Graph([(1, 2), (2, 3), (2, 3), (3, 4), (1, 4),....:(1, 4), (4, 5), (5, 6), (4, 6), (6, 7)], multiedges=True)
sage: H.cycle_basis()[[4, 1], [3, 2], [4, 1, 2, 3], [6, 4, 5]]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(2), a ), (Integer(0), Integer(2),˓→(Integer(0), Integer(1),c ), (Integer(1), Integer(2), d )],...
multiedges=True)>>> G.cycle_basis()[[2, 0], [2, 0, 1]]>>> G.cycle_basis(output= edge )[[(0, 2, b ), (2, 0, a )], [(1, 2, d ), (2, 0, a ), (0, 1, c )]]>>> H = Graph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(2), Integer(3)), (Integer(3), Integer(4)), (Integer(1),␣
˓→Integer(4)),...
(Integer(1), Integer(4)), (Integer(4), Integer(5)),␣
˓→(Integer(5), Integer(6)), (Integer(4), Integer(6)), (Integer(6),␣
˓→Integer(7))], multiedges=True)>>> H.cycle_basis()[[4, 1], [3, 2], [4, 1, 2, 3], [6, 4, 5]]b ),␣

Disconnected graph:
sage: G.add_cycle(["Hey", "Wuuhuu", "Really ?"])
sage: [sorted(c) for c in G.cycle_basis()]˓→needs networkx[[ Hey , Really ? , Wuuhuu ], [0, 2], [0, 1, 2]]
sage: [sorted(c) for c in G.cycle_basis(output= edge )]#␣#␣(continues on next page)

92

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs networkx[[( Hey , Really ? , None),( Really ? , Wuuhuu , None),( Wuuhuu , Hey , None)],[(0, 2, a ), (2, 0, b )],[(0, 1, c ), (1, 2, d ), (2, 0,
˓→

b )]]

>>> from sage.all import *>>> G.add_cycle(["Hey", "Wuuhuu", "Really ?"])>>> [sorted(c) for c in G.cycle_basis()]˓→needs networkx[[ Hey , Really ? , Wuuhuu ], [0, 2], [0, 1, 2]]>>> [sorted(c) for c in G.cycle_basis(output= edge )]˓→needs networkx[[( Hey , Really ? , None),( Really ? , Wuuhuu , None),( Wuuhuu , Hey , None)],[(0, 2, a ), (2, 0, b )],[(0, 1, c ), (1, 2, d ), (2, 0, b )]]#␣#␣Graph that allows multiple edges but does not contain any:
sage: G = graphs.CycleGraph(3)sage: G.allow_multiple_edges(True)
sage: G.cycle_basis()[[2, 0, 1]]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> G.allow_multiple_edges(True)>>> G.cycle_basis()[[2, 0, 1]]

Not yet implemented for directed graphs:
sage: G = DiGraph([(0, 2, a ), (0, 1, c ), (1, 2, d )])sage: G.cycle_basis()
Traceback (most recent call last):...
NotImplementedError: not implemented for directed graphs>>> from sage.all import *>>> G = DiGraph([(Integer(0), Integer(2), a ), (Integer(0), Integer(1),˓→ (Integer(1), Integer(2),d )])>>> G.cycle_basis()
Traceback (most recent call last):...
NotImplementedError: not implemented for directed graphsc ),degree(vertices=None, labels=False)
Return the degree (in + out for digraphs) of a vertex or of vertices.
INPUT:• vertices – a vertex or an iterable container of vertices (default: None); if vertices is a single
vertex, returns the number of neighbors of that vertex. If vertices is an iterable container of vertices,
returns a list of degrees. If vertices is None, same as listing all vertices.
1.1. Generic graphs (common to directed/undirected)

93Graph Theory, Release 10.4

• labels – boolean (default: False); when True, return a dictionary mapping each vertex in vertices to its degree. Otherwise, return the degree of a single vertex or a list of the degrees of eachvertex in vertices
OUTPUT:• When vertices is a single vertex and labels is False, returns the degree of that vertex as aninteger• When vertices is an iterable container of vertices (or None) and labels is False, returns a listof integers. The 𝑖-th value is the degree of the 𝑖-th vertex in the list vertices. When vertices isNone, the 𝑖-th value is the degree of 𝑖-th vertex in the ordering list(self), which might be different
from the ordering of the vertices given by g.vertices(sort=True).
• When labels is True, returns a dictionary mapping each vertex in vertices to its degree
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.degree(5)3>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.degree(Integer(5))
3sage: K = graphs.CompleteGraph(9)sage: K.degree()[8, 8, 8, 8, 8, 8, 8, 8, 8]>>> from sage.all import *>>> K = graphs.CompleteGraph(Integer(9))>>> 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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(0), Integer(2)], Integer(2): [Integer(3)], Integer(3):␣
˓→[Integer(4)], Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]}˓→)>>> D.degree(vertices=[Integer(0), Integer(1), Integer(2)], labels=True){0: 5, 1: 4, 2: 3}>>> D.degree()[5, 4, 3, 3, 3, 2]

When vertices=None and labels=False, the 𝑖-th value of the returned list is the degree of the 𝑖-th
vertex in the list list(self):
sage: # needs sage.combinat
sage: D = digraphs.DeBruijn(4, 2)(continues on next page)

94

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: D.delete_vertex( 20 )sage: print(D.degree())[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
sage: print(D.degree(vertices=list(D)))[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
sage: print(D.degree(vertices=D.vertices(sort=False)))[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]>>> from sage.all import *>>> # needs sage.combinat>>> D = digraphs.DeBruijn(Integer(4), Integer(2))>>> D.delete_vertex( 20 )>>> print(D.degree())[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]>>> print(D.degree(vertices=list(D)))[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]>>> print(D.degree(vertices=D.vertices(sort=False)))[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]

degree_histogram()
Return a list, whose 𝑖-th entry is the frequency of degree 𝑖.
EXAMPLES:
sage: G = graphs.Grid2dGraph(9, 12)
sage: G.degree_histogram()[0, 0, 4, 34, 70]>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(9), Integer(12))>>> 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]>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(9), Integer(12)).to_directed()>>> G.degree_histogram()[0, 0, 0, 0, 4, 0, 34, 0, 70]

degree_iterator(vertices=None, labels=False)
Return an iterator over the degrees of the (di)graph.
In the case of a digraph, the degree is defined as the sum of the in-degree and the out-degree, i.e. the total
number of edges incident to a given vertex.
INPUT:• vertices – a vertex or an iterable container of vertices (default: None); if vertices is a single
vertex, the iterator will yield the number of neighbors of that vertex. If vertices is an iterable container of vertices, return an iterator over the degrees of these vertices. If vertices is None, same aslisting all vertices.
• labels – boolean (default: False); whether to return an iterator over degrees (labels=False),
or over tuples (vertex, degree)
1.1. Generic graphs (common to directed/undirected)

95

Graph Theory, Release 10.4

Note: The returned iterator yields values in order specified by list(vertices). When vertices isNone, it yields values in the same order as list(self), which might be different from the ordering of thevertices given by g.vertices(sort=True).
EXAMPLES:
sage: G = graphs.Grid2dGraph(3, 4)
sage: for i in G.degree_iterator():....:print(i)
2
3
3
...
3
2
sage: for i in G.degree_iterator(labels=True):....:
print(i)((0, 0), 2)((0, 1), 3)((0, 2), 3)...
((2, 2), 3)((2, 3), 2)>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(3), Integer(4))>>> for i in G.degree_iterator():...
print(i)
2
3
3
...
3
2
>>> for i in G.degree_iterator(labels=True):...
print(i)((0, 0), 2)((0, 1), 3)((0, 2), 3)...
((2, 2), 3)((2, 3), 2)
sage: D = graphs.Grid2dGraph(2,4).to_directed()sage: for i in D.degree_iterator():....:print(i)
4
6
...
6
4
sage: for i in D.degree_iterator(labels=True):....:
print(i)((0, 0), 4)((0, 1), 6)(continues on next page)

96

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)...
((1, 2), 6)((1, 3), 4)>>> from sage.all import *>>> D = graphs.Grid2dGraph(Integer(2),Integer(4)).to_directed()>>> for i in D.degree_iterator():...
print(i)
4
6
...
6
4
>>> for i in D.degree_iterator(labels=True):...
print(i)((0, 0), 4)((0, 1), 6)...
((1, 2), 6)((1, 3), 4)

When vertices=None yields values in the order of list(D):sage: V = list(D)sage: D = digraphs.DeBruijn(4, 2)
˓→needs sage.combinat
sage: D.delete_vertex( 20 )˓→needs sage.combinat
sage: print(list(D.degree_iterator()))˓→needs sage.combinat[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]
sage: print([D.degree(v) for v in D])
˓→needs sage.combinat[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]>>> from sage.all import *>>> V = list(D)>>> D = digraphs.DeBruijn(Integer(4), Integer(2))˓→# needs sage.combinat>>> D.delete_vertex( 20 )˓→needs sage.combinat>>> print(list(D.degree_iterator()))˓→needs sage.combinat[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]>>> print([D.degree(v) for v in D])
˓→needs sage.combinat[7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8]

#␣
#␣
#␣

#␣

␣
#␣
#␣

#␣

degree_sequence()
Return the degree sequence of this (di)graph.
EXAMPLES:
The degree sequence of an undirected graph:1.1. Generic graphs (common to directed/undirected)

97Graph Theory, Release 10.4

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]>>> from sage.all import *>>> g = Graph({Integer(1): [Integer(2), Integer(5)], Integer(2): [Integer(1),␣
˓→Integer(5), Integer(3), Integer(4)], Integer(3): [Integer(2), Integer(5)],␣
˓→Integer(4): [Integer(3)], Integer(5): [Integer(2), Integer(3)]})>>> g.degree_sequence()[4, 3, 3, 2, 2]

The degree sequence of a digraph:
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]>>> from sage.all import *>>> g = DiGraph({Integer(1): [Integer(2), Integer(5), Integer(6)],␣
˓→Integer(2): [Integer(3), Integer(6)], Integer(3): [Integer(4), Integer(6)],␣
˓→Integer(4): [Integer(6)], Integer(5): [Integer(4), Integer(6)]})>>> 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]>>> from sage.all import *>>> graphs.PetersenGraph().degree_sequence()[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]>>> graphs.HouseGraph().degree_sequence()[3, 3, 2, 2, 2]>>> graphs.FlowerSnark().degree_sequence()[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

degree_to_cell(vertex, cell)
Returns the number of edges from vertex to an edge in cell. In the case of a digraph, returns a tuple (in_degree,
out_degree).
EXAMPLES:
sage: G = graphs.CubeGraph(3)sage: cell = G.vertices(sort=True)[:3]
sage: G.degree_to_cell( 011 , cell)2
sage: G.degree_to_cell( 111 , cell)0>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(3))(continues on next page)98

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> cell = G.vertices(sort=True)[:Integer(3)]>>> G.degree_to_cell( 011 , cell)
2>>> 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)>>> from sage.all import *>>> D = DiGraph({ Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(3),Integer(4)], Integer(3):[Integer(4),Integer(5)]})>>> cell = [Integer(0),Integer(1),Integer(2)]>>> D.degree_to_cell(Integer(5), cell)(0, 0)>>> D.degree_to_cell(Integer(3), cell)(2, 0)>>> D.degree_to_cell(Integer(0), cell)(0, 2)

delete_edge(u, v=None, label=None)
Delete the edge from u to v.
This method returns 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(9)sage: G.size()36
sage: G.delete_edge( 1, 2 )sage: G.delete_edge( (3, 4) )sage: G.delete_edges( [ (5, 6), (7, 8) ] )sage: G.size()
32>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(9))(continues on next page)

1.1. Generic graphs (common to directed/undirected)

99

Graph Theory, Release 10.4

(continued from previous page)>>> G.size()36>>> G.delete_edge( Integer(1), Integer(2) )>>> G.delete_edge( (Integer(3), Integer(4)) )>>> G.delete_edges( [ (Integer(5), Integer(6)), (Integer(7), Integer(8)) ] )>>> G.size()
32
sage: G.delete_edge( 2, 3, label )sage: G.delete_edge( (4, 5, label ) )sage: G.delete_edges( [ (6, 7, label ) ] )sage: G.size()
32
sage: G.has_edge( (4, 5) ) # correct!
True
sage: G.has_edge( (4, 5, label ) ) # correct!
False>>> from sage.all import *>>> G.delete_edge( Integer(2), Integer(3), label )>>> G.delete_edge( (Integer(4), Integer(5), label ) )>>> G.delete_edges( [ (Integer(6), Integer(7), label ) ] )>>> G.size()32>>> G.has_edge( (Integer(4), Integer(5)) ) # correct!
True>>> G.has_edge( (Integer(4), Integer(5), label ) ) # correct!
False
sage: C = digraphs.Complete(9)sage: C.size()72
sage: C.delete_edge( 1, 2 )sage: C.delete_edge( (3, 4) )sage: C.delete_edges( [ (5, 6), (7, 8) ] )sage: C.size()
68>>> from sage.all import *>>> C = digraphs.Complete(Integer(9))>>> C.size()72>>> C.delete_edge( Integer(1), Integer(2) )>>> C.delete_edge( (Integer(3), Integer(4)) )>>> C.delete_edges( [ (Integer(5), Integer(6)), (Integer(7), Integer(8)) ] )>>> C.size()
68
sage: C.delete_edge( 2, 3, label )sage: C.delete_edge( (4, 5, label ) )sage: C.delete_edges( [ (6, 7, label ) ] )sage: C.size() # correct!
68
sage: C.has_edge( (4, 5) ) # correct!
True(continues on next page)

100

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: C.has_edge( (4, 5,
False

label ) ) # correct!

>>> from sage.all import *>>> C.delete_edge( Integer(2), Integer(3), label )>>> C.delete_edge( (Integer(4), Integer(5), label ) )>>> C.delete_edges( [ (Integer(6), Integer(7), label ) ] )>>> C.size() # correct!
68>>> C.has_edge( (Integer(4), Integer(5)) ) # correct!
True>>> C.has_edge( (Integer(4), Integer(5), label ) ) # correct!
False

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>>> from sage.all import *>>> K12 = graphs.CompleteGraph(Integer(12))>>> K4 = graphs.CompleteGraph(Integer(4))>>> K12.size()66>>> K12.delete_edges(K4.edge_iterator())>>> K12.size()
60
sage: K12 = digraphs.Complete(12)sage: K4 = digraphs.Complete(4)sage: K12.size()132
sage: K12.delete_edges(K4.edge_iterator())
sage: K12.size()120>>> from sage.all import *>>> K12 = digraphs.Complete(Integer(12))>>> K4 = digraphs.Complete(Integer(4))>>> K12.size()132>>> K12.delete_edges(K4.edge_iterator())>>> K12.size()
120

delete_multiedge(u, v)
Delete all edges from u to v.

1.1. Generic graphs (common to directed/undirected)

101Graph Theory, Release 10.4

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(sort=True)[(0, 1, None), (0, 1, None), (0, 1, None), (1, 2, None), (2, 3, None)]sage: G.delete_multiedge(0, 1)
sage: G.edges(sort=True)[(1, 2, None), (2, 3, None)]>>> from sage.all import *>>> G = Graph(multiedges=True, sparse=True)>>> G.add_edges([(Integer(0), Integer(1)), (Integer(0), Integer(1)),␣
˓→(Integer(0), Integer(1)), (Integer(1), Integer(2)), (Integer(2),␣
˓→Integer(3))])>>> G.edges(sort=True)[(0, 1, None), (0, 1, None), (0, 1, None), (1, 2, None), (2, 3, None)]>>> G.delete_multiedge(Integer(0), Integer(1))>>> G.edges(sort=True)[(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(sort=True)[(0, 1, 1), (0, 1, 2), (0, 1, 3), (1, 0, None), (1, 2, None), (2, 3, None)]sage: D.delete_multiedge(0, 1)
sage: D.edges(sort=True)[(1, 0, None), (1, 2, None), (2, 3, None)]>>> from sage.all import *>>> D = DiGraph(multiedges=True, sparse=True)>>> D.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(0),␣
˓→Integer(1), Integer(2)), (Integer(0), Integer(1), Integer(3)), (Integer(1),␣
˓→Integer(0), None), (Integer(1), Integer(2), None), (Integer(2), Integer(3),␣
˓→None)])>>> D.edges(sort=True)[(0, 1, 1), (0, 1, 2), (0, 1, 3), (1, 0, None), (1, 2, None), (2, 3, None)]>>> D.delete_multiedge(Integer(0), Integer(1))>>> D.edges(sort=True)[(1, 0, None), (1, 2, None), (2, 3, None)]delete_vertex(vertex, in_order=False)
Delete vertex, removing all incident edges.
Deleting a non-existent vertex will raise an exception.
INPUT:• in_order – boolean (default: False); if True, this deletes the 𝑖-th vertex in the sorted list of vertices,
i.e. G.vertices(sort=True)[i]EXAMPLES:
sage: G = Graph(graphs.WheelGraph(9))
sage: G.delete_vertex(0)sage: G.show()˓→needs sage.plot

102

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph(graphs.WheelGraph(Integer(9)))>>> G.delete_vertex(Integer(0))>>> G.show()˓→needs sage.plot#␣

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(sort=True)[1, 2, 3, 4, 5]
sage: D.delete_vertex(0)Traceback (most recent call last):...
ValueError: vertex (0) not in the graph>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5)], Integer(1): [Integer(2)], Integer(2): [Integer(3)],␣
˓→Integer(3): [Integer(4)], Integer(4): [Integer(5)], Integer(5):␣
˓→[Integer(1)]})>>> D.delete_vertex(Integer(0)); D
Digraph on 5 vertices>>> D.vertices(sort=True)[1, 2, 3, 4, 5]>>> D.delete_vertex(Integer(0))
Traceback (most recent call last):...
ValueError: vertex (0) not in the graphsage: G = graphs.CompleteGraph(4).line_graph(labels=False)
sage: G.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G.delete_vertex(0, in_order=True)
sage: G.vertices(sort=True)[(0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G = graphs.PathGraph(5)sage: G.set_vertices({0: no delete , 1: delete })sage: G.delete_vertex(1)sage: G.get_vertices(){0: no delete , 2: None, 3: None, 4: None}sage: G.get_pos(){0: (0, 0), 2: (2, 0), 3: (3, 0), 4: (4, 0)}>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4)).line_graph(labels=False)>>> G.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]>>> G.delete_vertex(Integer(0), in_order=True)>>> G.vertices(sort=True)[(0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]>>> G = graphs.PathGraph(Integer(5))>>> G.set_vertices({Integer(0): no delete , Integer(1): delete })>>> G.delete_vertex(Integer(1))>>> G.get_vertices()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

103Graph Theory, Release 10.4

(continued from previous page){0: no delete , 2: None, 3: None, 4: None}>>> G.get_pos(){0: (0, 0), 2: (2, 0), 3: (3, 0), 4: (4, 0)}delete_vertices(vertices)
Delete vertices from the (di)graph taken from an iterable container of vertices.
Deleting a non-existent vertex will raise an exception, in which case none of the vertices in vertices isdeleted.
EXAMPLES:
sage: D = DiGraph({0: [1, 2, 3, 4, 5], 1: [2], 2: [3], 3: [4], 4: [5], 5: [1]}˓→)
sage: D.delete_vertices([1, 2, 3, 4, 5]); D
Digraph on 1 vertex
sage: D.vertices(sort=False)[0]sage: D.delete_vertices([1])
Traceback (most recent call last):...
ValueError: vertex (1) not in the graph>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5)], Integer(1): [Integer(2)], Integer(2): [Integer(3)],␣
˓→Integer(3): [Integer(4)], Integer(4): [Integer(5)], Integer(5):␣
˓→[Integer(1)]})>>> D.delete_vertices([Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5)]); D
Digraph on 1 vertex>>> D.vertices(sort=False)[0]>>> D.delete_vertices([Integer(1)])
Traceback (most recent call last):...
ValueError: vertex (1) not in the graphdensity()
Return the density of the (di)graph.
The density of a (di)graph is defined as the number of edges divided by number of possible edges.
In the case of a multigraph, raises an error, since there is an infinite number of possible edges.
EXAMPLES:
sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], 5: [7, 8], 6: [8,˓→9], 7: [9]}sage: G = Graph(d); G.density()
1/3
sage: G = Graph({0: [1, 2], 1: [0]}); G.density()
2/3
sage: G = DiGraph({0: [1, 2], 1: [0]}); G.density()
1/2

104

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> d = {Integer(0): [Integer(1),Integer(4),Integer(5)], Integer(1):␣
˓→[Integer(2),Integer(6)], Integer(2): [Integer(3),Integer(7)], Integer(3):␣
˓→[Integer(4),Integer(8)], Integer(4): [Integer(9)], Integer(5): [Integer(7),␣
˓→Integer(8)], Integer(6): [Integer(8),Integer(9)], Integer(7): [Integer(9)]}>>> G = Graph(d); G.density()
1/3>>> G = Graph({Integer(0): [Integer(1), Integer(2)], Integer(1): [Integer(0)]}˓→); G.density()
2/3>>> G = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(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>>> from sage.all import *>>> G.allow_loops(True)>>> G.density()
1/3

depth_first_search(start, ignore_direction=False, neighbors=None, edges=False)
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 – boolean (default: False); only applies to directed graphs. If True, searches
across edges in either direction.
• neighbors – function (default: None); a function that inputs a vertex and return a list of vertices.
For an undirected graph, neighbors is by default the neighbors() function. For a digraph, theneighbors function defaults to the neighbor_out_iterator() function of the graph.
• edges – boolean (default: False); whether to return the edges of the DFS tree in the order of visit or
the vertices (default). Edges are directed in root to leaf orientation of the tree.
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:
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]>>> from sage.all import *>>> G = Graph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

105

Graph Theory, Release 10.4

(continued from previous page)

Integer(2): [Integer(3)], Integer(3): [Integer(4)], Integer(4):␣
˓→[Integer(0)]})>>> list(G.depth_first_search(Integer(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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(4), Integer(5)], Integer(2): [Integer(5)], Integer(3):␣
˓→[Integer(6)], Integer(5): [Integer(7)], Integer(6): [Integer(7)],␣
˓→Integer(7): [Integer(0)]})>>> list(D.depth_first_search(Integer(0)))[0, 3, 6, 7, 2, 5, 1, 4]>>> list(D.depth_first_search(Integer(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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(1): [Integer(4), Integer(5)], Integer(2): [Integer(5)], Integer(3):␣
˓→[Integer(6)], Integer(5): [Integer(7)], Integer(6): [Integer(7)],␣
˓→Integer(7): [Integer(0)]})>>> list(D.depth_first_search([Integer(0)]))[0, 3, 6, 7, 2, 5, 1, 4]>>> list(D.depth_first_search([Integer(0), Integer(6)]))[0, 3, 6, 7, 2, 5, 1, 4]More generally, you can specify a neighbors function. For example, you can traverse the graph backwards
by setting neighbors to be the neighbors_in() function of the graph:
sage: D = digraphs.Path(10)sage: D.add_path([22, 23, 24, 5])
sage: D.add_path([5, 33, 34, 35])
sage: list(D.depth_first_search(5, neighbors=D.neighbors_in))[5, 24, 23, 22, 4, 3, 2, 1, 0]
sage: list(D.breadth_first_search(5, neighbors=D.neighbors_in))[5, 4, 24, 3, 23, 2, 22, 1, 0]
sage: list(D.depth_first_search(5, neighbors=D.neighbors_out))[5, 33, 34, 35, 6, 7, 8, 9](continues on next page)

106

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: list(D.breadth_first_search(5, neighbors=D.neighbors_out))[5, 6, 33, 7, 34, 8, 35, 9]>>> from sage.all import *>>> D = digraphs.Path(Integer(10))>>> D.add_path([Integer(22), Integer(23), Integer(24), Integer(5)])>>> D.add_path([Integer(5), Integer(33), Integer(34), Integer(35)])>>> list(D.depth_first_search(Integer(5), neighbors=D.neighbors_in))[5, 24, 23, 22, 4, 3, 2, 1, 0]>>> list(D.breadth_first_search(Integer(5), neighbors=D.neighbors_in))[5, 4, 24, 3, 23, 2, 22, 1, 0]>>> list(D.depth_first_search(Integer(5), neighbors=D.neighbors_out))[5, 33, 34, 35, 6, 7, 8, 9]>>> list(D.breadth_first_search(Integer(5), neighbors=D.neighbors_out))[5, 6, 33, 7, 34, 8, 35, 9]

You can get edges of the DFS tree instead of the vertices using the edges parameter:
sage: D = digraphs.Path(5)sage: list(D.depth_first_search(2, edges=True))[(2, 3), (3, 4)]
sage: list(D.depth_first_search(2, edges=True, ignore_direction=True))[(2, 3), (3, 4), (2, 1), (1, 0)]>>> from sage.all import *>>> D = digraphs.Path(Integer(5))>>> list(D.depth_first_search(Integer(2), edges=True))[(2, 3), (3, 4)]>>> list(D.depth_first_search(Integer(2), edges=True, ignore_direction=True))[(2, 3), (3, 4), (2, 1), (1, 0)]disjoint_routed_paths(pairs, solver, verbose=None, integrality_tolerance=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 theirendpoints and are vertex-disjoint otherwise.
INPUT:• pairs – list of pairs of vertices• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
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:
sage: g = graphs.Grid2dGraph(5, 5)
sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))])˓→# needs sage.numerical.mip

1.1. Generic graphs (common to directed/undirected)

␣107Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5), Integer(5))>>> p1,p2 = g.disjoint_routed_paths([((Integer(0), Integer(0)), (Integer(0),␣
˓→Integer(4))), ((Integer(4), Integer(4)), (Integer(4), Integer(0)))])
␣˓→# needs sage.numerical.mip

Though there is obviously no solution to the problem in which each corner is sending information to the
opposite one:sage: g = graphs.Grid2dGraph(5, 5)
sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))])˓→# needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: the disjoint routed paths do not exist

␣>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5), Integer(5))>>> p1,p2 = g.disjoint_routed_paths([((Integer(0), Integer(0)), (Integer(4),␣
˓→Integer(4))), ((Integer(0), Integer(4)), (Integer(4), Integer(0)))])
␣˓→# needs sage.numerical.mip
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 – string (default: pairs ); if set to pairs , each element v in the first graph will
be named (0, v) and each element u in other will be named (1, u) in the result. If set tointegers , the elements of the result will be relabeled with consecutive integers.
• immutable – boolean (default: None); whether to create a mutable/immutable disjoint union. immutable=None (default) means that the graphs and their disjoint union will behave the same way.
See also:• union()• join()EXAMPLES:
sage: G = graphs.CycleGraph(3)sage: H = graphs.CycleGraph(4)sage: J = G.disjoint_union(H); J
Cycle graph disjoint_union Cycle graph: Graph on 7 vertices
sage: J.vertices(sort=True)[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (1, 3)]
sage: J = G.disjoint_union(H, labels= integers ); J
Cycle graph disjoint_union Cycle graph: Graph on 7 vertices
sage: J.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6]
sage: (G + H).vertices(sort=True) # + -operator is a shortcut[0, 1, 2, 3, 4, 5, 6]

108

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> H = graphs.CycleGraph(Integer(4))>>> J = G.disjoint_union(H); J
Cycle graph disjoint_union Cycle graph: Graph on 7 vertices>>> J.vertices(sort=True)[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (1, 3)]>>> J = G.disjoint_union(H, labels= integers ); J
Cycle graph disjoint_union Cycle graph: Graph on 7 vertices>>> J.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6]>>> (G + H).vertices(sort=True) # + -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 pathsage: H = graphs.CycleGraph(3)sage: J = G.disjoint_union(H); J
Custom path disjoint_union Cycle graph: Graph on 5 vertices
sage: J.vertices(sort=True)[(0, a ), (0, b ), (1, 0), (1, 1), (1, 2)]>>> from sage.all import *>>> G = Graph({ a : [ b ]})>>> G.name("Custom path")>>> G.name()
Custom path>>> H = graphs.CycleGraph(Integer(3))>>> J = G.disjoint_union(H); J
Custom path disjoint_union Cycle graph: Graph on 5 vertices>>> J.vertices(sort=True)[(0, a ), (0, b ), (1, 0), (1, 1), (1, 2)]

disjunctive_product(other)
Return the disjunctive product of self and other.
The disjunctive product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) = 𝑉 (𝐺) × 𝑉 (𝐻), and((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff either :• (𝑢, 𝑤) is an edge of 𝐺, or• (𝑣, 𝑥) is an edge of 𝐻.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)sage: D = Z.disjunctive_product(Z); D
Graph on 4 vertices
sage: D.plot()# long time
˓→needs sage.plot
Graphics object consisting of 11 graphics primitives#␣>>> from sage.all import *>>> Z = graphs.CompleteGraph(Integer(2))>>> D = Z.disjunctive_product(Z); D(continues on next page)

1.1. Generic graphs (common to directed/undirected)

109

Graph Theory, Release 10.4

(continued from previous page)

Graph on 4 vertices>>> D.plot()# long time
˓→needs sage.plot
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
˓→needs sage.plot
Graphics object consisting of 46 graphics primitives#␣>>> from sage.all import *>>> C = graphs.CycleGraph(Integer(5))>>> D = C.disjunctive_product(Z); D
Graph on 10 vertices>>> D.plot()# long time
˓→needs sage.plot
Graphics object consisting of 46 graphics primitives#␣distance(u, v, by_weight=False, weight_function=None, check_weight=True)
Return the (directed) distance from u to v in the (di)graph.
The distance is 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 – boolean (default: False); 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).
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); whether to check that the weight_function outputs
a number for each edge.
EXAMPLES:
sage: G = graphs.CycleGraph(9)sage: G.distance(0,1)
1
sage: G.distance(0,4)
4sage: G.distance(0,5)
4sage: 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
˓→needs sage.plot#␣(continues on next page)

110

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.distance(0, 3)
2
sage: G.distance(0, 3, by_weight=True)
3>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(9))>>> G.distance(Integer(0),Integer(1))
1>>> G.distance(Integer(0),Integer(4))
4>>> G.distance(Integer(0),Integer(5))
4>>> G = Graph({Integer(0):[], Integer(1):[]})>>> G.distance(Integer(0),Integer(1))+Infinity>>> G = Graph({ Integer(0): {Integer(1): Integer(1)}, Integer(1):˓→{Integer(2): Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3):˓→{Integer(4): Integer(2)}, Integer(4): {Integer(0): Integer(2)}}, sparse =␣˓→True)>>> G.plot(edge_labels=True).show()# long time#␣˓→needs sage.plot>>> G.distance(Integer(0), Integer(3))
2>>> G.distance(Integer(0), Integer(3), by_weight=True)3

distance_all_pairs(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the distances between all pairs of vertices.
INPUT:• by_weight boolean (default: 𝐹 𝑎𝑙𝑠𝑒`); if True, the edges in the graph are weighted; if False, alledges have weight 1.
• algorithm – string (default: None); one of the following algorithms:–

BFS : the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False.

–

Floyd-Warshall-Cython : 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 withweighted 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.

1.1. Generic graphs (common to directed/undirected)

111

Graph Theory, Release 10.4

• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); whether to 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 thetime 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 suggest 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}}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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:
sage: g = graphs.RandomGNP(20,.3)
sage: distances = g.distance_all_pairs()
sage: all((g.distance(0,v) == Infinity and v not in distances[0]) or....:g.distance(0,v) == distances[0][v] for v in g)
True

112

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(20),RealNumber( .3 ))>>> distances = g.distance_all_pairs()>>> all((g.distance(Integer(0),v) == Infinity and v not in␣˓→distances[Integer(0)]) or...
g.distance(Integer(0),v) == distances[Integer(0)][v] for v in g)
True

See also:• distance_matrix()• shortest_path_all_pairs()
distance_matrix(vertices, base_ring=None, **kwds)
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 by default(vertices == None) indexed with the positions of the vertices of the (di)graph in the ordering vertices(). When vertices is set, the position of the vertices in this ordering is used. The intersection ofrow 𝑖 and column 𝑗 contains the shortest path distance from the vertex at the 𝑖-th position to the vertex at the𝑗-th position.
Note that even when the vertices are consecutive integers starting from one, usually the vertex is not equal toits index.
INPUT:• vertices – list (default: None); the ordering of the vertices defining how they should appear in thematrix. By default, the ordering given by vertices() is used. Because vertices() only works if
the vertices can be sorted, using vertices is useful when working with possibly non-sortable objects
in Python 3.
• base_ring – a ring (default: determined from the weights); the base ring of the matrix space to use.
• **kwds – other keywords to pass to the subfunction distance_all_pairs() or to matrix()
EXAMPLES:
sage: d = DiGraph({1: [2, 3], 2: [3], 3: [4], 4: [1]})sage: d.distance_matrix()
˓→needs sage.modules[0 1 1 2][3 0 1 2][2 3 0 1][1 2 2 0]
sage: d.distance_matrix(vertices=[4, 3, 2, 1])
˓→needs sage.modules[0 2 2 1][1 0 3 2][2 1 0 3][2 1 1 0]
sage: G = graphs.CubeGraph(3)sage: G.distance_matrix()
˓→needs sage.modules[0 1 1 2 1 2 2 3]

#␣

#␣

#␣

(continues on next page)

1.1. Generic graphs (common to directed/undirected)

113

Graph Theory, Release 10.4

(continued from previous page)[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]>>> from sage.all import *>>> d = DiGraph({Integer(1): [Integer(2), Integer(3)], Integer(2):␣
˓→[Integer(3)], Integer(3): [Integer(4)], Integer(4): [Integer(1)]})>>> d.distance_matrix()
˓→needs sage.modules[0 1 1 2][3 0 1 2][2 3 0 1][1 2 2 0]>>> d.distance_matrix(vertices=[Integer(4), Integer(3), Integer(2),␣
˓→Integer(1)])# needs sage.modules[0 2 2 1][1 0 3 2][2 1 0 3][2 1 1 0]>>> G = graphs.CubeGraph(Integer(3))>>> G.distance_matrix()
˓→needs sage.modules[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 oforder 𝑛 is (−1)𝑛−1 (𝑛 − 1)2𝑛−2 :sage: all(T.distance_matrix().det() == (-1)^9*(9)*2^8
˓→needs sage.modules....:
for T in graphs.trees(10))
True>>> from sage.all import *>>> all(T.distance_matrix().det() == (˓→Integer(1))**Integer(9)*(Integer(9))*Integer(2)**Integer(8)˓→# needs sage.modules...
for T in graphs.trees(Integer(10)))
True

#␣

␣

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

114

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

distances_distribution(G)Return the distances distribution of the (di)graph in a dictionary.
This method ignores all edge labels, so that the distance considered is the topological distance.
OUTPUT:
A dictionary d such that the number of pairs of vertices at distance k (if any) is equal to 𝑑[𝑘] ·|𝑉 (𝐺)| · (|𝑉 (𝐺)| − 1).
Note: We consider that two vertices that do not belong to the same connected component are at infinite
distance, and we do not take the trivial pairs of vertices (𝑣, 𝑣) at distance 0 into account. Empty (di)graphsand (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(){}>>> from sage.all import *>>> g = Graph()>>> g.distances_distribution(){}

A Graph of order 1:
sage: g = Graph()
sage: g.add_vertex(1)sage: g.distances_distribution(){}>>> from sage.all import *>>> g = Graph()>>> g.add_vertex(Integer(1))>>> 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}>>> from sage.all import *>>> g = Graph()>>> g.add_vertices([Integer(1),Integer(2)])>>> g.distances_distribution(){+Infinity: 1}

The Petersen Graph:1.1. Generic graphs (common to directed/undirected)

115

Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: g.distances_distribution(){1: 1/3, 2: 2/3}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.add_edge( good , wine )>>> 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)˓→# needs sage.combinat
sage: D.distances_distribution()˓→# needs sage.combinat{1: 1/4, 2: 11/28, 3: 5/14}

␣␣>>> from sage.all import *>>> D = digraphs.DeBruijn(Integer(2),Integer(3))˓→# needs sage.combinat>>> D.distances_distribution()
˓→# needs sage.combinat{1: 1/4, 2: 11/28, 3: 5/14}

␣dominating_set(g, k, independent=1, total=False, connected=False, value_only=False, solver=False,verbose=None, integrality_tolerance=0)
Return a minimum distance-𝑘 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.
A minimum distance-𝑘 dominating set is a set 𝑆 of vertices of 𝐺 of minimal cardinality such that any vertex
of 𝐺 is in 𝑆 or at distance at most 𝑘 from a vertex in 𝑆. A distance-0 dominating set is the set of vertices
itself, and when 𝑘 is the radius of the graph, any vertex dominates all the other vertices.
As an optimization problem, it can be expressed as follows, where 𝑁 𝑘 (𝑢) denotes the set of vertices at distanceat most 𝑘 from 𝑢 (the set of neighbors when 𝑘 = 1):∑︁Minimize :𝑏𝑣𝑣∈𝐺Such that : ∀𝑣 ∈ 𝐺, 𝑏𝑣 +∑︁

𝑏𝑢 ≥ 1𝑢∈𝑁 𝑘 (𝑣)∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
116

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

INPUT:• k – a non-negative integer (default: 1); the domination distance• independent – boolean (default: False); when True, computes a minimum independent dominating set, that is a minimum dominating set that is also an independent set (see also independent_set())• total – boolean (default: False); when True, computes a total dominating set (see the See the
Wikipedia article Dominating_set)• connected – boolean (default: False); when True, computes a connected dominating set (seeWikipedia article Connected_dominating_set)• value_only – boolean (default: False); whether to only return the cardinality of the computed
dominating set, or to return its list of vertices (default)• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic illustration on a PappusGraph:
sage: g = graphs.PappusGraph()
sage: g.dominating_set(value_only=True)˓→# needs sage.numerical.mip
5␣>>> from sage.all import *>>> g = graphs.PappusGraph()>>> g.dominating_set(value_only=True)
˓→# needs sage.numerical.mip
5

If we build a graph from two disjoint stars, then link their centers we will find a difference between the
cardinality of an independent set and a stable independent set:sage: g = 2 * graphs.StarGraph(5)sage: g.add_edge(0, 6)
sage: len(g.dominating_set())˓→# needs sage.numerical.mip
2
sage: len(g.dominating_set(independent=True))˓→# needs sage.numerical.mip
6␣␣>>> from sage.all import *>>> g = Integer(2) * graphs.StarGraph(Integer(5))>>> g.add_edge(Integer(0), Integer(6))>>> len(g.dominating_set())˓→# needs sage.numerical.mip
2>>> len(g.dominating_set(independent=True))(continues on next page)

1.1. Generic graphs (common to directed/undirected)

117Graph Theory, Release 10.4

(continued from previous page)# needs sage.numerical.mip

˓→

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)˓→# needs sage.numerical.mip
4␣>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.dominating_set(total=True, value_only=True)
˓→# needs sage.numerical.mip
4

The dominating set is calculated for both the directed and undirected graphs (modification introduced in Issue#17905):sage: g = digraphs.Path(3)sage: g.dominating_set(value_only=True)˓→# needs sage.numerical.mip
2
sage: g = graphs.PathGraph(3)sage: g.dominating_set(value_only=True)˓→# needs sage.numerical.mip1␣␣>>> from sage.all import *>>> g = digraphs.Path(Integer(3))>>> g.dominating_set(value_only=True)
˓→# needs sage.numerical.mip
2>>> g = graphs.PathGraph(Integer(3))>>> g.dominating_set(value_only=True)
˓→# needs sage.numerical.mip
1

Cardinality of distance-𝑘 dominating sets:
sage: G = graphs.PetersenGraph()
sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]␣˓→# needs sage.numerical.mip[10, 3, 1]
sage: G = graphs.PathGraph(5)sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]␣˓→# needs sage.numerical.mip[5, 2, 1]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> [G.dominating_set(k=k, value_only=True) for k in range(G.radius() +␣˓→Integer(1))]# needs sage.numerical.mip[10, 3, 1]>>> G = graphs.PathGraph(Integer(5))(continues on next page)

118

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> [G.dominating_set(k=k, value_only=True) for k in range(G.radius() +␣˓→Integer(1))]# needs sage.numerical.mip[5, 2, 1]dominating_sets(g, k, independent=1, total=False, connected=False, solver=False, verbose=None,
integrality_tolerance=0)
Return an iterator over the minimum distance-𝑘 dominating sets 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.
A minimum distance-𝑘 dominating set is a set 𝑆 of vertices of 𝐺 of minimal cardinality such that any vertex
of 𝐺 is in 𝑆 or at distance at most 𝑘 from a vertex in 𝑆. A distance-0 dominating set is the set of vertices
itself, and when 𝑘 is the radius of the graph, any vertex dominates all the other vertices.
As an optimization problem, it can be expressed as follows, where 𝑁 𝑘 (𝑢) denotes the set of vertices at distanceat most 𝑘 from 𝑢 (the set of neighbors when 𝑘 = 1):∑︁Minimize :𝑏𝑣𝑣∈𝐺Such that : ∀𝑣 ∈ 𝐺, 𝑏𝑣 +∑︁

𝑏𝑢 ≥ 1𝑢∈𝑁 𝑘 (𝑣)∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
We use constraints generation to iterate over the minimum distance-𝑘 dominating sets. That is, after reportinga solution, we add a constraint to discard it and solve the problem again until no more solution can be found.
INPUT:• k – a non-negative integer (default: 1); the domination distance• independent – boolean (default: False); when True, computes minimum independent dominating
sets, that is minimum dominating sets that are also independent sets (see also independent_set())• total – boolean (default: False); when True, computes total dominating sets (see the See the
Wikipedia article Dominating_set)• connected – boolean (default: False); when True, computes connected dominating sets (seeWikipedia article Connected_dominating_set)• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
Number of distance-𝑘 dominating sets of a Path graph of order 10:
sage: g = graphs.PathGraph(10)sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)]˓→# needs sage.numerical.mip[1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10]

1.1. Generic graphs (common to directed/undirected)

␣119Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PathGraph(Integer(10))>>> [sum(Integer(1) for _ in g.dominating_sets(k=k)) for k in␣˓→range(Integer(11))]# needs sage.numerical.mip[1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10]If we build a graph from two disjoint stars, then link their centers we will find a difference between the
cardinality of an independent set and a stable independent set:sage: g = 2 * graphs.StarGraph(5)sage: g.add_edge(0, 6)
sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)]˓→# needs sage.numerical.mip[1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12]␣>>> from sage.all import *>>> g = Integer(2) * graphs.StarGraph(Integer(5))>>> g.add_edge(Integer(0), Integer(6))>>> [sum(Integer(1) for _ in g.dominating_sets(k=k)) for k in␣˓→range(Integer(11))]# needs sage.numerical.mip[1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12]

The total dominating set of the Petersen graph has cardinality 4:
sage: G = graphs.PetersenGraph()
sage: G.dominating_set(total=True, value_only=True)˓→# needs sage.numerical.mip
4
sage: sorted(G.dominating_sets(k=1))
˓→# needs sage.numerical.mip[[0, 2, 6],[0, 3, 9],[0, 7, 8],[1, 3, 7],[1, 4, 5],[1, 8, 9],[2, 4, 8],[2, 5, 9],[3, 5, 6],[4, 6, 7]]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.dominating_set(total=True, value_only=True)
˓→# needs sage.numerical.mip
4>>> sorted(G.dominating_sets(k=Integer(1)))˓→# needs sage.numerical.mip[[0, 2, 6],[0, 3, 9],[0, 7, 8],[1, 3, 7],[1, 4, 5],[1, 8, 9],[2, 4, 8],[2, 5, 9],

␣

␣

␣

(continues on next page)

120

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[3, 5, 6],[4, 6, 7]]

Independent distance-𝑘 dominating sets of a Path graph:
sage: # needs sage.numerical.mip
sage: G = graphs.PathGraph(6)sage: sorted(G.dominating_sets(k=1, independent=True))[[1, 4]]sage: sorted(G.dominating_sets(k=2, independent=True))[[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5]]
sage: sorted(G.dominating_sets(k=3, independent=True))[[2], [3]]>>> from sage.all import *>>> # needs sage.numerical.mip>>> G = graphs.PathGraph(Integer(6))>>> sorted(G.dominating_sets(k=Integer(1), independent=True))[[1, 4]]>>> sorted(G.dominating_sets(k=Integer(2), independent=True))[[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5]]>>> sorted(G.dominating_sets(k=Integer(3), independent=True))[[2], [3]]The dominating set is calculated for both the directed and undirected graphs (modification introduced in Issue#17905):sage: # needs sage.numerical.mip
sage: g = digraphs.Path(3)sage: g.dominating_set(value_only=True)2
sage: list(g.dominating_sets())[[0, 1], [0, 2]]
sage: list(g.dominating_sets(k=2))[[0]]
sage: g = graphs.PathGraph(3)sage: g.dominating_set(value_only=True)1
sage: next(g.dominating_sets())[1]>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = digraphs.Path(Integer(3))>>> g.dominating_set(value_only=True)2>>> list(g.dominating_sets())[[0, 1], [0, 2]]>>> list(g.dominating_sets(k=Integer(2)))[[0]]>>> g = graphs.PathGraph(Integer(3))>>> g.dominating_set(value_only=True)
1>>> next(g.dominating_sets())[1]

Minimum connected dominating sets of the Petersen graph:1.1. Generic graphs (common to directed/undirected)

121Graph Theory, Release 10.4

sage: G = graphs.PetersenGraph()
sage: G.dominating_set(total=True, value_only=True)˓→# needs sage.numerical.mip
4
sage: sorted(G.dominating_sets(k=1, connected=True))˓→# needs sage.numerical.mip[[0, 1, 2, 6],[0, 1, 4, 5],[0, 3, 4, 9],[0, 5, 7, 8],[1, 2, 3, 7],[1, 6, 8, 9],[2, 3, 4, 8],[2, 5, 7, 9],[3, 5, 6, 8],[4, 6, 7, 9]]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.dominating_set(total=True, value_only=True)
˓→# needs sage.numerical.mip
4>>> sorted(G.dominating_sets(k=Integer(1), connected=True))˓→# needs sage.numerical.mip[[0, 1, 2, 6],[0, 1, 4, 5],[0, 3, 4, 9],[0, 5, 7, 8],[1, 2, 3, 7],[1, 6, 8, 9],[2, 3, 4, 8],[2, 5, 7, 9],[3, 5, 6, 8],[4, 6, 7, 9]]

␣

␣

␣

Subgraph induced by the dominating set is connected:
sage: G = graphs.PetersenGraph()
sage: all(G.subgraph(vertices=dom).is_connected()....:for dom in G.dominating_set(k=1, connected=True))
True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> all(G.subgraph(vertices=dom).is_connected()...
for dom in G.dominating_set(k=Integer(1), connected=True))
True

Minimum distance-k connected dominating sets of the Tietze graph:
sage: G = graphs.TietzeGraph()
sage: sorted(G.dominating_sets(k=2, connected=True))[[0, 9], [1, 0], [2, 3], [4, 3], [5, 6], [7, 6], [8, 0], [10, 3], [11, 6]]
sage: sorted(G.dominating_sets(k=3, connected=True))[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]]122

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.TietzeGraph()>>> sorted(G.dominating_sets(k=Integer(2), connected=True))[[0, 9], [1, 0], [2, 3], [4, 3], [5, 6], [7, 6], [8, 0], [10, 3], [11, 6]]>>> sorted(G.dominating_sets(k=Integer(3), connected=True))[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]]dominator_tree(g, root, return_dict=False, reverse=False)
Use 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 theconnected 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 – the input Sage (Di)Graph• root – the root of the dominator tree
• return_dict – boolean (default: False); if True, the function returns a dictionary associating toeach vertex its parent in the dominator tree. If False (default), it returns the whole tree, as a Graphor 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 fromroot. 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)]}>>> from sage.all import *>>> g = graphs.GridGraph([Integer(2),Integer(2)]).dominator_tree((Integer(0),˓→Integer(0)))>>> g.to_dictionary()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

123Graph Theory, Release 10.4

(continued from previous page){(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 , theparent 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}>>> from sage.all import *>>> G = Integer(2) * graphs.CycleGraph(Integer(3))>>> v = Integer(0)>>> w = Integer(3)>>> G.add_edge(v,w)>>> G.dominator_tree(Integer(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]}>>> from sage.all import *>>> g = digraphs.Circuit(Integer(10)).dominator_tree(Integer(5))>>> g.to_dictionary(){0: [1], 1: [2], 2: [3], 3: [4], 4: [], 5: [6], 6: [7], 7: [8], 8: [9], 9:␣
˓→[0]}>>> g = digraphs.Circuit(Integer(10)).dominator_tree(Integer(5), reverse=True)>>> 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)}>>> from sage.all import *>>> graphs.GridGraph([Integer(2),Integer(2)]).dominator_tree((Integer(0),˓→Integer(0)), return_dict=True){(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 0)}

edge_boundary(vertices1, vertices2=None, labels=True, sort=False, key=None)
Return a list of edges (u,v,l) with u in vertices1 and v in vertices2.

124

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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 – boolean (default: True); if False, each edge is a tuple (𝑢, 𝑣) of vertices• sort – boolean (default: False); whether to sort the result• key – a function (default: None); a function that takes an edge as its one argument and returns a valuethat can be used for comparisons in the sorting algorithm (we must have sort=True)
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>>> from sage.all import *>>> K = graphs.CompleteBipartiteGraph(Integer(9), Integer(3))>>> len(K.edge_boundary([Integer(0), Integer(1), Integer(2), Integer(3),␣
˓→Integer(4), Integer(5), Integer(6), Integer(7), Integer(8)], [Integer(9),␣
˓→Integer(10), Integer(11)]))27>>> 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>>> from sage.all import *>>> K = graphs.CompleteBipartiteGraph(Integer(9), Integer(3)).to_directed()>>> len(K.edge_boundary([Integer(0), Integer(1), Integer(2), Integer(3),␣
˓→Integer(4), Integer(5), Integer(6), Integer(7), Integer(8)], [Integer(9),␣
˓→Integer(10), Integer(11)]))27>>> 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)]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(3):␣
˓→[Integer(0)]})>>> D.edge_boundary([Integer(0)], sort=True)[(0, 1, None), (0, 2, None)](continues on next page)

1.1. Generic graphs (common to directed/undirected)

125Graph Theory, Release 10.4

(continued from previous page)>>> D.edge_boundary([Integer(0)], labels=False, sort=True)[(0, 1), (0, 2)]

Using the key argument to order multiple edges of incomparable types (see Issue #35903):
sage: G = Graph([(1, A , 4), (1, 2, 3)])sage: G.edge_boundary([1], sort=True)
Traceback (most recent call last):...
TypeError: unsupported operand parent(s) for <: Integer Ring and <class˓→ str >sage: G.edge_boundary([1], sort=True, key=str)[( A , 1, 4), (1, 2, 3)]
sage: G.edge_boundary([1], sort=True, key=lambda e:e[2])[(1, 2, 3), ( A , 1, 4)]
sage: G.edge_boundary([1], labels=False, sort=True, key=lambda e:e[2])Traceback (most recent call last):...
IndexError: tuple index out of range>>> from sage.all import *>>> G = Graph([(Integer(1), A , Integer(4)), (Integer(1), Integer(2),␣
˓→Integer(3))])>>> G.edge_boundary([Integer(1)], sort=True)
Traceback (most recent call last):...
TypeError: unsupported operand parent(s) for <: Integer Ring and <class˓→ str >>>> G.edge_boundary([Integer(1)], sort=True, key=str)[( A , 1, 4), (1, 2, 3)]>>> G.edge_boundary([Integer(1)], sort=True, key=lambda e:e[Integer(2)])[(1, 2, 3), ( A , 1, 4)]>>> G.edge_boundary([Integer(1)], labels=False, sort=True, key=lambda␣
˓→e:e[Integer(2)])
Traceback (most recent call last):...
IndexError: tuple index out of range

edge_connectivity(G, value_only=True, implementation=None, use_edge_labels=False, vertices=False,
solver=None, verbose=0, integrality_tolerance=0.001)
Return 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 Graphobject, and compute the connectivity of this other graph.
INPUT:• G – the input Sage (Di)Graph• value_only – boolean (default: True)– When set to True (default), only the value is returned.
126

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

– When set to False, both the value and a minimum vertex cut are returned.
• implementation – string (default: None); selects an implementation:– None (default) – selects the best implementation available– "boost" – use the Boost graph library (which is much more efficient). It is not available when
edge_labels=True, and it is unreliable for directed graphs (see Issue #18753).
-"Sage" – use Sage’s implementation based on integer linear
programming• 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic application on the PappusGraph:
sage: from sage.graphs.connectivity import edge_connectivity
sage: g = graphs.PappusGraph()
sage: edge_connectivity(g)3sage: g.edge_connectivity()3>>> from sage.all import *>>> from sage.graphs.connectivity import edge_connectivity>>> g = graphs.PappusGraph()>>> edge_connectivity(g)3>>> g.edge_connectivity()
3

The edge connectivity of a complete graph is its minimum degree, and one of the two parts of the bipartition
is reduced to only one vertex. The graph of the cut edges is isomorphic to a Star graph:
sage: g = graphs.CompleteGraph(5)sage: [ value, edges, [ setA, setB ]] = edge_connectivity(g,vertices=True)
sage: value
4
sage: len(setA) == 1 or len(setB) == 1
True(continues on next page)

1.1. Generic graphs (common to directed/undirected)

127Graph Theory, Release 10.4

(continued from previous page)

sage: cut = Graph()
sage: cut.add_edges(edges)
sage: cut.is_isomorphic(graphs.StarGraph(4))
True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> [ value, edges, [ setA, setB ]] = edge_connectivity(g,vertices=True)>>> value
4>>> len(setA) == Integer(1) or len(setB) == Integer(1)True>>> cut = Graph()>>> cut.add_edges(edges)>>> cut.is_isomorphic(graphs.StarGraph(Integer(4)))
True

Even if obviously in any graph we know that the edge connectivity is less than the minimum degree of thegraph:
sage: g = graphs.RandomGNP(10,.3)
sage: min(g.degree()) >= edge_connectivity(g)True>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(10),RealNumber( .3 ))>>> 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: tree = graphs.RandomTree(10)sage: for u,v in tree.edge_iterator(labels=None):....:tree.set_edge_label(u, v, random())
sage: minimum = min(tree.edge_labels())
sage: [_, [(_, _, l)]] = edge_connectivity(tree, value_only=False,˓→# needs sage.numerical.mip....:
use_edge_labels=True)
sage: l == minimum˓→# needs sage.numerical.mip
True

␣

␣

>>> from sage.all import *>>> tree = graphs.RandomTree(Integer(10))>>> for u,v in tree.edge_iterator(labels=None):...
tree.set_edge_label(u, v, random())>>> minimum = min(tree.edge_labels())>>> [_, [(_, _, l)]] = edge_connectivity(tree, value_only=False,
˓→# needs sage.numerical.mip...
use_edge_labels=True)>>> l == minimum
˓→# needs sage.numerical.mip
True

When value_only=True and implementation="sage", this function is optimized for small con128

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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>>> from sage.all import *>>> g = Integer(2) * graphs.PetersenGraph()>>> 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>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(3))>>> 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, implementation="boost")˓→# needs sage.numerical.mip....:== edge_connectivity(g, implementation="sage"))True␣>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(15), RealNumber( .3 ))>>> (edge_connectivity(g, implementation="boost")
˓→# needs sage.numerical.mip...
== 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}]]>>> from sage.all import *>>> edge_connectivity(digraphs.Circuit(Integer(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 Issue #18753):
sage: g = digraphs.Path(3)sage: edge_connectivity(g)0.0sage: edge_connectivity(g, implementation="boost")
1(continues on next page)

1.1. Generic graphs (common to directed/undirected)

129Graph Theory, Release 10.4

(continued from previous page)

sage: g.add_edge(1, 0)
sage: edge_connectivity(g)0.0sage: edge_connectivity(g, implementation="boost")0>>> from sage.all import *>>> g = digraphs.Path(Integer(3))>>> edge_connectivity(g)0.0>>> edge_connectivity(g, implementation="boost")
1>>> g.add_edge(Integer(1), Integer(0))>>> edge_connectivity(g)0.0>>> edge_connectivity(g, implementation="boost")0edge_cut(s, t, value_only, use_edge_labels=True, vertices=False, algorithm=False, solver='FF',verbose=None, integrality_tolerance=0)
Return a minimum edge cut between vertices 𝑠 and 𝑡.
A minimum edge cut between two vertices 𝑠 and 𝑡 of self is a set 𝐴 of edges of minimum weight such thatthe graph obtained by removing 𝐴 from the graph is disconnected. For more information, see the Wikipedia
article Cut_(graph_theory).
INPUT:• s – source vertex• t – sink vertex• value_only – boolean (default: True); whether to return only the weight of a minimum cut (True)or a list of edges of a minimum cut (False)• use_edge_labels – boolean (default: False); whether to compute a weighted minimum edge cut
where the weight of an edge is defined by its label (if an edge has no label, 1 is assumed), or to computea cut of minimum cardinality (i.e., edge weights are set to 1)• vertices – boolean (default: False); whether set to True, return a list of edges in the edge cut andthe two sets of vertices that are disconnected by the cut
Note: vertices=True implies value_only=False.
• algorithm – string (default: FF ); algorithm to use:
– If algorithm = "FF", a Python implementation of the Ford-Fulkerson algorithm is used
– If algorithm = "LP", the problem is solved using Linear Programming.
– If algorithm = "igraph", the igraph implementation of the Goldberg-Tarjan algorithm isused (only available when igraph is installed)– If algorithm = None, the problem is solved using the default maximum flow algorithm (seeflow())• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
130

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
Note: The use of Linear Programming for non-integer problems may possibly mean the presence of a (slight)
numerical noise.
OUTPUT:
Real number or tuple, depending on the given arguments (examples are given below).
EXAMPLES:
A basic application in the Pappus graph:
sage: g = graphs.PappusGraph()
sage: g.edge_cut(1, 2, value_only=True)
3>>> from sage.all import *>>> g = graphs.PappusGraph()>>> g.edge_cut(Integer(1), Integer(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]]]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.edge_cut(Integer(0), Integer(3), vertices=True)[3, [(0, 1, None), (0, 4, None), (0, 5, None)], [[0], [1, 2, 3, 4, 5, 6, 7, 8,
˓→ 9]]]

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())>>> from sage.all import *>>> g = graphs.PathGraph(Integer(15))>>> 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(g.edge_labels())
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]) == minimumTrue1.1. Generic graphs (common to directed/undirected)

131Graph Theory, Release 10.4>>> from sage.all import *>>> minimum = min(g.edge_labels())>>> minimum == g.edge_cut(Integer(0), Integer(14), use_edge_labels=True)
True>>> [value, [e]] = g.edge_cut(Integer(0), Integer(14), use_edge_labels=True,␣
˓→value_only=False)>>> g.edge_label(e[Integer(0)], e[Integer(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>>> from sage.all import *>>> value, edges, [set1, set2] = g.edge_cut(Integer(0), Integer(14), use_edge_
˓→labels=True,...
vertices=True)>>> g.subgraph(set1).is_isomorphic(graphs.PathGraph(len(set1)))
True>>> g.subgraph(set2).is_isomorphic(graphs.PathGraph(len(set2)))
True>>> len(set1) + len(set2) == g.order()Trueedge_disjoint_paths(s, t, algorithm, solver='FF', verbose=None, integrality_tolerance=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 numberof pairwise edge-independent paths from 𝑠 to 𝑡.
This function returns a list of such paths.
INPUT:• algorithm – string (default: "FF"); the algorithm to use among:– "FF", a Python implementation of the Ford-Fulkerson algorithm– "LP", the flow problem is solved using Linear Programming• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
Only used when 𝑙𝑔𝑜𝑟𝑖𝑡ℎ𝑚` is "LP".
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
Only used when 𝑙𝑔𝑜𝑟𝑖𝑡ℎ𝑚` is "LP".
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().

132

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Only used when 𝑙𝑔𝑜𝑟𝑖𝑡ℎ𝑚` is "LP".
Note: This function is topological: it does not take the eventual weights of the edges into account.
EXAMPLES:
In a complete bipartite graphsage: g = graphs.CompleteBipartiteGraph(2, 3)
sage: g.edge_disjoint_paths(0, 1)[[0, 2, 1], [0, 3, 1], [0, 4, 1]]>>> from sage.all import *>>> g = graphs.CompleteBipartiteGraph(Integer(2), Integer(3))>>> g.edge_disjoint_paths(Integer(0), Integer(1))[[0, 2, 1], [0, 3, 1], [0, 4, 1]]

edge_disjoint_spanning_trees(k, algorithm, root=None, solver=None, verbose=None,
integrality_tolerance=0)
Return the desired number of edge-disjoint spanning trees/arborescences.
INPUT:• k – integer; the required number of edge-disjoint spanning trees/arborescences• algorithm – string (default: None); specify the algorithm to use among:– "Roskind-Tarjan" – use the algorithm proposed by Roskind and Tarjan [RT1985] for findingedge-disjoint spanning-trees in undirected simple graphs in time 𝑂(𝑚 log 𝑚 + 𝑘 2 𝑛2 ).
– "MILP" – use a mixed integer linear programming formulation. This is the default method for
directed graphs.
– None – use "Roskind-Tarjan" for undirected graphs and "MILP" for directed graphs.
• root – vertex (default: None); root of the disjoint arborescences when the graph is directed. If set toNone, the first vertex in the graph is picked.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
ALGORITHM:
Mixed Integer Linear Program.
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 [Kai2012].
• The implementation of a Matroid class and of the Matroid Union Theorem (see section 42.3 of[Sch2003]), applied to the cycle Matroid (see chapter 51 of [Sch2003]).
EXAMPLES:
The Petersen Graph does have a spanning tree (it is connected):
1.1. Generic graphs (common to directed/undirected)

133Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: [T] = g.edge_disjoint_spanning_trees(1)˓→needs sage.numerical.mip
sage: T.is_tree()
˓→needs sage.numerical.mip
True

#␣
#␣

>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> [T] = g.edge_disjoint_spanning_trees(Integer(1))˓→# needs sage.numerical.mip>>> T.is_tree()
˓→needs sage.numerical.mip
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)˓→needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences>>> from sage.all import *>>> g.edge_disjoint_spanning_trees(Integer(2))˓→# needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences#␣␣

By Edmonds’ theorem, a graph which is 𝑘-connected always has 𝑘 edge-disjoint arborescences, regardless of
the root we pick:
sage: # needs sage.numerical.mip
sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf.
˓→#32169
sage: k = Integer(g.edge_connectivity())
sage: while not k:....:
g = digraphs.RandomDirectedGNP(11, .3)....:
k = Integer(g.edge_connectivity())
sage: arborescences = g.edge_disjoint_spanning_trees(k)# long time (up␣˓→to 15s on sage.math, 2011)
sage: all(a.is_directed_acyclic() for a in arborescences)# long timeTrue
sage: all(a.is_connected() for a in arborescences) # long timeTrue>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = digraphs.RandomDirectedGNP(Integer(11), RealNumber( .3 )) # reduced␣
˓→from 30 to 11, cf. #32169>>> k = Integer(g.edge_connectivity())>>> while not k:...
g = digraphs.RandomDirectedGNP(Integer(11), RealNumber( .3 ))(continues on next page)

134

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)...
k = Integer(g.edge_connectivity())>>> arborescences = g.edge_disjoint_spanning_trees(k)# long time (up to␣˓→15s on sage.math, 2011)>>> all(a.is_directed_acyclic() for a in arborescences)# long timeTrue>>> all(a.is_connected() for a in arborescences) # long timeTrue

In the undirected case, we can only ensure half of it:
sage: # needs sage.numerical.mip
sage: g = graphs.RandomGNP(14, .3) # reduced from 30 to 14, see #32169
sage: while not g.is_biconnected():....:g = graphs.RandomGNP(14, .3)
sage: k = Integer(g.edge_connectivity()) // 2
sage: trees = g.edge_disjoint_spanning_trees(k)sage: all(t.is_tree() for t in trees)
True>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.RandomGNP(Integer(14), RealNumber( .3 )) # reduced from 30 to␣
˓→14, see #32169>>> while not g.is_biconnected():...
g = graphs.RandomGNP(Integer(14), RealNumber( .3 ))>>> k = Integer(g.edge_connectivity()) // Integer(2)>>> trees = g.edge_disjoint_spanning_trees(k)>>> all(t.is_tree() for t in trees)
True

Check the validity of the algorithms for undirected graphs:
sage: # needs sage.numerical.mip
sage: g = graphs.RandomGNP(12, .7)
sage: k = Integer(g.edge_connectivity()) // 2
sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP")
sage: all(t.is_tree() for t in trees)True
sage: all(g.order() == t.size() + 1 for t in trees)True
sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="Roskind-Tarjan")sage: all(t.is_tree() for t in trees)True
sage: all(g.order() == t.size() + 1 for t in trees)
True>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.RandomGNP(Integer(12), RealNumber( .7 ))>>> k = Integer(g.edge_connectivity()) // Integer(2)>>> trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP")>>> all(t.is_tree() for t in trees)
True>>> all(g.order() == t.size() + Integer(1) for t in trees)True>>> trees = g.edge_disjoint_spanning_trees(k, algorithm="Roskind-Tarjan")(continues on next page)

1.1. Generic graphs (common to directed/undirected)

135Graph Theory, Release 10.4

(continued from previous page)>>> all(t.is_tree() for t in trees)
True>>> all(g.order() == t.size() + Integer(1) for t in trees)
True

Example of Issue #32169:
sage: d6 = r [E_S?_hKIH@eos[BSg???Q@FShGC?hTHUGM?IPug?JOEYCdOzdkQGo
sage: d6 += r @ADA@AAg?GAQW?[aIaSwHYcD@qQb@Dd?\hJTI@OHlJ_?C_OEIKoeC
sage: d6 += r R@_BC?Q??YBFosqITEA?IvCU_
sage: G = DiGraph(d6, format= dig6 )sage: G.edge_connectivity()
˓→needs sage.numerical.mip
5
sage: G.edge_disjoint_spanning_trees(5)# long time
˓→needs sage.numerical.mip[Digraph on 28 vertices,
Digraph on 28 vertices,
Digraph on 28 vertices,
Digraph on 28 vertices,
Digraph on 28 vertices]>>> from sage.all import *>>> d6 = r [E_S?_hKIH@eos[BSg???Q@FShGC?hTHUGM?IPug?JOEYCdOzdkQGo>>> d6 += r @ADA@AAg?GAQW?[aIaSwHYcD@qQb@Dd?\hJTI@OHlJ_?C_OEIKoeC>>> d6 += r R@_BC?Q??YBFosqITEA?IvCU_>>> G = DiGraph(d6, format= dig6 )>>> G.edge_connectivity()
˓→needs sage.numerical.mip
5>>> G.edge_disjoint_spanning_trees(Integer(5))# long time˓→# needs sage.numerical.mip[Digraph on 28 vertices,
Digraph on 28 vertices,
Digraph on 28 vertices,
Digraph on 28 vertices,
Digraph on 28 vertices]

#␣

#␣

#␣

␣

Small cases:
sage: # needs sage.numerical.mip
sage: Graph().edge_disjoint_spanning_trees(0)[]sage: Graph(1).edge_disjoint_spanning_trees(0)[]sage: Graph(2).edge_disjoint_spanning_trees(0)[]sage: Graph([(0, 1)]).edge_disjoint_spanning_trees(0)[]sage: Graph([(0, 1)]).edge_disjoint_spanning_trees(1)[Graph on 2 vertices]sage: Graph([(0, 1)]).edge_disjoint_spanning_trees(2)Traceback (most recent call last):...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences

136

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.numerical.mip>>> Graph().edge_disjoint_spanning_trees(Integer(0))[]>>> Graph(Integer(1)).edge_disjoint_spanning_trees(Integer(0))[]>>> Graph(Integer(2)).edge_disjoint_spanning_trees(Integer(0))[]>>> Graph([(Integer(0), Integer(1))]).edge_disjoint_spanning_trees(Integer(0))[]>>> Graph([(Integer(0), Integer(1))]).edge_disjoint_spanning_trees(Integer(1))[Graph on 2 vertices]>>> Graph([(Integer(0), Integer(1))]).edge_disjoint_spanning_trees(Integer(2))
Traceback (most recent call last):...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences

edge_iterator(vertices=None, labels=True, ignore_direction=False, sort_vertices=True)
Return an iterator over edges.
The iterator returned is over the edges incident with any vertex given in the parameter vertices. If thegraph is directed, iterates over edges going out only. If vertices is None, then returns an iterator over alledges. If self is directed, returns outgoing edges only.
INPUT:• vertices – object (default: None); a vertex, a list of vertices or None
• labels – boolean (default: True); if False, each edge isa tuple (𝑢, 𝑣) of vertices• ignore_direction – boolean (default: False); only applies todirected graphs. If True, searches across edges in either direction.
• sort_vertices – boolean (default: True); only applies to undirected graphs. If True, sort theends of the edges. Not sorting the ends is faster.
Note: It is somewhat safe to modify the graph during iterating.
vertices must be specified if modifying the vertices.
Without multiedges, you can safely use this graph to relabel edges or delete some edges. If you add edges,
they might later appear in the iterator or not (depending on the internal order of vertices).
In case of multiedges, all arcs from one vertex to another are internally cached. So the iterator will yield them,even if you delete them all after seeing the first one.
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)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

137Graph Theory, Release 10.4

(continued from previous page)(0, 1, None)(0, 2, None)>>> from sage.all import *>>> for i in graphs.PetersenGraph().edge_iterator([Integer(0)]):... print(i)(0, 1, None)(0, 4, None)(0, 5, None)>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(0)]})>>> for i in D.edge_iterator([Integer(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)]>>> from sage.all import *>>> G = graphs.TetrahedralGraph()>>> list(G.edge_iterator(labels=False))[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G = graphs.TetrahedralGraph()
sage: list(G.edge_iterator(labels=False, sort_vertices=False))[(1, 0), (2, 0), (3, 0), (2, 1), (3, 1), (3, 2)]>>> from sage.all import *>>> G = graphs.TetrahedralGraph()>>> list(G.edge_iterator(labels=False, sort_vertices=False))[(1, 0), (2, 0), (3, 0), (2, 1), (3, 1), (3, 2)]
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)]>>> from sage.all import *>>> D = DiGraph({Integer(1): [Integer(0)], Integer(2): [Integer(0)]})>>> list(D.edge_iterator(Integer(0)))[]>>> list(D.edge_iterator(Integer(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()138

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

EXAMPLES:
sage: G = Graph({0: {1: edgelabel }})sage: G.edge_label(0, 1)
edgelabelsage: D = DiGraph({1: {2: up }, 2: {1:sage: D.edge_label(2, 1)
down

down }})>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1): edgelabel }})>>> G.edge_label(Integer(0), Integer(1))
edgelabel>>> D = DiGraph({Integer(1): {Integer(2): up }, Integer(2): {Integer(1):˓→ down }})>>> D.edge_label(Integer(2), Integer(1))
downsage: 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]>>> from sage.all import *>>> G = Graph(multiedges=True)>>> [G.add_edge(Integer(0), Integer(1), i) for i in range(Integer(1),␣
˓→Integer(6))][None, None, None, None, None]>>> sorted(G.edge_label(Integer(0), Integer(1)))[1, 2, 3, 4, 5]

edge_labels()
Return a list of the labels of all edges in self.
The output list is not sorted.
EXAMPLES:
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 ]>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1): x , Integer(2): z , Integer(3): a }˓→, Integer(2): {Integer(5):out }}, sparse=True)>>> G.edge_labels()[ x , z , a , out ]>>> G = DiGraph({Integer(0): {Integer(1): x , Integer(2): z , Integer(3): a
˓→ }, Integer(2): {Integer(5):out }}, sparse=True)>>> G.edge_labels()[ x , z , a , out ]edge_polytope(backend=None)

1.1. Generic graphs (common to directed/undirected)

139Graph Theory, Release 10.4

Return the edge polytope of self.
The edge polytope (EP) of a Graph on 𝑛 vertices is the polytope infor each edge (𝑖, 𝑗). Here 𝑒1 , . . . , 𝑒𝑛 denotes the standard basis.

𝑛defined as the convex hull of 𝑒𝑖 + 𝑒𝑗

INPUT:• backend – string or None (default); the backend to use; see sage.geometry.polyhedron.
constructor.Polyhedron()
EXAMPLES:
The EP of a 4-cycle is a square:
sage: G = graphs.CycleGraph(4)sage: P = G.edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> P = G.edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices

The EP of a complete graph on 4 vertices is cross polytope:
sage: G = graphs.CompleteGraph(4)sage: P = G.edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices
sage: P.is_combinatorially_isomorphic(polytopes.cross_polytope(3))#␣˓→needs sage.geometry.polyhedron
True>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> P = G.edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices>>> P.is_combinatorially_isomorphic(polytopes.cross_polytope(Integer(3)))␣˓→# needs sage.geometry.polyhedron
True

The EP of a graph is isomorphic to the subdirect sum of its connected components EPs:
sage: n = randint(3, 6)
sage: G1 = graphs.RandomGNP(n, 0.2)
˓→needs networkx
sage: n = randint(3, 6)
sage: G2 = graphs.RandomGNP(n, 0.2)
˓→needs networkx
sage: G = G1.disjoint_union(G2)˓→needs networkx
sage: P = G.edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: P1 = G1.edge_polytope()
˓→needs networkx sage.geometry.polyhedron

#␣

#␣
#␣
#␣
#␣
(continues on next page)

140

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: P2 = G2.edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2))
˓→needs networkx sage.geometry.polyhedron
True>>> from sage.all import *>>> n = randint(Integer(3), Integer(6))>>> G1 = graphs.RandomGNP(n, RealNumber( 0.2 ))˓→# needs networkx>>> n = randint(Integer(3), Integer(6))>>> G2 = graphs.RandomGNP(n, RealNumber( 0.2 ))˓→# needs networkx>>> G = G1.disjoint_union(G2)˓→needs networkx>>> P = G.edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> P1 = G1.edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> P2 = G2.edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> P.is_combinatorially_isomorphic(P1.subdirect_sum(P2))
˓→needs networkx sage.geometry.polyhedron
True

#␣
#␣

␣

␣
#␣
#␣
#␣
#␣
#␣

All trees on 𝑛 vertices have isomorphic EPs:
sage: n = randint(4, 10)
sage: G1 = graphs.RandomTree(n)sage: G2 = graphs.RandomTree(n)sage: P1 = G1.edge_polytope()
˓→needs sage.geometry.polyhedronsage: P2 = G2.edge_polytope()
˓→needs sage.geometry.polyhedronsage: P1.is_combinatorially_isomorphic(P2)˓→needs sage.geometry.polyhedron
True>>> from sage.all import *>>> n = randint(Integer(4), Integer(10))>>> G1 = graphs.RandomTree(n)>>> G2 = graphs.RandomTree(n)>>> P1 = G1.edge_polytope()
˓→needs sage.geometry.polyhedron>>> P2 = G2.edge_polytope()
˓→needs sage.geometry.polyhedron>>> P1.is_combinatorially_isomorphic(P2)˓→needs sage.geometry.polyhedron
True

#␣
#␣
#␣

#␣
#␣
#␣

However, there are still many different EPs:
sage: len(list(graphs(5)))
34
sage: polys = []sage: for G in graphs(5):#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

141Graph Theory, Release 10.4

(continued from previous page)needs sage.geometry.polyhedron....:
P = G.edge_polytope()....:
for P1 in polys:....:
if P.is_combinatorially_isomorphic(P1):
....:
break
....:
else:
....:
polys.append(P)sage: len(polys)
˓→needs sage.geometry.polyhedron19˓→>>> from sage.all import *>>> len(list(graphs(Integer(5))))34>>> polys = []>>> for G in graphs(Integer(5)):˓→# needs sage.geometry.polyhedron...
P = G.edge_polytope()...
for P1 in polys:...
if P.is_combinatorially_isomorphic(P1):
...
break
...
else:
...
polys.append(P)>>> len(polys)
˓→needs sage.geometry.polyhedron
19

#␣

␣

#␣

edges(vertices=None, labels=True, sort=False, key=None, ignore_direction=False, sort_vertices=True)
Return a EdgesView 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.
The returned EdgesView is over the edges incident with any vertex given in the parameter vertices (alledges if None). If self is directed, iterates over outgoing edges only, unless parameter ignore_direction is True in which case it searches across edges in either direction.
INPUT:• vertices – object (default: None); a vertex, a list of vertices or None
• labels – boolean (default: True); if False, each edge is simply a pair (u, v) of vertices• sort – boolean (default: False); whether to sort edges according the ordering specified with parameter
key. If False (default), edges are not sorted. This is the fastest and less memory consuming method
for iterating over edges.
• key – a function (default: None); a function that takes an edge (a pair or a triple, according to thelabels keyword) as its one argument and returns a value that can be used for comparisons in thesorting algorithm• ignore_direction – boolean (default: False); only applies todirected graphs. If True, searches across edges in either direction.
• sort_vertices – boolean (default: True); only applies to undirected graphs. If True, sort theends of the edges. Not sorting the ends is faster.
OUTPUT: A EdgesView.

142

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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 thevertices will be sorted. However, if you need to guarantee a total order for the sorting of the edges, use
the key argument, as illustrated in the examples below.
EXAMPLES:
sage: graphs.DodecahedralGraph().edges(sort=True)[(0, 1, None), (0, 10, None), (0, 19, None), (1, 2, None),(1, 8, None), (2, 3, None), (2, 6, None), (3, 4, None),(3, 19, None), (4, 5, None), (4, 17, None), (5, 6, None),(5, 15, None), (6, 7, None), (7, 8, None), (7, 14, None),(8, 9, None), (9, 10, None), (9, 13, None), (10, 11, None),(11, 12, None), (11, 18, None), (12, 13, None), (12, 16, None),(13, 14, None), (14, 15, None), (15, 16, None), (16, 17, None),(17, 18, None), (18, 19, None)]>>> from sage.all import *>>> graphs.DodecahedralGraph().edges(sort=True)[(0, 1, None), (0, 10, None), (0, 19, None), (1, 2, None),(1, 8, None), (2, 3, None), (2, 6, None), (3, 4, None),(3, 19, None), (4, 5, None), (4, 17, None), (5, 6, None),(5, 15, None), (6, 7, None), (7, 8, None), (7, 14, None),(8, 9, None), (9, 10, None), (9, 13, None), (10, 11, None),(11, 12, None), (11, 18, None), (12, 13, None), (12, 16, None),(13, 14, None), (14, 15, None), (15, 16, None), (16, 17, None),(17, 18, None), (18, 19, None)]sage: graphs.DodecahedralGraph().edges(sort=True, 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)]>>> from sage.all import *>>> graphs.DodecahedralGraph().edges(sort=True, 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(sort=True)[(0, 1, None), (0, 10, None), (0, 19, None), (1, 0, None),(1, 2, None), (1, 8, None), (2, 1, None), (2, 3, None),(2, 6, None), (3, 2, None), (3, 4, None), (3, 19, None),(4, 3, None), (4, 5, None), (4, 17, None), (5, 4, None),(5, 6, None), (5, 15, None), (6, 2, None), (6, 5, None),(6, 7, None), (7, 6, None), (7, 8, None), (7, 14, None),(8, 1, None), (8, 7, None), (8, 9, None), (9, 8, None),(9, 10, None), (9, 13, None), (10, 0, None), (10, 9, None),(10, 11, None), (11, 10, None), (11, 12, None), (11, 18, None),(continues on next page)

1.1. Generic graphs (common to directed/undirected)

143Graph Theory, Release 10.4

(continued from previous page)(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(sort=True, 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)]>>> from sage.all import *>>> D = graphs.DodecahedralGraph().to_directed()>>> D.edges(sort=True)[(0, 1, None), (0, 10, None), (0, 19, None), (1, 0, None),(1, 2, None), (1, 8, None), (2, 1, None), (2, 3, None),(2, 6, None), (3, 2, None), (3, 4, None), (3, 19, None),(4, 3, None), (4, 5, None), (4, 17, None), (5, 4, None),(5, 6, None), (5, 15, None), (6, 2, None), (6, 5, None),(6, 7, None), (7, 6, None), (7, 8, None), (7, 14, None),(8, 1, None), (8, 7, None), (8, 9, None), (9, 8, None),(9, 10, None), (9, 13, None), (10, 0, None), (10, 9, None),(10, 11, None), (11, 10, None), (11, 12, None), (11, 18, None),(12, 11, None), (12, 13, None), (12, 16, None), (13, 9, None),(13, 12, None), (13, 14, None), (14, 7, None), (14, 13, None),(14, 15, None), (15, 5, None), (15, 14, None), (15, 16, None),(16, 12, None), (16, 15, None), (16, 17, None), (17, 4, None),(17, 16, None), (17, 18, None), (18, 11, None), (18, 17, None),(18, 19, None), (19, 0, None), (19, 3, None), (19, 18, None)]>>> D.edges(sort=True, 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 overriddenby specifying a key function. This first example just ignores the labels in the third component of the triple:
sage: G = graphs.CycleGraph(5)sage: G.edges(sort=True, key=lambda x: (x[1], -x[0]))[(0, 1, None), (1, 2, None), (2, 3, None), (3, 4, None), (0, 4, None)]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(5))>>> G.edges(sort=True, key=lambda x: (x[Integer(1)], -x[Integer(0)]))(continues on next page)

144

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[(0, 1, None), (1, 2, None), (2, 3, None), (3, 4, None), (0, 4, None)]

We set the labels to characters and then perform a default sort followed by a sort according to the labels:
sage: G = graphs.CycleGraph(5)sage: for e in G.edges(sort=False):....:
G.set_edge_label(e[0], e[1], chr(ord( A ) + e[0] + 5 * e[1]))sage: G.edges(sort=True)[(0, 1, F ), (0, 4, U ), (1, 2, L ), (2, 3, R ), (3, 4, X )]sage: G.edges(sort=True, key=lambda x: x[2])[(0, 1, F ), (1, 2, L ), (2, 3, R ), (0, 4, U ), (3, 4, X )]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(5))>>> for e in G.edges(sort=False):...
G.set_edge_label(e[Integer(0)], e[Integer(1)], chr(ord( A ) +␣˓→e[Integer(0)] + Integer(5) * e[Integer(1)]))>>> G.edges(sort=True)[(0, 1, F ), (0, 4, U ), (1, 2, L ), (2, 3, R ), (3, 4, X )]>>> G.edges(sort=True, key=lambda x: x[Integer(2)])[(0, 1, F ), (1, 2, L ), (2, 3, R ), (0, 4, U ), (3, 4, X )]We can restrict considered edges to those incident to a given set:sage: for i in graphs.PetersenGraph().edges(sort=True, vertices=[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.edges(sort=True, vertices=[0]):....:print(i)(0, 1, None)(0, 2, None)>>> from sage.all import *>>> for i in graphs.PetersenGraph().edges(sort=True, vertices=[Integer(0)]):...
print(i)(0, 1, None)(0, 4, None)(0, 5, None)>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(0)]})>>> for i in D.edges(sort=True, vertices=[Integer(0)]):...
print(i)(0, 1, None)(0, 2, None)

Ignoring the direction of edges:
sage: D = DiGraph({1: [0], 2: [0]})sage: D.edges(sort=True, vertices=0)[]
sage: D.edges(sort=True, vertices=0, ignore_direction=True)[(1, 0, None), (2, 0, None)](continues on next page)

1.1. Generic graphs (common to directed/undirected)

145Graph Theory, Release 10.4

(continued from previous page)

sage: D.edges(sort=True, vertices=[0], ignore_direction=True)[(1, 0, None), (2, 0, None)]>>> from sage.all import *>>> D = DiGraph({Integer(1): [Integer(0)], Integer(2): [Integer(0)]})>>> D.edges(sort=True, vertices=Integer(0))[]>>> D.edges(sort=True, vertices=Integer(0), ignore_direction=True)[(1, 0, None), (2, 0, None)]>>> D.edges(sort=True, vertices=[Integer(0)], ignore_direction=True)[(1, 0, None), (2, 0, None)]

Not sorting the ends of the edges:
sage: G = Graph()
sage: G = Graph()
sage: G.add_edges([[1,2], [2,3], [0,3]])
sage: list(G.edge_iterator(sort_vertices=False))[(3, 0, None), (2, 1, None), (3, 2, None)]>>> from sage.all import *>>> G = Graph()>>> G = Graph()>>> G.add_edges([[Integer(1),Integer(2)], [Integer(2),Integer(3)],␣
˓→[Integer(0),Integer(3)]])>>> list(G.edge_iterator(sort_vertices=False))[(3, 0, None), (2, 1, None), (3, 2, None)]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 ofvertices then it returns the list of all edges adjacent to those vertices. If vertices is None, it returns a listof all edges in graph. For digraphs, only lists outward edges.
INPUT:• vertices – object (default: None); a vertex, a list of vertices or None
• labels – boolean (default: True); if False, each edge isa tuple (𝑢, 𝑣) 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])[]>>> from sage.all import *>>> graphs.PetersenGraph().edges_incident([Integer(0), Integer(9)],␣
˓→labels=False)(continues on next page)

146

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[(0, 1), (0, 4), (0, 5), (4, 9), (6, 9), (7, 9)]>>> D = DiGraph({Integer(0): [Integer(1)]})>>> D.edges_incident([Integer(0)])[(0, 1, None)]>>> D.edges_incident([Integer(1)])[]

eigenspaces(laplacian=False)
Return the right eigenspaces of the adjacency matrix of the graph.
INPUT:• laplacian – boolean (default: False); if True, use theLaplacian 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 spacethat 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()
˓→needs sage.modules sage.rings.number_field[(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])]>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.eigenspaces()
˓→needs sage.modules sage.rings.number_field[(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]#␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

147Graph Theory, Release 10.4

(continued from previous page)(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]),
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 theoutput also contains the eigenvalues, the two outputs are slightly different:
sage: P.eigenspaces(laplacian=True)
˓→needs sage.modules sage.rings.number_field[(0, Vector space of degree 10 and dimension 1 over Rational Field
User basis matrix:[1 1 1 1 1 1 1 1 1 1]),
(5, Vector space of degree 10 and dimension 4 over Rational Field
User basis matrix:[ 1 0 0 0 -1 -1 -1 0 1 1]
[ 0 1 0 0 -1 0 -2 -1 1 2]
[ 0 0 1 0 -1 1 -1 -2 0 2]
[ 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])]>>> from sage.all import *>>> P.eigenspaces(laplacian=True)
˓→needs sage.modules sage.rings.number_field[(0, Vector space of degree 10 and dimension 1 over Rational Field
User basis matrix:[1 1 1 1 1 1 1 1 1 1]),
(5, Vector space of degree 10 and dimension 4 over Rational Field
User basis matrix:[ 1 0 0 0 -1 -1 -1 0 1 1]
[ 0 1 0 0 -1 0 -2 -1 1 2]
[ 0 0 1 0 -1 1 -1 -2 0 2]
[ 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])#␣#␣(continues on next page)

148

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)]

Notice how one eigenspace below is described with a square root of 2. For the two possible values (positive
and negative) there is a corresponding eigenspace:sage: C = graphs.CycleGraph(8)sage: C.eigenspaces()
˓→needs sage.modules sage.rings.number_field[(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 overNumber 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])]>>> from sage.all import *>>> C = graphs.CycleGraph(Integer(8))>>> C.eigenspaces()
˓→needs sage.modules sage.rings.number_field[(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 overNumber 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()
˓→needs sage.modules sage.rings.number_field[(1, Vector space of degree 3 and dimension 1 over Rational Field
User basis matrix:#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

149Graph Theory, Release 10.4

(continued from previous page)[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])]>>> from sage.all import *>>> T = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(0)]})>>> T.eigenspaces()
˓→needs sage.modules sage.rings.number_field[(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)
Return the right eigenvectors of the adjacency matrix of the graph.
INPUT:• laplacian – boolean (default: False); if True, use the Laplacian matrix (see kirchhoff_matrix())
OUTPUT:
A list of triples. Each triple begins with an eigenvalue of the adjacency matrix of the graph. This is followed
by a list of eigenvectors for the eigenvalue, when the eigenvectors are placed on the right side of the matrix.
Together, the eigenvectors form a basis for the eigenspace. The triple concludes with the algebraic multiplicityof the eigenvalue.
For some graphs, the exact eigenspaces provided by eigenspaces() provide additional insight into thestructure of the eigenspaces.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.eigenvectors()
˓→needs sage.modules sage.rings.number_field[(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),

#␣(continues on next page)

150

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)(0, 0, 0, 0, 1, -1, 0, 0, -1, 1)], 5)]>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.eigenvectors()
˓→needs sage.modules sage.rings.number_field[(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 theoutput also contains the eigenvalues, the two outputs are slightly different:
sage: P.eigenvectors(laplacian=True)
˓→needs sage.modules sage.rings.number_field[(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)]>>> from sage.all import *>>> P.eigenvectors(laplacian=True)
˓→needs sage.modules sage.rings.number_field[(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),#␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

151

Graph Theory, Release 10.4

(continued from previous page)(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()
˓→needs sage.modules sage.rings.number_field[(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),(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)]>>> from sage.all import *>>> C = graphs.CycleGraph(Integer(8))>>> C.eigenvectors()
˓→needs sage.modules sage.rings.number_field[(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),(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),

#␣

#␣

(continues on next page)

152

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)(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()#␣˓→needs sage.modules sage.rings.number_field[(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)]>>> from sage.all import *>>> T = DiGraph({Integer(0):[Integer(1)], Integer(1):[Integer(2)],␣
˓→Integer(2):[Integer(0)]})>>> T.eigenvectors()#␣˓→needs sage.modules sage.rings.number_field[(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.
If no Eulerian circuit is found, the method returns False.
This is implemented using Hierholzer’s algorithm.
INPUT:• return_vertices – boolean (default: False); optionallyprovide a list of vertices for the path• labels – boolean (default: True); whether to return edges
with labels (3-tuples)
1.1. Generic graphs (common to directed/undirected)

153

Graph Theory, Release 10.4

• path – boolean (default: False); find an Eulerian pathinsteadOUTPUT: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)]>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.eulerian_circuit()[(0, 4, None), (4, 3, None), (3, 2, None), (2, 1, None), (1, 0, None)]>>> 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]>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(7))>>> edges, vertices = g.eulerian_circuit(return_vertices=True)>>> 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>>> from sage.all import *>>> graphs.CompleteGraph(Integer(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)]>>> from sage.all import *>>> g = Graph({Integer(0): [], Integer(1): [Integer(2)], Integer(2):␣
˓→[Integer(3)], Integer(3): [Integer(1)], Integer(4): []})>>> g.eulerian_circuit(labels=False)[(1, 3), (3, 2), (2, 1)]
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)]154

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(2),␣
˓→Integer(4)], Integer(2):[Integer(3)], Integer(3):[Integer(1)]})>>> 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)]>>> from sage.all import *>>> g = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2),Integer(3)], Integer(2):[Integer(3),Integer(4)],␣
˓→Integer(3):[Integer(4)]})>>> g.is_eulerian(path=True)(0, 1)>>> 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()
Return a DiGraph which is an Eulerian orientation of the current graph.
An Eulerian graph being a graph such that any vertex has an even degree, an Eulerian orientation of a graphis 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 thewalk. When a vertex is reached which has no non-oriented edge (this vertex must have odd degree), the walkresumes at another vertex of odd degree, if any.
This algorithm has complexity 𝑂(𝑛 + 𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph, where 𝑚 isthe number of edges in the graph and 𝑛 is the number of vertices 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]>>> from sage.all import *>>> g = graphs.CubeGraph(Integer(4))>>> g.degree()[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]>>> o = g.eulerian_orientation()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

155Graph Theory, Release 10.4

(continued from previous page)>>> o.in_degree()[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]>>> 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]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> o = g.eulerian_orientation()>>> o.in_degree()[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]>>> 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 (default: None); select the output format explicitly. If set to None (default), theformat is set to be the file extension of filename. Admissible formats are: adjlist , dot ,edgelist , gexf , gml , graphml , multiline_adjlist , pajek .
• All other arguments are forwarded to the subfunction. For more information, see their respective documentation:
adjlistdot
edgelist
gexf
gml
graphmlmultiline_adjlist
pajek

networkx.readwrite.adjlist.write_adjlist()
networkx.drawing.nx_pydot.write_dot()
networkx.readwrite.edgelist.write_edgelist()
networkx.readwrite.gexf.write_gexf()
networkx.readwrite.gml.write_gml()
networkx.readwrite.graphml.write_graphml()
networkx.readwrite.multiline_adjlist.
write_multiline_adjlist()
networkx.readwrite.pajek.write_pajek()

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 networkx.readwrite).
EXAMPLES:
156

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: filename = tmp_filename(ext=".pajek")
sage: g.export_to_file(filename)
˓→needs networkx
sage: import networkx
˓→needs networkx
sage: G_networkx = networkx.read_pajek(filename)
˓→needs networkx
sage: Graph(G_networkx).is_isomorphic(g)˓→needs networkx
True
sage: filename = tmp_filename(ext=".edgelist")
sage: g.export_to_file(filename, data=False)
˓→needs networkx
sage: h = Graph(networkx.read_edgelist(filename))
˓→needs networkx
sage: g.is_isomorphic(h)˓→needs networkx
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> filename = tmp_filename(ext=".pajek")>>> g.export_to_file(filename)
˓→needs networkx>>> import networkx
˓→needs networkx>>> G_networkx = networkx.read_pajek(filename)
˓→needs networkx>>> Graph(G_networkx).is_isomorphic(g)˓→needs networkx
True>>> filename = tmp_filename(ext=".edgelist")>>> g.export_to_file(filename, data=False)
˓→needs networkx>>> h = Graph(networkx.read_edgelist(filename))
˓→needs networkx>>> g.is_isomorphic(h)˓→needs networkx
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 thisinformation one can define the faces of the embedding, which is what this method returns.
If no embedding is provided or stored as self._embedding, this method will compute the set of faces
from the embedding returned by is_planar() (if the graph is, of course, planar).
Warning: This method is not well defined when the graph is not connected. Indeed, the result may
contain several faces corresponding to the external face.
INPUT:• embedding – dictionary (default: None); a combinatorial embedding dictionary. Format: {v1:1.1. Generic graphs (common to directed/undirected)

157

Graph Theory, Release 10.4

[v2,v3], v2: [v1], v3: [v1]} (clockwise ordering of neighbors at each vertex). If set toNone (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 graphis, of course, planar).
Note: embedding is an ordered list based on the hash order of the vertices of graph. To avoid confusion,
it might be best to set the rot_sys based on a ‘nice_copy’ of the graph.
See also:• set_embedding()• get_embedding()• is_planar()• planar_dual()
EXAMPLES:
Providing an embedding:sage: T = graphs.TetrahedralGraph()
sage: T.faces({0: [1, 3, 2], 1: [0, 2, 3], 2: [0, 3, 1], 3: [0, 1, 2]})[[(0, 1), (1, 2), (2, 0)],[(0, 2), (2, 3), (3, 0)],[(0, 3), (3, 1), (1, 0)],[(1, 3), (3, 2), (2, 1)]]>>> from sage.all import *>>> T = graphs.TetrahedralGraph()>>> T.faces({Integer(0): [Integer(1), Integer(3), Integer(2)], Integer(1):␣
˓→[Integer(0), Integer(2), Integer(3)], Integer(2): [Integer(0), Integer(3),␣
˓→Integer(1)], Integer(3): [Integer(0), Integer(1), Integer(2)]})[[(0, 1), (1, 2), (2, 0)],[(0, 2), (2, 3), (3, 0)],[(0, 3), (3, 1), (1, 0)],[(1, 3), (3, 2), (2, 1)]]

With no embedding provided:
sage: graphs.TetrahedralGraph().faces()[[(0, 1), (1, 2), (2, 0)],[(0, 2), (2, 3), (3, 0)],[(0, 3), (3, 1), (1, 0)],[(1, 3), (3, 2), (2, 1)]]>>> from sage.all import *>>> graphs.TetrahedralGraph().faces()[[(0, 1), (1, 2), (2, 0)],[(0, 2), (2, 3), (3, 0)],[(0, 3), (3, 1), (1, 0)],[(1, 3), (3, 2), (2, 1)]]

With no embedding provided (non-planar graph):

158

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: graphs.PetersenGraph().faces()
Traceback (most recent call last):...
ValueError: no embedding is provided and the graph is not planar>>> from sage.all import *>>> graphs.PetersenGraph().faces()
Traceback (most recent call last):...
ValueError: no embedding is provided and the graph is not planar

feedback_vertex_set(value_only, solver=False, verbose=None, constraint_generation=0,
integrality_tolerance=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. Equivalently,
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); whether to return only the minimum cardinal of a minimum
vertex set, or the Set of vertices of a minimal feedback vertex set• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• constraint_generation – boolean (default: True); whether to use constraint generation whensolving the Mixed Integer Linear Program• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
ALGORITHMS:(Constraints generation)
When the parameter constraint_generation is enabled (default) the following MILP formulation isused 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 generation.
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 to1.1. Generic graphs (common to directed/undirected)

159

Graph Theory, Release 10.4

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: # needs sage.numerical.mip
sage: g = graphs.PetersenGraph()
sage: fvs = g.feedback_vertex_set()sage: len(fvs)
3sage: g.delete_vertices(fvs)sage: g.is_forest()
True>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.PetersenGraph()>>> fvs = g.feedback_vertex_set()>>> len(fvs)3>>> g.delete_vertices(fvs)>>> g.is_forest()
True

In a digraph built from a graph, any edge is replaced by arcs going in the two opposite directions, thus creatinga 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: # needs sage.numerical.mip
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 = next(cycle.edge_iterator(labels=None))sage: u in feedback or v in feedback
True>>> from sage.all import *>>> # needs sage.numerical.mip(continues on next page)

160

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> cycle = graphs.CycleGraph(Integer(5))>>> dcycle = DiGraph(cycle)>>> cycle.vertex_cover(value_only=True)
3>>> feedback = dcycle.feedback_vertex_set()>>> len(feedback)3>>> u,v = next(cycle.edge_iterator(labels=None))>>> 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
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> circuit = digraphs.Circuit(Integer(5))>>> circuit.feedback_vertex_set(value_only=True) == Integer(1)˓→# needs sage.numerical.mip
True

#␣

␣

flow(x, y, value_only, integer=True, use_edge_labels=False, vertex_bound=True, algorithm=False,
solver=None, verbose=None, integrality_tolerance=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
Observe that the integrality of the flow variables is automatic for all available solvers when all capacities areintegers.
INPUT:• x – source vertex• y – sink vertex• value_only – boolean (default: True); whether to return only the value of a maximal flow, or toalso return a flow graph (a copy of the current graph, such that each edge has the flow using it as a label,the edges without flow being omitted)• integer – boolean (default: True); whether to compute an optimal solution under the constraint thatthe flow going through an edge has to be an integer, or without this constraint• use_edge_labels – boolean (default: False); whether to compute a maximum flow where eachedge has a capacity defined by its label (if an edge has no label, capacity 1 is assumed), or to use default
edge capacity of 1
1.1. Generic graphs (common to directed/undirected)

161

Graph Theory, Release 10.4

• vertex_bound – boolean (default: False); when set to True, sets the maximum flow leaving avertex different from 𝑥 to 1 (useful for vertex connectivity parameters)• algorithm – string (default: None); the algorithm to use among:– "FF", a Python implementation of the Ford-Fulkerson algorithm (only available when vertex_bound = False)– "LP", the flow problem is solved using Linear Programming– "igraph", the igraph implementation of the Goldberg-Tarjan algorithm is used (only available
when igraph is installed and vertex_bound = False)
When algorithm = None (default), we use LP if vertex_bound = True, otherwise, we use
igraph if it is available, FF if it is not available.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
Only useful when algorithm "LP" is used to solve the flow problem.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
Only useful when algorithm "LP" is used to solve the flow problem.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
Only useful when algorithm == "LP" and integer == True.
Note: Even though the three different implementations are meant to return the same Flow values, they cannot
be expected to return the same Flow graphs.
Besides, the use of Linear Programming may possibly mean a (slight) numerical noise.
EXAMPLES:
Two basic applications of the flow method for the PappusGraph and the ButterflyGraph with parameter 2
sage: g=graphs.PappusGraph()
sage: int(g.flow(1,2))
3>>> from sage.all import *>>> g=graphs.PappusGraph()>>> int(g.flow(Integer(1),Integer(2)))
3sage: b=digraphs.ButterflyGraph(2)sage: int(b.flow(( 00 , 1), ( 00 , 2)))
1>>> from sage.all import *>>> b=digraphs.ButterflyGraph(Integer(2))>>> int(b.flow(( 00 , Integer(1)), ( 00 , Integer(2))))
1

162

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

The flow method can be used to compute a matching in a bipartite graph by linking a source 𝑠 to all thevertices of the first set and linking a sink 𝑡 to all the vertices of the second set, then computing a maximum𝑠 − 𝑡 flow
sage: g = DiGraph()
sage: g.add_edges(( s , i) for i in range(4))
sage: g.add_edges((i, 4 + j) for i in range(4) for j in range(4))
sage: g.add_edges((4 + i, t ) for i in range(4))
sage: [cardinal, flow_graph] = g.flow( s , t , integer=True, value_
˓→only=False)
sage: flow_graph.delete_vertices([ s , t ])sage: flow_graph.size()4>>> from sage.all import *>>> g = DiGraph()>>> g.add_edges(( s , i) for i in range(Integer(4)))>>> g.add_edges((i, Integer(4) + j) for i in range(Integer(4)) for j in␣˓→range(Integer(4)))>>> g.add_edges((Integer(4) + i, t ) for i in range(Integer(4)))>>> [cardinal, flow_graph] = g.flow( s , t , integer=True, value_only=False)>>> flow_graph.delete_vertices([ s , t ])>>> flow_graph.size()4

The undirected case:sage: g = Graph()
sage: g.add_edges(( s , i) for i in range(4))
sage: g.add_edges((i, 4 + j) for i in range(4) for j in range(4))
sage: g.add_edges((4 + i, t ) for i in range(4))
sage: [cardinal, flow_graph] = g.flow( s , t , integer=True, value_
˓→only=False)
sage: flow_graph.delete_vertices([ s , t ])sage: flow_graph.size()4>>> from sage.all import *>>> g = Graph()>>> g.add_edges(( s , i) for i in range(Integer(4)))>>> g.add_edges((i, Integer(4) + j) for i in range(Integer(4)) for j in␣˓→range(Integer(4)))>>> g.add_edges((Integer(4) + i, t ) for i in range(Integer(4)))>>> [cardinal, flow_graph] = g.flow( s , t , integer=True, value_only=False)>>> flow_graph.delete_vertices([ s , t ])>>> flow_graph.size()4

genus(set_embedding=True, on_embedding=None, minimal=True, maximal=False, circular=None,ordered=True)
Return 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.

1.1. Generic graphs (common to directed/undirected)

163

Graph Theory, Release 10.4

Note: This function uses Euler’s formula and thus it is necessary to consider only connected graphs.
INPUT:• set_embedding – boolean (default: True); whether or not to store an embedding attribute of thecomputed (minimal) genus of the graph• on_embedding – two kinds of input are allowed (default:None):– a dictionary representing a combinatorial embedding on which the genus should be computed. Notethat this must be a valid embedding for the graph. The dictionary structure 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 asvalues. 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 (default: True); whether or not to compute the minimal genus of the graph (i.e.,testing all embeddings). If minimal is False, then either maximal must be True or on_embedding must not be None. If on_embedding is not None, it will take priority over minimal. Similarly, if maximal is True, it will take priority over minimal.
• maximal – boolean (default: False); whether or not to compute the maximal genus of the graph (i.e.,testing all embeddings). If maximal is False, then either minimal must be True or on_embedding must not be None. If on_embedding is not None, it will take priority over maximal.
However, maximal takes priority over the default minimal.
• circular – list (default: None); if circular is a list of vertices, the method computes the genus
preserving a planar embedding of the this list. If circular is defined, on_embedding is not a valid
option.
• ordered – boolean (default: True); if circular is True, then whether or not the boundary order
may be permuted (default is True, which means the boundary order is preserved)
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.genus() # tests for minimal genus by default
1
sage: g.genus(on_embedding=True, maximal=True) # on_embedding overrides␣
˓→minimal and maximal arguments
1
sage: g.genus(maximal=True) # setting maximal to True overrides default␣
˓→minimal=True3
sage: g.genus(on_embedding=g.get_embedding()) # can also send a valid␣
˓→combinatorial embedding dict3
sage: (graphs.CubeGraph(3)).genus()0
sage: K23 = graphs.CompleteBipartiteGraph(2,3)
sage: K23.genus()0
sage: K33 = graphs.CompleteBipartiteGraph(3,3)(continues on next page)

164

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: K33.genus()
1>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.genus() # tests for minimal genus by default
1>>> g.genus(on_embedding=True, maximal=True) # on_embedding overrides minimal␣˓→and maximal arguments
1>>> g.genus(maximal=True) # setting maximal to True overrides default␣
˓→minimal=True3>>> g.genus(on_embedding=g.get_embedding()) # can also send a valid␣
˓→combinatorial embedding dict3>>> (graphs.CubeGraph(Integer(3))).genus()0>>> K23 = graphs.CompleteBipartiteGraph(Integer(2),Integer(3))>>> K23.genus()0>>> K33 = graphs.CompleteBipartiteGraph(Integer(3),Integer(3))>>> 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 ])0sage: cube.is_circular_planar()True
sage: cube.genus(circular=[ 01 , 10 ])0sage: cube.genus(circular=[ 01 , 10 ], on_embedding=True)
Traceback (most recent call last):...
ValueError: on_embedding is not a valid option when circular is defined
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>>> from sage.all import *>>> cube = graphs.CubeGraph(Integer(2))>>> cube.genus(circular=[ 01 , 10 ])0>>> cube.is_circular_planar()True>>> cube.genus(circular=[ 01 , 10 ])0>>> cube.genus(circular=[ 01 , 10 ], on_embedding=True)
Traceback (most recent call last):...
ValueError: on_embedding is not a valid option when circular is defined(continues on next page)

1.1. Generic graphs (common to directed/undirected)

165

Graph Theory, Release 10.4

(continued from previous page)>>> 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 ultimately
computable for every connected graph – but the embedding we obtain for the simple graph can’t be easily
converted to an embedding of a non-simple graph. Also, the maximal genus of a multigraph does not triviallycorrespond to that of its simple graph:
sage: G = DiGraph({0: [0, 1, 1, 1], 1: [2, 2, 3, 3], 2: [1, 3, 3], 3: [0, 3]})sage: G.genus()
Traceback (most recent call last):...
NotImplementedError: cannot work with embeddings of non-simple graphs
sage: G.to_simple().genus()0
sage: G.genus(set_embedding=False)0sage: G.genus(maximal=True, set_embedding=False)
Traceback (most recent call last):...
NotImplementedError: cannot compute the maximal genus of a graph with loops␣
˓→or multiple edges>>> from sage.all import *>>> G = DiGraph({Integer(0): [Integer(0), Integer(1), Integer(1), Integer(1)],
˓→ Integer(1): [Integer(2), Integer(2), Integer(3), Integer(3)], Integer(2):␣
˓→[Integer(1), Integer(3), Integer(3)], Integer(3): [Integer(0), Integer(3)]})>>> G.genus()
Traceback (most recent call last):...
NotImplementedError: cannot work with embeddings of non-simple graphs>>> G.to_simple().genus()0>>> G.genus(set_embedding=False)0>>> G.genus(maximal=True, set_embedding=False)
Traceback (most recent call last):...
NotImplementedError: cannot compute the maximal genus of a graph with loops␣
˓→or multiple edges

We break graphs with cut vertices into their blocks, which greatly speeds up computation of minimal genus.
This is not implemented for maximal genus:
sage: G = graphs.RandomBlockGraph(10, 5)
sage: G.genus()
10>>> from sage.all import *>>> G = graphs.RandomBlockGraph(Integer(10), Integer(5))>>> G.genus()
10

166

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

get_embedding()
Return the stored embedding or None.
If the stored embedding is no longer valid (because of vertex/edge additions) then the stored embedding is
discarded and None is returned. In case some vertex/edge has been deleted, the stored embedding is updated
accordingly.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.genus()
1sage: 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]}>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.genus()1>>> G.get_embedding(){0: [1, 4, 5], 1: [0, 2, 6], 2: [1, 3, 7], 3: [2, 4, 8],
4: [0, 3, 9], 5: [0, 7, 8], 6: [1, 9, 8], 7: [2, 5, 9],
8: [3, 6, 5], 9: [4, 6, 7]}Note that the embeddings gets properly modified on vertex or edge deletion:
sage: G.delete_edge(0, 1)
sage: G.delete_vertex(3)sage: G.get_embedding(){0: [4, 5],
1: [2, 6],
2: [1, 7],
4: [0, 9],
5: [0, 7, 8],
6: [1, 9, 8],
7: [2, 5, 9],
8: [6, 5],
9: [4, 6, 7]}>>> from sage.all import *>>> G.delete_edge(Integer(0), Integer(1))>>> G.delete_vertex(Integer(3))>>> G.get_embedding(){0: [4, 5],
1: [2, 6],
2: [1, 7],
4: [0, 9],
5: [0, 7, 8],
6: [1, 9, 8],
7: [2, 5, 9],
8: [6, 5],
9: [4, 6, 7]}

But not under edge addition:

1.1. Generic graphs (common to directed/undirected)

167

Graph Theory, Release 10.4

sage: G.add_edge(0, 7)
sage: G.get_embedding() is None
True>>> from sage.all import *>>> G.add_edge(Integer(0), Integer(7))>>> G.get_embedding() is None
True

get_pos(dim=2)
Return the position dictionary.
The position dictionary specifies the coordinates of each vertex.
INPUT:• dim – integer (default: 2); whether to return the position dictionary in the plane (dim == 2) or in the
3-dimensional space
EXAMPLES:
By default, the position of a graph is None:sage: G = Graph()
sage: G.get_pos()sage: G.get_pos() is None
True
sage: P = G.plot(save_pos=True)
˓→needs sage.plot
sage: G.get_pos()
˓→needs sage.plot
{}

#␣
#␣

>>> from sage.all import *>>> G = Graph()>>> G.get_pos()>>> G.get_pos() is None
True>>> P = G.plot(save_pos=True)
˓→needs sage.plot>>> G.get_pos()
˓→needs sage.plot
{}

#␣
#␣

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...)}>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.get_pos(){0: (0.0, 1.0),...
9: (0.475..., 0.154...)}

168

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Note that the position dictionary is modified on vertex removal:
sage: G.delete_vertex(0)sage: G.get_pos(){1: (-0.951..., 0.309...),...
9: (0.475..., 0.154...)}>>> from sage.all import *>>> G.delete_vertex(Integer(0))>>> G.get_pos(){1: (-0.951..., 0.309...),...
9: (0.475..., 0.154...)}

But is deleted on vertex addition:
sage: G.add_vertex(0)sage: G.get_pos() is None
True>>> from sage.all import *>>> G.add_vertex(Integer(0))>>> G.get_pos() is None
True

get_vertex(vertex)
Retrieve the object associated with a given vertex.
If no associated object is found, None is returned.
INPUT:• vertex – the given vertex
EXAMPLES:
sage: d = {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(sort=True)[0, 1, 2, 3]
sage: T.set_vertices(d)sage: T.get_vertex(1)Flower Snark: Graph on 20 vertices>>> from sage.all import *>>> d = {Integer(0): graphs.DodecahedralGraph(), Integer(1): graphs.
˓→FlowerSnark(), Integer(2): graphs.MoebiusKantorGraph(), Integer(3): graphs.
˓→PetersenGraph()}>>> d[Integer(2)]Moebius-Kantor Graph: Graph on 16 vertices>>> T = graphs.TetrahedralGraph()>>> T.vertices(sort=True)[0, 1, 2, 3]>>> T.set_vertices(d)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

169Graph Theory, Release 10.4

(continued from previous page)>>> T.get_vertex(Integer(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}>>> from sage.all import *>>> d = {Integer(0): graphs.DodecahedralGraph(), Integer(1): graphs.
˓→FlowerSnark(), Integer(2): graphs.MoebiusKantorGraph(), Integer(3): graphs.
˓→PetersenGraph()}>>> T = graphs.TetrahedralGraph()>>> T.set_vertices(d)>>> T.get_vertices([Integer(1), Integer(2)]){1: Flower Snark: Graph on 20 vertices,2: Moebius-Kantor Graph: Graph on 16 vertices}

girth(certificate=False)
Return the girth of the graph.
The girth is the length of the shortest cycle in the graph (directed cycle if the graph is directed). Graphs
without (directed) cycles have infinite girth.
INPUT:• certificate – boolean (default: False); whether to return (g, c), where g is the girth and c is
a list of vertices of a (directed) cycle of length g in the graph, thus providing a certificate that the girthis at most g, or None if g infinite
EXAMPLES:
sage: graphs.TetrahedralGraph().girth()3
sage: graphs.CubeGraph(3).girth()4
sage: graphs.PetersenGraph().girth(certificate=True)(5, [4, 3, 2, 1, 0])
sage: graphs.HeawoodGraph().girth()6
sage: next(graphs.trees(9)).girth()+Infinity# random>>> from sage.all import *>>> graphs.TetrahedralGraph().girth()(continues on next page)

170

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)3>>> graphs.CubeGraph(Integer(3)).girth()4>>> graphs.PetersenGraph().girth(certificate=True)(5, [4, 3, 2, 1, 0])>>> graphs.HeawoodGraph().girth()
6>>> next(graphs.trees(Integer(9))).girth()+Infinity# random

See also:• odd_girth() – return the odd girth of the graph.
graphics_array_defaults = { graph_border : True,
vertex_labels : False, vertex_size : 50}

layout :circular ,graphplot(**options)
Return a GraphPlot object.
See GraphPlot for more details.
INPUT:• **options – parameters for the GraphPlot constructor
EXAMPLES:
Creating a GraphPlot object uses the same options as plot():
sage: 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(edge_labels=True, color_by_label=True,
˓→needs sage.plot....:
edge_style= dashed )sage: GP.plot()
˓→needs sage.plot
Graphics object consisting of 22 graphics primitives#␣#␣>>> from sage.all import *>>> g = Graph({}, loops=True, multiedges=True, sparse=True)>>> g.add_edges([(Integer(0),Integer(0), a ),(Integer(0),Integer(0), b ),˓→(Integer(0),Integer(1), c ),(Integer(0),Integer(1), d ),...
(Integer(0),Integer(1), e ),(Integer(0),Integer(1), f ),(Integer(0),˓→Integer(1), f ),(Integer(2),Integer(1), g ),(Integer(2),Integer(2), h )])>>> GP = g.graphplot(edge_labels=True, color_by_label=True,#␣˓→needs sage.plot...
edge_style= dashed )>>> GP.plot()#␣˓→needs sage.plot
Graphics object consisting of 22 graphics primitives

We can modify the GraphPlot object. Notice that the changes are cumulative:
sage: # needs sage.plot
sage: GP.set_edges(edge_style= solid )(continues on next page)

1.1. Generic graphs (common to directed/undirected)

171

Graph Theory, Release 10.4

(continued from previous page)

sage: GP.plot()
Graphics object consisting of 22 graphics primitives
sage: GP.set_vertices(talk=True)
sage: GP.plot()
Graphics object consisting of 22 graphics primitives>>> from sage.all import *>>> # needs sage.plot>>> GP.set_edges(edge_style= solid )>>> GP.plot()
Graphics object consisting of 22 graphics primitives>>> GP.set_vertices(talk=True)>>> GP.plot()
Graphics object consisting of 22 graphics primitives

graphviz_string(labels='string', vertex_labels=True, edge_labels=False, edge_color=None,edge_colors=None, edge_options=(), color_by_label=False, rankdir='down',
subgraph_clusters=[], **options)
Return a representation in the dot language.
The dot language is a text based format for graphs. It is used by the software suite graphviz. The
specifications of the language are available on the web (see the reference [dotspec]).
INPUT:• labels – string (default: "string"); either "string" or "latex". If labels is "string",
latex commands 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"– a 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 inhexadecimal code.
• edge_colors – dictionary (default: None); a dictionary whose keys are colors and values are list ofedges. 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 – 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 andedge_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 withgraphviz): the preferred ranking direction for acyclic layouts; see the rankdir option ofgraphviz.
• subgraph_clusters – a list of lists of vertices (default: []); From [dotspec]: “If supported, thelayout engine will do the layout so that the nodes belonging to the cluster are drawn together, with theentire drawing of the cluster contained within a bounding rectangle. Note that, for good and bad, cluster
172

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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"];}>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1): None, Integer(2): None}, Integer(1):˓→{Integer(0): None, Integer(2): None},...
Integer(2): {Integer(0): None, Integer(1): None, Integer(3):˓→ foo }, Integer(3): {Integer(2):foo }},...
sparse=True)>>> print(G.graphviz_string(edge_labels=True))graph {
node_0 [label="0"];node_1 [label="1"];
node_2 [label="2"];node_3 [label="3"];<BLANKLINE>
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}}$"];}>>> from sage.all import *>>> print(G.graphviz_string(edge_labels=True, labels="latex"))(continues on next page)

1.1. Generic graphs (common to directed/undirected)

173

Graph Theory, Release 10.4

(continued from previous page)graph {
node [shape="plaintext"];
node_0 [label=" ", texlbl="$0$"];
node_1 [label=" ", texlbl="$1$"];
node_2 [label=" ", texlbl="$2$"];
node_3 [label=" ", texlbl="$3$"];<BLANKLINE>
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:....: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"];foo }, 3: {}},

edge [color="red"];node_0 -> node_1;
node_0 -> node_2;
node_1 -> node_2;
node_2 -> node_3;}>>> from sage.all import *>>> G = DiGraph({Integer(0): {Integer(1): None, Integer(2): None},␣
˓→Integer(1): {Integer(2): None}, Integer(2): {Integer(3):foo },␣
˓→Integer(3): {}},...
sparse=True)>>> print(G.graphviz_string(edge_color="red"))digraph {node_0 [label="0"];node_1 [label="1"];
node_2 [label="2"];node_3 [label="3"];<BLANKLINE>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:
sage: # needs sage.symbolic
sage: f(x) = -1 / x
sage: g(x) = 1 / (x + 1)
sage: G = DiGraph()(continues on next page)

174

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

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))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$"];# random

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",
˓→needs sage.symbolic....:color_by_label=True))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$"];# random#␣

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)

175Graph Theory, Release 10.4

(continued from previous page)

sage: print(G.graphviz_string(labels="latex",# random˓→needs sage.symbolic....:color_by_label={f: "red", g: "blue"}))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"];}>>> from sage.all import *>>> # needs sage.symbolic>>> __tmp__=var("x"); f = symbolic_expression(-Integer(1) / x).function(x)>>> __tmp__=var("x"); g = symbolic_expression(Integer(1) / (x + Integer(1))).
˓→function(x)>>> G = DiGraph()>>> G.add_edges((i, f(i), f) for i in (Integer(1), Integer(2), Integer(1)/˓→Integer(2), Integer(1)/Integer(4)))>>> G.add_edges((i, g(i), g) for i in (Integer(1), Integer(2), Integer(1)/˓→Integer(2), Integer(1)/Integer(4)))>>> print(G.graphviz_string(labels="latex",# random...
edge_labels=True))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$"];<BLANKLINE>
node_10 -> node_2 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"];(continues on next page)

176

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

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}$"];}>>> print(G.graphviz_string(labels="latex",
˓→needs sage.symbolic...
color_by_label=True))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$"];<BLANKLINE>
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"];}# random#␣>>> print(G.graphviz_string(labels="latex",# random˓→needs sage.symbolic...
color_by_label={f: "red", g: "blue"}))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$"];<BLANKLINE>
node_10 -> node_2 [color = "red"];node_10 -> node_6 [color = "blue"];#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

177Graph Theory, Release 10.4

(continued from previous page)

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 tobottom. 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 {rankdir=LR
node_0 [label="1"];
node_1 [label="2"];node_0 -> node_1;}>>> from sage.all import *>>> D = DiGraph([(Integer(1), Integer(2))])>>> print(D.graphviz_string(rankdir="up"))digraph {rankdir=BT
node_0 [label="1"];
node_1 [label="2"];<BLANKLINE>
node_0 -> node_1;}>>> print(D.graphviz_string(rankdir="down"))
digraph {(continues on next page)

178

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

node_0 [label="1"];
node_1 [label="2"];<BLANKLINE>
node_0 -> node_1;}>>> print(D.graphviz_string(rankdir="left"))digraph {rankdir=RL
node_0 [label="1"];
node_1 [label="2"];<BLANKLINE>
node_0 -> node_1;}>>> print(D.graphviz_string(rankdir="right"))
digraph {rankdir=LR
node_0 [label="1"];
node_1 [label="2"];<BLANKLINE>
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"• "dot" (a string containing a sequence of options in dot format)• "label" (a string)• "label_style" ("string" or "latex")• "edge_string" ("--" or "->")• "dir" ("forward", "back", "both" or "none")• "backward" (boolean), instead of defining the edge in the graphviz string as u -> v it draws it asv -> u [dir=back] and instead of u -> v [dir=back] it draws it as v -> u, this changes
the way it is drawn by Graphviz’s dot program: vertex v will be above vertex u instead of below.
Here we state that the graph should be laid out so that edges starting from 1 are going backward (e.g. goingup instead of down):
sage: def edge_options(data):....:u, v, label = data....:
return {"dir":"back"} if u == 1 else {}sage: print(G.graphviz_string(edge_options=edge_options))
˓→needs sage.symbolic
digraph {node_0 [label="-1"];
node_1 [label="-1/2"];
node_2 [label="1/2"];
node_3 [label="-2"];
node_4 [label="1/4"];
node_5 [label="-4"];
node_6 [label="1/3"];
node_7 [label="2/3"];
node_8 [label="4/5"];# random#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

179

Graph Theory, Release 10.4

(continued from previous page)

node_9 [label="1"];
node_10 [label="2"];node_2 -> node_3;
node_2 -> node_7;
node_4 -> node_5;
node_4 -> node_8;
node_9 -> node_0 [dir=back];
node_9 -> node_2 [dir=back];
node_10 -> node_1;
node_10 -> node_6;}>>> from sage.all import *>>> def edge_options(data):...
u, v, label = data...
return {"dir":"back"} if u == Integer(1) else {}>>> print(G.graphviz_string(edge_options=edge_options))
˓→needs sage.symbolic
digraph {node_0 [label="-1"];
node_1 [label="-1/2"];
node_2 [label="1/2"];
node_3 [label="-2"];
node_4 [label="1/4"];
node_5 [label="-4"];
node_6 [label="1/3"];
node_7 [label="2/3"];
node_8 [label="4/5"];
node_9 [label="1"];
node_10 [label="2"];<BLANKLINE>
node_2 -> node_3;
node_2 -> node_7;
node_4 -> node_5;
node_4 -> node_8;
node_9 -> node_0 [dir=back];
node_9 -> node_2 [dir=back];
node_10 -> node_1;
node_10 -> node_6;}# random#␣

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["dir"]= "back"....:
return options
sage: print(G.graphviz_string(edge_options=edge_options))# random#␣˓→needs sage.symbolic
digraph {(continues on next page)

180

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

node_0 [label="-1"];
node_1 [label="-1/2"];
node_2 [label="1/2"];
node_3 [label="-2"];
node_4 [label="1/4"];
node_5 [label="-4"];
node_6 [label="1/3"];
node_7 [label="2/3"];
node_8 [label="4/5"];
node_9 [label="1"];
node_10 [label="2"];node_2 -> node_3 [label="coucou", color = "red"];node_2 -> node_7 [x=1,y=2, color = "blue"];
node_4 -> node_5 [color = "red"];node_4 -> node_8 [color = "blue"];
node_9 -> node_0 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$", color␣
˓→= "red"];node_9 -> node_2 [color = "blue", dir=back];
node_10 -> node_1 [color = "red"];node_10 -> node_6 [color = "blue"];}>>> from sage.all import *>>> def edge_options(data):...
u, v, label = data...
options = {"color": {f: "red", g: "blue"}[label]}...
if (u,v) == (Integer(1)/Integer(2), -Integer(2)): options["label"]␣˓→= "coucou"; options["label_style"] = "string"...
if (u,v) == (Integer(1)/Integer(2),Integer(2)/Integer(3)): options[
˓→"dot"]= "x=1,y=2"...
if (u,v) == (Integer(1),-Integer(1)): options["label_style"] =˓→"latex"...
if (u,v) == (Integer(1), Integer(1)/Integer(2)): options["dir"]␣˓→= "back"...
return options>>> print(G.graphviz_string(edge_options=edge_options))# random#␣˓→needs sage.symbolic
digraph {node_0 [label="-1"];
node_1 [label="-1/2"];
node_2 [label="1/2"];
node_3 [label="-2"];
node_4 [label="1/4"];
node_5 [label="-4"];
node_6 [label="1/3"];
node_7 [label="2/3"];
node_8 [label="4/5"];
node_9 [label="1"];
node_10 [label="2"];<BLANKLINE>
node_2 -> node_3 [label="coucou", color = "red"];node_2 -> node_7 [x=1,y=2, color = "blue"];
node_4 -> node_5 [color = "red"];node_4 -> node_8 [color = "blue"];
node_9 -> node_0 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$", color␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

181Graph Theory, Release 10.4

(continued from previous page)= "red"];node_9 -> node_2 [color = "blue", dir=back];
node_10 -> node_1 [color = "red"];node_10 -> node_6 [color = "blue"];˓→}

We test the possible values of the dir edge option:
sage: edges = [(0,1, a ), (1,2, b ), (2,3, c ), (3,4, d )]sage: G = DiGraph(edges)
sage: def edge_options(data):....:
u,v,label = data....:
if label == a : return { dir : forward }....:if label == b : return { dir : back }....:if label == c : return { dir : none }....:if label == d : return { dir : both }sage: print(G.graphviz_string(edge_options=edge_options))
digraph {node_0 [label="0"];node_1 [label="1"];
node_2 [label="2"];node_3 [label="3"];
node_4 [label="4"];
node_0 -> node_1;
node_1 -> node_2 [dir=back];
node_2 -> node_3 [dir=none];node_3 -> node_4 [dir=both];}>>> from sage.all import *>>> edges = [(Integer(0),Integer(1), a ), (Integer(1),Integer(2), b ),␣
˓→(Integer(2),Integer(3), c ), (Integer(3),Integer(4), d )]>>> G = DiGraph(edges)>>> def edge_options(data):...
u,v,label = data...
if label == a : return { dir : forward }...
if label == b : return { dir : back }...
if label == c : return { dir : none }...
if label == d : return { dir : both }>>> print(G.graphviz_string(edge_options=edge_options))
digraph {node_0 [label="0"];node_1 [label="1"];
node_2 [label="2"];node_3 [label="3"];
node_4 [label="4"];<BLANKLINE>
node_0 -> node_1;
node_1 -> node_2 [dir=back];
node_2 -> node_3 [dir=none];node_3 -> node_4 [dir=both];}We test the same graph and dir edge options but with backward=True, which reverses the natural
direction each edge wants to be pointing for the layout:

182

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: def edge_options(data):....:
u,v,label = data....:
if label == a : return { dir : forward , backward :True}....:
if label == b : return { dir : back , backward :True}....:
if label == c : return { dir : none , backward :True}....:
if label == d : return { dir : both , backward :True}
sage: print(G.graphviz_string(edge_options=edge_options))
digraph {node_0 [label="0"];node_1 [label="1"];
node_2 [label="2"];node_3 [label="3"];
node_4 [label="4"];
node_1 -> node_0 [dir=back];
node_2 -> node_1;
node_3 -> node_2 [dir=none];node_4 -> node_3 [dir=both];}>>> from sage.all import *>>> def edge_options(data):...
u,v,label = data...
if label == a : return { dir : forward , backward :True}...
if label == b : return { dir : back , backward :True}...
if label == c : return { dir : none , backward :True}...
if label == d : return { dir : both , backward :True}>>> print(G.graphviz_string(edge_options=edge_options))
digraph {node_0 [label="0"];node_1 [label="1"];
node_2 [label="2"];node_3 [label="3"];
node_4 [label="4"];<BLANKLINE>
node_1 -> node_0 [dir=back];
node_2 -> node_1;
node_3 -> node_2 [dir=none];node_4 -> node_3 [dir=both];}graphviz_to_file_named(filename, **options)Write a representation in the dot language in a file.
The dot language is a plaintext format for graph structures.
graphviz_string() for available options.

See the documentation of

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

1.1. Generic graphs (common to directed/undirected)

183Graph Theory, Release 10.4

(continued from previous page)

sage: import tempfile
sage: with tempfile.NamedTemporaryFile(mode="a+t") as f:....:
G.graphviz_to_file_named(f.name, edge_labels=True)....:
print(f.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"];}>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1): None, Integer(2): None}, Integer(1):˓→{Integer(0): None, Integer(2): None},...
Integer(2): {Integer(0): None, Integer(1): None, Integer(3):˓→ foo }, Integer(3): {Integer(2):foo }},...
sparse=True)>>> import tempfile>>> with tempfile.NamedTemporaryFile(mode="a+t") as f:...
G.graphviz_to_file_named(f.name, edge_labels=True)...
print(f.read())
graph {
node_0 [label="0"];node_1 [label="1"];
node_2 [label="2"];node_3 [label="3"];<BLANKLINE>
node_0 -- node_1;
node_0 -- node_2;
node_1 -- node_2;
node_2 -- node_3 [label="foo"];}

greedy_dominating_set(G, k=1, vertices=None, ordering=None, return_sets=False, closest=False)
Return a greedy distance-𝑘 dominating set of the graph.
A distance-𝑘 dominating set 𝑆 of a graph 𝐺 is a set of its vertices of minimal cardinality such that any vertex
of 𝐺 is in 𝑆 or is at distance at most 𝑘 from a vertex in 𝑆. See the Wikipedia article Dominating_set.
When 𝐺 is directed, vertex 𝑢 can be a dominator of vertex 𝑣 if there is a directed path of length at most 𝑘from 𝑢 to 𝑣.
This method implements a greedy heuristic to find a minimal dominatic set.
INPUT:• G – a Graph• k – integer (default: 1); the domination distance to consider• vertices – iterable container of vertices (default: None); when specified, return a dominating set ofthe specified vertices only
• ordering – string (default: None); specify the order in which to consider the vertices

184

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

– None – if vertices is None, then consider the vertices in the order given by list(G). Otherwise, consider the vertices in the order of iteration of vertices.
– "degree_min" – consider the vertices by increasing degree– "degree_max" – consider the vertices by decreasing degree• return_sets – boolean (default: False); whether to return the vertices of the dominating set only
(default), or a dictionary mapping each vertex of the dominating set to the set of vertices it dominates.
• closest – boolean (default: False); whether to attach a vertex to its closest dominator or not. Thisparameter is use only when return_sets is True.
EXAMPLES:
Dominating sets of a path:sage: from sage.graphs.domination import greedy_dominating_set
sage: G = graphs.PathGraph(5)sage: sorted(greedy_dominating_set(G, ordering=None))[0, 2, 4]
sage: sorted(greedy_dominating_set(G, ordering="degree_min"))[0, 2, 4]
sage: sorted(greedy_dominating_set(G, ordering="degree_max"))[1, 3]
sage: sorted(greedy_dominating_set(G, k=2, ordering=None))[0, 3]
sage: sorted(greedy_dominating_set(G, k=2, ordering="degree_min"))[0, 4]
sage: sorted(greedy_dominating_set(G, k=2, ordering="degree_max"))[1, 4]
sage: greedy_dominating_set(G, k=3, ordering="degree_min", return_sets=True,␣
˓→closest=False){0: {0, 1, 2, 3}, 4: {4}}sage: greedy_dominating_set(G, k=3, ordering="degree_min", return_sets=True,␣
˓→closest=True){0: {0, 2, 3}, 4: {1, 4}}>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set>>> G = graphs.PathGraph(Integer(5))>>> sorted(greedy_dominating_set(G, ordering=None))[0, 2, 4]>>> sorted(greedy_dominating_set(G, ordering="degree_min"))[0, 2, 4]>>> sorted(greedy_dominating_set(G, ordering="degree_max"))[1, 3]>>> sorted(greedy_dominating_set(G, k=Integer(2), ordering=None))[0, 3]>>> sorted(greedy_dominating_set(G, k=Integer(2), ordering="degree_min"))[0, 4]>>> sorted(greedy_dominating_set(G, k=Integer(2), ordering="degree_max"))[1, 4]>>> greedy_dominating_set(G, k=Integer(3), ordering="degree_min", return_˓→sets=True, closest=False){0: {0, 1, 2, 3}, 4: {4}}>>> greedy_dominating_set(G, k=Integer(3), ordering="degree_min", return_˓→sets=True, closest=True){0: {0, 2, 3}, 4: {1, 4}}

1.1. Generic graphs (common to directed/undirected)

185Graph Theory, Release 10.4

Asking for a dominating set of a subset of vertices:sage: from sage.graphs.domination import greedy_dominating_set
sage: from sage.graphs.domination import is_dominating
sage: G = graphs.PetersenGraph()
sage: vertices = {0, 1, 2, 3, 4, 5}
sage: dom = greedy_dominating_set(G, vertices=vertices, return_sets=True)
sage: sorted(dom)[0, 2]
sage: is_dominating(G, dom, focus=vertices)
True
sage: is_dominating(G, dom)
False
sage: dominated = [u for v in dom for u in dom[v]]sage: sorted(dominated) == sorted(vertices)
True>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set>>> from sage.graphs.domination import is_dominating>>> G = graphs.PetersenGraph()>>> vertices = {Integer(0), Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5)}>>> dom = greedy_dominating_set(G, vertices=vertices, return_sets=True)>>> sorted(dom)[0, 2]>>> is_dominating(G, dom, focus=vertices)
True>>> is_dominating(G, dom)
False>>> dominated = [u for v in dom for u in dom[v]]>>> sorted(dominated) == sorted(vertices)
True

Influence of the ordering of the vertices on the result:
sage: from sage.graphs.domination import greedy_dominating_set
sage: G = graphs.StarGraph(4)sage: greedy_dominating_set(G, vertices=[0, 1, 2, 3, 4])[0]
sage: sorted(greedy_dominating_set(G, vertices=[1, 2, 3, 4, 0]))[1, 2, 3, 4]>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set>>> G = graphs.StarGraph(Integer(4))>>> greedy_dominating_set(G, vertices=[Integer(0), Integer(1), Integer(2),␣
˓→Integer(3), Integer(4)])[0]>>> sorted(greedy_dominating_set(G, vertices=[Integer(1), Integer(2),␣
˓→Integer(3), Integer(4), Integer(0)]))[1, 2, 3, 4]

Dominating set of a directed graph:
sage: from sage.graphs.domination import greedy_dominating_set
sage: D = digraphs.Path(3)(continues on next page)

186

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: sorted(greedy_dominating_set(D, vertices=[0, 1, 2]))[0, 2]>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set>>> D = digraphs.Path(Integer(3))>>> sorted(greedy_dominating_set(D, vertices=[Integer(0), Integer(1),␣
˓→Integer(2)]))[0, 2]

hamiltonian_cycle(algorithm, solver='tsp', constraint_generation=None, verbose=None,verbose_constraints=0, integrality_tolerance=False)
Return a Hamiltonian cycle/circuit of the current graph/digraph.
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 dependingon the instance.
ALGORITHM:
See traveling_salesman_problem() for ‘tsp’ algorithm and find_hamiltonian() fromsage.graphs.generic_graph_pyx for ‘backtrack’ algorithm.
INPUT:• algorithm – string (default: tsp ); one of ‘tsp’ or ‘backtrack’• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• constraint_generation – boolean (default: None); whether to use constraint generation whensolving the Mixed Integer Linear Program.
When constraint_generation = None, constraint generation is used whenever the graph hasa density larger than 70%.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• verbose_constraints – boolean (default: False); whether to display which constraints are being
generated• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
If using the tsp algorithm, returns a Hamiltonian cycle/circuit if it exists; otherwise, raises a EmptySetError exception. If using the backtrack algorithm, returns a pair (B, P). If B is True then
P is a Hamiltonian cycle and if B is False, P is a longest path found by the algorithm. Observe that if
B is False, the graph may still be Hamiltonian. The backtrack algorithm is only implemented for
undirected graphs.
Warning: The backtrack algorithm may loop endlessly on graphs with vertices of degree 1.
NOTE:

1.1. Generic graphs (common to directed/undirected)

187Graph Theory, Release 10.4

This function, as is_hamiltonian(), computes a Hamiltonian cycle if it exists: the user should NOT testfor 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()
˓→needs sage.numerical.mip
TSP from Heawood graph: Graph on 14 vertices>>> from sage.all import *>>> g = graphs.HeawoodGraph()>>> g.hamiltonian_cycle()
˓→needs sage.numerical.mip
TSP from Heawood graph: Graph on 14 vertices#␣#␣

The Petersen Graph, though, is not
sage: g = graphs.PetersenGraph()
sage: g.hamiltonian_cycle()
˓→needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: the given graph is not Hamiltonian>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.hamiltonian_cycle()
˓→needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: the given graph is not Hamiltonian#␣#␣Now, using the backtrack algorithm in the Heawood graphsage: G = graphs.HeawoodGraph()
sage: G.hamiltonian_cycle(algorithm= backtrack )(True, [...])>>> from sage.all import *>>> G = graphs.HeawoodGraph()>>> G.hamiltonian_cycle(algorithm= backtrack )(True, [...])

And now in the Petersen graphsage: G = graphs.PetersenGraph()
sage: B, P = G.hamiltonian_cycle(algorithm= backtrack )sage: B
False
sage: len(P)10(continues on next page)

188

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.has_edge(P[0], P[-1])False>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> B, P = G.hamiltonian_cycle(algorithm= backtrack )
>>> B
False
>>> len(P)10>>> G.has_edge(P[Integer(0)], P[-Integer(1)])
False

Finally, we test the algorithm in a cube graph, which is Hamiltonian
sage: G = graphs.CubeGraph(3)sage: G.hamiltonian_cycle(algorithm= backtrack )(True, [...])>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(3))>>> G.hamiltonian_cycle(algorithm= backtrack )(True, [...])

hamiltonian_path(s, t=None, use_edge_labels=None, maximize=False, algorithm=False, solver='MILP',
verbose=None, integrality_tolerance=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 ora maximum weight Hamiltonian path (if maximize == True).
See also:• longest_path()• hamiltonian_cycle()
INPUT:• s – vertex (default: None); if specified, then forces the source of the path (the method then returns a
Hamiltonian path starting at s)• t – vertex (default: None); if specified, then forces the destination of the path (the method then returns
a Hamiltonian path ending at t)• use_edge_labels – boolean (default: False); whether to compute a weighted hamiltonian pathwhere the weight of an edge is defined by its label (a label set to None or {} being considered as a weightof 1), or a non-weighted hamiltonian path• maximize – boolean (default: False); whether to compute a minimum (default) or a maximum(when maximize == True) weight hamiltonian path. This parameter is considered only if
use_edge_labels == True.
• algorithm – string (default: "MILP"); the algorithm the use among "MILP" and "backtrack";
two remarks on this respect:
1.1. Generic graphs (common to directed/undirected)

189Graph Theory, Release 10.4

– While the MILP formulation returns an exact answer, the backtrack algorithm is a randomized
heuristic.
– The backtrack algorithm does not support edge weighting, so setting use_edge_labels=True
will force the use of the MILP algorithm.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
A subgraph of self corresponding to a (directed if self is directed) hamiltonian path. If no hamiltonian
path is found, return None. If use_edge_labels == True, a pair weight, path is returned.
EXAMPLES:
The 3 × 3-grid has a Hamiltonian path, a 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: # needs sage.numerical.mip
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)>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.Grid2dGraph(Integer(3), Integer(3))>>> g.hamiltonian_path()
Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices>>> g.hamiltonian_path(s=(Integer(0), Integer(0)), t=(Integer(2), Integer(2)))
Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices>>> g.hamiltonian_path(s=(Integer(0), Integer(0)), t=(Integer(2), Integer(2)),
˓→ use_edge_labels=True)(8, Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices)>>> g.hamiltonian_path(s=(Integer(0), Integer(0)), t=(Integer(0),␣
˓→Integer(1))) is None
True>>> g.hamiltonian_path(s=(Integer(0), Integer(0)), t=(Integer(0), Integer(1)),
˓→ use_edge_labels=True)(0, None)has_edge(u, v=None, label=None)
Check whether (u, v) is an edge of the (di)graph.
INPUT: The following forms are accepted:• G.has_edge( 1, 2 )190

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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>>> from sage.all import *>>> graphs.EmptyGraph().has_edge(Integer(9), Integer(2))
False>>> DiGraph().has_edge(Integer(9), Integer(2))
False>>> G = Graph(sparse=True)>>> G.add_edge(Integer(0), Integer(1), "label")>>> G.has_edge(Integer(0), Integer(1), "different label")
False>>> G.has_edge(Integer(0), Integer(1), "label")True

has_loops()
Return whether there are loops in the (di)graph
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edge((0, 0))
sage: G.has_loops()
True
sage: G.loops()[(0, 0, None)]sage: G.allow_loops(False); G
Graph on 1 vertex
sage: G.has_loops()
False
sage: G.edges(sort=True)[]
sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

191Graph Theory, Release 10.4

(continued from previous page)True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()[(0, 0, None)]sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)[]>>> from sage.all import *>>> G = Graph(loops=True); G
Looped graph on 0 vertices>>> G.has_loops()
False>>> G.allows_loops()
True>>> G.add_edge((Integer(0), Integer(0)))>>> G.has_loops()
True>>> G.loops()[(0, 0, None)]>>> G.allow_loops(False); G
Graph on 1 vertex>>> G.has_loops()
False>>> G.edges(sort=True)[]>>> D = DiGraph(loops=True); D
Looped digraph on 0 vertices>>> D.has_loops()
False>>> D.allows_loops()
True>>> D.add_edge((Integer(0), Integer(0)))>>> D.has_loops()
True>>> D.loops()[(0, 0, None)]>>> D.allow_loops(False); D
Digraph on 1 vertex>>> D.has_loops()
False>>> D.edges(sort=True)[]

has_multiple_edges(to_undirected=False)
Return whether there are multiple edges in the (di)graph.
INPUT:• to_undirected – (default: False); if True, runs the test on the undirected version of a DiGraph.
Otherwise, treats DiGraph edges (u, v) and (v, u) as unique individual edges.

192

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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(sort=True)[(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(sort=True)[(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 )]>>> from sage.all import *>>> G = Graph(multiedges=True, sparse=True); G
Multi-graph on 0 vertices>>> G.has_multiple_edges()
False>>> G.allows_multiple_edges()
True>>> G.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> G.has_multiple_edges()
True(continues on next page)

1.1. Generic graphs (common to directed/undirected)

193Graph Theory, Release 10.4

(continued from previous page)>>> G.multiple_edges()[(0, 1, None), (0, 1, None), (0, 1, None)]>>> G.allow_multiple_edges(False); G
Graph on 2 vertices>>> G.has_multiple_edges()
False>>> G.edges(sort=True)[(0, 1, None)]>>> D = DiGraph(multiedges=True, sparse=True); D
Multi-digraph on 0 vertices>>> D.has_multiple_edges()
False>>> D.allows_multiple_edges()
True>>> D.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> D.has_multiple_edges()
True>>> D.multiple_edges()[(0, 1, None), (0, 1, None), (0, 1, None)]>>> D.allow_multiple_edges(False); D
Digraph on 2 vertices>>> D.has_multiple_edges()
False>>> D.edges(sort=True)[(0, 1, None)]>>> G = DiGraph({Integer(1): {Integer(2): h }, Integer(2): {Integer(1):˓→, sparse=True)>>> G.has_multiple_edges()
False>>> G.has_multiple_edges(to_undirected=True)
True>>> G.multiple_edges()[]>>> G.multiple_edges(to_undirected=True)[(1, 2, h ), (2, 1, g )]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>>> from sage.all import *>>> g = Graph(loops=True, multiedges=True)>>> g.add_edge(Integer(0), Integer(0))>>> g.has_multiple_edges()
False

has_vertex(vertex)
Check if vertex is one of the vertices of this graph.
INPUT:• vertex – the name of a vertex (see add_vertex())

194

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

EXAMPLES:
sage: g = Graph({0: [1, 2, 3], 2: [4]}); g
Graph on 5 vertices
sage: 2 in gTrue
sage: 10 in g
False
sage: graphs.PetersenGraph().has_vertex(99)
False>>> from sage.all import *>>> g = Graph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(2):␣
˓→[Integer(4)]}); g
Graph on 5 vertices>>> Integer(2) in g
True>>> Integer(10) in g
False>>> graphs.PetersenGraph().has_vertex(Integer(99))
False

igraph_graph(vertex_list=None, vertex_attrs={}, edge_attrs={})Return an igraph graph from the Sage 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 -ipython_igraph. For more information on the Python version of igraph, see http://igraph.org/python/.
INPUT:• vertex_list – list (default: None); defines a mapping from the vertices of the graph to consecutive
integers in (0, \ldots, n-1) . Otherwise, the result of :meth: vertices
will be used instead. Because :meth: vertices only works if thevertices can be sorted, using
vertex_list is useful when working with possibly
non-sortable objects in Python 3.
• vertex_attrs – dictionary (default: {}); a dictionary where the key is a string (the attribute name),
and the value is an iterable containing in position 𝑖 the label of the 𝑖-th vertex in the list vertex_list
if it is given or in vertices() when vertex_list == None (see http://igraph.org/python/doc/
igraph.Graph-class.html#__init__ for more information)• edge_attrs – dictionary (default: {}); a dictionary where the key is a string (the attribute name),
and the value is an iterable containing in position 𝑖 the label of the 𝑖-th edge in the list outputted by
edge_iterator() (see http://igraph.org/python/doc/igraph.Graph-class.html#__init__ for more
information)
Note: In igraph, a graph is weighted if the edge labels have attribute weight. Hence, to create a weighted
graph, it is enough to add this attribute.

Note: Often, Sage uses its own defined types for integer/floats. These types may not be igraph-compatible(see example below).

1.1. Generic graphs (common to directed/undirected)

195Graph Theory, Release 10.4

EXAMPLES:
Standard conversion:
sage: G = graphs.TetrahedralGraph()
sage: H = G.igraph_graph()# optional - python_igraphsage: H.summary()# optional - python_igraph
IGRAPH U--- 4 6 -sage: G = digraphs.Path(3)sage: H = G.igraph_graph()# optional - python_igraphsage: H.summary()# optional - python_igraph
IGRAPH D--- 3 2 ->>> from sage.all import *>>> G = graphs.TetrahedralGraph()>>> H = G.igraph_graph()# optional - python_igraph>>> H.summary()# optional - python_igraph
IGRAPH U--- 4 6 ->>> G = digraphs.Path(Integer(3))>>> H = G.igraph_graph()# optional - python_igraph>>> H.summary()# optional - python_igraph
IGRAPH D--- 3 2 --Adding edge attributes:
sage: G = Graph([(1, 2, a ), (2, 3, b )])sage: E = list(G.edge_iterator())
sage: H = G.igraph_graph(edge_attrs={ label : [e[2] for e in E]})
˓→- python_igraphsage: H.es[ label ]˓→- python_igraph[ a , b ]# optional␣
# optional␣

>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2), a ), (Integer(2), Integer(3), b )])>>> E = list(G.edge_iterator())>>> H = G.igraph_graph(edge_attrs={ label : [e[Integer(2)] for e in E]}) #␣
˓→optional - python_igraph>>> H.es[ label ]# optional -␣˓→python_igraph[ a , b ]If edges have an attribute weight, the igraph graph is considered weighted:
sage: G = Graph([(1, 2, { weight : 1}), (2, 3, { weight : 2})])sage: E = list(G.edge_iterator())
sage: H = G.igraph_graph(edge_attrs={ weight : [e[2][ weight ] for e in E]})
˓→# optional - python_igraphsage: H.is_weighted()
˓→# optional - python_igraphTrue
sage: H.es[ weight ]˓→# optional - python_igraph[1, 2]>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2), { weight : Integer(1)}), (Integer(2),␣
(continues on next page)

196

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Integer(3), { weight : Integer(2)})])>>> E = list(G.edge_iterator())>>> H = G.igraph_graph(edge_attrs={ weight : [e[Integer(2)][ weight ] for e␣˓→in E]})# optional - python_igraph>>> H.is_weighted()#␣˓→optional - python_igraphTrue>>> H.es[ weight ]#␣˓→optional - python_igraph[1, 2]
˓→

Adding vertex attributes:
sage: G = graphs.GridGraph([2, 2])
sage: H = G.igraph_graph(vertex_attrs={ name : G.vertices(sort=True)})
˓→optional - python_igraphsage: H.vs()[ name ]˓→optional - python_igraph[(0, 0), (0, 1), (1, 0), (1, 1)]>>> from sage.all import *>>> G = graphs.GridGraph([Integer(2), Integer(2)])>>> H = G.igraph_graph(vertex_attrs={ name : G.vertices(sort=True)})
˓→optional - python_igraph>>> H.vs()[ name ]˓→optional - python_igraph[(0, 0), (0, 1), (1, 0), (1, 1)]

#␣
#␣

#␣
#␣

Providing a mapping from vertices to consecutive integers:
sage: G = graphs.GridGraph([2, 2])
sage: V = list(G)sage: H = G.igraph_graph(vertex_list=V, vertex_attrs={ name : V})
˓→- python_igraphsage: H.vs()[ name ] == V
˓→- python_igraphTrue>>> from sage.all import *>>> G = graphs.GridGraph([Integer(2), Integer(2)])>>> V = list(G)>>> H = G.igraph_graph(vertex_list=V, vertex_attrs={ name : V})
˓→python_igraph>>> H.vs()[ name ] == V˓→python_igraphTrue# optional␣
# optional␣

# optional -␣# optional -␣

Sometimes, Sage integer/floats are not compatible with igraph:
sage: G = Graph([(0, 1, 2)])sage: E = list(G.edge_iterator())
sage: H = G.igraph_graph(edge_attrs={ capacity : [e[2] for e in E]})
˓→optional - python_igraphsage: H.maxflow_value(0, 1, capacity )˓→optional - python_igraph
1.0

#␣
#␣

(continues on next page)

1.1. Generic graphs (common to directed/undirected)

197Graph Theory, Release 10.4

(continued from previous page)

sage: H = G.igraph_graph(edge_attrs={ capacity : [float(e[2]) for e in E]})
˓→# optional - python_igraphsage: H.maxflow_value(0, 1, capacity )˓→# optional - python_igraph
2.0>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1), Integer(2))])>>> E = list(G.edge_iterator())>>> H = G.igraph_graph(edge_attrs={ capacity : [e[Integer(2)] for e in E]})
˓→# optional - python_igraph>>> H.maxflow_value(Integer(0), Integer(1), capacity )␣˓→# optional - python_igraph
1.0>>> H = G.igraph_graph(edge_attrs={ capacity : [float(e[Integer(2)]) for e in␣˓→E]})# optional - python_igraph>>> H.maxflow_value(Integer(0), Integer(1), capacity )␣˓→# optional - python_igraph2.0

incidence_matrix(oriented, sparse=None, vertices=True, edges=None, base_ring=None, **kwds)
Return the incidence matrix of the (di)graph.
Each row is a vertex, and each column is an edge. The vertices are ordered as obtained by the method
vertices(), except when parameter vertices is given (see below), and the edges as obtained by themethod edge_iterator().
If the graph is not directed, then return a matrix with entries in {0, 1, 2}. Each column will either containtwo 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 – boolean (default: None); when set to True, the matrix will be oriented (i.e. with entriesin −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 withthe option directed=True, a somewhat random direction is chosen for each edge.
• sparse – boolean (default: True); whether to use a sparse or a dense matrix• vertices – list, None, or True (default: None);– when a list, the 𝑖-th row of the matrix corresponds to the 𝑖-th vertex in the ordering of vertices,– when None, the 𝑖-th row of the matrix corresponds to the 𝑖-th vertex in the ordering given by method
vertices(),– when True, construct a morphism of free modules instead of a matrix, where the codomain’s basis
is indexed by the vertices.
• edges – list, None, or True (default: None);– when a list, the 𝑖-th column of the matrix corresponds to the 𝑖-th edge in the ordering of edges,– when None, the 𝑖-th column of the matrix corresponds to the 𝑖-th edge in the ordering given bymethod edge_iterator(),
198

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

– when True, construct a morphism of free modules instead of a matrix, where the domain’s basis isindexed by the edges.
• base_ring – a ring (default: ZZ); the base ring of the matrix space to use.
• **kwds – other keywords to pass to matrix().
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.incidence_matrix()
˓→needs sage.modules[1 1 1 0 0 0 0 0 0 0 0 0 0 0 0]
[1 0 0 1 1 0 0 0 0 0 0 0 0 0 0]
[0 0 0 1 0 1 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 1 0 1 1 0 0 0 0 0 0]
[0 1 0 0 0 0 0 1 0 1 0 0 0 0 0]
[0 0 1 0 0 0 0 0 0 0 1 1 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0 0 1 1 0]
[0 0 0 0 0 0 1 0 0 0 1 0 0 0 1]
[0 0 0 0 0 0 0 0 1 0 0 1 1 0 0]
[0 0 0 0 0 0 0 0 0 1 0 0 0 1 1]
sage: G.incidence_matrix(oriented=True)
˓→needs sage.modules[-1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0]
[ 1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 1 0 -1 -1 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 1 0 -1 -1 0 0 0 0 0 0]
[ 0 1 0 0 0 0 0 1 0 -1 0 0 0 0 0]
[ 0 0 1 0 0 0 0 0 0 0 -1 -1 0 0 0]
[ 0 0 0 0 1 0 0 0 0 0 0 0 -1 -1 0][ 0 0 0 0 0 0 1 0 0 0 1 0 0 0 -1][ 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0]
[ 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1]#␣#␣

sage: G = digraphs.Circulant(4, [1, 3])
sage: G.incidence_matrix()
˓→needs sage.modules[-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()
˓→needs sage.modules[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)
˓→needs sage.modules[2 1 1][0 1 1]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.incidence_matrix()
˓→needs sage.modules[1 1 1 0 0 0 0 0 0 0 0 0 0 0 0]

#␣

#␣

#␣

(continues on next page)

1.1. Generic graphs (common to directed/undirected)

199

Graph Theory, Release 10.4

(continued from previous page)[1 0 0 1 1 0 0 0 0 0 0 0 0 0 0]
[0 0 0 1 0 1 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 1 0 1 1 0 0 0 0 0 0]
[0 1 0 0 0 0 0 1 0 1 0 0 0 0 0]
[0 0 1 0 0 0 0 0 0 0 1 1 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0 0 1 1 0]
[0 0 0 0 0 0 1 0 0 0 1 0 0 0 1]
[0 0 0 0 0 0 0 0 1 0 0 1 1 0 0]
[0 0 0 0 0 0 0 0 0 1 0 0 0 1 1]>>> G.incidence_matrix(oriented=True)
˓→needs sage.modules[-1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0]
[ 1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 1 0 -1 -1 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 1 0 -1 -1 0 0 0 0 0 0]
[ 0 1 0 0 0 0 0 1 0 -1 0 0 0 0 0]
[ 0 0 1 0 0 0 0 0 0 0 -1 -1 0 0 0]
[ 0 0 0 0 1 0 0 0 0 0 0 0 -1 -1 0][ 0 0 0 0 0 0 1 0 0 0 1 0 0 0 -1][ 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0]
[ 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1]

#␣>>> G = digraphs.Circulant(Integer(4), [Integer(1), Integer(3)])>>> G.incidence_matrix()
˓→needs sage.modules[-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]#␣>>> graphs.CompleteGraph(Integer(3)).incidence_matrix()˓→# needs sage.modules[1 1 0][1 0 1][0 1 1]>>> G = Graph([(Integer(0), Integer(0)), (Integer(0), Integer(1)),␣
˓→(Integer(0), Integer(1))], loops=True, multiedges=True)>>> G.incidence_matrix(oriented=False)
˓→needs sage.modules[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)
˓→needs sage.modules
sage: m * m.transpose() == G.kirchhoff_matrix()
˓→needs sage.modules
True
sage: K = graphs.CompleteGraph(3)sage: m = K.incidence_matrix(oriented=True)
˓→needs sage.modules
sage: m * m.transpose() == K.kirchhoff_matrix()
˓→needs sage.modules

200

#␣
#␣

#␣
#␣
(continues on next page)

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True
sage: H = Graph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True)
sage: m = H.incidence_matrix(oriented=True)
˓→needs sage.modules
sage: m * m.transpose() == H.kirchhoff_matrix()
˓→needs sage.modules
True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> m = G.incidence_matrix(oriented=True)
˓→needs sage.modules>>> m * m.transpose() == G.kirchhoff_matrix()
˓→needs sage.modules
True

#␣
#␣

#␣
#␣

>>> K = graphs.CompleteGraph(Integer(3))>>> m = K.incidence_matrix(oriented=True)
˓→needs sage.modules>>> m * m.transpose() == K.kirchhoff_matrix()
˓→needs sage.modules
True

#␣
#␣

>>> H = Graph([(Integer(0), Integer(0)), (Integer(0), Integer(1)),␣
˓→(Integer(0), Integer(1))], loops=True, multiedges=True)>>> m = H.incidence_matrix(oriented=True)
˓→needs sage.modules>>> m * m.transpose() == H.kirchhoff_matrix()
˓→needs sage.modules
True

#␣
#␣

A different ordering of the vertices:sage: P5 = graphs.PathGraph(5)sage: P5.incidence_matrix()
˓→needs sage.modules[1 0 0 0][1 1 0 0][0 1 1 0][0 0 1 1][0 0 0 1]
sage: P5.incidence_matrix(vertices=[2, 4, 1, 3, 0])
˓→needs sage.modules[0 1 1 0][0 0 0 1][1 1 0 0][0 0 1 1][1 0 0 0]>>> from sage.all import *>>> P5 = graphs.PathGraph(Integer(5))>>> P5.incidence_matrix()
˓→needs sage.modules[1 0 0 0][1 1 0 0]

#␣

#␣

#␣

(continues on next page)

1.1. Generic graphs (common to directed/undirected)

201

Graph Theory, Release 10.4

(continued from previous page)[0 1 1 0][0 0 1 1][0 0 0 1]>>> P5.incidence_matrix(vertices=[Integer(2), Integer(4), Integer(1),␣
˓→Integer(3), Integer(0)])# needs sage.modules[0 1 1 0][0 0 0 1][1 1 0 0][0 0 1 1][1 0 0 0]

A different ordering of the edges:
sage: E = list(P5.edge_iterator(labels=False))
sage: P5.incidence_matrix(edges=E[::-1])
˓→needs sage.modules[0 0 0 1][0 0 1 1][0 1 1 0][1 1 0 0][1 0 0 0]
sage: P5.incidence_matrix(vertices=[2, 4, 1, 3, 0], edges=E[::-1])
˓→needs sage.modules[0 1 1 0][1 0 0 0][0 0 1 1][1 1 0 0][0 0 0 1]>>> from sage.all import *>>> E = list(P5.edge_iterator(labels=False))>>> P5.incidence_matrix(edges=E[::-Integer(1)])˓→# needs sage.modules[0 0 0 1][0 0 1 1][0 1 1 0][1 1 0 0][1 0 0 0]>>> P5.incidence_matrix(vertices=[Integer(2), Integer(4), Integer(1),␣
˓→Integer(3), Integer(0)], edges=E[::-Integer(1)])# needs sage.
˓→modules[0 1 1 0][1 0 0 0][0 0 1 1][1 1 0 0][0 0 0 1]

#␣

#␣

␣

A different base ring:sage: P5.incidence_matrix(base_ring=RDF)
˓→needs sage.modules[1.0 0.0 0.0 0.0]
[1.0 1.0 0.0 0.0]
[0.0 1.0 1.0 0.0]
[0.0 0.0 1.0 1.0]
[0.0 0.0 0.0 1.0]

202

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> P5.incidence_matrix(base_ring=RDF)
˓→needs sage.modules[1.0 0.0 0.0 0.0]
[1.0 1.0 0.0 0.0]
[0.0 1.0 1.0 0.0]
[0.0 0.0 1.0 1.0]
[0.0 0.0 0.0 1.0]#␣Creating an immutable matrix:
sage: m = P5.incidence_matrix(immutable=True); m˓→needs sage.modules[1 0 0 0][1 1 0 0][0 1 1 0][0 0 1 1][0 0 0 1]
sage: m[1,2] = 1
˓→needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).

#␣#␣>>> from sage.all import *>>> m = P5.incidence_matrix(immutable=True); m˓→needs sage.modules[1 0 0 0][1 1 0 0][0 1 1 0][0 0 1 1][0 0 0 1]>>> m[Integer(1),Integer(2)] = Integer(1)˓→# needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).

#␣␣Creating a module morphism:
sage: # needs sage.modules
sage: D12 = posets.DivisorLattice(12).hasse_diagram()
sage: phi_VE = D12.incidence_matrix(vertices=True, edges=True); phi_VE
Generic morphism:
From: Free module generated by{(1, 2), (1, 3), (2, 4), (2, 6), (3, 6), (4, 12), (6, 12)}over Integer Ring
To:
Free module generated by {1, 2, 3, 4, 6, 12} over Integer Ringsage: print(phi_VE._unicode_art_matrix())(1, 2) (1, 3) (2, 4) (2, 6) (3, 6) (4, 12) (6, 12)
1⎛
-1
-1
0
0
0
0
0⎞
2⎜
1
0
-1
-1
0
0
0⎟
3⎜
0
1
0
0
-1
0
0⎟
4⎜
0
0
1
0
0
-1
0⎟
6⎜
0
0
0
1
1
0
-1⎟
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

203

Graph Theory, Release 10.4

(continued from previous page)

12⎝
0
0
0
0
0
1
sage: E = phi_VE.domain()sage: P1 = E.monomial((2, 4)) + E.monomial((4, 12)); P1
B[(2, 4)] + B[(4, 12)]sage: P2 = E.monomial((2, 6)) + E.monomial((6, 12)); P2
B[(2, 6)] + B[(6, 12)]sage: phi_VE(P1 - P2)
0

1⎠>>> from sage.all import *>>> # needs sage.modules>>> D12 = posets.DivisorLattice(Integer(12)).hasse_diagram()>>> phi_VE = D12.incidence_matrix(vertices=True, edges=True); phi_VE
Generic morphism:
From: Free module generated by{(1, 2), (1, 3), (2, 4), (2, 6), (3, 6), (4, 12), (6, 12)}over Integer Ring
To:
Free module generated by {1, 2, 3, 4, 6, 12} over Integer Ring>>> print(phi_VE._unicode_art_matrix())(1, 2) (1, 3) (2, 4) (2, 6) (3, 6) (4, 12) (6, 12)
1⎛
-1
-1
0
0
0
0
0⎞
2⎜
1
0
-1
-1
0
0
0⎟
3⎜
0
1
0
0
-1
0
0⎟
4⎜
0
0
1
0
0
-1
0⎟
6⎜
0
0
0
1
1
0
-1⎟
12⎝
0
0
0
0
0
1
1⎠
>>> E = phi_VE.domain()>>> P1 = E.monomial((Integer(2), Integer(4))) + E.monomial((Integer(4),␣
˓→Integer(12))); P1
B[(2, 4)] + B[(4, 12)]>>> P2 = E.monomial((Integer(2), Integer(6))) + E.monomial((Integer(6),␣
˓→Integer(12))); P2
B[(2, 6)] + B[(6, 12)]>>> phi_VE(P1 - P2)0

is_bipartite(certificate=False)
Check whether the graph is bipartite.
Traverse the graph 𝐺 with breadth-first-search and color nodes.
INPUT:• certificate – boolean (default: False); whether to return a certificate. If set to True, the certificate returned is a proper 2-coloring when 𝐺 is bipartite, and an odd cycle otherwise.
EXAMPLES:
sage: graphs.CycleGraph(4).is_bipartite()True
sage: graphs.CycleGraph(5).is_bipartite()
False
sage: graphs.RandomBipartite(10, 10, 0.7).is_bipartite()
˓→needs numpy
True

204

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.CycleGraph(Integer(4)).is_bipartite()True>>> graphs.CycleGraph(Integer(5)).is_bipartite()
False>>> graphs.RandomBipartite(Integer(10), Integer(10), RealNumber( 0.7 )).is_˓→bipartite()# needs numpy
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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_bipartite()
False>>> false, oddcycle = g.is_bipartite(certificate=True)>>> len(oddcycle) % Integer(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>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(2): [Integer(1)], Integer(3): [Integer(4)]})>>> g.is_bipartite()
False>>> false, oddcycle = g.is_bipartite(certificate=True)>>> len(oddcycle) % Integer(2)1>>> graphs.CycleGraph(Integer(4)).random_orientation().is_bipartite()True>>> graphs.CycleGraph(Integer(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.

1.1. Generic graphs (common to directed/undirected)

205

Graph Theory, Release 10.4

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, eachof 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 package gap_packages needs to be installed:
to do so, it is enough to run sage -i gap_packages.
INPUT:• return_group (boolean; False) – If True, return a group for which the graph is a Cayley graph.
• mapping (boolean; False) – If True, return a mapping from vertices to group elements.
• generators (boolean; False) – If True, return the generating set of the Cayley graph.
• allow_disconnected (boolean; False) – If True, disconnected graphs are considered Cayley ifthey 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, checkthat the graph is vertex-transitive and perform the check on one of its connected components. If a simple graphhas 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()˓→needs sage.groups
False

#␣

>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_cayley()˓→needs sage.groups
False

#␣

A Cayley digraph is a Cayley graph:
sage: C7 = groups.permutation.Cyclic(7)˓→needs sage.groups
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)
˓→needs sage.groups
sage: d.is_cayley()˓→needs sage.groups
True

#␣

#␣
#␣

>>> from sage.all import *>>> C7 = groups.permutation.Cyclic(Integer(7))␣˓→# needs sage.groups>>> S = [(Integer(1),Integer(2),Integer(3),Integer(4),Integer(5),Integer(6),˓→Integer(7)), (Integer(1),Integer(3),Integer(5),Integer(7),Integer(2),˓→Integer(4),Integer(6)), (Integer(1),Integer(5),Integer(2),Integer(6),(continues on next page)

206

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Integer(3),Integer(7),Integer(4))]>>> d = C7.cayley_graph(generators=S)
˓→needs sage.groups>>> d.is_cayley()˓→needs sage.groups
True
˓→

#␣
#␣

Graphs with loops and multiedges will have identity and repeated elements, respectively, among the generators:
sage: # needs sage.rings.finite_rings
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)
˓→needs sage.groups
sage: S # random
˓→needs sage.groups[(),(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)]#␣#␣>>> from sage.all import *>>> # needs sage.rings.finite_rings>>> g = Graph(graphs.PaleyGraph(Integer(9)), loops=True, multiedges=True)>>> g.add_edges([(u, u) for u in g])>>> g.add_edges([(u, u+Integer(1)) for u in g])>>> _, S = g.is_cayley(generators=True)#␣˓→needs sage.groups>>> S # random#␣˓→needs sage.groups[(),(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')
Check whether the given graph is chordal.
A Graph 𝐺 is said to be chordal if it contains no induced hole (a cycle of length at least 4).
Alternatively, chordality can be defined using a Perfect Elimination Order:
A Perfect Elimination Order of a graph 𝐺 is an ordering 𝑣1 , ..., 𝑣𝑛 of its vertex set such that for all 𝑖, theneighbors of 𝑣𝑖 whose index is greater that 𝑖 induce a complete subgraph in 𝐺. Hence, the graph 𝐺 can betotally erased by successively removing vertices whose neighborhood is a clique (also called simplicial vertices)[FG1965].
(It can be seen that if 𝐺 contains an induced hole, then it cannot have a perfect elimination order. Indeed,
if we write ℎ1 , ..., ℎ𝑘 the 𝑘 vertices of such a hole, then the first of those vertices to be removed would have
two non-adjacent neighbors in the graph.)1.1. Generic graphs (common to directed/undirected)

207

Graph Theory, Release 10.4

A Graph is then chordal if and only if it has a Perfect Elimination Order.
INPUT:• certificate – boolean (default: False); whether to return a certificate.
– If certificate = False (default), returns True or False accordingly.
– If certificate = True, returns :∗ (True, peo) when the graph is chordal, where peo is a perfect elimination order of its
vertices.
∗ (False, Hole) when the graph is not chordal, where Hole (a Graph object) is an induced
subgraph of self isomorphic to a hole.
• algorithm – string (default: "B"); the algorithm to choose among "A" or "B". While they willagree on whether the given graph is chordal, they cannot be expected to return the same certificates.
ALGORITHM:
This method implements the algorithm proposed in [RT1975] for the recognition of chordal graphs. The
time complexity of this algorithm is 𝑂(𝑛 + 𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph. The
algorithm works through computing a Lex BFS on the graph, then checking whether the order is a Perfect
Elimination Order by computing for each vertex 𝑣 the subgraph induced by its non-deleted neighbors, thentesting whether this graph is complete.
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>>> from sage.all import *>>> g = graphs.PathGraph(Integer(5)).lexicographic_product(graphs.
˓→CompleteGraph(Integer(3)))>>> g.is_chordal()True

The same goes with the product of a random lobster (which is a tree) and a Complete Graphsage: grl = graphs.RandomLobster(10, .5, .5)
˓→needs networkx
sage: g = grl.lexicographic_product(graphs.CompleteGraph(3))˓→needs networkx
sage: g.is_chordal()˓→needs networkx
True

#␣
#␣
#␣

>>> from sage.all import *>>> grl = graphs.RandomLobster(Integer(10), RealNumber( .5 ), RealNumber( .5˓→ ))# needs networkx>>> g = grl.lexicographic_product(graphs.CompleteGraph(Integer(3)))␣˓→# needs networkx>>> g.is_chordal()#␣˓→needs networkx
True

The disjoint union of chordal graphs is still chordal:

208

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: (2 * g).is_chordal()˓→needs networkx
True

#␣

>>> from sage.all import *>>> (Integer(2) * g).is_chordal()˓→# needs networkx
True␣

Let us check the certificate given by Sage is indeed a perfect elimination order:
sage: _, peo = g.is_chordal(certificate=True)
˓→needs networkx
sage: for v in peo:
˓→needs networkx....:
if not g.subgraph(g.neighbors(v)).is_clique():....:raise ValueError("this should never happen")....:g.delete_vertex(v)>>> from sage.all import *>>> _, peo = g.is_chordal(certificate=True)
˓→needs networkx>>> for v in peo:
˓→needs networkx...
if not g.subgraph(g.neighbors(v)).is_clique():...
raise ValueError("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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.girth()5>>> g.is_chordal()False

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>>> from sage.all import *>>> _, hole = g.is_chordal(certificate=True)>>> hole
Subgraph of (Petersen graph): Graph on 5 vertices(continues on next page)

1.1. Generic graphs (common to directed/undirected)

209

Graph Theory, Release 10.4

(continued from previous page)>>> hole.is_isomorphic(graphs.CycleGraph(Integer(5)))
True

is_circulant(certificate=False)
Check whether the graph is circulant.
For more information, see Wikipedia article Circulant_graph.
INPUT:• certificate – boolean (default: False); whether to return a certificate for yes-answers (see OUTPUT section)
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 graphas 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()
˓→needs sage.groups
False

#␣

>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_circulant()
˓→needs sage.groups
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)
˓→needs sage.groups(True, [(5, [1, 4]), (5, [2, 3])])>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.is_circulant(certificate=True)
˓→needs sage.groups(True, [(5, [1, 4]), (5, [2, 3])])#␣#␣The same goes for directed graphs:

210

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = digraphs.Circuit(5)sage: g.is_circulant(certificate=True)
˓→needs sage.groups(True, [(5, [1]), (5, [3]), (5, [2]), (5, [4])])>>> from sage.all import *>>> g = digraphs.Circuit(Integer(5))>>> g.is_circulant(certificate=True)
˓→needs sage.groups(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]:˓→needs sage.groups....:
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#␣>>> from sage.all import *>>> g = graphs.CirculantGraph(Integer(13), [Integer(2), Integer(3),␣
˓→Integer(10), Integer(11)])>>> for param in g.is_circulant(certificate=True)[Integer(1)]:˓→# needs sage.groups...
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␣

is_circular_planar(on_embedding=None, kuratowski=False, set_embedding=True, boundary=None,ordered=False, set_pos=False)
Check 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 specificset (the boundary) can be drawn on a circle, all other vertices being drawn inside of the circle. An order canbe defined on the vertices of the boundary in order to define how they are to appear on the circle.
INPUT:• on_embedding – dictionary (default: None); the embedding dictionary to test planarity on (i.e.: will
return True or False only for the given embedding)• kuratowski – boolean (default: False); whether to return a tuple with boolean first entry and theKuratowski subgraph (i.e. an edge subdivision of 𝐾5 or 𝐾3,3 ) as the second entry (see OUTPUT below)• set_embedding – boolean (default: True); 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 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.
• boundary – list (default: None); an ordered list 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.

1.1. Generic graphs (common to directed/undirected)

211Graph Theory, Release 10.4

• ordered – boolean (default: False); whether or not to consider the order of the boundary. It required
boundary to be defined.
• set_pos – boolean (default: False); whether or not to set the position dictionary (for plotting) toreflect the combinatorial embedding. Note that this value will default to False if set_embedding
is set to False. Also, the position dictionary will only be updated if a circular planar embedding isfound.
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 andwhose second entry is the Kuratowski subgraph (i.e. an edge subdivision of 𝐾5 or 𝐾3,3 ) isolated by theBoyer-Myrvold algorithm. Note that this graph might contain a vertex or edges that were not in the initialgraph. 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:[BM2004]
EXAMPLES:
sage: g439 = Graph({1: [5, 7], 2: [5, 6], 3: [6, 7], 4: [5, 6, 7]})sage: g439.show()˓→needs sage.plot
sage: g439.is_circular_planar(boundary=[1, 2, 3, 4])
False
sage: g439.is_circular_planar(kuratowski=True, boundary=[1, 2, 3, 4])(False, Kuratowski subgraph of (): Graph on 8 vertices)sage: g439.is_circular_planar(kuratowski=True, boundary=[1, 2, 3])(True, None)sage: g439.get_embedding(){1: [5, 7],
2: [6, 5],
3: [7, 6],
4: [5, 6, 7],
5: [2, 4, 1],
6: [3, 4, 2],
7: [1, 4, 3]}#␣>>> from sage.all import *>>> g439 = Graph({Integer(1): [Integer(5), Integer(7)], Integer(2):␣
˓→[Integer(5), Integer(6)], Integer(3): [Integer(6), Integer(7)], Integer(4):␣
˓→[Integer(5), Integer(6), Integer(7)]})>>> g439.show()#␣˓→needs sage.plot>>> g439.is_circular_planar(boundary=[Integer(1), Integer(2), Integer(3),␣
˓→Integer(4)])
False>>> g439.is_circular_planar(kuratowski=True, boundary=[Integer(1), Integer(2),˓→ Integer(3), Integer(4)])(continues on next page)212

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)(False, Kuratowski subgraph of (): Graph on 8 vertices)>>> g439.is_circular_planar(kuratowski=True, boundary=[Integer(1), Integer(2),˓→ Integer(3)])(True, None)>>> g439.get_embedding(){1: [5, 7],
2: [6, 5],
3: [7, 6],
4: [5, 6, 7],
5: [2, 4, 1],
6: [3, 4, 2],
7: [1, 4, 3]}Order matters:sage: 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>>> from sage.all import *>>> K23 = graphs.CompleteBipartiteGraph(Integer(2), Integer(3))>>> K23.is_circular_planar(boundary=[Integer(0), Integer(1), Integer(2),␣
˓→Integer(3)])
True>>> K23.is_circular_planar(ordered=True, boundary=[Integer(0), Integer(1),␣
˓→Integer(2), Integer(3)])
False

With a different order:
sage: K23.is_circular_planar(set_embedding=True, boundary=[0, 2, 1, 3])
True>>> from sage.all import *>>> K23.is_circular_planar(set_embedding=True, boundary=[Integer(0),␣
˓→Integer(2), Integer(1), Integer(3)])
True

is_clique(vertices=None, directed_clique=False, induced=True, loops=False)
Check 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 – a single vertex or an iterable container of vertices (default: None); when set,
check whether the set of vertices is a clique, otherwise check whether
self is a clique• directed_clique – boolean (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 – boolean (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.

1.1. Generic graphs (common to directed/undirected)

213

Graph Theory, Release 10.4

• loops – boolean (default: False); if set to True, check that each vertex of the graph has a loop, andexactly 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
sage: i = digraphs.Complete(4)sage: i.delete_edge([0, 1])
sage: i.is_clique(directed_clique=False, induced=True)
False
sage: i.is_clique(directed_clique=False, induced=False)
True
sage: i.is_clique(directed_clique=True)
False>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4))>>> g.is_clique([Integer(1), Integer(2), Integer(3)])
True>>> g.is_clique()True>>> h = graphs.CycleGraph(Integer(4))>>> h.is_clique([Integer(1), Integer(2)])
True>>> h.is_clique([Integer(1), Integer(2), Integer(3)])
False>>> h.is_clique()False>>> i = digraphs.Complete(Integer(4))>>> i.delete_edge([Integer(0), Integer(1)])>>> i.is_clique(directed_clique=False, induced=True)
False>>> i.is_clique(directed_clique=False, induced=False)
True>>> i.is_clique(directed_clique=True)
False

is_connected(G)Check whether the (di)graph is connected.
Note that in a graph, path connected is equivalent to connected.
INPUT:• G – the input graphSee also:

214

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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)Truesage: 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)Truesage: D = DiGraph({1: [0], 2: [0]})sage: is_connected(D)True>>> from sage.all import *>>> from sage.graphs.connectivity import is_connected>>> G = Graph({Integer(0): [Integer(1), Integer(2)], Integer(1): [Integer(2)],
˓→ Integer(3): [Integer(4), Integer(5)], Integer(4): [Integer(5)]})>>> is_connected(G)False>>> G.is_connected()
False>>> G.add_edge(Integer(0),Integer(3))>>> is_connected(G)True>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(2)], Integer(3): [Integer(4), Integer(5)], Integer(4):␣
˓→[Integer(5)]})>>> is_connected(D)False>>> D.add_edge(Integer(0), Integer(3))>>> is_connected(D)True>>> D = DiGraph({Integer(1): [Integer(0)], Integer(2): [Integer(0)]})>>> 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. Thisfunction works with simple graphs as well as graphs with loops and multiedges. In a digraph, a cut edge is anedge 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’ )1.1. Generic graphs (common to directed/undirected)

215

Graph Theory, Release 10.4

• 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 ))Truesage: 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>>> from sage.all import *>>> from sage.graphs.connectivity import is_cut_edge>>> G = graphs.CompleteGraph(Integer(4))>>> is_cut_edge(G,Integer(0),Integer(2))
False>>> G.is_cut_edge(Integer(0),Integer(2))
False>>> G = graphs.CompleteGraph(Integer(4))>>> G.add_edge((Integer(0),Integer(5), silly ))>>> is_cut_edge(G,(Integer(0),Integer(5), silly ))True>>> G = Graph([[Integer(0),Integer(1)],[Integer(0),Integer(2)],[Integer(3),˓→Integer(4)],[Integer(4),Integer(5)],[Integer(3),Integer(5)]])>>> is_cut_edge(G,(Integer(0),Integer(1)))
True>>> G = Graph([[Integer(0),Integer(1)],[Integer(0),Integer(2)],[Integer(1),˓→Integer(1)]], loops = True)>>> is_cut_edge(G,(Integer(1),Integer(1)))(continues on next page)

216

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

False>>> G = digraphs.Circuit(Integer(5))>>> is_cut_edge(G,(Integer(0),Integer(1)))
False>>> G = graphs.CompleteGraph(Integer(6))>>> is_cut_edge(G,(Integer(0),Integer(7)))
Traceback (most recent call last):...
ValueError: edge not in graphis_cut_vertex(G, u, weak=False)
Check whether the input vertex is a cut-vertex.
A vertex is a cut-vertex if its removal from the (di)graph increases the number of (strongly) connected components. Isolated vertices or leafs are not cut-vertices. This function works with simple graphs as well as
graphs with loops and multiple edges.
INPUT:• G – a Sage (Di)Graph• u – a vertex• weak – boolean (default: False); whether the connectivity of directed graphs is to be taken in the
weak sense, that is ignoring edges orientations
OUTPUT:
Return True if u is a cut-vertex, and False otherwise.
EXAMPLES:
Giving a LollipopGraph(4,2), that is a complete graph with 4 vertices with a pending edge:
sage: 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>>> from sage.all import *>>> from sage.graphs.connectivity import is_cut_vertex>>> G = graphs.LollipopGraph(Integer(4), Integer(2))>>> is_cut_vertex(G, Integer(0))
False>>> is_cut_vertex(G, Integer(3))
True>>> G.is_cut_vertex(Integer(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)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

217Graph Theory, Release 10.4

(continued from previous page)

sage: is_strongly_connected(D)Truesage: is_cut_vertex(D, 2)
True
sage: is_cut_vertex(D, 2, weak=True)
False>>> from sage.all import *>>> from sage.graphs.connectivity import is_strongly_connected>>> D = digraphs.Circuit(Integer(6))>>> is_strongly_connected(D)True>>> is_cut_vertex(D, Integer(2))
True>>> is_cut_vertex(D, Integer(2), weak=True)
False

Giving a vertex that is not in the graph:
sage: G = graphs.CompleteGraph(4)sage: is_cut_vertex(G, 7)
Traceback (most recent call last):...
ValueError: vertex (7) is not a vertex of the graph>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> is_cut_vertex(G, Integer(7))
Traceback (most recent call last):...
ValueError: vertex (7) is not a vertex of the graphis_cycle(directed_cycle=True)
Check whether self is a (directed) cycle graph.
We follow the definition provided in [BM2008] for undirected graphs. A cycle on three or more vertices isa simple graph whose vertices can be arranged in a cyclic order so that two vertices are adjacent if they areconsecutive 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 graphwithout loops nor multiple edges with has many arcs as vertices. A circuit on a vertex consists of a single
vertex provided with a loop.
INPUT:• directed_cycle – boolean (default: True); if set to True and the graph is directed, only return
True if self is a directed cycle graph (i.e., a circuit). If set to False, we ignore the direction ofedges and so opposite arcs become multiple (parallel) edges. This parameter is ignored for undirected
graphs.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.is_cycle()(continues on next page)

218

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

False
sage: graphs.CycleGraph(5).is_cycle()True
sage: Graph([(0,1 )]).is_cycle()
False
sage: Graph([(0, 1), (0, 1)], multiedges=True).is_cycle()True
sage: Graph([(0, 1), (0, 1), (0, 1)], multiedges=True).is_cycle()
False
sage: Graph().is_cycle()
False
sage: G = Graph([(0, 0)], loops=True)
sage: G.is_cycle()True
sage: digraphs.Circuit(3).is_cycle()True
sage: digraphs.Circuit(2).is_cycle()True
sage: digraphs.Circuit(2).is_cycle(directed_cycle=False)
True
sage: D = DiGraph(graphs.CycleGraph(3))
sage: D.is_cycle()
False
sage: D.is_cycle(directed_cycle=False)
False
sage: D.edges(sort=True, labels=False)[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.is_cycle()
False>>> graphs.CycleGraph(Integer(5)).is_cycle()
True>>> Graph([(Integer(0),Integer(1) )]).is_cycle()
False>>> Graph([(Integer(0), Integer(1)), (Integer(0), Integer(1))],␣
˓→multiedges=True).is_cycle()
True>>> Graph([(Integer(0), Integer(1)), (Integer(0), Integer(1)), (Integer(0),␣
˓→Integer(1))], multiedges=True).is_cycle()
False>>> Graph().is_cycle()
False>>> G = Graph([(Integer(0), Integer(0))], loops=True)>>> G.is_cycle()True>>> digraphs.Circuit(Integer(3)).is_cycle()True>>> digraphs.Circuit(Integer(2)).is_cycle()True>>> digraphs.Circuit(Integer(2)).is_cycle(directed_cycle=False)
True>>> D = DiGraph(graphs.CycleGraph(Integer(3)))>>> D.is_cycle()
False(continues on next page)

1.1. Generic graphs (common to directed/undirected)

219

Graph Theory, Release 10.4

(continued from previous page)>>> D.is_cycle(directed_cycle=False)
False>>> D.edges(sort=True, labels=False)[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]

is_drawn_free_of_edge_crossings()
Check whether the position dictionary for this graph is set and that position dictionary gives a planar 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: pos = D.layout(layout= planar , save_pos=True)
sage: D.is_drawn_free_of_edge_crossings()
True>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> pos = D.layout(layout= planar , save_pos=True)>>> D.is_drawn_free_of_edge_crossings()
Trueis_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 numberof 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 overthe integers whose rows and columns represent cells of the partition, and whose i,j entry is the numberof 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]])Falsesage: 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)
˓→needs sage.modules[1 2 0][1 0 2][0 2 1]#␣>>> from sage.all import *>>> G = graphs.PetersenGraph()(continues on next page)

220

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G.is_equitable([[Integer(0),Integer(4)],[Integer(1),Integer(3),Integer(5),˓→Integer(9)],[Integer(2),Integer(6),Integer(8)],[Integer(7)]])
False>>> G.is_equitable([[Integer(0),Integer(4)],[Integer(1),Integer(3),Integer(5),˓→Integer(9)],[Integer(2),Integer(6),Integer(8),Integer(7)]])
True>>> G.is_equitable([[Integer(0),Integer(4)],[Integer(1),Integer(3),Integer(5),˓→Integer(9)],[Integer(2),Integer(6),Integer(8),Integer(7)]], quotient_
˓→matrix=True)# needs sage.modules[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)]]>>> from sage.all import *>>> ss = (graphs.WheelGraph(Integer(6))).line_graph(labels=False)>>> prt = [[(Integer(0), Integer(1))], [(Integer(0), Integer(2)), (Integer(0),˓→ Integer(3)), (Integer(0), Integer(4)), (Integer(1), Integer(2)),␣
˓→(Integer(1), Integer(4))], [(Integer(2), Integer(3)), (Integer(3),␣
˓→Integer(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.
>>> from sage.all import *>>> 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>>> from sage.all import *>>> ss = (graphs.WheelGraph(Integer(5))).line_graph(labels=False)>>> ss.is_equitable(prt)False

is_eulerian(path=False)
Check whether the graph is Eulerian.
A graph is Eulerian if it has a (closed) tour that visits each edge exactly once.
INPUT:• path – boolean (default: False); by default this function finds if the graph contains a closed tour
visiting each edge once, i.e. an Eulerian cycle. If you want to test the existence of an Eulerian path, set
this argument to True. Graphs with this property are sometimes called semi-Eulerian.
1.1. Generic graphs (common to directed/undirected)

221Graph Theory, Release 10.4

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 thatwould 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>>> from sage.all import *>>> graphs.CompleteGraph(Integer(4)).is_eulerian()False>>> graphs.CycleGraph(Integer(4)).is_eulerian()True>>> g = DiGraph({Integer(0):[Integer(1),Integer(2)], Integer(1):[Integer(2)]}˓→); g.is_eulerian()False>>> g = DiGraph({Integer(0):[Integer(2)], Integer(1):[Integer(3)],␣
˓→Integer(2):[Integer(0),Integer(1)], Integer(3):[Integer(2)]}); g.is_˓→eulerian()True>>> g = DiGraph({Integer(0):[Integer(1)], Integer(1):[Integer(2)],␣
˓→Integer(2):[Integer(0)], Integer(3):[]}); g.is_eulerian()True>>> g = Graph([(Integer(1),Integer(2)), (Integer(2),Integer(3)), (Integer(3),˓→Integer(1)), (Integer(4),Integer(5)), (Integer(5),Integer(6)), (Integer(6),˓→Integer(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>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1)]}); g.is_eulerian(path=True)(1, 0)>>> graphs.CycleGraph(Integer(4)).is_eulerian(path=True)
False>>> g = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(2),˓→Integer(3)], Integer(2): [Integer(4)]}); g.is_eulerian(path=True)
False

222

Chapter 1. Graph objects and methods

Graph Theory, Release 10.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>>> from sage.all import *>>> g = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2),Integer(3)], Integer(2):[Integer(3),Integer(4)],␣
˓→Integer(3):[Integer(4)]}, multiedges=True)>>> g.is_eulerian()
False>>> e = g.is_eulerian(path=True); e(0, 1)>>> g.add_edge(e)>>> g.is_eulerian(path=False)
True>>> 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 tocomplete graphs or odd cycles.
A connected graph is not degree-choosable if and only if it is a Gallai tree [ERT1979].
EXAMPLES:
A complete graph is, or course, a Gallai Tree:sage: g = graphs.CompleteGraph(15)sage: g.is_gallai_tree()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(15))>>> g.is_gallai_tree()True

The Petersen Graph is not:sage: g = graphs.PetersenGraph()
sage: g.is_gallai_tree()False>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_gallai_tree()False

1.1. Generic graphs (common to directed/undirected)

223

Graph Theory, Release 10.4

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(sort=False)])sage: g.is_gallai_tree()True>>> from sage.all import *>>> g = Integer(8) * graphs.CompleteGraph(Integer(6))>>> g.add_edges([(-Integer(1), c[Integer(0)]) for c in g.connected_
˓→components(sort=False)])>>> g.is_gallai_tree()True

is_geodetic(G)Check whether the input (di)graph is geodetic.
A graph 𝐺 is geodetic if there exists only one shortest path between every pair of its vertices. This can bechecked in time 𝑂(𝑛𝑚) for SparseGraph and 𝑂(𝑛𝑚 + 𝑛2 ) for DenseGraph in unweighted (di)graphswith 𝑛 nodes and 𝑚 edges. Examples of geodetic graphs are trees, cliques and odd cycles. See the Wikipedia
article Geodetic_graph for more details.
(Di)graphs with multiple edges are not considered geodetic.
INPUT:• G – a graph or a digraph
EXAMPLES:
Trees, cliques and odd cycles are geodetic:sage: T = graphs.RandomTree(20)sage: T.is_geodetic()Truesage: all(graphs.CompleteGraph(n).is_geodetic() for n in range(8))
Truesage: all(graphs.CycleGraph(n).is_geodetic() for n in range(3, 16, 2))
True>>> from sage.all import *>>> T = graphs.RandomTree(Integer(20))>>> T.is_geodetic()
True>>> all(graphs.CompleteGraph(n).is_geodetic() for n in range(Integer(8)))
True>>> all(graphs.CycleGraph(n).is_geodetic() for n in range(Integer(3),␣
˓→Integer(16), Integer(2)))
True

Even cycles of order at least 4 are not geodetic:sage: all(graphs.CycleGraph(n).is_geodetic() for n in range(4, 17, 2))
False>>> from sage.all import *>>> all(graphs.CycleGraph(n).is_geodetic() for n in range(Integer(4),␣
(continues on next page)

224

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Integer(17), Integer(2)))
False
˓→

The Petersen graph is geodetic:sage: P = graphs.PetersenGraph()
sage: P.is_geodetic()
True>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.is_geodetic()
True

Grid graphs are not geodetic:sage: G = graphs.Grid2dGraph(2, 3)
sage: G.is_geodetic()
False>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(2), Integer(3))>>> G.is_geodetic()
False

This method is also valid for digraphs:
sage: G = DiGraph(graphs.PetersenGraph())
sage: G.is_geodetic()Truesage: G = digraphs.Path(5)sage: G.add_path([0, a , b , c , 4])
sage: G.is_geodetic()
False>>> from sage.all import *>>> G = DiGraph(graphs.PetersenGraph())>>> G.is_geodetic()
True>>> G = digraphs.Path(Integer(5))>>> G.add_path([Integer(0), a , b , c , Integer(4)])>>> G.is_geodetic()
False

is_hamiltonian(solver, constraint_generation=None, verbose=None, verbose_constraints=0,
integrality_tolerance=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().
1.1. Generic graphs (common to directed/undirected)

225

Graph Theory, Release 10.4

INPUT:• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• constraint_generation (boolean) – whether to use constraint generation when solving theMixed Integer Linear Program. When constraint_generation = None, constraint generation is used whenever the graph has a density larger than 70%.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• verbose_constraints – boolean (default: False); whether to display which constraints are being
generated• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
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()
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.HeawoodGraph()>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

#␣

The Petergraph, though, is not
sage: g = graphs.PetersenGraph()
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
False>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
False

#␣

#␣

is_immutable()
Check whether the graph is immutable.
EXAMPLES:

226

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = graphs.PetersenGraph()
sage: G.is_immutable()False
sage: Graph(G, immutable=True).is_immutable()True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.is_immutable()
False>>> Graph(G, immutable=True).is_immutable()True

is_independent_set(vertices=None)
Check whether vertices is an independent set of self.
An independent set is a set of vertices such that there is no edge between any two vertices.
INPUT:• vertices – a single vertex or an iterable container of vertices (default: None); when set,
check whether the given set of vertices is an independent set,otherwise, check whether the set of vertices ofself is an independent set
EXAMPLES:
sage: graphs.CycleGraph(4).is_independent_set([1,3])
True
sage: graphs.CycleGraph(4).is_independent_set([1,2,3])
False>>> from sage.all import *>>> graphs.CycleGraph(Integer(4)).is_independent_set([Integer(1),Integer(3)])
True>>> graphs.CycleGraph(Integer(4)).is_independent_set([Integer(1),Integer(2),˓→Integer(3)])
False

is_interval(certificate=False)
Check whether the graph is an interval graph.
An interval graph is one where every vertex can be seen as an interval on the real line so that there is an edgein the graph iff the corresponding intervals intersects.
See the Wikipedia article Interval_graph for more information.
INPUT:• certificate – boolean (default: False);– When certificate=False, returns True is the graph is an interval graph and False otherwise– When certificate=True, returns either (False, None) or (True, d) where d isa dictionary whose keys are the vertices and values are pairs of integers. They correspond to anembedding of the interval graph, each vertex being represented by an interval going from the firstof the two values to the second.
ALGORITHM:

1.1. Generic graphs (common to directed/undirected)

227

Graph Theory, Release 10.4

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)})>>> from sage.all import *>>> g = Graph({Integer(1): [Integer(2), Integer(3), Integer(4)], Integer(4):␣
˓→[Integer(2), Integer(3)]})>>> g.is_interval()
True>>> 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 cannot be an interval graph:
sage: g = graphs.PetersenGraph()
sage: g.is_interval()
False>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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>>> from sage.all import *>>> g = Graph({Integer(1): [Integer(4), Integer(2), Integer(3)], Integer(2):␣
˓→[Integer(3), Integer(5)], Integer(3): [Integer(6)]})>>> g.is_interval()
False

See also:• Interval Graph Recognition.
• PQ – implementation of PQ-Trees• is_chordal()• IntervalGraph()• RandomIntervalGraph()

228

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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 – boolean (default: False); if True allows only permutations respecting edge labels
OUTPUT:• 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˓→needs sage.groups
sage: D = graphs.DodecahedralGraph()
sage: E = copy(D)sage: gamma = SymmetricGroup(20).random_element()
˓→needs sage.groups
sage: E.relabel(gamma)
˓→needs sage.groups
sage: D.is_isomorphic(E)True>>> from sage.all import *>>> from sage.groups.perm_gps.permgroup_named import SymmetricGroup˓→needs sage.groups>>> D = graphs.DodecahedralGraph()>>> E = copy(D)>>> gamma = SymmetricGroup(Integer(20)).random_element()˓→# needs sage.groups>>> E.relabel(gamma)
˓→needs sage.groups>>> D.is_isomorphic(E)
True

#␣

#␣
#␣

#␣

␣
#␣

sage: D = graphs.DodecahedralGraph()
sage: S = SymmetricGroup(20)#␣˓→needs sage.groups
sage: gamma = S.random_element()#␣˓→needs sage.groups
sage: E = copy(D)#␣˓→needs sage.groups
sage: E.relabel(gamma)#␣˓→needs sage.groups
sage: a,b = D.is_isomorphic(E, certificate=True); a
True
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: graphics_array([D.plot(pos=position_D), E.plot(pos=position_E)]).show()␣
˓→ # long time, needs sage.plot

1.1. Generic graphs (common to directed/undirected)

229

Graph Theory, Release 10.4>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> S = SymmetricGroup(Integer(20))␣˓→# needs sage.groups>>> gamma = S.random_element()#␣˓→needs sage.groups>>> E = copy(D)#␣˓→needs sage.groups>>> E.relabel(gamma)#␣˓→needs sage.groups>>> a,b = D.is_isomorphic(E, certificate=True); a
True>>> from sage.graphs.generic_graph_pyx import spring_layout_fast>>> position_D = spring_layout_fast(D)>>> position_E = {}>>> for vert in position_D:... position_E[b[vert]] = position_D[vert]>>> graphics_array([D.plot(pos=position_D), E.plot(pos=position_E)]).show()˓→# long time, needs sage.plot
sage: g=graphs.HeawoodGraph()
sage: g.is_isomorphic(g)True>>> from sage.all import *>>> g=graphs.HeawoodGraph()>>> g.is_isomorphic(g)TrueMultigraphs:
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>>> from sage.all import *>>> G = Graph(multiedges=True,sparse=True)>>> G.add_edge((Integer(0),Integer(1),Integer(1)))>>> G.add_edge((Integer(0),Integer(1),Integer(2)))>>> G.add_edge((Integer(0),Integer(1),Integer(3)))>>> G.add_edge((Integer(0),Integer(1),Integer(4)))>>> H = Graph(multiedges=True,sparse=True)>>> H.add_edge((Integer(3),Integer(4)))>>> H.add_edge((Integer(3),Integer(4)))>>> H.add_edge((Integer(3),Integer(4)))>>> H.add_edge((Integer(3),Integer(4)))>>> G.is_isomorphic(H)
True

230

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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})>>> from sage.all import *>>> A = DiGraph( { Integer(0) : [Integer(1),Integer(2)] } )>>> B = DiGraph( { Integer(1) : [Integer(0),Integer(2)] } )>>> A.is_isomorphic(B, certificate=True)(True, {0: 1, 1: 0, 2: 2})

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: H = G.relabel([1,2,3,4,0], inplace=False)
sage: G.is_isomorphic(H, edge_labels=True)
True>>> from sage.all import *>>> G = Graph(sparse=True)>>> G.add_edges( [(Integer(0),Integer(1), a ),(Integer(1),Integer(2), b ),˓→(Integer(2),Integer(3), c ),(Integer(3),Integer(4), b ),(Integer(4),˓→Integer(0), a )] )>>> H = G.relabel([Integer(1),Integer(2),Integer(3),Integer(4),Integer(0)],␣
˓→inplace=False)>>> 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})>>> from sage.all import *>>> G = DiGraph()>>> G.add_edges( [(Integer(0),Integer(1), a ),(Integer(1),Integer(2), b ),˓→(Integer(2),Integer(3), c ),(Integer(3),Integer(4), b ),(Integer(4),˓→Integer(0), a )] )>>> H = G.relabel([Integer(1),Integer(2),Integer(3),Integer(4),Integer(0)],␣
˓→inplace=False)>>> G.is_isomorphic(H, edge_labels=True)
True>>> 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)
Check whether the graph is planar.
This wraps the reference implementation provided by John Boyer of the linear time planarity algorithm byedge addition due to Boyer Myrvold. (See reference code in planarity).
1.1. Generic graphs (common to directed/undirected)

231Graph Theory, Release 10.4

Note: The argument on_embedding takes precedence over set_embedding. This means that only theon_embedding combinatorial embedding will be tested for planarity and no _embedding attribute will
be set as a result of this function call, unless on_embedding is None.
REFERENCE:[BM2004]
See also:• “Almost planar graph”: is_apex()• “Measuring non-planarity”: genus(), crossing_number()• planar_dual()• faces()• is_polyhedral()
INPUT:• on_embedding – dictionary (default: None); the embedding dictionary to test planarity on (i.e.: will
return True or False only for the given embedding)• kuratowski – boolean (default: False); whether to return a tuple with boolean as first entry. If thegraph is nonplanar, will return the Kuratowski subgraph (i.e. an edge subdivision of 𝐾5 or 𝐾3,3 ) as thesecond tuple entry. If the graph is planar, returns None as the second entry. When set to False, only
a boolean answer is returned.
• set_embedding – boolean (default: False); whether to set the instance field variable that contains
a combinatorial embedding (clockwise ordering of neighbors at each vertex). This value will only be set
if a planar embedding is found. It is stored as a Python dict: v1: [n1,n2,n3] where v1 is a vertex
and n1,n2,n3 are its neighbors.
• set_pos – boolean (default: False); whether to set the position dictionary (for plotting) to reflect the
combinatorial embedding. Note that this value will default to False if set_emb is set to False. Also, theposition dictionary will only be updated if a planar embedding is found.
EXAMPLES:
sage: g = graphs.CubeGraph(4)sage: g.is_planar()False>>> from sage.all import *>>> g = graphs.CubeGraph(Integer(4))>>> 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],(continues on next page)

232

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

4: [0, 5, 7],
5: [1, 6, 4],
6: [2, 7, 5],
7: [4, 6, 3]}>>> from sage.all import *>>> g = graphs.CircularLadderGraph(Integer(4))>>> g.is_planar(set_embedding=True)
True>>> 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()
˓→needs sage.modules[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]

#␣>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> (g.is_planar(kuratowski=True))[Integer(1)].adjacency_matrix()˓→# needs sage.modules[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,Kuratowski subgraph of (Complete bipartite graph of order 4+3): Graph on 6␣
˓→vertices)sage: result[1].is_isomorphic(graphs.CompleteBipartiteGraph(3, 3))
True

1.1. Generic graphs (common to directed/undirected)

233Graph Theory, Release 10.4>>> from sage.all import *>>> k43 = graphs.CompleteBipartiteGraph(Integer(4), Integer(3))>>> result = k43.is_planar(kuratowski=True); result(False,Kuratowski subgraph of (Complete bipartite graph of order 4+3): Graph on 6␣
˓→vertices)>>> result[Integer(1)].is_isomorphic(graphs.CompleteBipartiteGraph(Integer(3),˓→ Integer(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 ofmultiple-edged or looped graphs
sage: G.is_planar(set_embedding=True)
Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofmultiple-edged or looped graphs
sage: G.is_planar(kuratowski=True)(True, None)sage: G.is_planar(set_pos=True)
True
sage: sorted(G.get_pos().items())[(0, [0, 0]), (1, [0, 1])]>>> from sage.all import *>>> G = Graph({Integer(0): [Integer(1), Integer(1)]}, multiedges=True)>>> G.is_planar()
True>>> G.is_planar(on_embedding={})Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofmultiple-edged or looped graphs>>> G.is_planar(set_embedding=True)
Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofmultiple-edged or looped graphs>>> G.is_planar(kuratowski=True)(True, None)>>> G.is_planar(set_pos=True)
True>>> sorted(G.get_pos().items())[(0, [0, 0]), (1, [0, 1])]

Digraphs with multiple edges or loops or pairs of opposite arcs are partially supported (Issue #35152):
sage: D = digraphs.Complete(3)sage: D.is_planar()(continues on next page)

234

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True
sage: D.is_planar(set_pos=True)
True
sage: sorted(D.get_pos().items())[(0, [0, 1]), (1, [1, 1]), (2, [1, 0])]sage: D.is_planar(on_embedding={})Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofdigraphs with pairs of opposite arcs
sage: D.is_planar(set_embedding=True)
Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofdigraphs with pairs of opposite arcs
sage: D.is_planar(kuratowski=True)(True, None)sage: D.allow_multiple_edges(True)
sage: D.add_edges(D.edges(sort=False))
sage: D.allow_loops(True)
sage: D.add_edges((u, u) for u in D)
sage: D.is_planar()True
sage: D.is_planar(kuratowski=True)(True, None)sage: D.is_planar(set_pos=True)
True
sage: D.is_planar(set_embedding=True)
Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofmultiple-edged or looped graphs
sage: D.is_planar(on_embedding={})Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofmultiple-edged or looped graphs>>> from sage.all import *>>> D = digraphs.Complete(Integer(3))>>> D.is_planar()True>>> D.is_planar(set_pos=True)
True>>> sorted(D.get_pos().items())[(0, [0, 1]), (1, [1, 1]), (2, [1, 0])]>>> D.is_planar(on_embedding={})Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofdigraphs with pairs of opposite arcs>>> D.is_planar(set_embedding=True)
Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofdigraphs with pairs of opposite arcs
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

235

Graph Theory, Release 10.4

(continued from previous page)>>> D.is_planar(kuratowski=True)(True, None)>>> D.allow_multiple_edges(True)>>> D.add_edges(D.edges(sort=False))>>> D.allow_loops(True)>>> D.add_edges((u, u) for u in D)>>> D.is_planar()True>>> D.is_planar(kuratowski=True)(True, None)>>> D.is_planar(set_pos=True)
True>>> D.is_planar(set_embedding=True)
Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofmultiple-edged or looped graphs>>> D.is_planar(on_embedding={})Traceback (most recent call last):...
NotImplementedError: cannot compute with embeddings ofmultiple-edged or looped graphs
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: bFalse
sage: k.vertices(sort=True)[0, 1, 2, 3, 4]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G = Graph(G, multiedges=True)>>> G.add_edge(Integer(0), Integer(1))>>> G.is_planar()False>>> b,k = G.is_planar(kuratowski=True)
>>> b
False
>>> k.vertices(sort=True)[0, 1, 2, 3, 4]

is_regular(k=None)
Check whether this graph is (𝑘-)regular.
INPUT:• k – integer (default: None); the degree of regularity to check for
EXAMPLES:
sage: G = graphs.HoffmanSingletonGraph()
sage: G.is_regular()(continues on next page)

236

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True
sage: G.is_regular(9)False>>> from sage.all import *>>> G = graphs.HoffmanSingletonGraph()>>> G.is_regular()
True>>> G.is_regular(Integer(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>>> from sage.all import *>>> next(G.degree_iterator())
7

The house graph is not regular:
sage: graphs.HouseGraph().is_regular()False>>> from sage.all import *>>> graphs.HouseGraph().is_regular()False

A graph without vertices is 𝑘-regular for every 𝑘:
sage: Graph().is_regular()True>>> from sage.all import *>>> 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 pathgraph 𝑃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 :1.1. Generic graphs (common to directed/undirected)

237

Graph Theory, Release 10.4

sage: graphs.PathGraph(4).is_self_complementary()Truesage: graphs.PathGraph(5).is_self_complementary()
False>>> from sage.all import *>>> graphs.PathGraph(Integer(4)).is_self_complementary()True>>> graphs.PathGraph(Integer(5)).is_self_complementary()
False

The only self-complementary directed path is 𝑃2 :sage: digraphs.Path(2).is_self_complementary()Truesage: digraphs.Path(3).is_self_complementary()
False>>> from sage.all import *>>> digraphs.Path(Integer(2)).is_self_complementary()True>>> digraphs.Path(Integer(3)).is_self_complementary()
False

Every Paley graph is self-complementary:sage: G = graphs.PaleyGraph(9)˓→needs sage.libs.pari
sage: G.is_self_complementary()
˓→needs sage.libs.pari
True

#␣
#␣

>>> from sage.all import *>>> G = graphs.PaleyGraph(Integer(9))˓→# needs sage.libs.pari>>> G.is_self_complementary()
˓→needs sage.libs.pari
True

␣
#␣

is_subgraph(other, induced=True, up_to_isomorphism=False)
Check whether self is a subgraph of other.
Warning: The arguments induced and up_to_isomorphism are set respectively to True andFalse by default.
INPUT:• other – a Sage (Di)Graph• induced – boolean (default: True); if set to True check whether the graph is an induced subgraphof other that is if the vertices of the graph are also vertices of other, and the edges of the graph areequal 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 arealso in other and all edges of the graph are also in other.

238

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• up_to_isomorphism – boolean (default: False); if set to True check whether other is a subgraph ignoring the labeling of vertices and edges. Otherwise, vertex and edge labellings must coincidein the copy or induced copy.
OUTPUT:boolean – True iff the graph is a (possibly induced) subgraph of other.
See also:
For more advanced search of subgraphs isomorphic to a given graph, you could consider the following methods:• subgraph_search() – find a subgraph isomorphic to other inside of the graph• subgraph_search_count() – count the number of such copies• subgraph_search_iterator() – iterator over all the copies of other contained in the graph
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: G = P.subgraph(range(6))
sage: G.is_subgraph(P)True
sage: H = graphs.CycleGraph(5)sage: G = graphs.PathGraph(5)sage: G.is_subgraph(H)
False
sage: G.is_subgraph(H, induced=False)
True
sage: H.is_subgraph(G, induced=False)
False>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> G = P.subgraph(range(Integer(6)))>>> G.is_subgraph(P)
True>>> H = graphs.CycleGraph(Integer(5))>>> G = graphs.PathGraph(Integer(5))>>> G.is_subgraph(H)
False>>> G.is_subgraph(H, induced=False)
True>>> H.is_subgraph(G, induced=False)
False

The 4x4 grid contains a path of length 15 and an induced path of length 11:
sage: p11 = graphs.PathGraph(11)sage: p15 = graphs.PathGraph(15)sage: g = graphs.Grid2dGraph(4, 4)
sage: p15.is_subgraph(g, induced=False, up_to_isomorphism=True)
˓→needs sage.modules
True
sage: p15.is_subgraph(g, induced=True, up_to_isomorphism=True)
˓→needs sage.modules#␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

239

Graph Theory, Release 10.4

(continued from previous page)

False
sage: p11.is_subgraph(g, induced=True, up_to_isomorphism=True)
˓→needs sage.modules
True>>> from sage.all import *>>> p11 = graphs.PathGraph(Integer(11))>>> p15 = graphs.PathGraph(Integer(15))>>> g = graphs.Grid2dGraph(Integer(4), Integer(4))>>> p15.is_subgraph(g, induced=False, up_to_isomorphism=True)
˓→needs sage.modules
True>>> p15.is_subgraph(g, induced=True, up_to_isomorphism=True)
˓→needs sage.modules
False>>> p11.is_subgraph(g, induced=True, up_to_isomorphism=True)
˓→needs sage.modules
True

#␣

#␣

#␣

#␣

is_transitively_reduced()
Check whether the digraph is transitively reduced.
A digraph is transitively reduced if it is equal to its transitive reduction. A graph is transitively reduced if it
is a forest.
EXAMPLES:
sage: d = DiGraph({0: [1], 1: [2], 2: [3]})sage: d.is_transitively_reduced()True
sage: 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>>> from sage.all import *>>> d = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)]})>>> d.is_transitively_reduced()True>>> d = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(2)]})>>> d.is_transitively_reduced()
False>>> d = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(2)], Integer(2): []})>>> d.is_transitively_reduced()
False

is_vertex_transitive(partition=None, verbosity=0, edge_labels=False, order=False,
return_group=True, orbits=False)
240

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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()
˓→needs sage.groupsTrue
sage: D = graphs.DodecahedralGraph()
sage: D.is_vertex_transitive()
˓→needs sage.groupsTrue
sage: R = graphs.RandomGNP(2000, .01)
˓→needs networkx
sage: R.is_vertex_transitive()
˓→needs networkx
False>>> from sage.all import *>>> G = Graph({Integer(0):[Integer(1)],Integer(1):[Integer(2)]})>>> G.is_vertex_transitive()
False>>> P = graphs.PetersenGraph()>>> P.is_vertex_transitive()
˓→needs sage.groups
True>>> D = graphs.DodecahedralGraph()>>> D.is_vertex_transitive()
˓→needs sage.groups
True>>> R = graphs.RandomGNP(Integer(2000), RealNumber( .01 ))˓→# needs networkx>>> R.is_vertex_transitive()
˓→needs networkx
False

#␣

#␣

#␣
#␣

#␣

#␣

␣
#␣

katz_centrality(alpha, u=None)
Return the Katz centrality of vertex 𝑢.
Katz centrality of a node is a measure of centrality in a graph network. Katz centrality computes the relative
influence of a node within a network. Connections made with distant neighbors are, however penalized by anattenuation factor 𝛼.
See the Wikipedia article Katz_centrality for more information.
INPUT:• alpha – a nonnegative real number, must be less than the reciprocal of the spectral radius of the graph(the maximum absolute eigenvalue of the adjacency matrix).
• u – the vertex whose Katz centrality needs to be measured (default: None)OUTPUT: a list containing the Katz centrality of each vertex if u=None otherwise Katz centrality of thevertex u.

1.1. Generic graphs (common to directed/undirected)

241Graph Theory, Release 10.4

EXAMPLES:
We compute the Katz centrality of a 4-cycle (note that by symmetry, all 4 vertices have the same centrality)
sage: G = graphs.CycleGraph(4)sage: G.katz_centrality(1/20)
˓→needs sage.modules sage.rings.number_field{0: 1/9, 1: 1/9, 2: 1/9, 3: 1/9}>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> G.katz_centrality(Integer(1)/Integer(20))˓→# needs sage.modules sage.rings.number_field{0: 1/9, 1: 1/9, 2: 1/9, 3: 1/9}

#␣␣Note that in the below example the nodes having indegree 0 also have the Katz centrality value as 0, as thesenodes are not influenced by other nodes.
sage: G = DiGraph({1: [10], 2:[10,11], 3:[10,11], 4:[], 5:[11, 4], 6:[11],....:7:[10,11], 8:[10,11], 9:[10], 10:[11, 5, 8], 11:[6]})sage: G.katz_centrality(.85) # rel tol 1e-14
˓→needs sage.modules sage.rings.number_field{1: 0.000000000000000,
2: 0.000000000000000,
3: 0.000000000000000,
4: 16.7319819819820,
5: 18.6846846846847,
6: 173.212076941807,
7: 0.000000000000000,
8: 18.6846846846847,
9: 0.000000000000000,
10: 20.9819819819820,
11: 202.778914049184}#␣>>> from sage.all import *>>> G = DiGraph({Integer(1): [Integer(10)], Integer(2):[Integer(10),
˓→Integer(11)], Integer(3):[Integer(10),Integer(11)], Integer(4):[],␣
˓→Integer(5):[Integer(11), Integer(4)], Integer(6):[Integer(11)],...
Integer(7):[Integer(10),Integer(11)],␣
˓→Integer(8):[Integer(10),Integer(11)], Integer(9):[Integer(10)],␣
˓→Integer(10):[Integer(11), Integer(5), Integer(8)], Integer(11):[Integer(6)]}˓→)>>> G.katz_centrality(RealNumber( .85 )) # rel tol 1e-14
␣˓→# needs sage.modules sage.rings.number_field{1: 0.000000000000000,
2: 0.000000000000000,
3: 0.000000000000000,
4: 16.7319819819820,
5: 18.6846846846847,
6: 173.212076941807,
7: 0.000000000000000,
8: 18.6846846846847,
9: 0.000000000000000,
10: 20.9819819819820,
11: 202.778914049184}

See also:

242

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• katz_matrix()• Wikipedia article Katz_centrality
katz_matrix(alpha, nonedgesonly=False, vertices=None)
Return the Katz matrix of the graph.
Katz centrality of a node is a measure of centrality in a graph network. Katz centrality computes the relative
influence of a node within a network. Connections made with distant neighbors are, however penalized by anattenuation factor 𝛼.
Adding the values in the Katz matrix of all columns in a particular row gives the Katz centrality measure of
the vertex represented by that particular row. Katz centrality measures influence by taking into account the
total number of walks between a pair of nodes.
See the Wikipedia article Katz_centrality for more information.
INPUT:• alpha – a nonnegative real number, must be less than the reciprocal of the spectral radius of the graph(the maximum absolute eigenvalue of the adjacency matrix)• nonedgesonly – boolean (default: True); if True, value for each edge present in the graph is set
to zero.
• vertices – list (default: None); the ordering of the vertices defining how they should appear in thematrix. By default, the ordering given by GenericGraph.vertices() is used.
OUTPUT: the Katz matrix of the graph with parameter alpha
EXAMPLES:
We find the Katz matrix of an undirected 4-cycle.
sage: G = graphs.CycleGraph(4)sage: G.katz_matrix(1/20)
˓→needs sage.modules sage.rings.number_field[1/198 5/99 1/198 5/99][ 5/99 1/198 5/99 1/198][1/198 5/99 1/198 5/99][ 5/99 1/198 5/99 1/198]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> G.katz_matrix(Integer(1)/Integer(20))˓→# needs sage.modules sage.rings.number_field[1/198 5/99 1/198 5/99][ 5/99 1/198 5/99 1/198][1/198 5/99 1/198 5/99][ 5/99 1/198 5/99 1/198]#␣␣

We find the Katz matrix of an undirected 4-cycle with all entries other than those which correspond to
non-edges zeroed out.
sage: G.katz_matrix(1/20, True)
˓→needs sage.modules sage.rings.number_field[0
0 1/1980][0
0
0 1/198][1/19800
0][0
1/198 00]1.1. Generic graphs (common to directed/undirected)

#␣

243

Graph Theory, Release 10.4>>> from sage.all import *>>> G.katz_matrix(Integer(1)/Integer(20), True)˓→# needs sage.modules sage.rings.number_field[0
0 1/1980][0
0
0 1/198][1/19800
0][0
1/198 00]␣This will give an error if alpha<=0 or alpha>=1/spectral_radius = 1/max (A.eigenvalues()).
We find the Katz matrix in a fan on 6 vertices.
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.katz_matrix(1/10)#␣˓→needs sage.modules sage.rings.number_field[
169/2256545/451225/188605/451225/188545/4512␣
˓→485/4512][
545/4512 7081/297792 4355/37224
229/9024595/37224 4073/297792
␣˓→109/9024][
25/188 4355/37224
172/4653
45/376125/4653
595/37224
␣
˓→ 5/376][
605/4512229/9024
45/376337/9024
45/376229/9024␣˓→121/9024][
25/188595/37224
125/4653
45/376
172/4653 4355/37224
␣
˓→ 5/376][
545/4512 4073/297792
595/37224
229/9024 4355/37224 7081/297792
␣˓→109/9024][
485/4512
109/9024
5/376
121/9024
5/376
109/9024␣˓→97/9024]>>> from sage.all import *>>> H = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(0),˓→Integer(3)),(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(0),˓→Integer(6)),(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(4)),(Integer(4),Integer(5))])>>> H.katz_matrix(Integer(1)/Integer(10))␣˓→# needs sage.modules sage.rings.number_field[
169/2256545/451225/188605/451225/188545/4512␣
˓→485/4512][
545/4512 7081/297792 4355/37224
229/9024595/37224 4073/297792
␣˓→109/9024][
25/188 4355/37224
172/4653
45/376125/4653
595/37224
␣
˓→ 5/376][
605/4512229/9024
45/376337/9024
45/376229/9024␣˓→121/9024][
25/188595/37224
125/4653
45/376
172/4653 4355/37224
␣
˓→ 5/376][
545/4512 4073/297792
595/37224
229/9024 4355/37224 7081/297792
␣˓→109/9024][
485/4512
109/9024
5/376
121/9024
5/376
109/9024␣˓→97/9024]

See also:• katz_centrality()• Wikipedia article Katz_centrality

244

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

kirchhoff_matrix(weighted=None, indegree=True, normalized=False, signless=False, **kwds)
Return the Kirchhoff matrix (a.k.a. the Laplacian) of the graph.
The Kirchhoff matrix is defined to be 𝐷 + 𝑀 if signless and 𝐷 − 𝑀 otherwise, 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 if signless and 𝐷−1/2 (𝐷 −𝑀 )𝐷−1/2 otherwise.
(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 – boolean (default: None);– If True, the weighted adjacency matrix is used for 𝑀 , and the diagonal matrix 𝐷 takes into accountthe 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 – boolean (default: True); this parameter is considered only for digraphs.
– 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
• normalized – boolean (default: False);– If True, the returned matrix is 𝐷−1/2 (𝐷 + 𝑀 )𝐷−1/2 for signless and 𝐷−1/2 (𝐷 − 𝑀 )𝐷−1/2
otherwise, 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 𝐷 + 𝑀 for signless and 𝐷 − 𝑀 otherwise is returned• signless – boolean (default: False);– If True, 𝐷 + 𝑀 is used in calculation of Kirchhoff matrix– Else, 𝐷 − 𝑀 is used in calculation of Kirchhoff matrix• vertices – list, None, or True (default: None);– when a list, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering ofvertices,– when None, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering
given by GenericGraph.vertices() with sort=True.
– when True, construct an endomorphism of a free module instead of a matrix, where the module’sbasis is indexed by the vertices.
If the vertices are not comparable, the keyword vertices must be used to specify an ordering, or a
TypeError exception will be raised.
Note that any additional keywords will be passed on to either the adjacency_matrix() orweighted_adjacency_matrix() method.
AUTHORS:• Tom Boothby• Jason Grout
1.1. Generic graphs (common to directed/undirected)

245Graph Theory, Release 10.4

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˓→needs sage.modules[ 8 -1 -3 -4][-1 3 -2 0][-3 -2 5 0][-4 0 0 4]
sage: M = G.kirchhoff_matrix(); M˓→needs sage.modules[ 3 -1 -1 -1][-1 2 -1 0][-1 -1 2 0][-1 0 0 1]
sage: M = G.laplacian_matrix(normalized=True); M˓→needs sage.modules sage.symbolic[
1 -1/6*sqrt(3)*sqrt(2) -1/6*sqrt(3)*sqrt(2)˓→3*sqrt(3)][-1/6*sqrt(3)*sqrt(2)
1
-1/2
˓→
0]
[-1/6*sqrt(3)*sqrt(2)
-1/2
1
˓→
0]
[
-1/3*sqrt(3)
0
0
˓→
1]
sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M˓→needs sage.modules[8 1 3 4][1 3 2 0][3 2 5 0][4 0 0 4]
sage: G = Graph({0: [], 1: [2]})sage: G.laplacian_matrix(normalized=True)
˓→needs sage.modules[ 0 0 0][ 0 1 -1]
[ 0 -1 1]
sage: G.laplacian_matrix(normalized=True, signless=True)
˓→needs sage.modules[0 0 0][0 1 1][0 1 1]

#␣

#␣

#␣
-1/
␣
␣
␣
#␣

#␣

#␣

>>> from sage.all import *>>> G = Graph(sparse=True)>>> G.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(1),␣
˓→Integer(2), Integer(2)), (Integer(0), Integer(2), Integer(3)), (Integer(0),␣
˓→Integer(3), Integer(4))])>>> M = G.kirchhoff_matrix(weighted=True); M#␣˓→needs sage.modules[ 8 -1 -3 -4][-1 3 -2 0][-3 -2 5 0][-4 0 0 4]>>> M = G.kirchhoff_matrix(); M#␣˓→needs sage.modules(continues on next page)

246

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[ 3 -1 -1 -1][-1 2 -1 0][-1 -1 2 0][-1 0 0 1]>>> M = G.laplacian_matrix(normalized=True); M˓→needs sage.modules sage.symbolic[
1 -1/6*sqrt(3)*sqrt(2) -1/6*sqrt(3)*sqrt(2)˓→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]
>>> M = G.kirchhoff_matrix(weighted=True, signless=True); M˓→needs sage.modules[8 1 3 4][1 3 2 0][3 2 5 0][4 0 0 4]>>> G = Graph({Integer(0): [], Integer(1): [Integer(2)]})>>> G.laplacian_matrix(normalized=True)
˓→needs sage.modules[ 0 0 0][ 0 1 -1]
[ 0 -1 1]>>> G.laplacian_matrix(normalized=True, signless=True)
˓→needs sage.modules[0 0 0][0 1 1][0 1 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()#␣˓→needs sage.modules[ 4 -3][-4 3]>>> from sage.all import *>>> G = DiGraph({Integer(1): {Integer(1): Integer(2), Integer(2): Integer(3)},
˓→ Integer(2): {Integer(1): Integer(4)}}, weighted=True, sparse=True)>>> G.laplacian_matrix()#␣˓→needs sage.modules[ 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)#␣˓→needs sage.modules[ 3 -3][-4 4]

1.1. Generic graphs (common to directed/undirected)

247

Graph Theory, Release 10.4>>> from sage.all import *>>> G = DiGraph({Integer(1): {Integer(1): Integer(2), Integer(2): Integer(3)},
˓→ Integer(2): {Integer(1): Integer(4)}}, weighted=True, sparse=True)>>> G.laplacian_matrix(indegree=False)#␣˓→needs sage.modules[ 3 -3][-4 4]

A different ordering of the vertices (see adjacency_matrix() and weighted_adjacency_matrix()):
sage: G = Graph(sparse=True)
sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)])sage: M = G.kirchhoff_matrix(vertices=[3, 2, 1, 0]); M˓→needs sage.modules[ 1 0 0 -1][ 0 2 -1 -1][ 0 -1 2 -1][-1 -1 -1 3]
sage: M = G.kirchhoff_matrix(weighted=True, vertices=[3, 2, 1, 0]); M˓→needs sage.modules[ 4 0 0 -4][ 0 5 -2 -3][ 0 -2 3 -1][-4 -3 -1 8]#␣#␣>>> from sage.all import *>>> G = Graph(sparse=True)>>> G.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(1),␣
˓→Integer(2), Integer(2)), (Integer(0), Integer(2), Integer(3)), (Integer(0),␣
˓→Integer(3), Integer(4))])>>> M = G.kirchhoff_matrix(vertices=[Integer(3), Integer(2), Integer(1),␣
˓→Integer(0)]); M# needs sage.modules[ 1 0 0 -1][ 0 2 -1 -1][ 0 -1 2 -1][-1 -1 -1 3]>>> M = G.kirchhoff_matrix(weighted=True, vertices=[Integer(3), Integer(2),␣
˓→Integer(1), Integer(0)]); M# needs sage.modules[ 4 0 0 -4][ 0 5 -2 -3][ 0 -2 3 -1][-4 -3 -1 8]

When parameter immutable=True is passed, the output matrix is immutable:
sage: G = Graph([(0, 1)])
sage: M = G.kirchhoff_matrix(vertices=[0, 1], immutable=True)
˓→needs sage.modules
sage: M.is_immutable()
˓→needs sage.modules
True

#␣
#␣

>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1))])>>> M = G.kirchhoff_matrix(vertices=[Integer(0), Integer(1)], immutable=True)␣
˓→# needs sage.modules(continues on next page)

248

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> M.is_immutable()
˓→needs sage.modules
True

#␣

Creating a module morphism:
sage: # needs sage.modules
sage: G = Graph(sparse=True, weighted=True)
sage: G.add_edges([( A , B , 1), ( B , C , 2), ( A , C , 3), ( A ,˓→4)])
sage: phi = G.laplacian_matrix(weighted=True, vertices=True); phi
Generic endomorphism ofFree module generated by { A , B , C , D } over Integer Ringsage: print(phi._unicode_art_matrix())
A B C DA⎛ 8 -1 -3 -4⎞
B⎜-1 3 -2 0⎟
C⎜-3 -2 5 0⎟
D⎝-4 0 0 4⎠>>> from sage.all import *>>> # needs sage.modules>>> G = Graph(sparse=True, weighted=True)>>> G.add_edges([( A , B , Integer(1)), ( B , C , Integer(2)), ( A ,˓→Integer(3)), ( A ,D , Integer(4))])>>> phi = G.laplacian_matrix(weighted=True, vertices=True); phi
Generic endomorphism ofFree module generated by { A , B , C , D } over Integer Ring>>> print(phi._unicode_art_matrix())
A B C DA⎛ 8 -1 -3 -4⎞
B⎜-1 3 -2 0⎟
C⎜-3 -2 5 0⎟
D⎝-4 0 0 4⎠

D ,␣

C ,␣

kronecker_product(other)
Return the tensor product of self and other.
The tensor product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of thevertices 𝑉 (𝐺) and 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff - (𝑢, 𝑤) is an edge of self, and - (𝑣, 𝑥) is an edgeof other.
The tensor product is also known as the categorical product and the Kronecker product (referring to the
Kronecker matrix product). See the Wikipedia article Kronecker_product.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)sage: C = graphs.CycleGraph(5)sage: T = C.tensor_product(Z); T
Graph on 10 vertices
sage: T.size()
10
sage: T.plot()# long time
˓→needs sage.plot
Graphics object consisting of 21 graphics primitives

1.1. Generic graphs (common to directed/undirected)

#␣

249

Graph Theory, Release 10.4>>> from sage.all import *>>> Z = graphs.CompleteGraph(Integer(2))>>> C = graphs.CycleGraph(Integer(5))>>> T = C.tensor_product(Z); T
Graph on 10 vertices>>> T.size()
10>>> T.plot()# long time
˓→needs sage.plot
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
˓→needs sage.plot
Graphics object consisting of 1101 graphics primitives>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> P = graphs.PetersenGraph()>>> T = D.tensor_product(P); T
Graph on 200 vertices>>> T.size()
900>>> T.plot()# long time
˓→needs sage.plot
Graphics object consisting of 1101 graphics primitives

#␣

#␣

#␣

laplacian_matrix(weighted=None, indegree=True, normalized=False, signless=False, **kwds)
Return the Kirchhoff matrix (a.k.a. the Laplacian) of the graph.
The Kirchhoff matrix is defined to be 𝐷 + 𝑀 if signless and 𝐷 − 𝑀 otherwise, 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 if signless and 𝐷−1/2 (𝐷 −𝑀 )𝐷−1/2 otherwise.
(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 – boolean (default: None);– If True, the weighted adjacency matrix is used for 𝑀 , and the diagonal matrix 𝐷 takes into accountthe 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 – boolean (default: True); this parameter is considered only for digraphs.
– 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

250

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

By default, indegree is set to True
• normalized – boolean (default: False);– If True, the returned matrix is 𝐷−1/2 (𝐷 + 𝑀 )𝐷−1/2 for signless and 𝐷−1/2 (𝐷 − 𝑀 )𝐷−1/2
otherwise, 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 𝐷 + 𝑀 for signless and 𝐷 − 𝑀 otherwise is returned• signless – boolean (default: False);– If True, 𝐷 + 𝑀 is used in calculation of Kirchhoff matrix– Else, 𝐷 − 𝑀 is used in calculation of Kirchhoff matrix• vertices – list, None, or True (default: None);– when a list, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering ofvertices,– when None, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering
given by GenericGraph.vertices() with sort=True.
– when True, construct an endomorphism of a free module instead of a matrix, where the module’sbasis is indexed by the vertices.
If the vertices are not comparable, the keyword vertices must be used to specify an ordering, or a
TypeError exception will be raised.
Note that any additional keywords will be passed on to either the adjacency_matrix() orweighted_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˓→needs sage.modules[ 8 -1 -3 -4][-1 3 -2 0][-3 -2 5 0][-4 0 0 4]
sage: M = G.kirchhoff_matrix(); M˓→needs sage.modules[ 3 -1 -1 -1][-1 2 -1 0][-1 -1 2 0][-1 0 0 1]
sage: M = G.laplacian_matrix(normalized=True); M˓→needs sage.modules sage.symbolic[
1 -1/6*sqrt(3)*sqrt(2) -1/6*sqrt(3)*sqrt(2)˓→3*sqrt(3)][-1/6*sqrt(3)*sqrt(2)
1
-1/2
˓→
0]
[-1/6*sqrt(3)*sqrt(2)
-1/2
1

#␣

#␣

#␣
-1/
␣
␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

251Graph Theory, Release 10.4

(continued from previous page)0][-1/3*sqrt(3)
0
0
˓→
1]
sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M˓→needs sage.modules[8 1 3 4][1 3 2 0][3 2 5 0][4 0 0 4]˓→

sage: G = Graph({0: [], 1: [2]})sage: G.laplacian_matrix(normalized=True)
˓→needs sage.modules[ 0 0 0][ 0 1 -1]
[ 0 -1 1]
sage: G.laplacian_matrix(normalized=True, signless=True)
˓→needs sage.modules[0 0 0][0 1 1][0 1 1]

␣
#␣

#␣

#␣

>>> from sage.all import *>>> G = Graph(sparse=True)>>> G.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(1),␣
˓→Integer(2), Integer(2)), (Integer(0), Integer(2), Integer(3)), (Integer(0),␣
˓→Integer(3), Integer(4))])>>> M = G.kirchhoff_matrix(weighted=True); M#␣˓→needs sage.modules[ 8 -1 -3 -4][-1 3 -2 0][-3 -2 5 0][-4 0 0 4]>>> M = G.kirchhoff_matrix(); M#␣˓→needs sage.modules[ 3 -1 -1 -1][-1 2 -1 0][-1 -1 2 0][-1 0 0 1]>>> M = G.laplacian_matrix(normalized=True); M#␣˓→needs sage.modules sage.symbolic[
1 -1/6*sqrt(3)*sqrt(2) -1/6*sqrt(3)*sqrt(2)-1/˓→3*sqrt(3)][-1/6*sqrt(3)*sqrt(2)
1
-1/2
␣
˓→
0]
[-1/6*sqrt(3)*sqrt(2)
-1/2
1
␣
˓→
0]
[
-1/3*sqrt(3)
0
0
␣
˓→
1]
>>> M = G.kirchhoff_matrix(weighted=True, signless=True); M#␣˓→needs sage.modules[8 1 3 4][1 3 2 0][3 2 5 0][4 0 0 4](continues on next page)

252

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G = Graph({Integer(0): [], Integer(1): [Integer(2)]})>>> G.laplacian_matrix(normalized=True)
˓→needs sage.modules[ 0 0 0][ 0 1 -1]
[ 0 -1 1]>>> G.laplacian_matrix(normalized=True, signless=True)
˓→needs sage.modules[0 0 0][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()#␣˓→needs sage.modules[ 4 -3][-4 3]>>> from sage.all import *>>> G = DiGraph({Integer(1): {Integer(1): Integer(2), Integer(2): Integer(3)},
˓→ Integer(2): {Integer(1): Integer(4)}}, weighted=True, sparse=True)>>> G.laplacian_matrix()#␣˓→needs sage.modules[ 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)#␣˓→needs sage.modules[ 3 -3][-4 4]>>> from sage.all import *>>> G = DiGraph({Integer(1): {Integer(1): Integer(2), Integer(2): Integer(3)},
˓→ Integer(2): {Integer(1): Integer(4)}}, weighted=True, sparse=True)>>> G.laplacian_matrix(indegree=False)#␣˓→needs sage.modules[ 3 -3][-4 4]

A different ordering of the vertices (see adjacency_matrix() and weighted_adjacency_matrix()):
sage: G = Graph(sparse=True)
sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)])sage: M = G.kirchhoff_matrix(vertices=[3, 2, 1, 0]); M˓→needs sage.modules[ 1 0 0 -1][ 0 2 -1 -1][ 0 -1 2 -1][-1 -1 -1 3]
sage: M = G.kirchhoff_matrix(weighted=True, vertices=[3, 2, 1, 0]); M˓→needs sage.modules#␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

253Graph Theory, Release 10.4

(continued from previous page)[ 4 0 0 -4][ 0 5 -2 -3][ 0 -2 3 -1][-4 -3 -1 8]>>> from sage.all import *>>> G = Graph(sparse=True)>>> G.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(1),␣
˓→Integer(2), Integer(2)), (Integer(0), Integer(2), Integer(3)), (Integer(0),␣
˓→Integer(3), Integer(4))])>>> M = G.kirchhoff_matrix(vertices=[Integer(3), Integer(2), Integer(1),␣
˓→Integer(0)]); M# needs sage.modules[ 1 0 0 -1][ 0 2 -1 -1][ 0 -1 2 -1][-1 -1 -1 3]>>> M = G.kirchhoff_matrix(weighted=True, vertices=[Integer(3), Integer(2),␣
˓→Integer(1), Integer(0)]); M# needs sage.modules[ 4 0 0 -4][ 0 5 -2 -3][ 0 -2 3 -1][-4 -3 -1 8]

When parameter immutable=True is passed, the output matrix is immutable:
sage: G = Graph([(0, 1)])
sage: M = G.kirchhoff_matrix(vertices=[0, 1], immutable=True)
˓→needs sage.modules
sage: M.is_immutable()
˓→needs sage.modules
True

#␣
#␣

>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1))])>>> M = G.kirchhoff_matrix(vertices=[Integer(0), Integer(1)], immutable=True)␣
˓→# needs sage.modules>>> M.is_immutable()#␣˓→needs sage.modules
True

Creating a module morphism:
sage: # needs sage.modules
sage: G = Graph(sparse=True, weighted=True)
sage: G.add_edges([( A , B , 1), ( B , C , 2), ( A , C , 3), ( A ,˓→4)])
sage: phi = G.laplacian_matrix(weighted=True, vertices=True); phi
Generic endomorphism ofFree module generated by { A , B , C , D } over Integer Ringsage: print(phi._unicode_art_matrix())
A B C DA⎛ 8 -1 -3 -4⎞
B⎜-1 3 -2 0⎟
C⎜-3 -2 5 0⎟
D⎝-4 0 0 4⎠

254

D ,␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.modules>>> G = Graph(sparse=True, weighted=True)>>> G.add_edges([( A , B , Integer(1)), ( B , C , Integer(2)), ( A ,˓→Integer(3)), ( A ,D , Integer(4))])>>> phi = G.laplacian_matrix(weighted=True, vertices=True); phi
Generic endomorphism ofFree module generated by { A , B , C , D } over Integer Ring>>> print(phi._unicode_art_matrix())
A B C DA⎛ 8 -1 -3 -4⎞
B⎜-1 3 -2 0⎟
C⎜-3 -2 5 0⎟
D⎝-4 0 0 4⎠

C ,␣latex_options()
Return an instance of GraphLatex for the graph.
Changes to this object will affect the LaTeX version of the graph. For a full explanation of how to use LaTeX
to render graphs, see the introduction to the graph_latex module.
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: opts = g.latex_options()
sage: opts
LaTeX options for Petersen graph: {}sage: opts.set_option( tkz_style , Classic )˓→needs sage.plot
sage: opts
˓→needs sage.plot
LaTeX options for Petersen graph: { tkz_style :>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> opts = g.latex_options()>>> opts
LaTeX options for Petersen graph: {}>>> opts.set_option( tkz_style , Classic )˓→needs sage.plot>>> opts
˓→needs sage.plot
LaTeX options for Petersen graph: { tkz_style :#␣#␣Classic }#␣#␣Classic }layout(layout=None, pos=None, dim=2, save_pos=False, **options)
Return a layout for the vertices of this graph.
INPUT:• layout – string (default:None); specifies a layout algorithm among "acyclic","acyclic_dummy", "circular", "ranked", "graphviz", "planar", "spring","forest" or "tree"• pos – dictionary (default: None); a dictionary of positions• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
• save_pos – boolean (default: False); whether to save the positions• **options – layout options (see below)
1.1. Generic graphs (common to directed/undirected)

255

Graph Theory, Release 10.4

If layout is set, the specified 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: D2 = g.layout(); D2 # random{( 0 , 0): [2.69..., 0.43...],( 0 , 1): [1.35..., 0.86...],( 1 , 0): [0.89..., -0.42...],( 1 , 1): [2.26..., -0.87...]}
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.get_pos(){( 0 , 0): [0.3..., 0],( 0 , 1): [0.3..., 1],( 1 , 0): [0.6..., 0],( 1 , 1): [0.6..., 1]}
sage: D3 = g.layout(dim=3); D3 # random{( 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...]}>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(1))>>> D2 = g.layout(); D2 # random{( 0 , 0): [2.69..., 0.43...],( 0 , 1): [1.35..., 0.86...],( 1 , 0): [0.89..., -0.42...],( 1 , 1): [2.26..., -0.87...]}>>> 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]}>>> g.get_pos(){( 0 , 0): [0.3..., 0],( 0 , 1): [0.3..., 1],( 1 , 0): [0.6..., 0],( 1 , 1): [0.6..., 1]}>>> D3 = g.layout(dim=Integer(3)); D3 # random{( 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...]}

256

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Some safety tests:
sage: sorted(D2.keys()) == sorted(D3.keys()) == sorted(g)Truesage: isinstance(D2, dict) and isinstance(D3, dict)True
sage: [c in RDF for c in D2[( 0 , 0)]]
[True, True]
sage: [c in RDF for c in D3[( 0 , 0)]]
[True, True, True]>>> from sage.all import *>>> sorted(D2.keys()) == sorted(D3.keys()) == sorted(g)True>>> isinstance(D2, dict) and isinstance(D3, dict)True>>> [c in RDF for c in D2[( 0 , Integer(0))]][True, True]>>> [c in RDF for c in D3[( 0 , Integer(0))]][True, True, True]

Here is the list of all the available layout options (**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 forest_roots : An iterable specifying which vertices to use as roots␣˓→for thelayout= forest
option. If no root is specified for a tree,␣˓→then one is chosen close to the center of the tree. Ignored unlesslayout=˓→ forest.
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 ,˓→ leftor 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␣˓→unlesslayout= tree.
>>> from sage.all import *>>> from sage.graphs.graph_plot import layout_options>>> for key, value in sorted(layout_options.items()):...
print("option {} : {}".format(key, value))(continues on next page)

1.1. Generic graphs (common to directed/undirected)

257

Graph Theory, Release 10.4

(continued from previous page)

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 forest_roots : An iterable specifying which vertices to use as roots␣˓→for thelayout= forest
option. If no root is specified for a tree,␣˓→then one is chosen close to the center of the tree. Ignored unlesslayout=˓→ forest.
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 ,˓→ leftor 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␣˓→unlesslayout= 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. Seelayout_graphviz() for installation instructions.
A subclass may implement another layout algorithm "blah", by implementing a method .layout_blah.
It may override the default layout by overriding layout_default(), and similarly override the predefinedlayouts.
Todo: use this feature for all the predefined graphs classes (like for the Petersen graph, …), rather thansystematically building the layout at construction time.
layout_circular(dim=2, center=(0, 0), radius=1, shift=0, angle=0, **options)
Return a circular layout for this graph
INPUT:• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
• center – tuple (default: (0, 0)); position of the center of the circle• radius – (default: 1); the radius of the circle

258

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• shift – (default: 0); rotation of the circle. A value of shift=1 will replace in the drawing the 𝑖-th
element of the list by the (𝑖 − 1)-th. Non-integer values are admissible, and a value of 𝛼 corresponds toa rotation of the circle by an angle of 𝛼2𝜋/𝑛 (where 𝑛 is the number of vertices set on the circle).
• angle – (default: 0); rotate the embedding of all vertices. For instance, when angle == 0, the firstvertex get position (center[0] + radius, center[1]). With a value of 𝜋/2, the first vertex
get position (center[0], center[1] + radius).
• **options – other parameters not used here
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")˓→needs sage.plot
Graphics object consisting of 22 graphics primitives#␣>>> from sage.all import *>>> G = graphs.CirculantGraph(Integer(7), [Integer(1), Integer(3)])>>> 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...)}>>> G.plot(layout="circular")˓→needs sage.plot
Graphics object consisting of 22 graphics primitives#␣layout_default(by_component=True, **options)
Return a spring layout for this graph.
INPUT:• by_components – boolean (default: True);• **options – options for method spring_layout_fast()
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:
sage: g = graphs.LadderGraph(3) #TODO!!!!
sage: g.layout_spring() # random{0: [1.0, -0.29...],
1: [1.64..., 0.30...],
2: [2.34..., 0.89...],
3: [1.49..., -0.83...],(continues on next page)

1.1. Generic graphs (common to directed/undirected)

259

Graph Theory, Release 10.4

(continued from previous page)

4: [2.14..., -0.30...],
5: [2.80..., 0.22...]}
sage: g = graphs.LadderGraph(7)sage: g.plot(layout="spring")
˓→needs sage.plot
Graphics object consisting of 34 graphics primitives>>> from sage.all import *>>> g = graphs.LadderGraph(Integer(3)) #TODO!!!!
>>> g.layout_spring() # random{0: [1.0, -0.29...],
1: [1.64..., 0.30...],
2: [2.34..., 0.89...],
3: [1.49..., -0.83...],
4: [2.14..., -0.30...],
5: [2.80..., 0.22...]}>>> g = graphs.LadderGraph(Integer(7))>>> g.plot(layout="spring")
˓→needs sage.plot
Graphics object consisting of 34 graphics primitives#␣#␣layout_extend_randomly(pos, dim=2)
Extend randomly a partial layout
INPUT:• pos – a dictionary mapping vertices to positions• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
OUTPUT: a dictionary mapping vertices to positions
The vertices not referenced in pos are assigned random positions within the box delimited by the othervertices.
EXAMPLES:
sage: H = digraphs.ButterflyGraph(1)sage: pos = {( 0 , 0): (0, 0), ( 1 , 1): (1, 1)}
sage: H.layout_extend_randomly(pos) # random{( 0 , 0): (0, 0),( 0 , 1): [0.0446..., 0.332...],( 1 , 0): [0.1114..., 0.514...],( 1 , 1): (1, 1)}
sage: xmin, xmax, ymin, ymax = H._layout_bounding_box(pos)sage: (xmin, ymin) == (0, 0) and (xmax, ymax) == (1, 1)
True>>> from sage.all import *>>> H = digraphs.ButterflyGraph(Integer(1))>>> pos = {( 0 , Integer(0)): (Integer(0), Integer(0)), ( 1 , Integer(1)):␣
˓→(Integer(1), Integer(1))}>>> H.layout_extend_randomly(pos) # random{( 0 , 0): (0, 0),( 0 , 1): [0.0446..., 0.332...],( 1 , 0): [0.1114..., 0.514...],( 1 , 1): (1, 1)}>>> xmin, xmax, ymin, ymax = H._layout_bounding_box(pos)(continues on next page)

260

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> (xmin, ymin) == (Integer(0), Integer(0)) and (xmax, ymax) == (Integer(1),␣
˓→Integer(1))
Truelayout_forest(tree_orientation='down', forest_roots=None, **options)
Return an ordered forest layout for this graph.
The function relies on layout_tree() to deal with each connected component.
INPUT:• forest_roots – an iterable of vertices (default: None); the root vertices of the trees in the forest; avertex is chosen close to the center of each component for which no root is specified in forest_roots
or if forest_roots is None
• tree_orientation – string (default: down ); the direction in which the tree is growing, can be
up , down , left or right• **options – other parameters ignored here
EXAMPLES:
sage: G = graphs.RandomTree(4) + graphs.RandomTree(5) + graphs.RandomTree(6)sage: p = G.layout_forest()
sage: G.plot(pos=p) # random#␣˓→needs sage.plot
Graphics object consisting of 28 graphics primitives
sage: P5 = graphs.PathGraph(5)sage: H = P5 + P5 + graphs.BalancedTree(2,2)˓→needs networkx
sage: p = H.layout_forest(forest_roots=[14,3])
˓→needs networkx
sage: H.plot(pos=p)˓→needs networkx sage.plot
Graphics object consisting of 32 graphics primitives>>> from sage.all import *>>> G = graphs.RandomTree(Integer(4)) + graphs.RandomTree(Integer(5)) +␣˓→graphs.RandomTree(Integer(6))>>> p = G.layout_forest()>>> G.plot(pos=p) # random
˓→needs sage.plot
Graphics object consisting of 28 graphics primitives>>> P5 = graphs.PathGraph(Integer(5))>>> H = P5 + P5 + graphs.BalancedTree(Integer(2),Integer(2))˓→# needs networkx>>> p = H.layout_forest(forest_roots=[Integer(14),Integer(3)])˓→# needs networkx>>> H.plot(pos=p)˓→needs networkx sage.plot
Graphics object consisting of 32 graphics primitives

#␣
#␣
#␣

#␣

␣
␣
#␣

layout_graphviz(dim=2, prog='dot', **options)
Call graphviz to compute a layout of the vertices of this graph.
INPUT:

1.1. Generic graphs (common to directed/undirected)

261

Graph Theory, Release 10.4

• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
• prog – one of “dot”, “neato”, “twopi”, “circo”, or “fdp”• **options – other parameters used by method graphviz_string()
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>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(2))>>> g.layout_graphviz() # optional - dot2tex graphviz{( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...],( ... , ...): [...,...]}>>> 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 analternative layout program:
sage: # optional - dot2tex graphviz
sage: g.plot(layout="graphviz", prog="dot")
Graphics object consisting of 29 graphics primitives
sage: g.plot(layout="graphviz", prog="neato")
Graphics object consisting of 29 graphics primitives
sage: g.plot(layout="graphviz", prog="twopi")
Graphics object consisting of 29 graphics primitives
sage: g.plot(layout="graphviz", prog="fdp")
Graphics object consisting of 29 graphics primitives
sage: g = graphs.BalancedTree(5,2)˓→needs networkx#␣(continues on next page)

262

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: g.plot(layout="graphviz", prog="circo")
˓→needs networkx
Graphics object consisting of 62 graphics primitives>>> from sage.all import *>>> # optional - dot2tex graphviz>>> g.plot(layout="graphviz", prog="dot")
Graphics object consisting of 29 graphics primitives>>> g.plot(layout="graphviz", prog="neato")
Graphics object consisting of 29 graphics primitives>>> g.plot(layout="graphviz", prog="twopi")
Graphics object consisting of 29 graphics primitives>>> g.plot(layout="graphviz", prog="fdp")
Graphics object consisting of 29 graphics primitives>>> g = graphs.BalancedTree(Integer(5),Integer(2))˓→# needs networkx>>> g.plot(layout="graphviz", prog="circo")
˓→needs networkx
Graphics object consisting of 62 graphics primitives

#␣

␣
#␣

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, etc. are in your path. The graphviz suitecan 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,
circular=False, **options)
Compute a planar layout of the graph using Schnyder’s algorithm.
If set_embedding is set, a new combinatorial embedding is computed for the layout. Otherwise: if
on_embedding is provided, then that combinatorial embedding is used for the layout. Otherwise: if a
combinatorial embedding is set to the instance field variable of the graph (e.g. using set_embedding()),
then that one is used, and if no combinatorial embedding is set, then one is computed.
If the graph is not planar, an error is raised.
INPUT:• set_embedding – boolean (default: False); whether to set the instance field variable that contains
a combinatorial embedding to the combinatorial embedding used for the planar layout (see get_embedding())• on_embedding – dictionary (default: None); provide a combinatorial embedding• external_face – a pair (𝑢, 𝑣) of vertices (default: None); the external face of the drawing is chosen
in such a way that 𝑢 and 𝑣 are consecutive vertices in the clockwise traversal of the external face, inparticular 𝑢𝑣 has to be an edge of the graph. If external_face == None, an arbitrary external
face is chosen.
• test – boolean (default: False); whether to perform sanity tests along the way
1.1. Generic graphs (common to directed/undirected)

263

Graph Theory, Release 10.4

• circular – ignored
EXAMPLES:
sage: g = graphs.PathGraph(10)sage: g.layout(layout= planar , save_pos=True, test=True){0: [0, 8],
1: [8, 1],
2: [1, 0],
3: [7, 1],
4: [1, 1],
5: [5, 3],
6: [2, 3],
7: [2, 4],
8: [1, 6],
9: [2, 5]}
sage: g = graphs.BalancedTree(3, 4)#␣˓→needs networkx
sage: pos = g.layout(layout= planar , save_pos=True, test=True)#␣˓→needs networkx
sage: pos[0]#␣˓→needs networkx[0, 119]sage: pos[120]#␣˓→needs networkx[21, 37]
sage: g = graphs.CycleGraph(7)sage: g.layout(layout= planar , save_pos=True, test=True){0: [0, 5], 1: [5, 1], 2: [1, 0], 3: [4, 1], 4: [1, 1], 5: [2, 2], 6: [1, 2]}
sage: g = graphs.CompleteGraph(5)sage: g.layout(layout= planar , save_pos=True, test=True, set_embedding=True)
Traceback (most recent call last):...
ValueError: Complete graph is not a planar graph>>> from sage.all import *>>> g = graphs.PathGraph(Integer(10))>>> g.layout(layout= planar , save_pos=True, test=True){0: [0, 8],
1: [8, 1],
2: [1, 0],
3: [7, 1],
4: [1, 1],
5: [5, 3],
6: [2, 3],
7: [2, 4],
8: [1, 6],
9: [2, 5]}>>> g = graphs.BalancedTree(Integer(3), Integer(4))˓→# needs networkx>>> pos = g.layout(layout= planar , save_pos=True, test=True)
˓→needs networkx>>> pos[Integer(0)]˓→# needs networkx[0, 119]>>> pos[Integer(120)]˓→# needs networkx[21, 37]

␣
#␣
␣

␣

(continues on next page)264

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> g = graphs.CycleGraph(Integer(7))>>> g.layout(layout= planar , save_pos=True, test=True){0: [0, 5], 1: [5, 1], 2: [1, 0], 3: [4, 1], 4: [1, 1], 5: [2, 2], 6: [1, 2]}>>> g = graphs.CompleteGraph(Integer(5))>>> g.layout(layout= planar , save_pos=True, test=True, set_embedding=True)
Traceback (most recent call last):...
ValueError: Complete graph is not a planar graph

Choose the external face of the drawing:
sage: g = graphs.CompleteGraph(4)sage: g.layout(layout= planar , external_face=(0,1)){0: [0, 2], 1: [2, 1], 2: [1, 0], 3: [1, 1]}
sage: g.layout(layout= planar , external_face=(3,1)){0: [2, 1], 1: [0, 2], 2: [1, 1], 3: [1, 0]}>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4))>>> g.layout(layout= planar , external_face=(Integer(0),Integer(1))){0: [0, 2], 1: [2, 1], 2: [1, 0], 3: [1, 1]}>>> g.layout(layout= planar , external_face=(Integer(3),Integer(1))){0: [2, 1], 1: [0, 2], 2: [1, 1], 3: [1, 0]}

Choose the embedding:sage: H = graphs.LadderGraph(4)sage: em = {0:[1,4], 4:[0,5], 1:[5,2,0], 5:[4,6,1],....:
2:[1,3,6], 6:[7,5,2], 3:[7,2], 7:[3,6]}
sage: p = H.layout_planar(on_embedding=em)
sage: p # random{2: [8.121320343559642, 1],
3: [2.1213203435596424, 6],
7: [3.1213203435596424, 0],
0: [5.121320343559642, 3],
1: [3.1213203435596424, 5],
4: [4.121320343559642, 3],
5: [4.121320343559642, 2],
6: [3.1213203435596424, 1],
9: [9.698670612749268, 1],
8: [8.698670612749268, 1],
10: [9.698670612749268, 0]}>>> from sage.all import *>>> H = graphs.LadderGraph(Integer(4))>>> em = {Integer(0):[Integer(1),Integer(4)], Integer(4):[Integer(0),˓→Integer(5)], Integer(1):[Integer(5),Integer(2),Integer(0)],␣
˓→Integer(5):[Integer(4),Integer(6),Integer(1)],...
Integer(2):[Integer(1),Integer(3),Integer(6)],␣
˓→Integer(6):[Integer(7),Integer(5),Integer(2)], Integer(3):[Integer(7),˓→Integer(2)], Integer(7):[Integer(3),Integer(6)]}>>> p = H.layout_planar(on_embedding=em)>>> p # random{2: [8.121320343559642, 1],
3: [2.1213203435596424, 6],
7: [3.1213203435596424, 0],(continues on next page)

1.1. Generic graphs (common to directed/undirected)

265Graph Theory, Release 10.4

(continued from previous page)

0: [5.121320343559642, 3],
1: [3.1213203435596424, 5],
4: [4.121320343559642, 3],
5: [4.121320343559642, 2],
6: [3.1213203435596424, 1],
9: [9.698670612749268, 1],
8: [8.698670612749268, 1],
10: [9.698670612749268, 0]}layout_ranked(heights=None, dim=2, spring=False, **options)
Return a ranked layout for this graph
INPUT:• heights – dictionary (default: None); a dictionary mapping heights to the list of vertices at this height• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
• spring – boolean (default: False);• **options – options for method spring_layout_fast()
OUTPUT: a dictionary mapping vertices to positions
Returns a layout computed by randomly arranging the vertices along the given heights
EXAMPLES:
sage: g = graphs.LadderGraph(3)sage: g.layout_ranked(heights={i: (i, i+3) for i in range(3)}) # random{0: [0.668..., 0],
1: [0.667..., 1],
2: [0.677..., 2],
3: [1.34..., 0],
4: [1.33..., 1],
5: [1.33..., 2]}
sage: g = graphs.LadderGraph(7)sage: g.plot(layout="ranked", heights={i: (i, i+7) for i in range(7)})˓→needs sage.plot
Graphics object consisting of 34 graphics primitives#␣>>> from sage.all import *>>> g = graphs.LadderGraph(Integer(3))>>> g.layout_ranked(heights={i: (i, i+Integer(3)) for i in range(Integer(3))}˓→)# random{0: [0.668..., 0],
1: [0.667..., 1],
2: [0.677..., 2],
3: [1.34..., 0],
4: [1.33..., 1],
5: [1.33..., 2]}>>> g = graphs.LadderGraph(Integer(7))>>> g.plot(layout="ranked", heights={i: (i, i+Integer(7)) for i in␣
˓→range(Integer(7))})# needs sage.plot
Graphics object consisting of 34 graphics primitives

layout_spring(by_component=True, **options)
Return a spring layout for this graph.
INPUT:
266

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• by_components – boolean (default: True);• **options – options for method spring_layout_fast()
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:
sage: g = graphs.LadderGraph(3) #TODO!!!!
sage: g.layout_spring() # random{0: [1.0, -0.29...],
1: [1.64..., 0.30...],
2: [2.34..., 0.89...],
3: [1.49..., -0.83...],
4: [2.14..., -0.30...],
5: [2.80..., 0.22...]}
sage: g = graphs.LadderGraph(7)sage: g.plot(layout="spring")
˓→needs sage.plot
Graphics object consisting of 34 graphics primitives>>> from sage.all import *>>> g = graphs.LadderGraph(Integer(3)) #TODO!!!!
>>> g.layout_spring() # random{0: [1.0, -0.29...],
1: [1.64..., 0.30...],
2: [2.34..., 0.89...],
3: [1.49..., -0.83...],
4: [2.14..., -0.30...],
5: [2.80..., 0.22...]}>>> g = graphs.LadderGraph(Integer(7))>>> g.plot(layout="spring")
˓→needs sage.plot
Graphics object consisting of 34 graphics primitives#␣#␣layout_tree(tree_orientation='down', tree_root=None, dim=2, **options)
Return an ordered tree layout for this graph.
The graph must be a tree (no non-oriented cycles). In case of doubt whether the graph is connected or not,prefer layout_forest().
INPUT:• tree_root – a vertex (default: None); the root vertex of the tree. By default (None) a vertex ischosen close to the center of the tree.
• tree_orientation – string (default: down ); the direction in which the tree is growing, can be
up , down , left or right• dim – integer (default: 2); the number of dimensions of the layout, 2 or 3
• **options – other parameters not used here
If the tree has been given a planar embedding (fixed circular order on the set of neighbors of every vertex)
using set_embedding, the algorithm will create a layout that respects this embedding.
OUTPUT: a dictionary mapping vertices to positions
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

267

Graph Theory, Release 10.4

sage: G = graphs.RandomTree(80)sage: G.plot(layout="tree", tree_orientation="right")
˓→needs sage.plot
Graphics object consisting of 160 graphics primitives#␣sage: T = graphs.RandomLobster(25, 0.3, 0.3)
˓→needs networkx
sage: T.show(layout= tree , tree_orientation= up )˓→needs networkx sage.plot#␣#␣

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)
˓→needs sage.plot#␣

sage: G = graphs.BalancedTree(2, 2)
˓→needs networkx
sage: G.layout_tree(tree_root=0)
˓→needs networkx{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)
˓→needs networkx
sage: G.plot(layout="tree", tree_root=0, tree_orientation="up")˓→needs networkx sage.plot
Graphics object consisting of 62 graphics primitives#␣#␣>>> from sage.all import *>>> G = graphs.RandomTree(Integer(80))>>> G.plot(layout="tree", tree_orientation="right")
˓→needs sage.plot
Graphics object consisting of 160 graphics primitives#␣#␣>>> T = graphs.RandomLobster(Integer(25), RealNumber( 0.3 ), RealNumber( 0.3
˓→ ))# needs networkx>>> T.show(layout= tree , tree_orientation= up )#␣˓→needs networkx sage.plot>>> G = graphs.HoffmanSingletonGraph()>>> T = Graph()>>> T.add_edges(G.min_spanning_tree(starting_vertex=Integer(0)))>>> T.show(layout= tree , tree_root=Integer(0))˓→# needs sage.plot>>> G = graphs.BalancedTree(Integer(2), Integer(2))˓→# needs networkx>>> G.layout_tree(tree_root=Integer(0))˓→# needs networkx{0: [1.5, 0],
1: [2.5, -1],␣␣␣(continues on next page)

268

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

2: [0.5, -1],
3: [3.0, -2],
4: [2.0, -2],
5: [1.0, -2],
6: [0.0, -2]}>>> G = graphs.BalancedTree(Integer(2), Integer(4))˓→# needs networkx>>> G.plot(layout="tree", tree_root=Integer(0), tree_orientation="up")˓→# needs networkx sage.plot
Graphics object consisting of 62 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)#␣
˓→needs sage.plot
Graphics object consisting of 18 graphics primitives>>> from sage.all import *>>> T = Graph([(Integer(0), Integer(1)), (Integer(0), Integer(6)),␣
˓→(Integer(0), Integer(3)), (Integer(1), Integer(2)), (Integer(1),␣
˓→Integer(5)), (Integer(3), Integer(4)), (Integer(3), Integer(7)),␣
˓→(Integer(3), Integer(8))])>>> T.set_embedding({Integer(0): [Integer(1), Integer(6), Integer(3)],␣
˓→Integer(1): [Integer(2), Integer(5), Integer(0)], Integer(2): [Integer(1)],␣
˓→Integer(3): [Integer(4), Integer(7), Integer(8), Integer(0)],...
Integer(4): [Integer(3)], Integer(5): [Integer(1)], Integer(6):␣
˓→[Integer(0)], Integer(7): [Integer(3)], Integer(8): [Integer(3)]})>>> 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]}>>> T.plot(layout="tree", tree_root=Integer(3))␣˓→# needs sage.plot
Graphics object consisting of 18 graphics primitives

lex_BFS(G, reverse=False, tree=False, initial_vertex=None, algorithm='fast')
1.1. Generic graphs (common to directed/undirected)

269

Graph Theory, Release 10.4

Perform a lexicographic breadth first search (LexBFS) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider• algorithm – string (default: "fast"); algorithm to use among:– "slow" – This algorithm maintains for each vertex left in the graph a code corresponding to thevertices already removed. The vertex of maximal code (according to the lexicographic order) isthen removed, and the codes are updated. See for instance [CK2008] for more details. The timecomplexity of this algorithm as described in [CK2008] is in 𝑂(𝑛 + 𝑚), where 𝑛 is the number ofvertices and 𝑚 is the number of edges, but our implementation is in 𝑂(𝑛2 ).
– "fast" – This algorithm uses the notion of slices to refine the position of the vertices in the ordering. The time complexity of this algorithm is in 𝑂(𝑛 + 𝑚), and our implementation follows thatcomplexity for SparseGraph. For DenseGraph, the complexity is 𝑂(𝑛2 ). See [HMPV2000]
and next section for more details.
ALGORITHM:
The "fast" algorithm is the 𝑂(𝑛 + 𝑚) time algorithm proposed in [HMPV2000], where 𝑛 is the numberof vertices and 𝑚 is the number of edges. It uses the notion of slices, i.e., subsets of consecutive vertices
in the ordering, and iteratively refines the slices by subdividing them into sub-slices to determine the exact
position of the vertices in the ordering.
Consider an ordering 𝜎 of the vertices. For a vertex 𝑣, we define 𝑁𝑖 (𝑣) = {𝑢|𝑢 ∈ 𝑁 (𝑣) and 𝜎(𝑢) < 𝑖},that is the subset of neighbors of 𝑣 appearing before the 𝑖-th vertex in the ordering 𝜎. Now, a slice of anordering 𝜎 is a set of consecutive vertices, 𝑆 = {𝑢|𝑖 ≤ 𝜎(𝑢) ≤ 𝑗}, such that for any 𝑢 ∈ 𝑆, we have
𝑁𝑖 (𝑢) = 𝑁𝑖 (𝜎 −1 (𝑖)) and for any 𝑣 such that 𝑗 < 𝜎(𝑣), 𝑁𝑖 (𝑣) ̸= 𝑁𝑖 (𝜎 −1 (𝑖)). The head of a slice is thefirst position of its vertices.
The algorithm starts with a single slice containing all vertices. Then, when the position of the 𝑖-th vertex 𝑣 isfixed, it explores the neighbors of 𝑣 that have not yet been ordered. Consider a slice 𝑆 such that 𝑁 (𝑥)∩𝑆 ̸= ∅.
The algorithm will rearrange the ordering of the vertices in 𝑆 so that the first vertices are the neighbors of 𝑣.
The sub-slice containing the neighbors of 𝑣 is assigned a new slice name, and the head of slice 𝑆 is set to theposition of the first vertex of 𝑆 ∖ 𝑁 (𝑣) in the ordering 𝜎.
Observe that each arc of the graph can induce the subdivision of a slice. Hence, the algorithm can use up to
𝑚 + 1 different slices.
See also:• Wikipedia article Lexicographic_breadth-first_search• lex_DFS() – perform a lexicographic depth first search (LexDFS) on the graph• lex_UP() – perform a lexicographic UP search (LexUP) on the graph• lex_DOWN() – perform a lexicographic DOWN search (LexDOWN) on the graph
EXAMPLES:
A Lex BFS is obviously an ordering of the vertices:

270

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = graphs.CompleteGraph(6)sage: len(g.lex_BFS()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_BFS()) == g.order()True

Lex BFS ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4,␣˓→5), (5, 6)])sage: g.lex_BFS()[1, 2, 3, 5, 4, 6]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)),␣
˓→(Integer(2), Integer(3)), (Integer(2), Integer(4)), (Integer(2),␣
˓→Integer(5)), (Integer(3), Integer(5)), (Integer(3), Integer(6)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))])>>> g.lex_BFS()[1, 2, 3, 5, 4, 6]

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_BFS(initial_vertex=2, algorithm="slow")[2, 3, 1]
sage: G.lex_BFS(initial_vertex=2, algorithm="fast")[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(1), Integer(3))])>>> G.lex_BFS(initial_vertex=Integer(2), algorithm="slow")[2, 3, 1]>>> G.lex_BFS(initial_vertex=Integer(2), algorithm="fast")[2, 3, 1]

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)]>>> from sage.all import *>>> g = graphs.PathGraph(Integer(3)).lexicographic_product(graphs.
˓→CompleteGraph(Integer(2)))>>> 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):1.1. Generic graphs (common to directed/undirected)

271

Graph Theory, Release 10.4

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>>> from sage.all import *>>> g = graphs.ClawGraph().lexicographic_product(graphs.
˓→CompleteGraph(Integer(2)))>>> v = g.lex_BFS()[-Integer(1)]>>> peo, tree = g.lex_BFS(initial_vertex = v, tree=True)>>> leaves = [v for v in tree if tree.in_degree(v) ==Integer(0)]>>> all(g.subgraph(g.neighbors(v)).is_clique() for v in leaves)
True

Different orderings for different traversals:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 , algorithm="fast")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]sage: G.lex_BFS(initial_vertex= 000 , algorithm="slow")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 , 111 ]sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 , 100 ]sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 , 101 ]>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 , algorithm="fast")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]>>> G.lex_BFS(initial_vertex= 000 , algorithm="slow")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 , 111 ]>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 , 100 ]>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 , 101 ]lex_DFS(G, reverse=False, tree=False, initial_vertex=None)
Perform a lexicographic depth first search (LexDFS) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider

272

Chapter 1. Graph objects and methods

Graph Theory, Release 10.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. Lex DFS differs from Lex BFS only in the way codes are updated after each iteration.
Time complexity is 𝑂(𝑛 + 𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number ofvertices and 𝑚 is the number of edges.
See [CK2008] for more details on the algorithm.
See also:• lex_BFS() – perform a lexicographic breadth first search (LexBFS) on the graph• lex_UP() – perform a lexicographic UP search (LexUP) on the graph• lex_DOWN() – perform a lexicographic DOWN search (LexDOWN) on the graph
EXAMPLES:
A Lex DFS is obviously an ordering of the vertices:sage: g = graphs.CompleteGraph(6)sage: len(g.lex_DFS()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_DFS()) == g.order()True

Lex DFS ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4,␣˓→5), (5, 6)])sage: g.lex_DFS()[1, 2, 3, 5, 6, 4]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)),␣
˓→(Integer(2), Integer(3)), (Integer(2), Integer(4)), (Integer(2),␣
˓→Integer(5)), (Integer(3), Integer(5)), (Integer(3), Integer(6)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))])>>> g.lex_DFS()[1, 2, 3, 5, 6, 4]

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_DFS(initial_vertex=2)[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(1), Integer(3))])>>> G.lex_DFS(initial_vertex=Integer(2))[2, 3, 1]

1.1. Generic graphs (common to directed/undirected)

273

Graph Theory, Release 10.4

Different orderings for different traversals:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 ,sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 ,sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

101 ,

111 ]

011 ,

111 ]

011 ,

100 ]

111 ,

101 ]

>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 , 101 ,>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 ,>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 ,>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 ,

111 ]
111 ]
100 ]
101 ]

lex_DOWN(G, reverse=False, tree=False, initial_vertex=None)
Perform a lexicographic DOWN search (LexDOWN) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider
ALGORITHM:
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. During the 𝑖-th iteration of the algorithm 𝑛 − 𝑖 is prepended to the codes of all neighbors of theselected vertex that are left in the graph.
Time complexity is 𝑂(𝑛 + 𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number ofvertices and 𝑚 is the number of edges.
See [Mil2017] for more details on the algorithm.
See also:• lex_BFS() – perform a lexicographic breadth first search (LexBFS) on the graph• lex_DFS() – perform a lexicographic depth first search (LexDFS) on the graph• lex_UP() – perform a lexicographic UP search (LexUP) on the graph
EXAMPLES:
A Lex DOWN is obviously an ordering of the vertices:
274

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = graphs.CompleteGraph(6)sage: len(g.lex_DOWN()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_DOWN()) == g.order()True

Lex DOWN ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4,␣˓→5), (5, 6)])sage: g.lex_DOWN()[1, 2, 3, 4, 6, 5]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)),␣
˓→(Integer(2), Integer(3)), (Integer(2), Integer(4)), (Integer(2),␣
˓→Integer(5)), (Integer(3), Integer(5)), (Integer(3), Integer(6)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))])>>> g.lex_DOWN()[1, 2, 3, 4, 6, 5]

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_DOWN(initial_vertex=2)[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(1), Integer(3))])>>> G.lex_DOWN(initial_vertex=Integer(2))[2, 3, 1]

Different orderings for different traversals:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 ,sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 ,sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

101 ,

111 ]

011 ,

111 ]

011 ,

100 ]

111 ,

101 ]

>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 , 101 ,>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 ,

111 ]
111 ]
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

275

Graph Theory, Release 10.4

(continued from previous page)>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

011 ,

100 ]

111 ,

101 ]

lex_UP(G, reverse=False, tree=False, initial_vertex=None)
Perform a lexicographic UP search (LexUP) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider
ALGORITHM:
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. During the 𝑖-th iteration of the algorithm 𝑖 is appended to the codes of all neighbors of theselected vertex that are left in the graph.
Time complexity is 𝑂(𝑛 + 𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number ofvertices and 𝑚 is the number of edges.
See [Mil2017] for more details on the algorithm.
See also:• lex_BFS() – perform a lexicographic breadth first search (LexBFS) on the graph• lex_DFS() – perform a lexicographic depth first search (LexDFS) on the graph• lex_DOWN() – perform a lexicographic DOWN search (LexDOWN) on the graph
EXAMPLES:
A Lex UP is obviously an ordering of the vertices:sage: g = graphs.CompleteGraph(6)sage: len(g.lex_UP()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_UP()) == g.order()True

Lex UP ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4,␣˓→5), (5, 6)])sage: g.lex_UP()[1, 2, 4, 5, 6, 3]

276

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)),␣
˓→(Integer(2), Integer(3)), (Integer(2), Integer(4)), (Integer(2),␣
˓→Integer(5)), (Integer(3), Integer(5)), (Integer(3), Integer(6)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))])>>> g.lex_UP()[1, 2, 4, 5, 6, 3]

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_UP(initial_vertex=2)[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(1), Integer(3))])>>> G.lex_UP(initial_vertex=Integer(2))[2, 3, 1]

Different orderings for different traversals:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 ,sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 ,sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

101 ,

111 ]

011 ,

111 ]

011 ,

100 ]

111 ,

101 ]

>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 , 101 ,>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 ,>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 ,>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 ,

111 ]
111 ]
100 ]
101 ]

lexicographic_product(other)
Return the lexicographic product of self and other.
The lexicographic product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) = 𝑉 (𝐺) × 𝑉 (𝐻), and((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff :• (𝑢, 𝑤) is an edge of 𝐺, or• 𝑢 = 𝑤 and (𝑣, 𝑥) is an edge of 𝐻.
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

277

Graph Theory, Release 10.4

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
˓→needs sage.plot
Graphics object consisting of 36 graphics primitives>>> from sage.all import *>>> Z = graphs.CompleteGraph(Integer(2))>>> C = graphs.CycleGraph(Integer(5))>>> L = C.lexicographic_product(Z); L
Graph on 10 vertices>>> L.plot()# long time
˓→needs sage.plot
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
˓→needs sage.plot
Graphics object consisting of 3501 graphics primitives>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> P = graphs.PetersenGraph()>>> L = D.lexicographic_product(P); L
Graph on 200 vertices>>> L.plot()# long time
˓→needs sage.plot
Graphics object consisting of 3501 graphics primitives

#␣

#␣

#␣

#␣

line_graph(g, labels=True)
Return the line graph of the (di)graph g.
INPUT:• labels – boolean (default: True); whether edge labels should be taken in consideration. If labels=True, the vertices of the line graph will be triples (u,v,label), and pairs of vertices otherwise.
The line graph of an undirected graph G is an undirected graph H such that the vertices of H are the edges of
G and two vertices e and f of H are adjacent if e and f share a common vertex in G. In other words, an edgein 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 isthe 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:
278

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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(sort=True)[(0, 1, None),(0, 2, None),(0, 3, None),(1, 2, None),(1, 3, None),(2, 3, None)]sage: h.am()˓→# needs sage.modules[0 1 1 1 1 0]
[1 0 1 1 0 1]
[1 1 0 0 1 1]
[1 1 0 0 1 1]
[1 0 1 1 0 1]
[0 1 1 1 1 0]
sage: h2 = g.line_graph(labels=False)
sage: h2.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: h2.am() == h.am()˓→# needs sage.modules
True
sage: g = DiGraph([[1..4], lambda i,j: i < j])sage: h = g.line_graph()
sage: h.vertices(sort=True)[(1, 2, None),(1, 3, None),(1, 4, None),(2, 3, None),(2, 4, None),(3, 4, None)]sage: h.edges(sort=True)[((1, 2, None), (2, 3, None), None),((1, 2, None), (2, 4, None), None),((1, 3, None), (3, 4, None), None),((2, 3, None), (3, 4, None), None)]␣␣>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4))>>> h = g.line_graph()>>> h.vertices(sort=True)[(0, 1, None),(0, 2, None),(0, 3, None),(1, 2, None),(1, 3, None),(2, 3, None)]>>> h.am()
˓→# needs sage.modules(continues on next page)

1.1. Generic graphs (common to directed/undirected)

279

Graph Theory, Release 10.4

(continued from previous page)[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]>>> h2 = g.line_graph(labels=False)>>> h2.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]>>> h2.am() == h.am()
˓→# needs sage.modules
True>>> g = DiGraph([(ellipsis_range(Integer(1),Ellipsis,Integer(4))), lambda i,
˓→j: i < j])>>> h = g.line_graph()>>> h.vertices(sort=True)[(1, 2, None),(1, 3, None),(1, 4, None),(2, 3, None),(2, 4, None),(3, 4, None)]>>> h.edges(sort=True)[((1, 2, None), (2, 3, None), None),((1, 2, None), (2, 4, None), None),((1, 3, None), (3, 4, None), None),((2, 3, None), (3, 4, None), None)]longest_cycle(induced, use_edge_labels=False, solver=False, verbose=None, integrality_tolerance=0)
Return the longest (induced) cycle of self.
This method uses an integer linear programming formulation based on subtour elimination constraints to findthe longest cycle. This cycle is elementary (or simple), and so without repeated vertices. When searching for
an induced cycle (i.e., a cycle without chord), it uses in addition cycle elimination constraints as proposed in[MMRS2022].
We assume that the longest cycle in graph has at least 3 vertices and at least 2 in a digraph. The longest
induced cycle as at least 4 vertices in both a graph and a digraph.
Note: Graphs and digraphs with loops or multiple edges are currently not accepted. It is certainly possible
to extend the method to accept them.
INPUT:• induced – boolean (default: False); whether to return the longest induced cycle or the longest cycle• use_edge_labels – boolean (default: False); whether to compute a cycle with maximum weight
where the weight of an edge is defined by its label (a label set to None or {} being considered as a weightof 1), or to compute a cycle with the largest possible number of edges (i.e., edge weights are set to 1)• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity; set to 0 by default, which means quiet

280

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values()
OUTPUT:
A subgraph of self corresponding to a (directed if self is directed) longest (induced) cycle.
use_edge_labels == True, a pair weight, cycle is returned.

If

EXAMPLES:
Longest (induced) cycle of a graph:
sage: G = graphs.Grid2dGraph(3, 4)
sage: G.longest_cycle(induced=False)
longest cycle from 2D Grid Graph for [3, 4]: Graph on 12 vertices
sage: G.longest_cycle(induced=True)
longest induced cycle from 2D Grid Graph for [3, 4]: Graph on 10 vertices>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(3), Integer(4))>>> G.longest_cycle(induced=False)
longest cycle from 2D Grid Graph for [3, 4]: Graph on 12 vertices>>> G.longest_cycle(induced=True)
longest induced cycle from 2D Grid Graph for [3, 4]: Graph on 10 vertices

Longest (induced) cycle in a digraph:
sage: D = digraphs.Circuit(8)sage: D.add_edge(0, 2)
sage: D.longest_cycle(induced=False)
longest cycle from Circuit: Digraph on 8 vertices
sage: D.longest_cycle(induced=True)
longest induced cycle from Circuit: Digraph on 7 vertices
sage: D.add_edge(1, 0)
sage: D.longest_cycle(induced=False)
longest cycle from Circuit: Digraph on 8 vertices
sage: D.longest_cycle(induced=True)
longest induced cycle from Circuit: Digraph on 7 vertices
sage: D.add_edge(2, 0)
sage: D.longest_cycle(induced=False)
longest cycle from Circuit: Digraph on 8 vertices
sage: D.longest_cycle(induced=True)
longest induced cycle from Circuit: Digraph on 0 vertices>>> from sage.all import *>>> D = digraphs.Circuit(Integer(8))>>> D.add_edge(Integer(0), Integer(2))>>> D.longest_cycle(induced=False)
longest cycle from Circuit: Digraph on 8 vertices>>> D.longest_cycle(induced=True)
longest induced cycle from Circuit: Digraph on 7 vertices>>> D.add_edge(Integer(1), Integer(0))>>> D.longest_cycle(induced=False)
longest cycle from Circuit: Digraph on 8 vertices>>> D.longest_cycle(induced=True)
longest induced cycle from Circuit: Digraph on 7 vertices>>> D.add_edge(Integer(2), Integer(0))>>> D.longest_cycle(induced=False)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

281

Graph Theory, Release 10.4

(continued from previous page)

longest cycle from Circuit: Digraph on 8 vertices>>> D.longest_cycle(induced=True)
longest induced cycle from Circuit: Digraph on 0 vertices

Longest (induced) cycle when considering edge weights:
sage: D = digraphs.Circuit(15)sage: for u, v in D.edges(labels=False):....:
D.set_edge_label(u, v, 1)
sage: D.add_edge(0, 10, 50)
sage: D.add_edge(11, 1, 1)
sage: D.add_edge(13, 0, 1)
sage: D.longest_cycle(induced=False, use_edge_labels=False)
longest cycle from Circuit: Digraph on 15 vertices
sage: D.longest_cycle(induced=False, use_edge_labels=True)(55, longest cycle from Circuit: Digraph on 6 vertices)sage: D.longest_cycle(induced=True, use_edge_labels=False)
longest induced cycle from Circuit: Digraph on 11 vertices
sage: D.longest_cycle(induced=True, use_edge_labels=True)(54, longest induced cycle from Circuit: Digraph on 5 vertices)>>> from sage.all import *>>> D = digraphs.Circuit(Integer(15))>>> for u, v in D.edges(labels=False):...
D.set_edge_label(u, v, Integer(1))>>> D.add_edge(Integer(0), Integer(10), Integer(50))>>> D.add_edge(Integer(11), Integer(1), Integer(1))>>> D.add_edge(Integer(13), Integer(0), Integer(1))>>> D.longest_cycle(induced=False, use_edge_labels=False)
longest cycle from Circuit: Digraph on 15 vertices>>> D.longest_cycle(induced=False, use_edge_labels=True)(55, longest cycle from Circuit: Digraph on 6 vertices)>>> D.longest_cycle(induced=True, use_edge_labels=False)
longest induced cycle from Circuit: Digraph on 11 vertices>>> D.longest_cycle(induced=True, use_edge_labels=True)(54, longest induced cycle from Circuit: Digraph on 5 vertices)longest_path(s, t=None, use_edge_labels=None, algorithm=False, solver='MILP', verbose=None,
integrality_tolerance=0)
Return a longest path of self.
INPUT:• s – a vertex (default: None); forces the source of the path (the method then returns the longest pathstarting at s). The argument is set to None by default, which means that no constraint is set upon thefirst vertex in the path.
This parameter can only be used when algorithm is "MILP".
• t – a vertex (default: None); forces the destination of the path (the method then returns the longest pathending at t). The argument is set to None by default, which means that no constraint is set upon the lastvertex in the path.
This parameter can only be used when algorithm is "MILP".
• use_edge_labels – boolean (default: False); whether to compute a path with maximum weight
where the weight of an edge is defined by its label (a label set to None or {} being considered as a weightof 1), or to compute a path with the longest possible number of edges (i.e., edge weights are set to 1)
282

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

This parameter can only be used when algorithm is "MILP".
• algorithm – string (default: "MILP"); the algorithm to use among "MILP", "backtrack" and"heuristic":– "MILP" returns an exact answer.
– "backtrack" is renamed "heuristic" (Issue #36574).
– "heuristic" is a randomized heuristic for finding a long path in an unweighted (di)graph. This
heuristic does not take into account parameters s, t and use_edge_labels. An error is raised
if these parameters are set.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
Note: The length of a path is assumed to be the number of its edges, or the sum of their labels (whenuse_edge_labels == True).
OUTPUT:
A subgraph of self corresponding to a (directed if self is directed) longest path. If use_edge_labels== True, a pair weight, path is returned.
ALGORITHM:
Mixed Integer Linear Programming (this problem is known to be NP-Hard).
EXAMPLES:Petersen’s graph being hypohamiltonian, it has a longest path of length 𝑛 − 2:sage: g = graphs.PetersenGraph()
sage: lp = g.longest_path()˓→needs sage.numerical.mip
sage: lp.order() >= g.order() - 2
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> lp = g.longest_path()˓→needs sage.numerical.mip>>> lp.order() >= g.order() - Integer(2)˓→# needs sage.numerical.mip
True

#␣
#␣

#␣
␣

The heuristic totally agrees:
sage: g = graphs.PetersenGraph()
sage: p = g.longest_path(algorithm="heuristic").edges(sort=True, labels=False)
sage: len(p)91.1. Generic graphs (common to directed/undirected)

283

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> p = g.longest_path(algorithm="heuristic").edges(sort=True, labels=False)>>> len(p)
9

0

5
1

4
6

9

7

8

2

3

Let us compute the longest path on a random graph with random weights, and ensure the resulting graph isindeed a path:sage: g = graphs.RandomGNP(15, 0.3)
sage: for u, v in g.edge_iterator(labels=False):....:
g.set_edge_label(u, v, random())
sage: lp = g.longest_path()˓→needs sage.numerical.mip
sage: (not lp.is_forest() or not max(lp.degree()) <= 2
˓→needs sage.numerical.mip....: or not lp.is_connected())
False>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(15), RealNumber( 0.3 ))>>> for u, v in g.edge_iterator(labels=False):...
g.set_edge_label(u, v, random())>>> lp = g.longest_path()

#␣
#␣

#␣
(continues on next page)284

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.numerical.mip>>> (not lp.is_forest() or not max(lp.degree()) <= Integer(2)˓→# needs sage.numerical.mip... or not lp.is_connected())
False
˓→

␣

loop_edges(labels=True)
Return a list of all loops in the (di)graph
INPUT:• labels – boolean (default: True); whether returned edges have labels ((u,v,l)) or not ((u,v))
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edges([(0, 0), (1, 1), (2, 2), (3, 3), (2, 3)])sage: G.loop_edges()[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]sage: G.loop_edges(labels=False)[(0, 0), (1, 1), (2, 2), (3, 3)]
sage: G.allows_loops()
True
sage: G.has_loops()
True
sage: G.allow_loops(False)
sage: G.has_loops()
False
sage: G.loop_edges()[]sage: G.edges(sort=True)[(2, 3, None)]sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()[(0, 0, None)]sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)[]
sage: G = graphs.PetersenGraph()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

285

Graph Theory, Release 10.4

(continued from previous page)

sage: G.loops()[]>>> from sage.all import *>>> G = Graph(loops=True); G
Looped graph on 0 vertices>>> G.has_loops()
False>>> G.allows_loops()
True>>> G.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> G.loop_edges()[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]>>> G.loop_edges(labels=False)[(0, 0), (1, 1), (2, 2), (3, 3)]>>> G.allows_loops()
True>>> G.has_loops()
True>>> G.allow_loops(False)>>> G.has_loops()
False>>> G.loop_edges()[]>>> G.edges(sort=True)[(2, 3, None)]>>> D = DiGraph(loops=True); D
Looped digraph on 0 vertices>>> D.has_loops()
False>>> D.allows_loops()
True>>> D.add_edge((Integer(0), Integer(0)))>>> D.has_loops()
True>>> D.loops()[(0, 0, None)]>>> D.allow_loops(False); D
Digraph on 1 vertex>>> D.has_loops()
False>>> D.edges(sort=True)[]>>> G = graphs.PetersenGraph()>>> 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)]

286

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> D = DiGraph(Integer(4), loops=True)>>> D.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> 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)]>>> from sage.all import *>>> G = Graph(Integer(4), loops=True, multiedges=True, sparse=True)>>> G.add_edges((i, i) for i in range(Integer(4)))>>> G.loop_edges()[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]>>> G.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1))])>>> 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]>>> from sage.all import *>>> G = Graph({Integer(0): [Integer(0)], Integer(1): [Integer(1), Integer(2),␣
˓→Integer(3)], Integer(2): [Integer(3)]}, loops=True)>>> G.loop_vertices()[0, 1]

loops(labels=True)
Return a list of all loops in the (di)graph
INPUT:• labels – boolean (default: True); whether returned edges have labels ((u,v,l)) or not ((u,v))
EXAMPLES:
sage: G = Graph(loops=True); G
Looped graph on 0 vertices
sage: G.has_loops()
False
sage: G.allows_loops()
True
sage: G.add_edges([(0, 0), (1, 1), (2, 2), (3, 3), (2, 3)])sage: G.loop_edges()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

287

Graph Theory, Release 10.4

(continued from previous page)[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]sage: G.loop_edges(labels=False)[(0, 0), (1, 1), (2, 2), (3, 3)]
sage: G.allows_loops()
True
sage: G.has_loops()
True
sage: G.allow_loops(False)
sage: G.has_loops()
False
sage: G.loop_edges()[]sage: G.edges(sort=True)[(2, 3, None)]sage: D = DiGraph(loops=True); D
Looped digraph on 0 vertices
sage: D.has_loops()
False
sage: D.allows_loops()
True
sage: D.add_edge((0, 0))
sage: D.has_loops()
True
sage: D.loops()[(0, 0, None)]sage: D.allow_loops(False); D
Digraph on 1 vertex
sage: D.has_loops()
False
sage: D.edges(sort=True)[]
sage: G = graphs.PetersenGraph()
sage: G.loops()[]>>> from sage.all import *>>> G = Graph(loops=True); G
Looped graph on 0 vertices>>> G.has_loops()
False>>> G.allows_loops()
True>>> G.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> G.loop_edges()[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)]>>> G.loop_edges(labels=False)[(0, 0), (1, 1), (2, 2), (3, 3)]>>> G.allows_loops()
True>>> G.has_loops()
True>>> G.allow_loops(False)(continues on next page)

288

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G.has_loops()
False>>> G.loop_edges()[]>>> G.edges(sort=True)[(2, 3, None)]>>> D = DiGraph(loops=True); D
Looped digraph on 0 vertices>>> D.has_loops()
False>>> D.allows_loops()
True>>> D.add_edge((Integer(0), Integer(0)))>>> D.has_loops()
True>>> D.loops()[(0, 0, None)]>>> D.allow_loops(False); D
Digraph on 1 vertex>>> D.has_loops()
False>>> D.edges(sort=True)[]>>> G = graphs.PetersenGraph()>>> 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)]>>> from sage.all import *>>> D = DiGraph(Integer(4), loops=True)>>> D.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> 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)]>>> from sage.all import *>>> G = Graph(Integer(4), loops=True, multiedges=True, sparse=True)>>> G.add_edges((i, i) for i in range(Integer(4)))>>> G.loop_edges()[(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None)](continues on next page)

1.1. Generic graphs (common to directed/undirected)

289

Graph Theory, Release 10.4

(continued from previous page)>>> G.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1))])>>> G.loop_edges(labels=False)[(0, 0), (0, 0), (1, 1), (1, 1), (2, 2), (3, 3)]

max_cut(value_only, use_edge_labels=True, vertices=False, solver=False, verbose=None,
integrality_tolerance=0)
Return a maximum edge cut of the graph.
For more information, see the Wikipedia article Maximum_cut.
INPUT:• value_only – boolean (default: False); whether to return only the size of the maximum edge cut,or to also return the list of edges of the maximum edge cut• use_edge_labels – boolean (default: False); whether to compute a weighted maximum cut where
the weight of an edge is defined by its label (if an edge has no label, 1 is assumed), or to compute a cutof maximum cardinality (i.e., edge weights are set to 1)• vertices – boolean (default: False); whether to return the two sets of vertices that are disconnectedby the cut. This implies value_only=False.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
Quite obviously, the max cut of a bipartite graph is the number of edges, and the two sets of vertices are thetwo sides:
sage: # needs sage.numerical.mip
sage: g = graphs.CompleteBipartiteGraph(5,6)
sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True)
sage: value == 5*6
True
sage: bsetA, bsetB = map(list, g.bipartite_sets())
sage: ((bsetA == setA and bsetB == setB)....: or (bsetA == setB and bsetB == setA))
True>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.CompleteBipartiteGraph(Integer(5),Integer(6))>>> [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True)>>> value == Integer(5)*Integer(6)True>>> bsetA, bsetB = map(list, g.bipartite_sets())>>> ((bsetA == setA and bsetB == setB)... or (bsetA == setB and bsetB == setA))
True

The max cut of a Petersen graph:

290

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: g.max_cut()˓→# needs sage.numerical.mip
12>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.max_cut()
˓→needs sage.numerical.mip
12#␣

maximum_leaf_number(G, solver=None, verbose=0, integrality_tolerance=0.001)
Return the maximum leaf number of the graph.
The maximum leaf number is the maximum possible number of leaves of a spanning tree of 𝐺. This isalso the cardinality of the complement of a minimum connected dominating set. See the Wikipedia article
Connected_dominating_set.
The MLN of a graph with less than 2 vertices is 0, while the MLN of a connected graph with 2 or 3 vertices
is 1 or 2 respectively.
INPUT:• G – a Graph• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
Empty graph:
sage: G = Graph()
sage: G.maximum_leaf_number()0>>> from sage.all import *>>> G = Graph()>>> G.maximum_leaf_number()0Petersen graph:
sage: G = graphs.PetersenGraph()
sage: G.maximum_leaf_number()6>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.maximum_leaf_number()6

1.1. Generic graphs (common to directed/undirected)

291

Graph Theory, Release 10.4

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 newvertex is created.
In the case of multigraphs, the multiplicity is preserved.
INPUT:• vertices – the list of vertices to be merged
Note: If u and v are distinct vertices in vertices, any edges between u and v will be lost.
EXAMPLES:
sage: g = graphs.CycleGraph(3)sage: g.merge_vertices([0, 1])
sage: g.edges(sort=True)[(0, 2, None)]sage: P = graphs.PetersenGraph()
sage: P.merge_vertices([5, 7])
sage: P.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 8, 9]>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(3))>>> g.merge_vertices([Integer(0), Integer(1)])>>> g.edges(sort=True)[(0, 2, None)]>>> P = graphs.PetersenGraph()>>> P.merge_vertices([Integer(5), Integer(7)])>>> P.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 8, 9]

When the first vertex in vertices is None, a new vertex is created:sage: g = graphs.CycleGraph(5)sage: g.vertices(sort=True)[0, 1, 2, 3, 4]
sage: g.merge_vertices([None, 1, 3])
sage: g.edges(sort=True, labels=False)[(0, 4), (0, 5), (2, 5), (4, 5)]>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.vertices(sort=True)[0, 1, 2, 3, 4]>>> g.merge_vertices([None, Integer(1), Integer(3)])>>> g.edges(sort=True, labels=False)[(0, 4), (0, 5), (2, 5), (4, 5)]With a Multigraph
292

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = graphs.CycleGraph(3)sage: g.allow_multiple_edges(True)
sage: g.merge_vertices([0, 1])
sage: g.edges(sort=True, labels=False)[(0, 2), (0, 2)]>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(3))>>> g.allow_multiple_edges(True)>>> g.merge_vertices([Integer(0), Integer(1)])>>> g.edges(sort=True, labels=False)[(0, 2), (0, 2)]

min_spanning_tree(weight_function=None, algorithm='Prim_Boost', starting_vertex=None, check=False,
by_weight=False, check_weight=True)
Return 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:• algorithm – string (default: "Prim_Boost"); the algorithm to use in computing a minimum spanning tree of G. The following algorithms are supported:– "Prim_Boost" – Prim’s algorithm (Boost implementation)– "Prim_fringe" – a variant of Prim’s algorithm that ignores the labels on the edges– "Prim_edge" – a variant of Prim’s algorithm– "Kruskal" – Kruskal’s algorithm– "Filter_Kruskal" – a variant of Kruskal’s algorithm [OSS2009]– "Kruskal_Boost" – Kruskal’s algorithm (Boost implementation)– "Boruvka" – Boruvka’s algorithm– NetworkX – uses NetworkX’s minimum spanning tree implementation• starting_vertex – a vertex (default: None); the vertex from which to begin the search for aminimum 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 thecurrent method. See the documentation of the corresponding functions for details on what sort of sanity
checks will be performed.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If Noneand by_weight is True, we use the edge label l , if l is not None, else 1 as a weight. The
weight_function can be used to transform the label into a weight (note that, if the weight returned
is not convertible to a float, an error is raised)• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• check_weight – boolean (default: True); whether to check that the weight_function outputs
a number for each edge.

1.1. Generic graphs (common to directed/undirected)

293Graph Theory, Release 10.4

OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:• sage.graphs.spanning_tree.kruskal()• sage.graphs.spanning_tree.filter_kruskal()• sage.graphs.spanning_tree.boruvka()• sage.graphs.base.boost_graph.min_spanning_tree()
EXAMPLES:
Kruskal’s algorithm:
sage: g = graphs.CompleteGraph(5)sage: len(g.min_spanning_tree())
4sage: weight = lambda e: 1 / ((e[0] + 1) * (e[1] + 1))
sage: E = g.min_spanning_tree(weight_function=weight)
sage: T = Graph(E)sage: set(g) == set(T) and T.order() == T.size() + 1 and T.is_tree()True
sage: sum(map(weight, E))
5/12
sage: E = g.min_spanning_tree(weight_function=weight,....:
algorithm= Kruskal_Boost )sage: Graph(E).is_tree(); sum(map(weight, E))
True
5/12
sage: g = graphs.PetersenGraph()
sage: g.allow_multiple_edges(True)
sage: g.add_edges(g.edge_iterator())
sage: T = Graph(g.min_spanning_tree())
sage: set(g) == set(T) and T.order() == T.size() + 1 and T.is_tree()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> len(g.min_spanning_tree())
4>>> weight = lambda e: Integer(1) / ((e[Integer(0)] + Integer(1)) *␣˓→(e[Integer(1)] + Integer(1)))>>> E = g.min_spanning_tree(weight_function=weight)>>> T = Graph(E)>>> set(g) == set(T) and T.order() == T.size() + Integer(1) and T.is_tree()True>>> sum(map(weight, E))
5/12>>> E = g.min_spanning_tree(weight_function=weight,...
algorithm= Kruskal_Boost )>>> Graph(E).is_tree(); sum(map(weight, E))
True
5/12
>>> g = graphs.PetersenGraph()>>> g.allow_multiple_edges(True)(continues on next page)294

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> g.add_edges(g.edge_iterator())>>> T = Graph(g.min_spanning_tree())>>> set(g) == set(T) and T.order() == T.size() + Integer(1) and T.is_tree()
True

Boruvka’s algorithm:
sage: sorted(g.min_spanning_tree(algorithm= Boruvka ))[(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None),(2, 3, None), (2, 7, None), (3, 8, None), (4, 9, None)]>>> from sage.all import *>>> sorted(g.min_spanning_tree(algorithm= Boruvka ))[(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None),(2, 3, None), (2, 7, None), (3, 8, None), (4, 9, None)]Prim’s algorithm:
sage: g = graphs.CompleteGraph(5)sage: for algo in [ Prim_edge , Prim_fringe , Prim_Boost ]:....:E = g.min_spanning_tree(algorithm=algo, weight_function=weight)....:
T = Graph(E)....:print(set(g) == set(T) and T.order() == T.size() + 1 and T.is_
˓→tree())
True
True
True
>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> for algo in [ Prim_edge , Prim_fringe , Prim_Boost ]:...
E = g.min_spanning_tree(algorithm=algo, weight_function=weight)...
T = Graph(E)...
print(set(g) == set(T) and T.order() == T.size() + Integer(1) and T.
˓→is_tree())
True
True
True

NetworkX algorithm:
sage: sorted(g.min_spanning_tree(algorithm= NetworkX ))˓→needs networkx[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None)]>>> from sage.all import *>>> sorted(g.min_spanning_tree(algorithm= NetworkX ))˓→needs networkx[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None)]#␣#␣More complicated weights:
sage: G = Graph([(0, 1, { name :....:(0, 2, { name :....:(1, 2, { name :

a ,
b ,
b ,

weight : 1}),weight : 3}),weight : 1})])(continues on next page)

1.1. Generic graphs (common to directed/undirected)

295

Graph Theory, Release 10.4

(continued from previous page)

sage: sorted(G.min_spanning_tree(algorithm= Boruvka ,....:weight_function=lambda e: e[2][ weight ]))[(0, 1, { name : a , weight : 1}), (1, 2, { name : b , weight : 1})]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1), { name : a , weight : Integer(1)}),...
(Integer(0), Integer(2), { name : b , weight : Integer(3)}),...
(Integer(1), Integer(2), { name : b , weight : Integer(1)})])>>> sorted(G.min_spanning_tree(algorithm= Boruvka ,...
weight_function=lambda e: e[Integer(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: sorted(g.min_spanning_tree(algorithm= Boruvka ))[(1, 2, 1), (1, 3, 2)]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2), Integer(1)), (Integer(1), Integer(3),␣
˓→Integer(2)), (Integer(2), Integer(3), Integer(1))])>>> sorted(g.min_spanning_tree(algorithm= Boruvka ))[(1, 2, 1), (1, 3, 2)]

In order to use weights, we need either to set variable weighted to True, or to specify a weight function
or set by_weight to True:
sage: g.weighted(True)
sage: Graph(g.min_spanning_tree()).edges(sort=True)[(1, 2, 1), (2, 3, 1)]
sage: g.weighted(False)
sage: Graph(g.min_spanning_tree()).edges(sort=True)[(1, 2, 1), (1, 3, 2)]
sage: Graph(g.min_spanning_tree(by_weight=True)).edges(sort=True)[(1, 2, 1), (2, 3, 1)]
sage: Graph(g.min_spanning_tree(weight_function=lambda e: e[2])).
˓→edges(sort=True)[(1, 2, 1), (2, 3, 1)]>>> from sage.all import *>>> g.weighted(True)>>> Graph(g.min_spanning_tree()).edges(sort=True)[(1, 2, 1), (2, 3, 1)]>>> g.weighted(False)>>> Graph(g.min_spanning_tree()).edges(sort=True)[(1, 2, 1), (1, 3, 2)]>>> Graph(g.min_spanning_tree(by_weight=True)).edges(sort=True)[(1, 2, 1), (2, 3, 1)]>>> Graph(g.min_spanning_tree(weight_function=lambda e: e[Integer(2)])).
˓→edges(sort=True)[(1, 2, 1), (2, 3, 1)]

Note that the order of the vertices on each edge is not guaranteed and may differ from an algorithm to theother:

296

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g.weighted(True)
sage: sorted(g.min_spanning_tree())[(2, 1, 1), (3, 2, 1)]
sage: sorted(g.min_spanning_tree(algorithm= Boruvka ))[(1, 2, 1), (2, 3, 1)]
sage: Graph(g.min_spanning_tree()).edges(sort=True)[(1, 2, 1), (2, 3, 1)]>>> from sage.all import *>>> g.weighted(True)>>> sorted(g.min_spanning_tree())[(2, 1, 1), (3, 2, 1)]>>> sorted(g.min_spanning_tree(algorithm= Boruvka ))[(1, 2, 1), (2, 3, 1)]>>> Graph(g.min_spanning_tree()).edges(sort=True)[(1, 2, 1), (2, 3, 1)]

minimum_cycle_basis(algorithm=None, weight_function=None, by_weight=False, check_weight=True)
Return a minimum weight cycle basis of the graph.
A cycle basis is a list of cycles (list of vertices forming a cycle) of self. Note that the vertices are notnecessarily returned in the order in which they appear in the cycle.
A minimum weight cycle basis is a cycle basis that minimizes the sum of the weights (length for unweighted
graphs) of its cycles.
Not implemented for directed graphs and multigraphs.
INPUT:• algorithm – string (default: None); algorithm to use:
– If algorithm = "NetworkX", use networkx implementation– If algorithm = None, use Sage Cython implementation• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• check_weight – boolean (default: True); whether to check that the weight_function outputs
a number for each edge.
EXAMPLES:
sage: g = Graph([(1, 2, 3), (2, 3, 5), (3, 4, 8), (4, 1, 13),....:
(1, 3, 250), (5, 6, 9), (6, 7, 17), (7, 5, 20)])
sage: sorted(g.minimum_cycle_basis(by_weight=True))[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]
sage: sorted(g.minimum_cycle_basis(by_weight=False))[[1, 2, 3], [1, 3, 4], [5, 6, 7]]
sage: sorted(g.minimum_cycle_basis(by_weight=True, algorithm= NetworkX ))˓→needs networkx, random (changes in networkx 3.2)[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]
sage: g.minimum_cycle_basis(by_weight=False, algorithm= NetworkX )˓→needs networkx, random (changes in networkx 3.2)[[1, 2, 3], [1, 3, 4], [5, 6, 7]]

1.1. Generic graphs (common to directed/undirected)

#␣

#␣

297

Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2), Integer(3)), (Integer(2), Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(4), Integer(8)), (Integer(4), Integer(1),␣
˓→Integer(13)),...
(Integer(1), Integer(3), Integer(250)), (Integer(5),␣
˓→Integer(6), Integer(9)), (Integer(6), Integer(7), Integer(17)), (Integer(7),˓→ Integer(5), Integer(20))])>>> sorted(g.minimum_cycle_basis(by_weight=True))[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]>>> sorted(g.minimum_cycle_basis(by_weight=False))[[1, 2, 3], [1, 3, 4], [5, 6, 7]]>>> sorted(g.minimum_cycle_basis(by_weight=True, algorithm= NetworkX ))#␣˓→needs networkx, random (changes in networkx 3.2)[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]>>> g.minimum_cycle_basis(by_weight=False, algorithm= NetworkX )#␣˓→needs networkx, random (changes in networkx 3.2)[[1, 2, 3], [1, 3, 4], [5, 6, 7]]
sage: g = Graph([(1, 2), (2, 3), (3, 4), (4, 5), (5, 1), (5, 3)])sage: sorted(g.minimum_cycle_basis(by_weight=False))[[1, 2, 3, 5], [3, 4, 5]]
sage: sorted(g.minimum_cycle_basis(by_weight=False, algorithm= NetworkX ))˓→needs networkx, random (changes in networkx 3.2)[[1, 2, 3, 5], [3, 4, 5]]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(3), Integer(4)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(1)), (Integer(5), Integer(3))])>>> sorted(g.minimum_cycle_basis(by_weight=False))[[1, 2, 3, 5], [3, 4, 5]]>>> sorted(g.minimum_cycle_basis(by_weight=False, algorithm= NetworkX ))˓→needs networkx, random (changes in networkx 3.2)[[1, 2, 3, 5], [3, 4, 5]]#␣#␣

See also:• cycle_basis()• Wikipedia article Cycle_basis
multicommodity_flow(terminals, integer, use_edge_labels=True, vertex_bound=False, solver=False,verbose=None, integrality_tolerance=0)
Solve a multicommodity flow problem.
In the multicommodity flow problem, we are given a set of pairs (𝑠𝑖 , 𝑡𝑖 ), called terminals meaning that 𝑠𝑖 iswilling 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, an intensity of 1 is assumed.
• integer boolean (default: True); whether to require an integer multicommodity flow
298

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• use_edge_labels – boolean (default: False); whether to compute a multicommodity flow where
each edge has a capacity defined by its label (if an edge has no label, capacity 1 is assumed), or to use
default edge capacity of 1
• vertex_bound – boolean (default: False); 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 offlow even though vertex_bound is set to True, as this parameter is meant to represent topologicalproperties.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
Only useful when parameter ìnteger is True.
ALGORITHM:(Mixed Integer) Linear Program, depending on the value of integer.
EXAMPLES:
An easy way to obtain a satisfiable multicommodity flow 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()]
˓→needs networkx
sage: h = g.multicommodity_flow(matching)
˓→needs networkx
sage: len(h)˓→needs networkx
5>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> matching = [(u,v) for u,v,_ in g.matching()]
˓→needs networkx>>> h = g.multicommodity_flow(matching)
˓→needs networkx>>> len(h)˓→needs networkx
5

#␣
#␣
#␣

#␣
#␣
#␣

We could also have considered g as symmetric and computed the multicommodity flow in this version instead.
In this case, however edges can be used in both directions at the same time:
sage: h = DiGraph(g).multicommodity_flow(matching)
˓→needs networkx
sage: len(h)˓→needs networkx
5>>> from sage.all import *>>> h = DiGraph(g).multicommodity_flow(matching)
˓→needs networkx

#␣
#␣

#␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

299

Graph Theory, Release 10.4

(continued from previous page)>>> len(h)˓→needs networkx
5#␣An exception is raised when the problem has no solution
sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching])
˓→needs networkx
Traceback (most recent call last):...
EmptySetError: the multicommodity flow problem has no solution#␣>>> from sage.all import *>>> h = g.multicommodity_flow([(u,v,Integer(3)) for u,v in matching])˓→# needs networkx
Traceback (most recent call last):...
EmptySetError: the multicommodity flow problem has no solution␣multiple_edges(to_undirected=False, labels=True, sort=False, key=None)
Return any multiple edges in the (di)graph.
INPUT:• to_undirected – boolean (default: False)• labels – boolean (default: True); whether to include labels• sort – boolean (default: False); whether to sort the result• key – a function (default: None); a function that takes an edge as its one argument and returns a valuethat can be used for comparisons in the sorting algorithm (we must have sort=True)
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(sort=True)[(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()(continues on next page)

300

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)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(sort=True)[(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 )]>>> from sage.all import *>>> G = Graph(multiedges=True, sparse=True); G
Multi-graph on 0 vertices>>> G.has_multiple_edges()
False>>> G.allows_multiple_edges()
True>>> G.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> G.has_multiple_edges()
True>>> G.multiple_edges(sort=True)[(0, 1, None), (0, 1, None), (0, 1, None)]>>> G.allow_multiple_edges(False); G
Graph on 2 vertices>>> G.has_multiple_edges()
False>>> G.edges(sort=True)[(0, 1, None)]>>> D = DiGraph(multiedges=True, sparse=True); D
Multi-digraph on 0 vertices>>> D.has_multiple_edges()
False>>> D.allows_multiple_edges()
True>>> D.add_edges([(Integer(0), Integer(1))] * Integer(3))>>> D.has_multiple_edges()
True>>> D.multiple_edges(sort=True)[(0, 1, None), (0, 1, None), (0, 1, None)]>>> D.allow_multiple_edges(False); D
Digraph on 2 vertices>>> D.has_multiple_edges()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

301Graph Theory, Release 10.4

(continued from previous page)

False>>> D.edges(sort=True)[(0, 1, None)]>>> G = DiGraph({Integer(1): {Integer(2): h }, Integer(2): {Integer(1):˓→, sparse=True)>>> G.has_multiple_edges()
False>>> G.has_multiple_edges(to_undirected=True)
True>>> G.multiple_edges()[]>>> G.multiple_edges(to_undirected=True, sort=True)[(1, 2, h ), (2, 1, g )]g }}Using the key argument to order multiple edges of incomparable types (see Issue #35903):
sage: G = Graph([( A , B , 3), (1, 2, 1), ( A , B , 4), (1, 2, 2)],␣
˓→multiedges=True)
sage: G.multiple_edges(sort=True)
Traceback (most recent call last):...
TypeError: unsupported operand parent(s) for <: Integer Ring and <class˓→ str >sage: G.multiple_edges(labels=False, sort=True, key=str)[( A , B ), ( A , B ), (1, 2), (1, 2)]
sage: G.multiple_edges(sort=True, key=str)[( A , B , 3), ( A , B , 4), (1, 2, 1), (1, 2, 2)]
sage: G.multiple_edges(labels=True, sort=True, key=lambda e:e[2])[(1, 2, 1), (1, 2, 2), ( A , B , 3), ( A , B , 4)]
sage: G.multiple_edges(labels=False, sort=True, key=lambda e:e[2])Traceback (most recent call last):...
IndexError: tuple index out of range>>> from sage.all import *>>> G = Graph([( A , B , Integer(3)), (Integer(1), Integer(2), Integer(1)), (˓→ A ,
B , Integer(4)), (Integer(1), Integer(2), Integer(2))],␣
˓→multiedges=True)>>> G.multiple_edges(sort=True)
Traceback (most recent call last):...
TypeError: unsupported operand parent(s) for <: Integer Ring and <class˓→ str >>>> G.multiple_edges(labels=False, sort=True, key=str)[( A , B ), ( A , B ), (1, 2), (1, 2)]>>> G.multiple_edges(sort=True, key=str)[( A , B , 3), ( A , B , 4), (1, 2, 1), (1, 2, 2)]>>> G.multiple_edges(labels=True, sort=True, key=lambda e:e[Integer(2)])[(1, 2, 1), (1, 2, 2), ( A , B , 3), ( A , B , 4)]>>> G.multiple_edges(labels=False, sort=True, key=lambda e:e[Integer(2)])
Traceback (most recent call last):...
IndexError: tuple index out of range

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

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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 𝑢, 𝑣 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 (default: False); whether to return only the size of the minimum multiway
cut, or to return the list of edges of the multiway cut• use_edge_labels – boolean (default: False); whether to compute a weighted minimum multiway
cut where the weight of an edge is defined by its label (if an edge has no label, 1 is assumed), or to computea cut of minimum cardinality (i.e., edge weights are set to 1)• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
Of course, a multiway cut between two vertices correspond to a minimum edge cut:sage: g = graphs.PetersenGraph()
sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only=True)
˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.edge_cut(Integer(0),Integer(3)) == g.multiway_cut([Integer(0),˓→Integer(3)], value_only=True)# needs sage.numerical.mip
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
˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> g.multiway_cut([Integer(0),Integer(3),Integer(9)], value_only=True) ==␣
˓→Integer(2)*Integer(3)# needs sage.numerical.mip
True

In this case, though, the vertices are an independent set. If we pick instead vertices 0, 9, and 7, we can save4 edges in the multiway cut:sage: g.multiway_cut([0,7,9], value_only=True) == 2*3 - 1
˓→needs sage.numerical.mip
True

1.1. Generic graphs (common to directed/undirected)

#␣

303

Graph Theory, Release 10.4>>> from sage.all import *>>> g.multiway_cut([Integer(0),Integer(7),Integer(9)], value_only=True) ==␣
˓→Integer(2)*Integer(3) - Integer(1)# needs sage.numerical.
˓→mip
True

This example, though, does not work in the directed case anymore, as it is not possible in Petersen’s graph tomutualise edges:
sage: g = DiGraph(g)sage: g.multiway_cut([0,7,9], value_only=True) == 3*3
˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> g = DiGraph(g)>>> g.multiway_cut([Integer(0),Integer(7),Integer(9)], value_only=True) ==␣
˓→Integer(3)*Integer(3)# needs sage.numerical.mip
True

Of course, a multiway cut between the whole vertex set contains all the edges of the graph:
sage: C = g.multiway_cut(g.vertices(sort=False))
˓→needs sage.numerical.mip
sage: set(C) == set(g.edges(sort=False))
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> C = g.multiway_cut(g.vertices(sort=False))
˓→needs sage.numerical.mip>>> set(C) == set(g.edges(sort=False))
˓→needs sage.numerical.mip
True

#␣
#␣

#␣
#␣

name(new=None)
Return or set the graph’s name.
INPUT:• new – string (default: None); by default (new == None), the method returns the name of the graph.
When name is set, the string representation of that object becomes the new name of the (di)graph (new==removes any name).
EXAMPLES:
sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], 5: [7, 8], 6: [8,˓→9], 7: [9]}sage: G = Graph(d); G
Graph on 10 vertices
sage: G.name("Petersen Graph"); GPetersen Graph: Graph on 10 vertices
sage: G.name(new=""); GGraph on 10 vertices
sage: G.name()
sage: G.name(42); G(continues on next page)

304

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

42: Graph on 10 vertices
sage: G.name()42>>> from sage.all import *>>> d = {Integer(0): [Integer(1),Integer(4),Integer(5)], Integer(1):␣
˓→[Integer(2),Integer(6)], Integer(2): [Integer(3),Integer(7)], Integer(3):␣
˓→[Integer(4),Integer(8)], Integer(4): [Integer(9)], Integer(5): [Integer(7),␣
˓→Integer(8)], Integer(6): [Integer(8),Integer(9)], Integer(7): [Integer(9)]}>>> G = Graph(d); G
Graph on 10 vertices>>> G.name("Petersen Graph"); GPetersen Graph: Graph on 10 vertices>>> G.name(new=""); GGraph on 10 vertices>>> G.name()>>> G.name(Integer(42)); G
42: Graph on 10 vertices>>> G.name()
42neighbor_iterator(vertex, closed=False)
Return an iterator over neighbors of vertex.
When closed is set to True, the returned iterator also contains vertex.
INPUT:• vertex – a vertex of self
• closed – a boolean (default: False); whether to return the closed neighborhood of vertex, i.e.,
including vertex, or the open neighborhood in which vertex is included only if there is a loop on
that vertex.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: for i in G.neighbor_iterator(0):....:print(i)145sage: D = G.to_directed()sage: for i in D.neighbor_iterator(0):....:print(i)1
45>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> for i in G.neighbor_iterator(Integer(0)):...
print(i)145(continues on next page)

1.1. Generic graphs (common to directed/undirected)

305

Graph Theory, Release 10.4

(continued from previous page)>>> D = G.to_directed()>>> for i in D.neighbor_iterator(Integer(0)):...
print(i)145sage: D = DiGraph({0: [1, 2], 3: [0]})sage: sorted(D.neighbor_iterator(0))[1, 2, 3]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(3):␣
˓→[Integer(0)]})>>> sorted(D.neighbor_iterator(Integer(0)))[1, 2, 3]
sage: g = graphs.CubeGraph(3)sage: sorted(g.neighbor_iterator( 010 , closed=True))[ 000 , 010 , 011 , 110 ]>>> from sage.all import *>>> g = graphs.CubeGraph(Integer(3))>>> sorted(g.neighbor_iterator( 010 , closed=True))[ 000 , 010 , 011 , 110 ]sage: g = Graph(3, loops = True)
sage: g.add_edge(0,1)
sage: g.add_edge(0,0)
sage: list(g.neighbor_iterator(0, closed=True))[0, 1]
sage: list(g.neighbor_iterator(2, closed=True))[2]>>> from sage.all import *>>> g = Graph(Integer(3), loops = True)>>> g.add_edge(Integer(0),Integer(1))>>> g.add_edge(Integer(0),Integer(0))>>> list(g.neighbor_iterator(Integer(0), closed=True))[0, 1]>>> list(g.neighbor_iterator(Integer(2), closed=True))[2]

neighbors(vertex, closed=False)
Return a list of neighbors (in and out if directed) of vertex.
G[vertex] also works. When closed is set to True, the returned iterator also contains vertex.
INPUT:• vertex – a vertex of self
• closed – a boolean (default: False); whether to return the closed neighborhood of vertex, i.e.,
including vertex, or the open neighborhood in which vertex is included only if there is a loop on
that vertex.

306

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: sorted(P.neighbors(3))[2, 4, 8]
sage: sorted(P[4])[0, 3, 9]
sage: sorted(P.neighbors(3, closed=True))[2, 3, 4, 8]>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> sorted(P.neighbors(Integer(3)))[2, 4, 8]>>> sorted(P[Integer(4)])[0, 3, 9]>>> sorted(P.neighbors(Integer(3), closed=True))[2, 3, 4, 8]

networkx_graph(weight_function=None)
Return a new NetworkX graph from the Sage graph.
INPUT:• weight_function – function (default: None); a function that takes as input an edge (u, v, l)and outputs its weight.
EXAMPLES:
sage: G = graphs.TetrahedralGraph()
sage: N = G.networkx_graph()˓→needs networkx
sage: type(N)˓→needs networkx<class networkx.classes.graph.Graph >#␣#␣sage: def weight_fn(e):....:return e[2]sage: G1 = Graph([(1,2,1), (1,3,4), (2,3,3), (3,4,4)])
sage: H = G1.networkx_graph(weight_function=weight_fn)
˓→needs networkx
sage: H.edges(data=True)
˓→needs networkx
EdgeDataView([(1, 2, { weight : 1}), (1, 3, { weight : 4}),(2, 3, { weight : 3}), (3, 4, { weight : 4})])sage: G2 = DiGraph([(1,2,1), (1,3,4), (2,3,3), (3,4,4), (3,4,5)],....:
multiedges=True)
sage: H = G2.networkx_graph(weight_function=weight_fn)
˓→needs networkx
sage: H.edges(data=True)
˓→needs networkx
OutMultiEdgeDataView([(1, 2, { weight : 1}), (1, 3, { weight : 4}),(2, 3, { weight : 3}), (3, 4, { weight : 5}),(3, 4, { weight : 4})])>>> from sage.all import *>>> G = graphs.TetrahedralGraph()>>> N = G.networkx_graph()

#␣
#␣

#␣
#␣

#␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

307Graph Theory, Release 10.4

(continued from previous page)needs networkx>>> type(N)˓→needs networkx<class networkx.classes.graph.Graph >˓→#␣>>> def weight_fn(e):...
return e[Integer(2)]>>> G1 = Graph([(Integer(1),Integer(2),Integer(1)), (Integer(1),Integer(3),˓→Integer(4)), (Integer(2),Integer(3),Integer(3)), (Integer(3),Integer(4),˓→Integer(4))])>>> H = G1.networkx_graph(weight_function=weight_fn)#␣˓→needs networkx>>> H.edges(data=True)#␣˓→needs networkx
EdgeDataView([(1, 2, { weight : 1}), (1, 3, { weight : 4}),(2, 3, { weight : 3}), (3, 4, { weight : 4})])>>> G2 = DiGraph([(Integer(1),Integer(2),Integer(1)), (Integer(1),Integer(3),˓→Integer(4)), (Integer(2),Integer(3),Integer(3)), (Integer(3),Integer(4),˓→Integer(4)), (Integer(3),Integer(4),Integer(5))],...
multiedges=True)>>> H = G2.networkx_graph(weight_function=weight_fn)#␣˓→needs networkx>>> H.edges(data=True)#␣˓→needs networkx
OutMultiEdgeDataView([(1, 2, { weight : 1}), (1, 3, { weight : 4}),(2, 3, { weight : 3}), (3, 4, { weight : 5}),(3, 4, { weight : 4})])

nowhere_zero_flow(k, solver=None, verbose=None, integrality_tolerance=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 𝑘-flowwhich 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:

308

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• k – integer (default: 6); when set to a positive integer ≥ 2, search for a 𝑘-nowhere zero flow
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
A digraph with flow values stored as edge labels if a 𝑘-nowhere zero flow is found. If self is undirected,
the edges of this digraph indicate the selected orientation. If no feasible solution is found, an error is raised.
EXAMPLES:
The Petersen graph admits a (positive) 5-nowhere zero flow, but no 4-nowhere zero flow:
sage: g = graphs.PetersenGraph()
sage: h = g.nowhere_zero_flow(k=5)˓→needs sage.numerical.mip
sage: sorted(set(h.edge_labels()))˓→needs sage.numerical.mip[1, 2, 3, 4]
sage: h = g.nowhere_zero_flow(k=3)˓→needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: the problem has no feasible solution>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> h = g.nowhere_zero_flow(k=Integer(5))˓→# needs sage.numerical.mip>>> sorted(set(h.edge_labels()))˓→needs sage.numerical.mip[1, 2, 3, 4]>>> h = g.nowhere_zero_flow(k=Integer(3))˓→# needs sage.numerical.mip
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)
˓→needs sage.combinat
sage: h = g.nowhere_zero_flow(k=2)˓→needs sage.combinat sage.numerical.mip
sage: sorted(set(h.edge_labels()))˓→needs sage.combinat sage.numerical.mip[-1, 1]>>> from sage.all import *>>> g = digraphs.DeBruijn(Integer(2), Integer(3))˓→# needs sage.combinat>>> h = g.nowhere_zero_flow(k=Integer(2))

#␣
#␣
#␣

␣
␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

309

Graph Theory, Release 10.4

(continued from previous page)# needs sage.combinat sage.numerical.mip>>> sorted(set(h.edge_labels()))˓→needs sage.combinat sage.numerical.mip[-1, 1]˓→#␣

num_edges()
Return the number of edges.
Note that num_edges() also returns the number of edges in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.size()
15>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.size()
15

num_faces(embedding=None)
Return the number of faces of an embedded graph.
If no embedding is provided or stored as self._embedding, this method uses Euler’s formula (see the
Wikipedia article Euler_characteristic) to determine the number of faces if the graph is planar. If the graphis not planar, an error is raised.
If an embedding is provided or stored as self._embedding, this method calls method faces() to get
the list of faces induced by the embedding in each connected component of the graph. Then it returns thesum of size of these lists minus the number of connected components plus one to ensure that the external faceis counted only once.
INPUT:• embedding – dictionary (default: None); a combinatorial embedding dictionary. Format: {v1:[v2,v3], v2: [v1], v3: [v1]} (clockwise ordering of neighbors at each vertex). If set toNone (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 graphis, of course, planar).
EXAMPLES:
sage: T = graphs.TetrahedralGraph()
sage: T.num_faces()4>>> from sage.all import *>>> T = graphs.TetrahedralGraph()>>> T.num_faces()
4

The external face of a disconnected graph is counted only once:
sage: (T + T).num_faces()
7(continues on next page)

310

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: (T + T + T).num_faces()10>>> from sage.all import *>>> (T + T).num_faces()7>>> (T + T + T).num_faces()
10

Trees and forests have a single face:sage: T = graphs.RandomTree(10)sage: T.num_faces()1
sage: (T + T).num_faces()1>>> from sage.all import *>>> T = graphs.RandomTree(Integer(10))>>> T.num_faces()1>>> (T + T).num_faces()1

num_verts()
Return the number of vertices.
Note that len(G) and num_verts() also return the number of vertices in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.order()10>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.order()10sage: G = graphs.TetrahedralGraph()
sage: len(G)4>>> from sage.all import *>>> G = graphs.TetrahedralGraph()>>> len(G)4number_of_loops()
Return the number of edges that are loops
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

311

Graph Theory, Release 10.4

sage: G = Graph(4, loops=True)
sage: G.add_edges([(0, 0), (1, 1), (2, 2), (3, 3), (2, 3)])sage: G.edges(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: G.number_of_loops()
4>>> from sage.all import *>>> G = Graph(Integer(4), loops=True)>>> G.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> G.edges(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]>>> 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)])sage: D.edges(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: D.number_of_loops()
4>>> from sage.all import *>>> D = DiGraph(Integer(4), loops=True)>>> D.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> D.edges(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]>>> D.number_of_loops()4

odd_girth(algorithm='bfs', certificate=False)
Return the odd girth of the graph.
The odd girth is the length of the shortest cycle of odd length in the graph (directed cycle if the graph isdirected). Bipartite graphs have infinite odd girth.
INPUT:• algorithm – string (default: "bfs"); the algorithm to use:– "bfs" – BFS-based algorithm– any algorithm accepted by charpoly() for computation from the characteristic polynomial (see[Har1962] and [Big1993], p. 45)• certificate – boolean (default: False); whether to return (g, c), where g is the odd girth andc is a list of vertices of a (directed) cycle of length g in the graph, thus providing a certificate that the odd
girth is at most g, or None if g is infinite. So far, this parameter is accepted only when algorithm= "bfs".
EXAMPLES:
The McGee graph has girth 7 and therefore its odd girth is 7 as well:

312

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = graphs.McGeeGraph()˓→needs networkx
sage: G.girth()˓→needs networkx
7
sage: G.odd_girth()˓→needs networkx
7

#␣
#␣

#␣

>>> from sage.all import *>>> G = graphs.McGeeGraph()˓→needs networkx>>> G.girth()˓→needs networkx
7>>> G.odd_girth()˓→needs networkx
7

#␣
#␣

#␣

Any complete (directed) graph on more than 2 vertices contains a (directed) triangle and has thus odd girth3:
sage: G = graphs.CompleteGraph(5)sage: G.odd_girth(certificate=True)(3, [2, 1, 0])
sage: G = digraphs.Complete(5)sage: G.odd_girth(certificate=True)(3, [1, 2, 0])# random# random>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G.odd_girth(certificate=True) # random(3, [2, 1, 0])>>> G = digraphs.Complete(Integer(5))>>> G.odd_girth(certificate=True) # random(3, [1, 2, 0])

Bipartite graphs have no odd cycle and consequently have infinite odd girth:sage: G = graphs.RandomBipartite(6, 6, .5)
˓→needs numpy
sage: G.odd_girth()˓→needs numpy+Infinity
sage: G = graphs.Grid2dGraph(3, 4)
sage: G.odd_girth()+Infinity#␣#␣>>> from sage.all import *>>> G = graphs.RandomBipartite(Integer(6), Integer(6), RealNumber( .5 ))˓→# needs numpy>>> G.odd_girth()˓→needs numpy+Infinity>>> G = graphs.Grid2dGraph(Integer(3), Integer(4))>>> G.odd_girth()␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

313

Graph Theory, Release 10.4

(continued from previous page)+Infinity

The odd girth of a (directed) graph with loops is 1:
sage: # needs networkx
sage: G = graphs.RandomGNP(10, .5)
sage: G.allow_loops(True)
sage: G.add_edge(0, 0)
sage: G.odd_girth()1
sage: G = digraphs.RandomDirectedGNP(10, .5)
sage: G.allow_loops(True)
sage: G.add_edge(0, 0)
sage: G.odd_girth()1>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomGNP(Integer(10), RealNumber( .5 ))>>> G.allow_loops(True)>>> G.add_edge(Integer(0), Integer(0))>>> G.odd_girth()1>>> G = digraphs.RandomDirectedGNP(Integer(10), RealNumber( .5 ))>>> G.allow_loops(True)>>> G.add_edge(Integer(0), Integer(0))>>> G.odd_girth()1

See also:• girth() – return the girth of the graph.
order()
Return the number of vertices.
Note that len(G) and num_verts() also return the number of vertices in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.order()10>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.order()10sage: G = graphs.TetrahedralGraph()
sage: len(G)4>>> from sage.all import *>>> G = graphs.TetrahedralGraph()(continues on next page)

314

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> len(G)4pagerank(alpha=0.85, personalization=None, by_weight=False, weight_function=None, check_weight=True,
dangling=None, algorithm='scipy')
Return the PageRank of the vertices of self.
PageRank is a centrality measure earlier used to rank web pages. The PageRank algorithm outputs the probability distribution that a random walker in the graph visits a vertex.
See the Wikipedia article PageRank for more information.
INPUT:• alpha – float (default: 0.85); damping parameter for PageRank. alpha is the click-through probability useful for preventing sinks. The probability at any step, that an imaginary surfer who is randomly
clicking on links will continue is a damping factor d.
• personalization – dict (default: None); a dictionary keyed by vertices associating to each vertex
a value. The personalization can be specified for a subset of the vertices, if not specified a nodes personalization value will be taken as zero. The sum of the values must be nonzero. By default (None), a
uniform distribution is used.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); whether to check that the weight_function outputs
a number for each edge.
• dangling – dict (default: None); a dictionary keyed by a vertex the outedge of “dangling” vertices,(i.e., vertices without any outedges) points to and the dict value is the weight of that outedge. By default,
dangling vertices are given outedges according to the personalization vector (uniform if not specified).
It may be common to have the dangling dict to be the same as the personalization dict.
• algorithm – string (default: None); the algorithm to use incomputing PageRank of G. The following algorithms are supported:– NetworkX – uses NetworkX’s default implementation (Scipy as of 2.6)
– "Scipy" – uses Scipy’s PageRank algorithm implementation– "igraph" – uses igraph’s PageRank algorithm implementation– "None" – uses best implementation available
OUTPUT: a dictionary containing the PageRank value of each nodeNote: Parameters alpha, by_weight and weight_function are common to all algorithms. Parameters personalization and dangling are used only by algorithms NetworkX, Numpy and Scipy.
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

315Graph Theory, Release 10.4

sage: G = graphs.CycleGraph(4)sage: G.pagerank(algorithm="Networkx")
˓→needs networkx{0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25}
sage: G.pagerank(alpha=0.50, algorithm="igraph")˓→optional - python_igraph{0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25}
sage: G = Graph([(1, 2, 40), (2, 3, 50), (3, 4, 60),....:
(1, 4, 70), (4, 5, 80), (5, 6, 20)])
sage: G.pagerank(algorithm="NetworkX")
˓→needs networkx{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}
sage: G.pagerank(algorithm="NetworkX", by_weight=True)
˓→needs networkx{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
4: 0.3063198690713853,
5: 0.1700057609707141,
6: 0.05390084497706962}
sage: G.pagerank(algorithm="Scipy")
˓→needs networkx scipy{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}
sage: G.pagerank(algorithm="Scipy", by_weight=True)
˓→needs networkx scipy{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
4: 0.3063198690713853,
5: 0.1700057609707141,
6: 0.05390084497706962}
sage: G.pagerank(algorithm="igraph")˓→optional - python_igraph{1: 0.16112198303979128,
2: 0.16195368558382262,
3: 0.16112198303979125,
4: 0.23749999999999993,
5: 0.17775603392041744,
6: 0.10054631441617742}
sage: G.pagerank()
˓→needs networkx{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}#␣# abs tol 1e-9,␣

# abs tol 1e-9#␣# abs tol 1e-9#␣# abs tol 1e-9#␣# abs tol 1e-9#␣# abs tol 1e-9,␣

# abs tol 1e-9

#␣(continues on next page)

316

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.pagerank(by_weight=True)
˓→needs networkx{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
4: 0.3063198690713853,
5: 0.1700057609707141,
6: 0.05390084497706962}# abs tol 1e-9

#␣>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> G.pagerank(algorithm="Networkx")#␣˓→needs networkx{0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25}>>> G.pagerank(alpha=RealNumber( 0.50 ), algorithm="igraph")# abs tol␣˓→1e-9, optional - python_igraph{0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25}>>> G = Graph([(Integer(1), Integer(2), Integer(40)), (Integer(2), Integer(3),˓→ Integer(50)), (Integer(3), Integer(4), Integer(60)),...
(Integer(1), Integer(4), Integer(70)), (Integer(4), Integer(5),˓→ Integer(80)), (Integer(5), Integer(6), Integer(20))])>>> G.pagerank(algorithm="NetworkX")# abs tol 1e-9#␣˓→needs networkx{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}>>> G.pagerank(algorithm="NetworkX", by_weight=True) # abs tol 1e-9#␣˓→needs networkx{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
4: 0.3063198690713853,
5: 0.1700057609707141,
6: 0.05390084497706962}>>> G.pagerank(algorithm="Scipy")# abs tol 1e-9#␣˓→needs networkx scipy{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}>>> G.pagerank(algorithm="Scipy", by_weight=True)# abs tol 1e-9#␣˓→needs networkx scipy{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
4: 0.3063198690713853,
5: 0.1700057609707141,
6: 0.05390084497706962}>>> G.pagerank(algorithm="igraph")# abs tol 1e-9,␣˓→optional - python_igraph{1: 0.16112198303979128,(continues on next page)

1.1. Generic graphs (common to directed/undirected)

317

Graph Theory, Release 10.4

(continued from previous page)

2: 0.16195368558382262,
3: 0.16112198303979125,
4: 0.23749999999999993,
5: 0.17775603392041744,
6: 0.10054631441617742}>>> G.pagerank()
˓→needs networkx{1: 0.16112205885619563,
2: 0.1619531043247219,
3: 0.16112205885619563,
4: 0.2374999999999999,
5: 0.17775588228760858,
6: 0.100546895675278}>>> G.pagerank(by_weight=True)
˓→needs networkx{1: 0.16459583718588994,
2: 0.13977928595154515,
3: 0.16539840184339605,
4: 0.3063198690713853,
5: 0.1700057609707141,
6: 0.05390084497706962}# abs tol 1e-9#␣# abs tol 1e-9#␣

See also:• Wikipedia article PageRank
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 thisinformation one can obtain the dual of a plane graph, which is what the method returns. The vertices of thedual graph correspond to faces of the primal graph.
INPUT:• embedding – dictionary (default: None); a combinatorial embedding dictionary. Format: {v1:[v2,v3], v2: [v1], v3: [v1]} (clockwise ordering of neighbors at each vertex). If set toNone (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 graphis, 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>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(3))>>> C.planar_dual()Graph on 6 vertices>>> graphs.IcosahedralGraph().planar_dual().is_isomorphic(graphs.
˓→DodecahedralGraph())
True

318

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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>>> from sage.all import *>>> g = graphs.BuckyBall()>>> 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 faster3-vertex-connectivity test (Issue #24635).
plot(**options)
Return a Graphics object representing the (di)graph.
INPUT:• pos – an optional positioning dictionary• layout – string (default: None); specifies a kind of layout to use, takes precedence over pos–

circular – plots the graph with vertices evenly distributed on a circle–

spring – uses the traditional spring layout, using the graph’s current positions as initial 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 – boolean (default: True); whether to print vertex labels• edge_labels – boolean (default: False); whether to print edge labels. If True, the result ofstr(l) is printed on the edge for each label 𝑙. Labels equal to None are not printed (to set edge labels,
see set_edge_label()).
• edge_labels_background – the color of the edge labels background. The default is “white”. To
achieve a transparent background use “transparent”.
• vertex_size – size of vertices displayed• vertex_shape – the shape to draw the vertices, for example "o" for circle or "s" for square. Wholelist is available at https://matplotlib.org/api/markers_api.html. (Not available for multiedge digraphs.)• graph_border – boolean (default: False); whether to include a box around the graph• vertex_colors – dictionary (default: None); optional dictionary to specify vertex colors: each key
is a color recognizable by matplotlib, and each corresponding entry is a list of vertices. If a vertex is notlisted, it looks invisible on the resulting plot (it doesn’t get drawn).

1.1. Generic graphs (common to directed/undirected)

319

Graph Theory, Release 10.4

• edge_colors – dictionary (default: None); a dictionary specifying edge colors: each key is a color
recognized by matplotlib, and each entry is a list of edges.
• partition – a partition of the vertex set (default: None); if specified, plot will show each cell in adifferent color. vertex_colors takes precedence.
• talk – boolean (default: False); if True, prints large vertices with white backgrounds so that labels
are legible on slides• iterations – integer; how many iterations of the spring layout algorithm to go through, if applicable• color_by_label – a boolean or dictionary or function (default: False); whether to color each edge
with a different color according to its label; the colors are chosen along a rainbow, unless they are specified
by a function or dictionary mapping labels to colors; this option is incompatible with edge_color andedge_colors.
• heights – dictionary (default: None); if specified, this is a dictionary from a set of floating point
heights to a set of vertices• edge_style – keyword arguments passed into the edge-drawing routine. This currently only works
for directed graphs, since we pass off the undirected graph to networkx• tree_root – a vertex (default: None); if specified, this vertex is used as the root for the layout="tree" option. Otherwise, then one is chosen at random. Ignored unless layout= tree .
• tree_orientation – string (default: "down"); one of “up” or “down”. If “up” (resp., “down”),
then the root of the tree will appear on the bottom (resp., top) and the tree will grow upwards (resp.
downwards). Ignored unless layout= tree .
• save_pos – boolean (default: False); save position computed during plotting
Note:• This method supports any parameter accepted by sage.plot.graphics.Graphics.show().
• See the documentation of the sage.graphs.graph_plot module for information and examples
of how to define parameters that will be applied to all graph plots.
• Default parameters for this method and a specific graph can also be set through the options mechanism. 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 ofa 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],....:#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]#FFFF00 : [2, 7],(continues on next page)

320

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

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)
˓→needs sage.plot
sage: pl.show()˓→needs sage.plot#␣#␣>>> from sage.all import *>>> from sage.graphs.graph_plot import graphplot_options>>> sorted(graphplot_options.items())[...]>>> from math import sin, cos, pi>>> P = graphs.PetersenGraph()>>> d = { #FF0000 : [Integer(0), Integer(5)], #FF9900 : [Integer(1),␣
˓→Integer(6)],#FFFF00 : [Integer(2), Integer(7)],...
#00FF00 : [Integer(3), Integer(8)], #0000FF : [Integer(4),␣
˓→Integer(9)]}>>> pos_dict = {}>>> for i in range(Integer(5)):... x = float(cos(pi/Integer(2) + ((Integer(2)*pi)/Integer(5))*i))... y = float(sin(pi/Integer(2) + ((Integer(2)*pi)/Integer(5))*i))... pos_dict[i] = [x,y]>>> for i in range(Integer(5), Integer(10)):... x = float(RealNumber( 0.5 )*cos(pi/Integer(2) + ((Integer(2)*pi)/
˓→Integer(5))*i))... y = float(RealNumber( 0.5 )*sin(pi/Integer(2) + ((Integer(2)*pi)/
˓→Integer(5))*i))... pos_dict[i] = [x,y]>>> pl = P.plot(pos=pos_dict, vertex_colors=d)
˓→needs sage.plot>>> pl.show()˓→needs sage.plot#␣#␣

sage: C = graphs.CubeGraph(8)sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True)
˓→needs sage.plot
sage: P.show()˓→needs sage.plot>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(8))>>> P = C.plot(vertex_labels=False, vertex_size=Integer(0), graph_
˓→border=True)# needs sage.plot>>> P.show()˓→needs sage.plot
sage: G = graphs.HeawoodGraph()
sage: for u, v, l in G.edges(sort=False):....:
G.set_edge_label(u, v, ( + str(u) +sage: G.plot(edge_labels=True).show()˓→needs sage.plot

1.1. Generic graphs (common to directed/undirected),+ str(v) +

#␣
#␣

#␣

) )
#␣

321

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.HeawoodGraph()>>> for u, v, l in G.edges(sort=False):...
G.set_edge_label(u, v, ( + str(u) +>>> G.plot(edge_labels=True).show()˓→needs sage.plot,+ str(v) +) )#␣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]}, sparse=True)
sage: for u,v,l in D.edges(sort=False):....:
D.set_edge_label(u, v, ( + str(u) + , + str(v) + ) )sage: D.plot(edge_labels=True, layout= circular ).show()˓→needs sage.plot#␣>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(10), Integer(19)],␣
˓→Integer(1): [Integer(8), Integer(2)], Integer(2): [Integer(3), Integer(6)],␣
˓→Integer(3): [Integer(19), Integer(4)],...
Integer(4): [Integer(17), Integer(5)], Integer(5):␣
˓→[Integer(6), Integer(15)], Integer(6): [Integer(7)], Integer(7):␣
˓→[Integer(8), Integer(14)],...
Integer(8): [Integer(9)], Integer(9): [Integer(10),␣
˓→Integer(13)], Integer(10): [Integer(11)], Integer(11): [Integer(12),␣
˓→Integer(18)],...
Integer(12): [Integer(16), Integer(13)], Integer(13):␣
˓→[Integer(14)], Integer(14): [Integer(15)], Integer(15): [Integer(16)],...
Integer(16): [Integer(17)], Integer(17): [Integer(18)],␣
˓→Integer(18): [Integer(19)]}, sparse=True)>>> for u,v,l in D.edges(sort=False):...
D.set_edge_label(u, v, ( + str(u) + , + str(v) + ) )>>> D.plot(edge_labels=True, layout= circular ).show()#␣˓→needs sage.plot
sage: # needs sage.plot
sage: from sage.plot.colors import rainbow
sage: C = graphs.CubeGraph(5)sage: R = rainbow(5)sage: edge_colors = {R[i]: [] for i in range(5)}sage: for u, v, l in C.edges(sort=False):....: 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()>>> from sage.all import *>>> # needs sage.plot>>> from sage.plot.colors import rainbow>>> C = graphs.CubeGraph(Integer(5))>>> R = rainbow(Integer(5))>>> edge_colors = {R[i]: [] for i in range(Integer(5))}>>> for u, v, l in C.edges(sort=False):... for i in range(Integer(5)):(continues on next page)

322

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)...
if u[i] != v[i]:...
edge_colors[R[i]].append((u, v, l))>>> C.plot(vertex_labels=False, vertex_size=Integer(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)
˓→needs sage.plot#␣>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> Pi = [[Integer(6),Integer(5),Integer(15),Integer(14),Integer(7)],␣
˓→[Integer(16),Integer(13),Integer(8),Integer(2),Integer(4)], [Integer(12),
˓→Integer(17),Integer(9),Integer(3),Integer(1)], [Integer(0),Integer(19),
˓→Integer(18),Integer(10),Integer(11)]]>>> D.show(partition=Pi)#␣˓→needs sage.plot
sage: G = graphs.PetersenGraph()
sage: G.allow_loops(True)
sage: G.add_edge(0, 0)
sage: G.show()˓→needs sage.plot#␣>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.allow_loops(True)>>> G.add_edge(Integer(0), Integer(0))>>> G.show()˓→needs sage.plot#␣

sage: D = DiGraph({0: [0, 1], 1: [2], 2: [3]}, loops=True)
sage: D.show()˓→needs sage.plot
sage: D.show(edge_colors={(0, 1, 0): [(0, 1, None), (1, 2, None)],˓→needs sage.plot....:(0, 0, 0): [(2, 3, None)]})#␣#␣>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(0), Integer(1)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)]}, loops=True)>>> D.show()#␣˓→needs sage.plot>>> D.show(edge_colors={(Integer(0), Integer(1), Integer(0)): [(Integer(0),␣
˓→Integer(1), None), (Integer(1), Integer(2), None)],# needs sage.
˓→plot...
(Integer(0), Integer(0), Integer(0)): [(Integer(2),␣
˓→Integer(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)#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

323

Graph Theory, Release 10.4

(continued from previous page)needs sage.plot
Graphics object consisting of 11 graphics primitives˓→>>> from sage.all import *>>> pos = {Integer(0): [RealNumber( 0.0 ), RealNumber( 1.5 )], Integer(1): [˓→RealNumber( 0.8 ), RealNumber( 0.3 )], Integer(2): [-RealNumber( 0.6 ), ˓→RealNumber( 0.8 )], Integer(3): [RealNumber( 0.6 ), -RealNumber( 0.8 )],␣˓→Integer(4): [RealNumber( 0.8 ), RealNumber( 0.3 )]}>>> g = Graph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(3): [Integer(4)], Integer(4):␣
˓→[Integer(0)]})>>> g.plot(pos=pos, layout= spring , iterations=Integer(0))␣˓→# needs sage.plot
Graphics object consisting of 11 graphics primitives
sage: G = Graph()
sage: P = G.plot()
˓→needs sage.plot
sage: P.axes()
˓→needs sage.plot
False
sage: G = DiGraph()
sage: P = G.plot()
˓→needs sage.plot
sage: P.axes()
˓→needs sage.plot
False

#␣
#␣

#␣
#␣

>>> from sage.all import *>>> G = Graph()>>> P = G.plot()
˓→needs sage.plot>>> P.axes()
˓→needs sage.plot
False>>> G = DiGraph()>>> P = G.plot()
˓→needs sage.plot>>> P.axes()
˓→needs sage.plot
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...),
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 )#␣(continues on next page)

324

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.plot˓→>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> 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...),
6: (-0.47..., 0.15...),
7: (-0.29..., -0.40...),
8: (0.29..., -0.40...),
9: (0.47..., 0.15...)}>>> P = G.plot(save_pos=True, layout= spring )˓→needs sage.plot#␣The following illustrates the format of a position dictionary:
sage: G.get_pos() # currently random across platforms, see #9593
˓→needs sage.plot{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...]}>>> from sage.all import *>>> G.get_pos() # currently random across platforms, see #9593
˓→needs sage.plot{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]})
˓→needs sage.plot
Graphics object consisting of 14 graphics primitives

#␣

#␣

#␣

>>> from sage.all import *>>> T = list(graphs.trees(Integer(7)))(continues on next page)

1.1. Generic graphs (common to directed/undirected)

325

Graph Theory, Release 10.4

(continued from previous page)>>> t = T[Integer(3)]>>> t.plot(heights={Integer(0): [Integer(0)], Integer(1): [Integer(4),␣
˓→Integer(5), Integer(1)], Integer(2): [Integer(2)], Integer(3): [Integer(3),␣
˓→Integer(6)]})# needs sage.plot
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]})
˓→needs sage.plot
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]},
˓→needs sage.plot....:
edge_labels=True)
Graphics object consisting of 20 graphics primitives#␣#␣>>> from sage.all import *>>> T = list(graphs.trees(Integer(7)))>>> t = T[Integer(3)]>>> t.plot(heights={Integer(0): [Integer(0)], Integer(1): [Integer(4),␣
˓→Integer(5), Integer(1)], Integer(2): [Integer(2)], Integer(3): [Integer(3),␣
˓→Integer(6)]})# needs sage.plot
Graphics object consisting of 14 graphics primitives>>> t.set_edge_label(Integer(0), Integer(1), -Integer(7))>>> t.set_edge_label(Integer(0), Integer(5), Integer(3))>>> t.set_edge_label(Integer(0), Integer(5), Integer(99))>>> t.set_edge_label(Integer(1), Integer(2), Integer(1000))>>> t.set_edge_label(Integer(3), Integer(2), spam )>>> t.set_edge_label(Integer(2), Integer(6), Integer(3)/Integer(2))>>> t.set_edge_label(Integer(0), Integer(4), Integer(66))>>> t.plot(heights={Integer(0): [Integer(0)], Integer(1): [Integer(4),␣
˓→Integer(5), Integer(1)], Integer(2): [Integer(2)], Integer(3): [Integer(3),␣
˓→Integer(6)]},# needs sage.plot...
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 )˓→needs sage.plot
Graphics object consisting of 14 graphics primitives>>> from sage.all import *>>> T = list(graphs.trees(Integer(7)))>>> t = T[Integer(3)]>>> t.plot(layout= tree )˓→needs sage.plot
Graphics object consisting of 14 graphics primitives

326

#␣

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: t = DiGraph( JCC???@A??GO??CO??GO?? )sage: t.plot(layout= tree , tree_root=0, tree_orientation="up")˓→needs sage.plot
Graphics object consisting of 22 graphics primitives
sage: D = DiGraph({0: [1, 2, 3], 2: [1, 4], 3: [0]})sage: D.plot()
˓→needs sage.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 ))sage: D.plot(edge_labels=True, edge_colors=D._color_by_label())˓→needs sage.plot
Graphics object consisting of 34 graphics primitives
sage: D.plot(edge_labels=True, color_by_label={ a : blue , b :˓→needs sage.plot....:
edge_style= dashed )Graphics object consisting of 34 graphics primitives

#␣

#␣

#␣

red },#␣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 )˓→needs sage.plot
Graphics object consisting of 22 graphics primitives>>> from sage.all import *>>> t = DiGraph( JCC???@A??GO??CO??GO?? )>>> t.plot(layout= tree , tree_root=Integer(0), tree_orientation="up")˓→# needs sage.plot
Graphics object consisting of 22 graphics primitives>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(2): [Integer(1), Integer(4)], Integer(3): [Integer(0)]})>>> D.plot()
˓→needs sage.plot
Graphics object consisting of 16 graphics primitives>>> D = DiGraph(multiedges=True,sparse=True)>>> for i in range(Integer(5)):...
D.add_edge((i, i + Integer(1), a ))...
D.add_edge((i, i - Integer(1), b ))>>> D.plot(edge_labels=True, edge_colors=D._color_by_label())˓→needs sage.plot
Graphics object consisting of 34 graphics primitives>>> D.plot(edge_labels=True, color_by_label={ a : blue , b :˓→needs sage.plot...
edge_style= dashed )Graphics object consisting of 34 graphics primitives

#␣

␣

#␣

#␣

red },#␣>>> g = Graph({}, loops=True, multiedges=True, sparse=True)>>> g.add_edges([(Integer(0), Integer(0), a ), (Integer(0), Integer(0), b ),˓→ (Integer(0), Integer(1),c ), (Integer(0), Integer(1), d ),...
(Integer(0), Integer(1), e ), (Integer(0), Integer(1), f ),␣
˓→(Integer(0), Integer(1),f ), (Integer(2), Integer(1), g ), (Integer(2),␣
˓→Integer(2),h )])(continues on next page)

1.1. Generic graphs (common to directed/undirected)

327

Graph Theory, Release 10.4

(continued from previous page)>>> g.plot(edge_labels=True, color_by_label=True, edge_style= dashed )˓→needs sage.plot
Graphics object consisting of 22 graphics primitives#␣sage: # needs sage.modular
sage: S = SupersingularModule(389)sage: H = S.hecke_matrix(2)sage: D = DiGraph(H, sparse=True)
sage: P = D.plot()
˓→needs sage.plot#␣>>> from sage.all import *>>> # needs sage.modular>>> S = SupersingularModule(Integer(389))>>> H = S.hecke_matrix(Integer(2))>>> D = DiGraph(H, sparse=True)>>> P = D.plot()
˓→needs sage.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]})˓→needs sage.plot#␣>>> from sage.all import *>>> G = Graph({ a : [ a , b , b , b , e ], b : [ c , d , e ],...
c :[ c , d , d , d ], d :[ e ]}, sparse=True)>>> G.show(pos={ a :[Integer(0),Integer(1)], b :[Integer(1),Integer(1)], c
˓→ :[Integer(2),Integer(0)], d :[Integer(1),Integer(0)], e :[Integer(0),˓→Integer(0)]})# needs sage.plot

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='threejs', **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 agraph.
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 insteadof spheres• vertex_colors – dictionary (default: None); 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 does not get drawn).
• edge_colors – dictionary (default: None); 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 andedge_colors.
328

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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 – string (default: threejs ); the renderer to use among:–

threejs : interactive web-based 3D viewer using JavaScript and a WebGL renderer–jmol : interactive 3D viewer using Java–tachyon : ray tracer generating a static PNG image• 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)
˓→time, needs sage.plot
Graphics3d Object# long␣

>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(5))>>> G.plot3d(iterations=Integer(500), edge_size=None, vertex_size=RealNumber(
˓→ 0.04 ))# long time, needs sage.plot
Graphics3d Object

We plot a fairly complicated Cayley graph:
sage: A5 = AlternatingGroup(5); A5
˓→needs sage.groups
Alternating group of order 5!/2 as a permutation group
sage: G = A5.cayley_graph()˓→needs sage.groups
sage: G.plot3d(vertex_size=0.03, edge_size=0.01,# long time
˓→needs sage.groups sage.plot....:
vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0),....:color_by_label=True, iterations=200)
Graphics3d Object

#␣

#␣
#␣

>>> from sage.all import *>>> A5 = AlternatingGroup(Integer(5)); A5␣˓→# needs sage.groups
Alternating group of order 5!/2 as a permutation group>>> G = A5.cayley_graph()#␣˓→needs sage.groups>>> G.plot3d(vertex_size=RealNumber( 0.03 ), edge_size=RealNumber( 0.01 ),˓→# long time
# needs sage.groups sage.plot...
vertex_colors={(Integer(1),Integer(1),Integer(1)): list(G)},␣
˓→bgcolor=(Integer(0),Integer(0),Integer(0)),...
color_by_label=True, iterations=Integer(200))
Graphics3d Object

Some Tachyon examples:
1.1. Generic graphs (common to directed/undirected)

329

Graph Theory, Release 10.4

sage: D = graphs.DodecahedralGraph()
sage: P3D = D.plot3d(engine= tachyon )˓→needs sage.plot
sage: P3D.show()# long time
˓→needs sage.plot#␣#␣>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> P3D = D.plot3d(engine= tachyon )˓→needs sage.plot>>> P3D.show()# long time
˓→needs sage.plot#␣#␣

sage: G = graphs.PetersenGraph()
sage: G.plot3d(engine= tachyon ,# long time
˓→needs sage.plot....:
vertex_colors={(0,0,1): list(G)}).show()#␣>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.plot3d(engine= tachyon ,# long time#␣˓→needs sage.plot...
vertex_colors={(Integer(0),Integer(0),Integer(1)): list(G)}).
˓→show()
sage: C = graphs.CubeGraph(4)sage: C.plot3d(engine= tachyon ,# long time
˓→needs sage.plot....:
edge_colors={(0,1,0): C.edges(sort=False)},....:vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0)).show()#␣>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(4))>>> C.plot3d(engine= tachyon ,# long time#␣˓→needs sage.plot...
edge_colors={(Integer(0),Integer(1),Integer(0)): C.
˓→edges(sort=False)},...
vertex_colors={(Integer(1),Integer(1),Integer(1)): list(C)},␣
˓→bgcolor=(Integer(0),Integer(0),Integer(0))).show()
sage: K = graphs.CompleteGraph(3)sage: K.plot3d(engine= tachyon ,# long time
˓→needs sage.plot....:
edge_colors={(1,0,0): [(0,1,None)],....:(0,1,0): [(0,2,None)],....:(0,0,1): [(1,2,None)]}).show()#␣>>> from sage.all import *>>> K = graphs.CompleteGraph(Integer(3))>>> K.plot3d(engine= tachyon ,# long time#␣˓→needs sage.plot...
edge_colors={(Integer(1),Integer(0),Integer(0)): [(Integer(0),˓→Integer(1),None)],...
(Integer(0),Integer(1),Integer(0)): [(Integer(0),˓→Integer(2),None)],(continues on next page)

330

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)...
(Integer(0),Integer(0),Integer(1)): [(Integer(1),˓→Integer(2),None)]}).show()

A directed version of the dodecahedronsage: 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
˓→needs sage.plot#␣>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(10), Integer(19)],␣
˓→Integer(1): [Integer(8), Integer(2)], Integer(2): [Integer(3), Integer(6)],␣
˓→Integer(3): [Integer(19), Integer(4)],...
Integer(4): [Integer(17), Integer(5)], Integer(5):␣
˓→[Integer(6), Integer(15)], Integer(6): [Integer(7)], Integer(7):␣
˓→[Integer(8), Integer(14)],...
Integer(8): [Integer(9)], Integer(9): [Integer(10),␣
˓→Integer(13)], Integer(10): [Integer(11)], Integer(11): [Integer(12),␣
˓→Integer(18)],...
Integer(12): [Integer(16), Integer(13)], Integer(13):␣
˓→[Integer(14)], Integer(14): [Integer(15)], Integer(15): [Integer(16)],␣
˓→Integer(16): [Integer(17)],...
Integer(17): [Integer(18)], Integer(18): [Integer(19)],␣
˓→Integer(19): []})>>> D.plot3d().show()# long time#␣˓→needs sage.plot
sage: P = graphs.PetersenGraph().to_directed()sage: from sage.plot.colors import rainbow#␣˓→needs sage.plot
sage: R = rainbow(P.size(), rgbtuple )#␣˓→needs sage.plot
sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())}#␣
˓→needs sage.plot
sage: P.plot3d(engine= tachyon , edge_colors=edge_colors).show()# long␣˓→time, needs sage.plot>>> from sage.all import *>>> P = graphs.PetersenGraph().to_directed()>>> from sage.plot.colors import rainbow#␣˓→needs sage.plot>>> R = rainbow(P.size(), rgbtuple )#␣˓→needs sage.plot>>> edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())}#␣
˓→needs sage.plot>>> P.plot3d(engine= tachyon , edge_colors=edge_colors).show()# long time,
˓→ needs sage.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.show3d()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

331Graph Theory, Release 10.4

(continued from previous page)

Traceback (most recent call last):...
NotImplementedError: 3D plotting of multiple edges or loops not implemented>>> from sage.all import *>>> G = Graph({ a : [ a , b , b , b , e ], b : [ c , d , e ],...
c : [ c , d , d , d ], d : [ e ]}, sparse=True)>>> 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]])
˓→needs sage.plot
Graphics3d Object#␣>>> from sage.all import *>>> G = graphs.WheelGraph(Integer(7))>>> G.plot3d(partition=[[Integer(0)], [Integer(1), Integer(2), Integer(3),␣
˓→Integer(4), Integer(5), Integer(6)]])# needs sage.
˓→plotGraphics3d Object

See also:• plot()• graphviz_string()
power(k)Return the 𝑘-th power graph of self.
In the 𝑘-th power graph of a graph 𝐺, there is an edge between any pair of vertices at distance at most 𝑘 in 𝐺,
where the distance is considered in the unweighted graph. In a directed graph, there is an arc from a vertex 𝑢
to a vertex 𝑣 if there is a path of length at most 𝑘 in 𝐺 from 𝑢 to 𝑣.
INPUT:• k – integer; the maximum path length for considering edges in the power graph.
OUTPUT:• The kth power graph based on shortest distances between nodes.
EXAMPLES:
Testing on undirected graphs:
sage: G = Graph([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4), (4, 5)])sage: PG = G.power(2)sage: PG.edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (2, 5), (3,␣˓→4), (4, 5)]332

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1)), (Integer(1), Integer(2)),␣
˓→(Integer(2), Integer(3)), (Integer(3), Integer(0)), (Integer(2),␣
˓→Integer(4)), (Integer(4), Integer(5))])>>> PG = G.power(Integer(2))>>> PG.edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (2, 5), (3,␣˓→4), (4, 5)]

Testing on directed graphs:
sage: G = DiGraph([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4), (4, 5)])sage: PG = G.power(3)sage: PG.edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 2), (1, 3), (1, 4), (1, 5), (2,␣˓→0), (2, 1), (2, 3), (2, 4), (2, 5), (3, 0), (3, 1), (3, 2), (4, 5)]>>> from sage.all import *>>> G = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(2)),␣
˓→(Integer(2), Integer(3)), (Integer(3), Integer(0)), (Integer(2),␣
˓→Integer(4)), (Integer(4), Integer(5))])>>> PG = G.power(Integer(3))>>> PG.edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 2), (1, 3), (1, 4), (1, 5), (2,␣˓→0), (2, 1), (2, 3), (2, 4), (2, 5), (3, 0), (3, 1), (3, 2), (4, 5)]random_edge(**kwds)
Return a random edge of self.
INPUT:• **kwds – arguments to be passed down to the edge_iterator() method
EXAMPLES:
The returned value is an edge of self:
sage: g = graphs.PetersenGraph()
sage: u,v = g.random_edge(labels=False)
sage: g.has_edge(u,v)
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> u,v = g.random_edge(labels=False)>>> 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 lis the label of edge (u, v):
sage: g.random_edge()(3, 4, None)# random>>> from sage.all import *>>> g.random_edge() # random(3, 4, None)

1.1. Generic graphs (common to directed/undirected)333Graph Theory, Release 10.4

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]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> it = g.random_edge_iterator()>>> [g.has_edge(next(it)) for _ in range(Integer(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 lis 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)>>> from sage.all import *>>> print(next(g.random_edge_iterator())) # random(0, 5, None)>>> print(next(g.random_edge_iterator(labels=False))) # random(5, 7)

random_subgraph(p, inplace=False)
Return a random subgraph containing each vertex with probability p.
INPUT:• p – the probability of choosing a vertex• inplace – boolean (default: False); using inplace=True will simply delete the extra vertices
and edges from the current graph. This will modify the graph.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.random_subgraph(.25)
Subgraph of (Petersen graph): Graph on ... vert...
>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.random_subgraph(RealNumber( .25 ))Subgraph of (Petersen graph): Graph on ... vert...

334

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

random_vertex(**kwds)
Return a random vertex of self.
INPUT:• **kwds – arguments to be passed down to the vertex_iterator() method
EXAMPLES:
The returned value is a vertex of self:
sage: g = graphs.PetersenGraph()
sage: v = g.random_vertex()sage: v in g
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> v = g.random_vertex()>>> v in g
Truerandom_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]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> it = g.random_vertex_iterator()>>> [next(it) in g for _ in range(Integer(5))][True, True, True, True, True]

relabel(perm=None, inplace=True, return_map=False, check_input=True, complete_partial_function=True,
immutable=None)
Relabels the vertices of self
INPUT:• perm – a function, dictionary, iterable, 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.
time-consuming !.

1.1. Generic graphs (common to directed/undirected)

This can potentially be very

335

Graph Theory, Release 10.4

• 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 notrelabeled This can potentially be very time-consuming !.
• immutable (boolean) – with inplace=False, whether to create a mutable/immutable relabelledcopy. 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].
If perm is a list (or more generally, any iterable) of length n, then the first vertex returned by G.
vertices(sort=True) is relabeled to l[0], the second to l[1], …
If perm is a permutation, then each vertex v is relabeled to perm(v).
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 it is consistent (relabeling twice will give the same result).
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()
˓→needs sage.modules[0 1 0][1 0 1][0 1 0]#␣>>> from sage.all import *>>> G = graphs.PathGraph(Integer(3))>>> G.am()
˓→needs sage.modules[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()
˓→needs sage.modules[0 0 1][0 0 1][1 1 0]#␣>>> from sage.all import *>>> G.relabel({Integer(1):Integer(2),Integer(2):Integer(1)}, inplace=False).
˓→am()# needs sage.modules[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):

336

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G.relabel({1:2,2:1}, inplace=False,
˓→needs sage.modules....:
complete_partial_function=False).am()
Traceback (most recent call last):...
KeyError: 0#␣>>> from sage.all import *>>> G.relabel({Integer(1):Integer(2),Integer(2):Integer(1)}, inplace=False,˓→# needs sage.modules...
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()
˓→needs sage.modules[0 0 1][0 0 1][1 1 0]#␣>>> from sage.all import *>>> G.relabel([Integer(0),Integer(2),Integer(1)], inplace=False).am()˓→# needs sage.modules[0 0 1][0 0 1][1 1 0]␣

Relabeling using an iterable:
sage: G.relabel(iter((0,2,1)), inplace=False).am()
˓→needs sage.modules[0 0 1][0 0 1][1 1 0]#␣>>> from sage.all import *>>> G.relabel(iter((Integer(0),Integer(2),Integer(1))), inplace=False).am()˓→# needs sage.modules[0 0 1][0 0 1][1 1 0]␣

Relabeling using a Sage permutation:
sage: G = graphs.PathGraph(3)sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup˓→needs sage.groups
sage: S = SymmetricGroup(3)˓→needs sage.groups
sage: gamma = S( (1,2) )˓→needs sage.groups
sage: G.relabel(gamma, inplace=False).am()
˓→needs sage.groups sage.modules

#␣
#␣
#␣
#␣

(continues on next page)

1.1. Generic graphs (common to directed/undirected)

337

Graph Theory, Release 10.4

(continued from previous page)[0 0 1][0 0 1][1 1 0]sage: # needs sage.groups
sage: C5 = graphs.CycleGraph(5)sage: C5.relabel({u: str(u) for u in C5}, inplace=True)
sage: ar = C5.automorphism_group().random_element()
sage: R = C5.relabel(ar, inplace=False)
sage: perm = C5.is_isomorphic(R, certificate=True)[1]sage: perm == {u: ar(u) for u in C5}
True>>> from sage.all import *>>> G = graphs.PathGraph(Integer(3))>>> from sage.groups.perm_gps.permgroup_named import SymmetricGroup˓→needs sage.groups>>> S = SymmetricGroup(Integer(3))˓→# needs sage.groups>>> gamma = S( (1,2) )˓→needs sage.groups>>> G.relabel(gamma, inplace=False).am()
˓→needs sage.groups sage.modules[0 0 1][0 0 1][1 1 0]

#␣
␣
#␣
#␣

>>> # needs sage.groups>>> C5 = graphs.CycleGraph(Integer(5))>>> C5.relabel({u: str(u) for u in C5}, inplace=True)>>> ar = C5.automorphism_group().random_element()>>> R = C5.relabel(ar, inplace=False)>>> perm = C5.is_isomorphic(R, certificate=True)[Integer(1)]>>> perm == {u: ar(u) for u in C5}
True

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(sort=True)).random_element())
sage: D.sources()[1, 4]>>> from sage.all import *>>> set_random_seed(Integer(0)) # Results are reproducible>>> D = DiGraph({Integer(1): [Integer(2)], Integer(3): [Integer(4)]})>>> D.relabel(Permutations(D.vertices(sort=True)).random_element())>>> D.sources()[1, 4]

Relabeling using an injective function:
sage: G.edges(sort=True)[(0, 1, None), (1, 2, None)]sage: H = G.relabel(lambda i: i+10, inplace=False)(continues on next page)

338

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: H.vertices(sort=True)[10, 11, 12]
sage: H.edges(sort=True)[(10, 11, None), (11, 12, None)]>>> from sage.all import *>>> G.edges(sort=True)[(0, 1, None), (1, 2, None)]>>> H = G.relabel(lambda i: i+Integer(10), inplace=False)>>> H.vertices(sort=True)[10, 11, 12]>>> H.edges(sort=True)[(10, 11, None), (11, 12, None)]

Relabeling using a non injective function has no meaning:sage: G.edges(sort=True)[(0, 1, None), (1, 2, None)]sage: G.relabel(lambda i: 0, inplace=False)
Traceback (most recent call last):...
NotImplementedError: Non injective relabeling>>> from sage.all import *>>> G.edges(sort=True)[(0, 1, None), (1, 2, None)]>>> G.relabel(lambda i: Integer(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(sort=True)[(0, 1, None), (1, 2, None)]sage: G.relabel(lambda i: 0, check_input = False)
sage: G.edges(sort=True)[]>>> from sage.all import *>>> G.edges(sort=True)[(0, 1, None), (1, 2, None)]>>> G.relabel(lambda i: Integer(0), check_input = False)>>> G.edges(sort=True)[]

Recovering the relabeling with return_map:
sage: G = graphs.CubeGraph(3)sage: G.relabel(range(8), return_map=True){ 000 : 0,001 : 1,010 : 2,011 : 3,
100 : 4,
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

339

Graph Theory, Release 10.4

(continued from previous page)

101 : 5,
110 : 6,
111 : 7}>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(3))>>> G.relabel(range(Integer(8)), return_map=True){ 000 : 0,001 : 1,010 : 2,011 : 3,
100 : 4,101 : 5,
110 : 6,
111 : 7}

When no permutation is given, the relabeling is done to integers from 0 to N-1 but in an arbitrary order:
sage: G = graphs.CubeGraph(3)sage: G.vertices(sort=True)[ 000 , 001 , 010 , 011 , 100 ,sage: G.relabel()
sage: G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7]

101 ,

110 ,

111 ]

>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(3))>>> G.vertices(sort=True)[ 000 , 001 , 010 , 011 , 100 , 101 ,>>> G.relabel()>>> G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7]

110 ,

111 ]

In the above case, the mapping is arbitrary but consistent:
sage: map1 = G.relabel(inplace=False, return_map=True)
sage: map2 = G.relabel(inplace=False, return_map=True)
sage: map1 == map2
True>>> from sage.all import *>>> map1 = G.relabel(inplace=False, return_map=True)>>> map2 = G.relabel(inplace=False, return_map=True)>>> map1 == map2
True
sage: G = graphs.PathGraph(3)sage: G.relabel(lambda i: i+10, return_map=True){0: 10, 1: 11, 2: 12}>>> from sage.all import *>>> G = graphs.PathGraph(Integer(3))>>> G.relabel(lambda i: i+Integer(10), return_map=True){0: 10, 1: 11, 2: 12}

340

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

remove_loops(vertices=None)
Remove loops on vertices in vertices.
If vertices is None, removes all 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(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: G.remove_loops()
sage: G.edges(sort=True, 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(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]
sage: D.remove_loops()
sage: D.edges(sort=True, labels=False)[(2, 3)]sage: D.allows_loops()
True
sage: D.has_loops()
False>>> from sage.all import *>>> G = Graph(Integer(4), loops=True)>>> G.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> G.edges(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]>>> G.remove_loops()>>> G.edges(sort=True, labels=False)[(2, 3)]>>> G.allows_loops()
True>>> G.has_loops()
False>>> D = DiGraph(Integer(4), loops=True)>>> D.add_edges([(Integer(0), Integer(0)), (Integer(1), Integer(1)),␣
˓→(Integer(2), Integer(2)), (Integer(3), Integer(3)), (Integer(2),␣
˓→Integer(3))])>>> D.edges(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (3, 3)]>>> D.remove_loops()>>> D.edges(sort=True, labels=False)[(2, 3)]>>> D.allows_loops()
True>>> D.has_loops()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

341

Graph Theory, Release 10.4

(continued from previous page)

False

remove_multiple_edges()
Remove all multiple edges, retaining one edge for each.
See also:
See also allow_multiple_edges()
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(sort=True, labels=False)[(0, 1), (0, 1), (0, 1), (0, 1), (1, 2)]>>> from sage.all import *>>> G = Graph(multiedges=True, sparse=True)>>> G.add_edges([(Integer(0),Integer(1)), (Integer(0),Integer(1)),␣
˓→(Integer(0),Integer(1)), (Integer(0),Integer(1)), (Integer(1),Integer(2))])>>> G.edges(sort=True, labels=False)[(0, 1), (0, 1), (0, 1), (0, 1), (1, 2)]
sage: G.remove_multiple_edges()sage: G.edges(sort=True, labels=False)[(0, 1), (1, 2)]>>> from sage.all import *>>> G.remove_multiple_edges()>>> G.edges(sort=True, 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(sort=True, labels=False)[(0, 1), (0, 1), (0, 1), (0, 1), (1, 2)]
sage: D.remove_multiple_edges()sage: D.edges(sort=True, labels=False)[(0, 1), (1, 2)]>>> from sage.all import *>>> D = DiGraph(multiedges=True, sparse=True)>>> D.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(0),␣
˓→Integer(1), Integer(2)), (Integer(0), Integer(1), Integer(3)), (Integer(0),␣
˓→Integer(1), Integer(4)), (Integer(1), Integer(2), None)])>>> D.edges(sort=True, labels=False)[(0, 1), (0, 1), (0, 1), (0, 1), (1, 2)]>>> D.remove_multiple_edges()>>> D.edges(sort=True, labels=False)[(0, 1), (1, 2)]rooted_product(G, H, root=None)
Return the rooted product of 𝐺 and 𝐻.
The rooted product of two graphs 𝐺 and 𝐻 is the graph 𝑅 defined as follows: take a copy of 𝐺 and |𝑉 (𝐺)|copies of 𝐻, and for every vertex 𝑔𝑖 of 𝐺, identify 𝑔𝑖 with the root of the 𝑖-th copy of 𝐻. Mode formally, let
342

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

𝑉 (𝐺) = {𝑔1 , 𝑔2 , . . . , 𝑔𝑛 }, 𝑉 (𝐻) = {ℎ1 , ℎ2 , . . . , ℎ𝑚 }, and let ℎ1 be the root vertex of 𝐻. The vertex set
𝑉 (𝑅) is equal to the cartesian product of the sets of vertices 𝑉 (𝐺) and 𝑉 (𝐻), that is 𝑉 (𝑅) = {(𝑔𝑖 , ℎ𝑗 ) : 𝑔𝑖 ∈𝑉 (𝐺), ℎ𝑗 ∈ 𝑉 (𝐻)}. The edge set 𝐸(𝑅) is the union of the edges of a copy of 𝐺, that is {((𝑔𝑖 , ℎ1 ), (𝑔𝑗 , ℎ1 )) :(𝑔𝑖 , 𝑔𝑗 ) ∈ 𝐸(𝐺)}, and the edges of the copies of 𝐻 for every 𝑔𝑖 ∈ 𝑉 (𝐺), that is {((𝑔𝑖 , ℎ𝑗 ), (𝑔𝑖 , ℎ𝑘 )) :(ℎ𝑗 , ℎ𝑘 ) ∈ 𝑉 (𝐻)}.
See Wikipedia article Rooted_product_of_graphs for more details.
See also:• cartesian_product() – return the cartesian product of two graphs• graph_products – a module on graph products
EXAMPLES:
The rooted product of two trees is a tree:
sage: T1 = graphs.RandomTree(7)sage: T2 = graphs.RandomTree(8)sage: T = T1.rooted_product(T2)sage: T.is_tree()True>>> from sage.all import *>>> T1 = graphs.RandomTree(Integer(7))>>> T2 = graphs.RandomTree(Integer(8))>>> T = T1.rooted_product(T2)>>> T.is_tree()True

The rooted product of 𝐺 and 𝐻 depends on the selected root in 𝐻:
sage: G = graphs.CycleGraph(4)sage: H = graphs.PathGraph(3)sage: R1 = G.rooted_product(H, root=0)
sage: R2 = G.rooted_product(H, root=1)
sage: R1.is_isomorphic(R2)
False
sage: sorted(R1.degree())[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
sage: sorted(R2.degree())[1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> H = graphs.PathGraph(Integer(3))>>> R1 = G.rooted_product(H, root=Integer(0))>>> R2 = G.rooted_product(H, root=Integer(1))>>> R1.is_isomorphic(R2)
False>>> sorted(R1.degree())[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]>>> sorted(R2.degree())[1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]

The domination number of the rooted product of any graph 𝐺 and a path of order 2 is the order of 𝐺:

1.1. Generic graphs (common to directed/undirected)

343

Graph Theory, Release 10.4

sage: G = graphs.RandomGNP(20, .3)
sage: P = graphs.PathGraph(2)sage: R = G.rooted_product(P)sage: len(R.dominating_set()) == G.order()˓→# needs sage.numerical.mip
True
sage: G = digraphs.RandomDirectedGNP(20, .3)
sage: P = digraphs.Path(2)sage: R = G.rooted_product(P)sage: len(R.dominating_set()) == G.order()˓→# needs sage.numerical.mip
True

␣

␣

>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(20), RealNumber( .3 ))>>> P = graphs.PathGraph(Integer(2))>>> R = G.rooted_product(P)>>> len(R.dominating_set()) == G.order()˓→# needs sage.numerical.mip
True>>> G = digraphs.RandomDirectedGNP(Integer(20), RealNumber( .3 ))>>> P = digraphs.Path(Integer(2))>>> R = G.rooted_product(P)>>> len(R.dominating_set()) == G.order()˓→# needs sage.numerical.mip
True

The rooted product of two graphs is a subgraph of the cartesian product of the same two graphs:
sage: G = graphs.RandomGNP(6, .4)
sage: H = graphs.RandomGNP(7, .4)
sage: R = G.rooted_product(H)sage: C = G.cartesian_product(H)sage: R.is_subgraph(C, induced=False)
True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(6), RealNumber( .4 ))>>> H = graphs.RandomGNP(Integer(7), RealNumber( .4 ))>>> R = G.rooted_product(H)>>> C = G.cartesian_product(H)>>> R.is_subgraph(C, induced=False)
True

Corner cases:
sage: Graph().rooted_product(Graph())
Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0␣˓→vertices
sage: Graph(1).rooted_product(Graph())
Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0␣˓→vertices
sage: Graph().rooted_product(Graph(1))
Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0␣˓→vertices
sage: Graph(1).rooted_product(Graph(1))
Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex

344

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> Graph().rooted_product(Graph())
Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0␣˓→vertices>>> Graph(Integer(1)).rooted_product(Graph())
Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0␣˓→vertices>>> Graph().rooted_product(Graph(Integer(1)))
Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0␣˓→vertices>>> Graph(Integer(1)).rooted_product(Graph(Integer(1)))
Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex

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: d = {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]}sage: SD = DiGraph(d, 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, needs sage.plot>>> from sage.all import *>>> d = {Integer(1): [Integer(18), Integer(2)], Integer(2): [Integer(5),␣
˓→Integer(3)], Integer(3): [Integer(4), Integer(6)], Integer(4): [Integer(7),␣
˓→Integer(2)], Integer(5): [Integer(4)],...
Integer(6): [Integer(13), Integer(12)], Integer(7): [Integer(18),␣
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

345

Graph Theory, Release 10.4

(continued from previous page)

Integer(8), Integer(10)], Integer(8): [Integer(6), Integer(9), Integer(10)],
˓→ Integer(9): [Integer(6)],...
Integer(10): [Integer(11), Integer(13)], Integer(11): [Integer(12)],␣
˓→Integer(12): [Integer(13)], Integer(13): [Integer(17), Integer(14)],...
Integer(14): [Integer(16), Integer(15)], Integer(15): [Integer(2)],␣
˓→Integer(16): [Integer(13)], Integer(17): [Integer(15), Integer(13)],␣
˓→Integer(18): [Integer(13)]}>>> SD = DiGraph(d, sparse=True)>>> SD.set_edge_label(Integer(1), Integer(18), discrete )>>> SD.set_edge_label(Integer(4), Integer(7), discrete )>>> SD.set_edge_label(Integer(2), Integer(5), h = 0 )>>> SD.set_edge_label(Integer(7), Integer(18), h = 0 )>>> SD.set_edge_label(Integer(7), Integer(10), aut )>>> SD.set_edge_label(Integer(8), Integer(10), aut )>>> SD.set_edge_label(Integer(8), Integer(9), label )>>> SD.set_edge_label(Integer(8), Integer(6), no label )>>> SD.set_edge_label(Integer(13), Integer(17), k > h )>>> SD.set_edge_label(Integer(13), Integer(14), k = h )>>> SD.set_edge_label(Integer(17), Integer(15), v_k finite )>>> SD.set_edge_label(Integer(14), Integer(15), v_k m.c.r. )>>> posn = {Integer(1): [Integer(3), -Integer(3)], Integer(2): [Integer(0),␣
˓→Integer(2)], Integer(3): [Integer(0), Integer(13)], Integer(4): [Integer(3),˓→ Integer(9)],...
Integer(5): [Integer(3), Integer(3)], Integer(6): [Integer(16),␣
˓→Integer(13)], Integer(7): [Integer(6), Integer(1)], Integer(8): [Integer(6),˓→ Integer(6)],...
Integer(9): [Integer(6), Integer(11)], Integer(10): [Integer(9),␣
˓→Integer(1)], Integer(11): [Integer(10), Integer(6)], Integer(12):␣
˓→[Integer(13), Integer(6)],...
Integer(13): [Integer(16), Integer(2)], Integer(14): [Integer(10),
˓→ -Integer(6)], Integer(15): [Integer(0), -Integer(10)], Integer(16):␣
˓→[Integer(14), -Integer(6)],...
Integer(17): [Integer(16), -Integer(10)], Integer(18):␣
˓→[Integer(6), -Integer(4)]}>>> SD.plot(pos=posn, vertex_size=Integer(400), vertex_colors={ #FFFFFF
˓→ :list(range(Integer(1),Integer(19)))}, edge_labels=True).show()# long␣˓→time, needs sage.plot
˓→

sage: G = graphs.HeawoodGraph()
sage: for u,v,l in G.edges(sort=False):....: G.set_edge_label(u, v, ( + str(u) +sage: G.edges(sort=True)[(0, 1, (0,1) ),(0, 5, (0,5) ),(0, 13, (0,13) ),...
(11, 12, (11,12) ),(12, 13, (12,13) )]>>> from sage.all import *>>> G = graphs.HeawoodGraph()>>> for u,v,l in G.edges(sort=False):... G.set_edge_label(u, v, ( + str(u) +>>> G.edges(sort=True)[(0, 1, (0,1) ),(0, 5, (0,5) ),,,+ str(v) ++ str(v) +

) )

) )

(continues on next page)

346

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)(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(sort=True)[(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 )Traceback (most recent call last):...
RuntimeError: cannot set edge label, since there are multiple edges from 0 to␣˓→0>>> from sage.all import *>>> g = Graph({Integer(0): [Integer(0), Integer(1), Integer(1), Integer(2)]},␣
˓→loops=True, multiedges=True, sparse=True)>>> g.set_edge_label(Integer(0), Integer(0), test )>>> g.edges(sort=True)[(0, 0, test ), (0, 1, None), (0, 1, None), (0, 2, None)]>>> g.add_edge(Integer(0), Integer(0), test2 )>>> g.set_edge_label(Integer(0),Integer(0), test3 )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)]>>> from sage.all import *>>> dg = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(0)]},␣
˓→sparse=True)>>> dg.set_edge_label(Integer(0), Integer(1), Integer(5))>>> dg.set_edge_label(Integer(1), Integer(0), Integer(9))>>> dg.outgoing_edges(Integer(1))[(1, 0, 9)]>>> dg.incoming_edges(Integer(1))[(0, 1, 5)]>>> dg.outgoing_edges(Integer(0))[(0, 1, 5)]>>> dg.incoming_edges(Integer(0))[(1, 0, 9)]

1.1. Generic graphs (common to directed/undirected)

347

Graph Theory, Release 10.4

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>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1): Integer(1)}}, sparse=True)>>> G.num_edges()1>>> G.set_edge_label(Integer(0), Integer(1), Integer(1))>>> G.num_edges()1

set_embedding(embedding)Set a combinatorial embedding dictionary to _embedding attribute.
The dictionary embedding represents a combinatorial embedding of self and is organized as a mappingfrom vertex labels to list of vertex neighbors in clockwise order.
Parameter embedding is error-checked for validity.
Warning: Combinatorial embeddings are defined for simple graphs only (i.e., without loops or multiple
edges). Therefore, an error is raised when this method is used for a graph with loops or multiple edges.
INPUT:• embedding – dictionary representing a combinatorial embedding of self. Format: “{v1: [v2,v3],
v2: [v1], v3: [v1]}” (clockwise ordering of neighbors at each vertex).
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.set_embedding({0: [1, 5, 4], 1: [0, 2, 6], 2: [1, 3, 7],....:
3: [8, 2, 4], 4: [0, 9, 3], 5: [0, 8, 7],....:
6: [8, 1, 9], 7: [9, 2, 5], 8: [3, 5, 6],....:
9: [4, 6, 7]})sage: G.set_embedding({ s : [1, 5, 4], 1: [0, 2, 6], 2: [1, 3, 7],....:
3: [8, 2, 4], 4: [0, 9, 3], 5: [0, 8, 7],....:
6: [8, 1, 9], 7: [9, 2, 5], 8: [3, 5, 6],....:
9: [4, 6, 7]})
Traceback (most recent call last):...
ValueError: vertices in [ s ] from the embedding do not belong to the graph>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.set_embedding({Integer(0): [Integer(1), Integer(5), Integer(4)],␣
˓→Integer(1): [Integer(0), Integer(2), Integer(6)], Integer(2): [Integer(1),␣
˓→Integer(3), Integer(7)],...
Integer(3): [Integer(8), Integer(2), Integer(4)],␣
˓→Integer(4): [Integer(0), Integer(9), Integer(3)], Integer(5): [Integer(0),␣
˓→Integer(8), Integer(7)],...
Integer(6): [Integer(8), Integer(1), Integer(9)],␣
˓→Integer(7): [Integer(9), Integer(2), Integer(5)], Integer(8): [Integer(3),␣
(continues on next page)

348

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Integer(5), Integer(6)],...
Integer(9): [Integer(4), Integer(6), Integer(7)]})>>> G.set_embedding({ s : [Integer(1), Integer(5), Integer(4)], Integer(1):␣
˓→[Integer(0), Integer(2), Integer(6)], Integer(2): [Integer(1), Integer(3),␣
˓→Integer(7)],...
Integer(3): [Integer(8), Integer(2), Integer(4)],␣
˓→Integer(4): [Integer(0), Integer(9), Integer(3)], Integer(5): [Integer(0),␣
˓→Integer(8), Integer(7)],...
Integer(6): [Integer(8), Integer(1), Integer(9)],␣
˓→Integer(7): [Integer(9), Integer(2), Integer(5)], Integer(8): [Integer(3),␣
˓→Integer(5), Integer(6)],...
Integer(9): [Integer(4), Integer(6), Integer(7)]})
Traceback (most recent call last):...
ValueError: vertices in [ s ] from the embedding do not belong to the graph˓→

set_latex_options(**kwds)
Set multiple options for rendering a graph with LaTeX.
INPUT:• kwds – any number of option/value pairs to set many graph latex options at once (a variable number,in any order). Existing values are overwritten, new values are added. Existing values can be clearedby setting the value to None. Possible options are documented at sage.graphs.graph_latex.
GraphLatex.set_option().
This method is a convenience for setting the options of a graph directly on an instance of the graph. For afull 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 )˓→needs sage.plot
sage: opts = g.latex_options()
˓→needs sage.plot
sage: opts.get_option( tkz_style )˓→needs sage.plot
Welsh>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.set_latex_options(tkz_style= Welsh )˓→needs sage.plot>>> opts = g.latex_options()
˓→needs sage.plot>>> opts.get_option( tkz_style )˓→needs sage.plot
Welsh

#␣
#␣
#␣

#␣
#␣
#␣

set_pos(pos, dim=2)
Set the position dictionary.
The position dictionary specifies the coordinates of each vertex.
INPUT:• pos – a position dictionary for the vertices of the (di)graph1.1. Generic graphs (common to directed/undirected)

349

Graph Theory, Release 10.4

• dim – integer (default: 2); the number of coordinates per vertex
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.get_pos(){0: (..., ...),...
9: (..., ...)}>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.get_pos(){0: (..., ...),...
9: (..., ...)}The method get_pos() check the position dictionary so that invalid positioning are ignored:sage: G.set_pos(dict(enumerate( abcdefghi )))sage: P = G.plot() # positions are ignored
˓→needs sage.plot
sage: G.get_pos() is None˓→needs sage.plot
True>>> from sage.all import *>>> G.set_pos(dict(enumerate( abcdefghi )))>>> P = G.plot() # positions are ignored
˓→needs sage.plot>>> G.get_pos() is None˓→needs sage.plot
True

#␣
#␣

#␣
#␣

set_vertex(vertex, object)
Associate an arbitrary object with a vertex.
INPUT:• vertex – which vertex• object – object to associate to vertex
EXAMPLES:
sage: T = graphs.TetrahedralGraph()
sage: T.vertices(sort=True)[0, 1, 2, 3]
sage: T.set_vertex(1, graphs.FlowerSnark())
sage: T.get_vertex(1)Flower Snark: Graph on 20 vertices
sage: T.set_vertex(4, foo )Traceback (most recent call last):...
ValueError: vertex (4) not in the graph>>> from sage.all import *>>> T = graphs.TetrahedralGraph()(continues on next page)

350

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> T.vertices(sort=True)[0, 1, 2, 3]>>> T.set_vertex(Integer(1), graphs.FlowerSnark())>>> T.get_vertex(Integer(1))
Flower Snark: Graph on 20 vertices>>> T.set_vertex(Integer(4), foo )Traceback (most recent call last):...
ValueError: vertex (4) not in the graphset_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(sort=True)[0, 1, 2, 3]
sage: T.set_vertices(d)sage: T.get_vertex(1)Flower Snark: Graph on 20 vertices>>> from sage.all import *>>> d = {Integer(0): graphs.DodecahedralGraph(), Integer(1): graphs.
˓→FlowerSnark(), Integer(2): graphs.MoebiusKantorGraph(), Integer(3): graphs.
˓→PetersenGraph()}>>> d[Integer(2)]Moebius-Kantor Graph: Graph on 16 vertices>>> T = graphs.TetrahedralGraph()>>> T.vertices(sort=True)[0, 1, 2, 3]>>> T.set_vertices(d)>>> T.get_vertex(Integer(1))
Flower Snark: Graph on 20 vertices

shortest_path(u, v, by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return a list of vertices representing some shortest path from u to v.
If there is no path from 𝑢 to 𝑣, the returned list is empty.
For more information and more examples, see shortest_paths() (the inputs are very similar).
INPUT:• u, v – the start and the end vertices of the paths• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• algorithm – string (default: None); one of the following algorithms:–

BFS : performs a BFS from u. Does not work with edge weights.

1.1. Generic graphs (common to directed/undirected)

351

Graph Theory, Release 10.4–

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 withpositive weights.

–

Dijkstra_Bid_NetworkX : performs a Dijkstra visit from u and from v (NetworkX implementation). 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 alsowith negative weights, if there is no negative cycle.

– None (default): Sage chooses the best algorithm:
Dijkstra_Bid otherwise.

BFS_Bid

if by_weight is False,

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 negative weights
before running the algorithm. If there are, the user should explicitly input algorithm= Bellman-Ford_Boost .
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber 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 )˓→needs networkx[4, 3, 2, 1, 8]
sage: D.shortest_path(4, 8, algorithm= Dijkstra_Bid_NetworkX )˓→needs 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
˓→needs sage.plot
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,

#␣

#␣

#␣

#␣

(continues on next page)352

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs networkx....:
algorithm= Dijkstra_NetworkX )[0, 1, 2, 3]
sage: G.shortest_path(0, 3, by_weight=True,
˓→needs networkx....:
algorithm= Dijkstra_Bid_NetworkX )[0, 1, 2, 3]˓→#␣>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> D.shortest_path(Integer(4), Integer(9))[4, 17, 16, 12, 13, 9]>>> D.shortest_path(Integer(4), Integer(9), algorithm= BFS )[4, 3, 2, 1, 8, 9]>>> D.shortest_path(Integer(4), Integer(8), algorithm= Dijkstra_NetworkX )␣˓→# needs networkx[4, 3, 2, 1, 8]>>> D.shortest_path(Integer(4), Integer(8), algorithm= Dijkstra_Bid_NetworkX
˓→ )# needs networkx[4, 3, 2, 1, 8]>>> D.shortest_path(Integer(4), Integer(9), algorithm= Dijkstra_Bid )[4, 3, 19, 0, 10, 9]>>> D.shortest_path(Integer(5), Integer(5))[5]>>> D.delete_edges(D.edges_incident(Integer(13)))>>> D.shortest_path(Integer(13), Integer(4))[]>>> G = Graph({Integer(0): {Integer(1): Integer(1)}, Integer(1): {Integer(2):␣
˓→Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3): {Integer(4):␣
˓→Integer(2)}, Integer(4): {Integer(0): Integer(2)}},...
sparse=True)>>> G.plot(edge_labels=True).show()# long time#␣˓→needs sage.plot>>> G.shortest_path(Integer(0), Integer(3))[0, 4, 3]>>> G.shortest_path(Integer(0), Integer(3), by_weight=True)[0, 1, 2, 3]>>> G.shortest_path(Integer(0), Integer(3), by_weight=True,␣˓→# needs networkx...
algorithm= Dijkstra_NetworkX )[0, 1, 2, 3]>>> G.shortest_path(Integer(0), Integer(3), by_weight=True,␣˓→# needs networkx...
algorithm= Dijkstra_Bid_NetworkX )[0, 1, 2, 3]

Todo: Add options to return a path as a list of edges with or without edge labels. This can be useful in(di)graphs with multiple edges.
shortest_path_all_pairs(by_weight=False, algorithm=None, weight_function=None,check_weight=True)
Return a shortest path between each pair of vertices.
INPUT:

1.1. Generic graphs (common to directed/undirected)

353

Graph Theory, Release 10.4

• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• algorithm – string (default: None); one of the following algorithms:–

BFS : the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False.

–

Floyd-Warshall-Cython : 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).

–

Floyd-Warshall_Boost : the Boost implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).

–

Floyd-Warshall_SciPy : the SciPy 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 withweighted 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_Boost otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
OUTPUT:
A tuple (dist, pred). They are both dicts of dicts. The first indicates the length dist[u][v] of theshortest weighted path from 𝑢 to 𝑣. The second is a compact representation of all the paths - it indicates thepredecessor pred[u][v] of 𝑣 in the shortest path from 𝑢 to 𝑣.
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 thetime is actually spent building the final double dictionary. Everything on the subject is to be found in the
distances_all_pairs module.
EXAMPLES:
Some standard examples (see shortest_paths() for more examples on how to use the input variables):sage: G = Graph({0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}},␣
˓→sparse=True)
sage: G.plot(edge_labels=True).show()# long time
˓→needs sage.plot#␣(continues on next page)354

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

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}}>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1): Integer(1)}, Integer(1): {Integer(2):␣
˓→Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3): {Integer(4):␣
˓→Integer(2)}, Integer(4): {Integer(0): Integer(2)}}, sparse=True)>>> G.plot(edge_labels=True).show()# long time#␣˓→needs sage.plot>>> dist, pred = G.shortest_path_all_pairs(by_weight = True)>>> 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}}>>> 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}}>>> pred[Integer(0)]{0: None, 1: 0, 2: 1, 3: 2, 4: 0}>>> G = Graph({Integer(0): {Integer(1): { weight :Integer(1)}}, Integer(1):˓→{Integer(2): { weight :Integer(1)}}, Integer(2): {Integer(3): { weight(continues on next page)

1.1. Generic graphs (common to directed/undirected)

355

Graph Theory, Release 10.4

(continued from previous page):Integer(1)}},...
Integer(3): {Integer(4): { weight :Integer(2)}}, Integer(4):˓→{Integer(0): { weight :Integer(2)}}}, sparse=True)>>> dist, pred = G.shortest_path_all_pairs(weight_function=lambda e:␣
˓→e[Integer(2)][ weight ])>>> 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}}>>> pred{0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0},
1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0},
2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3},
3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3},
4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}}
˓→

So for example the shortest weighted path from 0 to 3 is obtained as follows. The predecessor of 3 ispred[0][3] == 2, the predecessor of 2 is pred[0][2] == 1, and the predecessor of 1 ispred[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}})>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1):None}, Integer(1): {Integer(2):None},␣
˓→Integer(2): {Integer(3): Integer(1)}, Integer(3): {Integer(4): Integer(2)},␣
˓→Integer(4): {Integer(0): Integer(2)}}, sparse=True)>>> 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},(continues on next page)

356

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

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}})>>> G.shortest_path_all_pairs(weight_function=lambda e:(e[Integer(2)] if␣
˓→e[Integer(2)] is not None else Integer(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")
˓→needs networkx
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
˓→needs scipy
sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8
˓→needs networkx scipy
True>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5),Integer(5))>>> d1, _ = g.shortest_path_all_pairs(algorithm="BFS")>>> d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython")>>> d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")>>> d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
˓→needs networkx>>> d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")>>> d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")>>> d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")>>> d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
˓→needs scipy>>> d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8
˓→needs networkx scipy
True

#␣

#␣
#␣

#␣

#␣
#␣

Checking that distances are equal regardless of the algorithm used:
sage: g = digraphs.RandomDirectedGNM(6,12)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

357

Graph Theory, Release 10.4

(continued from previous page)

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")
˓→needs networkx
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
˓→needs scipy
sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8
˓→needs networkx scipy
True>>> from sage.all import *>>> g = digraphs.RandomDirectedGNM(Integer(6),Integer(12))>>> d1, _ = g.shortest_path_all_pairs(algorithm="BFS")>>> d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython")>>> d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")>>> d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
˓→needs networkx>>> d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")>>> d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")>>> d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")>>> d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
˓→needs scipy>>> d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8
˓→needs networkx scipy
True

#␣

#␣
#␣

#␣

#␣
#␣

Checking that weighted distances are equal regardless of the algorithm used:
sage: g = graphs.CompleteGraph(5)sage: import random
sage: for v, w in g.edges(labels=False, sort=False):....:
g.add_edge(v, w, random.uniform(1, 10))sage: d1, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
˓→needs networkx
sage: d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")
sage: d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")
sage: d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")
sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
˓→needs scipy
sage: d1 == d2 == d3 == d4 == d5 == d6
˓→needs networkx scipy
True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> import random>>> for v, w in g.edges(labels=False, sort=False):...
g.add_edge(v, w, random.uniform(Integer(1), Integer(10)))>>> d1, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python")>>> d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX")
˓→needs networkx

#␣

#␣
#␣

#␣

(continues on next page)

358

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost")>>> d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost")>>> d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost")>>> d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy")
˓→needs scipy>>> d1 == d2 == d3 == d4 == d5 == d6
˓→needs networkx scipy
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>>> from sage.all import *>>> dist, path = g.shortest_path_all_pairs(algorithm="BFS")>>> u,v = g.random_vertex(), g.random_vertex()>>> p = [v]>>> while p[Integer(0)] is not None:...
p.insert(Integer(0),path[u][p[Integer(0)]])>>> len(p) == dist[u][v] + Integer(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>>> from sage.all import *>>> g = DiGraph([(Integer(0),Integer(1),-Integer(2)),(Integer(1),Integer(0),˓→Integer(1))], weighted=True)>>> 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 )˓→needs 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}},#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

359

Graph Theory, Release 10.4

(continued from previous page){0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})sage: g.shortest_path_all_pairs(algorithm= Floyd-Warshall-Python )({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})sage: g.shortest_path_all_pairs(algorithm= Floyd-Warshall-Cython )({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}},{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})sage: g.shortest_path_all_pairs(algorithm= Floyd-Warshall_SciPy )˓→needs scipy({0: {0: 0.0, 1: 1.0, 2: 2.0}, 1: {1: 0.0, 2: 1.0}, 2: {2: 0.0}},{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})#␣>>> from sage.all import *>>> g = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2))])>>> 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}})>>> g.shortest_path_all_pairs(algorithm= Dijkstra_NetworkX )#␣˓→needs 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}})>>> 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}})>>> 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}})>>> 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}})>>> g.shortest_path_all_pairs(algorithm= Floyd-Warshall_SciPy )#␣˓→needs scipy({0: {0: 0.0, 1: 1.0, 2: 2.0}, 1: {1: 0.0, 2: 1.0}, 2: {2: 0.0}},{0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}})In order to change the default behavior if the graph is disconnected, we can use default values with dictionaries:
sage: G = 2*graphs.PathGraph(2)sage: d,_ = G.shortest_path_all_pairs()
sage: import itertools
sage: from sage.rings.infinity import Infinity
sage: for u,v in itertools.combinations(G.vertex_iterator(), 2):....:
print("dist({}, {}) = {}".format(u,v, d[u].get(v,+Infinity)))dist(0, 1) = 1
dist(0, 2) = +Infinity
dist(0, 3) = +Infinity
dist(1, 2) = +Infinity
dist(1, 3) = +Infinity
dist(2, 3) = 1>>> from sage.all import *>>> G = Integer(2)*graphs.PathGraph(Integer(2))>>> d,_ = G.shortest_path_all_pairs()>>> import itertools>>> from sage.rings.infinity import Infinity(continues on next page)360

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> for u,v in itertools.combinations(G.vertex_iterator(), Integer(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)
Return the minimal length of a path from u to v.
If there is no path from 𝑢 to 𝑣, returns Infinity.
For more information and more examples, we refer to shortest_path() and shortest_paths(),
which have very similar inputs.
INPUT:• u, v – the start and the end vertices of the paths• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• algorithm – string (default: None); one of the following algorithms:–

BFS : performs a BFS from u. Does not work with edge weights.

–

BFS_Bid : performs a BFS from u and from v. Does not work with edge weights.

–

Dijkstra_NetworkX : the Dijkstra algorithm, implemented in NetworkX. Works only withpositive weights.

–

Dijkstra_Bid_NetworkX : performs a Dijkstra visit from u and from v (NetworkX implementation). 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 alsowith negative weights, if there is no negative cycle.

– None (default): Sage chooses the best algorithm:
Dijkstra_Bid otherwise.

BFS_Bid

if by_weight is False,

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 negative weights
before running the algorithm. If there are, the user should explicitly input algorithm= Bellman-Ford_Boost .
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

361

Graph Theory, Release 10.4

Standard examples:sage: D = graphs.DodecahedralGraph()
sage: D.shortest_path_length(4, 9)
5
sage: D.shortest_path_length(4, 9, algorithm= BFS )5
sage: D.shortest_path_length(4, 9, algorithm= Dijkstra_NetworkX )˓→needs networkx
5
sage: D.shortest_path_length(4, 9, algorithm= Dijkstra_Bid_NetworkX )˓→needs 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
˓→needs sage.plot
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,
˓→needs networkx....:
algorithm= Dijkstra_NetworkX )3sage: G.shortest_path_length(0, 3, by_weight=True,
˓→needs networkx....:
algorithm= Dijkstra_Bid_NetworkX )
3

#␣

#␣

#␣

#␣

#␣

>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> D.shortest_path_length(Integer(4), Integer(9))
5>>> D.shortest_path_length(Integer(4), Integer(9), algorithm= BFS )5>>> D.shortest_path_length(Integer(4), Integer(9), algorithm= Dijkstra_
˓→NetworkX )# needs networkx
5>>> D.shortest_path_length(Integer(4), Integer(9), algorithm= Dijkstra_Bid_
˓→NetworkX )# needs networkx
5>>> D.shortest_path_length(Integer(4), Integer(9), algorithm= Dijkstra_Bid )5>>> D.shortest_path_length(Integer(4), Integer(9), algorithm= Bellman-Ford_˓→Boost )5>>> D.shortest_path_length(Integer(5), Integer(5))
0(continues on next page)362

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> D.delete_edges(D.edges_incident(Integer(13)))>>> D.shortest_path_length(Integer(13), Integer(4))+Infinity>>> G = Graph({Integer(0): {Integer(1): Integer(1)}, Integer(1): {Integer(2):␣
˓→Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3): {Integer(4):␣
˓→Integer(2)}, Integer(4): {Integer(0): Integer(2)}},...
sparse=True)>>> G.plot(edge_labels=True).show()# long time#␣˓→needs sage.plot>>> G.shortest_path_length(Integer(0), Integer(3))
2>>> G.shortest_path_length(Integer(0), Integer(3), by_weight=True)
3>>> G.shortest_path_length(Integer(0), Integer(3), by_weight=True,␣˓→# needs networkx...
algorithm= Dijkstra_NetworkX )3>>> G.shortest_path_length(Integer(0), Integer(3), by_weight=True,␣˓→# needs networkx...
algorithm= Dijkstra_Bid_NetworkX )3

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>>> from sage.all import *>>> G = DiGraph({Integer(0): {Integer(1): Integer(1)}, Integer(1):˓→{Integer(2): Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3):˓→{Integer(4): Integer(2)}, Integer(4): {Integer(0): -Integer(2)}},...
sparse=True)>>> G.shortest_path_length(Integer(4), Integer(1), by_weight=True,␣
˓→algorithm=None)
Traceback (most recent call last):...
ValueError: the graph contains an edge with negative weight>>> G.shortest_path_length(Integer(4), Integer(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

1.1. Generic graphs (common to directed/undirected)

363

Graph Theory, Release 10.4>>> from sage.all import *>>> G = DiGraph([(Integer(0),Integer(1),Integer(1)), (Integer(1),Integer(2),˓→Integer(1)), (Integer(0),Integer(3),Integer(1000)), (Integer(3),Integer(4),˓→Integer(3000)), (Integer(4),Integer(2),Integer(1000))])>>> G.shortest_path_length(Integer(0), Integer(2), by_weight=True,...
algorithm= Bellman-Ford_Boost )-1000>>> G.shortest_path_length(Integer(0), Integer(2), by_weight=True)2

shortest_path_lengths(u, by_weight=False, algorithm=None, weight_function=None,check_weight=True)
Return 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
from 𝑢.
For more information on the input variables and more examples, we refer to shortest_paths() which
has the same input variables.
INPUT:• u – the starting vertex• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• algorithm – string (default: None); 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 withpositive 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 withnegative weights, if there is no negative cycle).

– None (default): Sage chooses the best algorithm:
BFS if by_weight is False,
Dijkstra_Boost if all weights are positive, Bellman-Ford_Boost otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber 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}

364

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> D.shortest_path_lengths(Integer(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
˓→needs sage.plot
sage: G.shortest_path_lengths(0, by_weight=True){0: 0, 1: 1, 2: 2, 3: 3, 4: 2}#␣>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1): Integer(1)}, Integer(1): {Integer(2):␣
˓→Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3): {Integer(4):␣
˓→Integer(2)}, Integer(4): {Integer(0): Integer(2)}},...
sparse=True)>>> G.plot(edge_labels=True).show()# long time#␣˓→needs sage.plot>>> G.shortest_path_lengths(Integer(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 ,#␣˓→needs 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}>>> from sage.all import *>>> D = DiGraph([(Integer(0),Integer(1),{ weight :Integer(1)}), (Integer(1),˓→Integer(2),{ weight :Integer(3)}), (Integer(0),Integer(2),{ weight
˓→ :Integer(5)})])>>> weight_function = lambda e: e[Integer(2)][ weight ]>>> D.shortest_path_lengths(Integer(1), algorithm= Dijkstra_NetworkX ,␣˓→# needs networkx...
by_weight=False){1: 0, 2: 1}>>> D.shortest_path_lengths(Integer(0), weight_function=weight_function){0: 0, 1: 1, 2: 4}>>> D.shortest_path_lengths(Integer(1), weight_function=weight_function){1: 0, 2: 3}

Negative weights:
sage: D = DiGraph([(0,1,{ weight :-1}), (1,2,{ weight :3}), (0,2,{ weight :5}˓→)])(continues on next page)

1.1. Generic graphs (common to directed/undirected)

365Graph Theory, Release 10.4

(continued from previous page)

sage: D.shortest_path_lengths(0, weight_function=weight_function){0: 0, 1: -1, 2: 2}>>> from sage.all import *>>> D = DiGraph([(Integer(0),Integer(1),{ weight :-Integer(1)}), (Integer(1),˓→Integer(2),{ weight :Integer(3)}), (Integer(0),Integer(2),{ weight
˓→ :Integer(5)})])>>> D.shortest_path_lengths(Integer(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>>> from sage.all import *>>> D = DiGraph([(Integer(0),Integer(1),{ weight :-Integer(5)}), (Integer(1),˓→Integer(2),{ weight :Integer(3)}), (Integer(2),Integer(0),{ weight
˓→ :Integer(1)})])>>> D.shortest_path_lengths(Integer(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")
˓→needs 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
˓→needs networkx
True

#␣

#␣

>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5),Integer(5))>>> d1 = g.shortest_path_lengths((Integer(0),Integer(0)), algorithm="BFS")>>> d2 = g.shortest_path_lengths((Integer(0),Integer(0)), algorithm="Dijkstra_
˓→NetworkX")# needs networkx>>> d3 = g.shortest_path_lengths((Integer(0),Integer(0)), algorithm="Dijkstra_
˓→Boost")>>> d4 = g.shortest_path_lengths((Integer(0),Integer(0)), algorithm="Bellman˓→Ford_Boost")>>> d1 == d2 == d3 == d4#␣˓→needs networkx
True

shortest_paths(u, by_weight=False, algorithm=None, weight_function=None, check_weight=True,
cutoff=None)
Return a dictionary associating to each vertex v a shortest path from u to v, if it exists.
366

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

If 𝑢 and 𝑣 are not connected, vertex 𝑣 is not present in the dictionary.
INPUT:• u – the starting vertex• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• algorithm – string (default: None); 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 withpositive 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 withnegative weights, if there is no negative cycle).

– None (default): Sage chooses the best algorithm:
BFS if by_weight is False,
Dijkstra_Boost if all weights are positive, Bellman-Ford_Boost otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
• cutoff – integer (default: None); integer depth to stop search (used only if algorithm== BFS )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]}>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> D.shortest_paths(Integer(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

1.1. Generic graphs (common to directed/undirected)

367

Graph Theory, Release 10.4>>> from sage.all import *>>> all(D.subgraph(p).is_isomorphic(graphs.PathGraph(len(p))) for p in D.
˓→shortest_paths(Integer(0)).values())
Truesage: 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#␣˓→needs sage.plot
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]}>>> from sage.all import *>>> D.shortest_paths(Integer(0), cutoff=Integer(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]}>>> G = Graph( { Integer(0): {Integer(1): Integer(1)}, Integer(1):˓→{Integer(2): Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3):˓→{Integer(4): Integer(2)}, Integer(4): {Integer(0): Integer(2)} },␣
˓→sparse=True)>>> G.plot(edge_labels=True).show()# long time#␣˓→needs sage.plot>>> G.shortest_paths(Integer(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]}>>> from sage.all import *>>> D = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(3)),(Integer(0),Integer(2),Integer(5))])>>> D.shortest_paths(Integer(0)){0: [0], 1: [0, 1], 2: [0, 2]}>>> D.shortest_paths(Integer(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]}>>> from sage.all import *>>> D = DiGraph([(Integer(0),Integer(1),{ weight :Integer(1)}),(Integer(1),˓→Integer(2),{ weight :Integer(3)}),(Integer(0),Integer(2),{ weight(continues on next page)

368

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page):Integer(5)})])>>> weight_function = lambda e:e[Integer(2)][ weight ]>>> D.shortest_paths(Integer(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}
˓→)>>> from sage.all import *>>> D.shortest_paths(Integer(0), weight_function=lambda e:e[Integer(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 ,˓→needs networkx....:
weight_function=lambda e:e[2], check_weight=False)
Traceback (most recent call last):...
TypeError: unsupported operand type(s) for +: int and dict#␣>>> from sage.all import *>>> D.shortest_paths(Integer(0), algorithm= Dijkstra_NetworkX ,˓→# needs networkx...
weight_function=lambda e:e[Integer(2)], check_˓→weight=False)
Traceback (most recent call last):...
TypeError: unsupported operand type(s) for +: int and dict␣

Negative weights:
sage: D = DiGraph([(0,1,1),(1,2,-2),(0,2,4)])
sage: D.shortest_paths(0, by_weight=True){0: [0], 1: [0, 1], 2: [0, 1, 2]}>>> from sage.all import *>>> D = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(0),Integer(2),Integer(4))])>>> D.shortest_paths(Integer(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):(continues on next page)

1.1. Generic graphs (common to directed/undirected)

369

Graph Theory, Release 10.4

(continued from previous page)...
ValueError: the graph contains a negative cycle>>> from sage.all import *>>> D.add_edge(Integer(2),Integer(0),Integer(0))>>> D.shortest_paths(Integer(0), by_weight=True)
Traceback (most recent call last):...
ValueError: the graph contains a negative cycle

shortest_simple_paths(source, target, weight_function=None, by_weight=False, check_weight=True,algorithm=None, report_edges=False, labels=False, report_weight=False)
Return an iterator over the simple paths between a pair of vertices.
This method returns an iterator over the simple paths (i.e., without repetition) from source to target. By
default (by_weight is False), the paths are reported by increasing number of edges. When by_weightis True, the paths are reported by increasing weights.
In case of weighted graphs negative weights are not allowed.
If source is the same vertex as target, then [[source]] is returned – a list containing the 1-vertex,
0-edge path source.
By default Yen s algorithm [Yen1970] is used for undirected graphs and Feng s algorithm is used for
directed graphs [Feng2014].
The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels
is kept in case of multiedges.
INPUT:• source – a vertex of the graph, where to start• target – a vertex of the graph, where to end• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• check_weight – boolean (default: True); whether to check that the weight_function outputs
a number for each edge.
• algorithm – string (default: None); the algorithm to use in computing k shortest paths of self.
The following algorithms are supported:– "Yen" – Yen’s algorithm [Yen1970]– "Feng" – an improved version of Yen’s algorithm but that works only for directed graphs[Feng2014]• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or listof edges. When set to False, the labels parameter is ignored.
• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices.
Otherwise a list of edges along with its edge labels are used to represent the path.
• report_weight – boolean (default: False); if False, just the path between source and target is returned. Otherwise a tuple of path length and path is returned.

370

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

EXAMPLES:
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30),....:
(2, 5, 20), (3, 5, 10), (4, 5, 30)])
sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Yen"))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]
sage: list(g.shortest_simple_paths(1, 5, algorithm="Yen"))[[1, 2, 5], [1, 3, 5], [1, 4, 5]]
sage: list(g.shortest_simple_paths(1, 1))[[1]]
sage: list(g.shortest_simple_paths(1, 5, by_weight=True,....:
report_edges=True, report_weight=True,␣
˓→labels=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng",....:
report_edges=True, report_weight=True))[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_
˓→weight=True))[(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])]sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True))[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng",....:
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20),....:
(3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)])sage: list(g.shortest_simple_paths(1, 6, by_weight = True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]
sage: list(g.shortest_simple_paths(1, 6, algorithm="Yen"))[[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]]
sage: list(g.shortest_simple_paths(1, 6,....:
report_edges=True, report_weight=True,␣
˓→labels=True))[(1, [(1, 6, 100)]),(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])]sage: list(g.shortest_simple_paths(1, 6, by_weight=True,....:
report_edges=True, report_weight=True,␣
˓→labels=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]sage: list(g.shortest_simple_paths(1, 6, by_weight=True,....:
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)],[(1, 6, 100)]]
sage: list(g.shortest_simple_paths(1, 6, report_edges=True, labels=True))[[(1, 6, 100)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)]]1.1. Generic graphs (common to directed/undirected)

371

Graph Theory, Release 10.4>>> from sage.all import *>>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1),␣
˓→Integer(3), Integer(10)), (Integer(1), Integer(4), Integer(30)),...
(Integer(2), Integer(5), Integer(20)), (Integer(3),␣
˓→Integer(5), Integer(10)), (Integer(4), Integer(5), Integer(30))])>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,␣
˓→algorithm="Yen"))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), algorithm="Yen"))[[1, 2, 5], [1, 3, 5], [1, 4, 5]]>>> list(g.shortest_simple_paths(Integer(1), Integer(1)))[[1]]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,...
report_edges=True, report_weight=True,␣
˓→labels=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,␣
˓→algorithm="Feng",...
report_edges=True, report_weight=True))[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), report_edges=True,␣
˓→report_weight=True))[(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,␣
˓→report_edges=True))[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,␣
˓→algorithm="Feng",...
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]>>> g = Graph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3),˓→ Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2),␣
˓→Integer(5), Integer(20)),...
(Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5),˓→ Integer(30)), (Integer(1), Integer(6), Integer(100)), (Integer(5),␣
˓→Integer(6), Integer(5))])>>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight = True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), algorithm="Yen"))[[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]]>>> list(g.shortest_simple_paths(Integer(1), Integer(6),...
report_edges=True, report_weight=True,␣
˓→labels=True))[(1, [(1, 6, 100)]),(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight=True,...
report_edges=True, report_weight=True,␣
˓→labels=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight=True,(continues on next page)372

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)...
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)],[(1, 6, 100)]]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), report_edges=True,␣
˓→labels=True))[[(1, 6, 100)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)]]show(method='matplotlib', **kwds)
Show the (di)graph.
INPUT:• method – string (default: "matplotlib"); method to use to display the graph, either "matplotlib", or "js" to visualize it in a browser using d3.js.
• Any other argument supported by the drawing functions:– "matplotlib" – see GenericGraph.plot and sage.plot.graphics.Graphics.
show()– "js" – see gen_html_code()
EXAMPLES:
sage: C = graphs.CubeGraph(8)sage: P = C.plot(vertex_labels=False, vertex_size=0, graph_border=True)
˓→needs sage.plot
sage: P.show()# long time (3s on sage.math, 2011),␣
˓→needs sage.plot#␣>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(8))>>> P = C.plot(vertex_labels=False, vertex_size=Integer(0), graph_
˓→border=True)# needs sage.plot>>> P.show()# long time (3s on sage.math, 2011), needs␣
˓→sage.plot

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='threejs', **kwds)
Plot the graph and show the resulting plot.
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 insteadof spheres• vertex_colors – dictionary (default: None); 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).

1.1. Generic graphs (common to directed/undirected)

373

Graph Theory, Release 10.4

• edge_colors – dictionary (default: None); 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 andedge_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 – string (default: threejs ); the renderer to use among:–

threejs : interactive web-based 3D viewer using JavaScript and a WebGL renderer–jmol : interactive 3D viewer using Java–tachyon : ray tracer generating a static PNG image• xres – resolution• yres – resolution• **kwds – passed on to the rendering engine
EXAMPLES:
sage: G = graphs.CubeGraph(5)sage: G.show3d(iterations=500, edge_size=None, vertex_size=0.04)
˓→time, needs sage.plot# long␣

>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(5))>>> G.show3d(iterations=Integer(500), edge_size=None, vertex_size=RealNumber(
˓→ 0.04 ))# long time, needs sage.plot

We plot a fairly complicated Cayley graph:
sage: A5 = AlternatingGroup(5); A5
˓→needs sage.groups
Alternating group of order 5!/2 as a permutation group
sage: G = A5.cayley_graph()˓→needs sage.groups
sage: G.show3d(vertex_size=0.03,# long time
˓→needs sage.groups sage.plot....:
edge_size=0.01, edge_size2=0.02,....:
vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0),....:color_by_label=True, iterations=200)>>> from sage.all import *>>> A5 = AlternatingGroup(Integer(5)); A5˓→# needs sage.groups
Alternating group of order 5!/2 as a permutation group>>> G = A5.cayley_graph()˓→needs sage.groups>>> G.show3d(vertex_size=RealNumber( 0.03 ),# long time

#␣

#␣
#␣

␣

#␣
␣
(continues on next page)

374

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)# needs sage.groups sage.plot...
edge_size=RealNumber( 0.01 ), edge_size2=RealNumber( 0.02 ),...
vertex_colors={(Integer(1),Integer(1),Integer(1)): list(G)},␣
˓→bgcolor=(Integer(0),Integer(0),Integer(0)),...
color_by_label=True, iterations=Integer(200))˓→

Some Tachyon examples:sage: D = graphs.DodecahedralGraph()
sage: D.show3d(engine= tachyon )# long time
˓→needs sage.plot#␣>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> D.show3d(engine= tachyon )# long time
˓→needs sage.plot#␣

sage: G = graphs.PetersenGraph()
sage: G.show3d(engine= tachyon ,# long time
˓→needs sage.plot....:
vertex_colors={(0,0,1): list(G)})#␣>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.show3d(engine= tachyon ,# long time#␣˓→needs sage.plot...
vertex_colors={(Integer(0),Integer(0),Integer(1)): list(G)})
sage: C = graphs.CubeGraph(4)sage: C.show3d(engine= tachyon ,# long time
˓→needs sage.plot....:
edge_colors={(0,1,0): C.edges(sort=False)},....:vertex_colors={(1,1,1): list(C)}, bgcolor=(0,0,0))#␣>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(4))>>> C.show3d(engine= tachyon ,# long time#␣˓→needs sage.plot...
edge_colors={(Integer(0),Integer(1),Integer(0)): C.
˓→edges(sort=False)},...
vertex_colors={(Integer(1),Integer(1),Integer(1)): list(C)},␣
˓→bgcolor=(Integer(0),Integer(0),Integer(0)))
sage: K = graphs.CompleteGraph(3)sage: K.show3d(engine= tachyon ,# long time
˓→needs sage.plot....:
edge_colors={(1,0,0): [(0, 1, None)],....:(0, 1, 0): [(0, 2, None)],....:(0, 0, 1): [(1, 2, None)]})>>> from sage.all import *>>> K = graphs.CompleteGraph(Integer(3))>>> K.show3d(engine= tachyon ,# long time
˓→needs sage.plot#␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

375

Graph Theory, Release 10.4

(continued from previous page)...
edge_colors={(Integer(1),Integer(0),Integer(0)): [(Integer(0),␣
˓→Integer(1), None)],...
(Integer(0), Integer(1), Integer(0)): [(Integer(0),␣
˓→Integer(2), None)],...
(Integer(0), Integer(0), Integer(1)): [(Integer(1),␣
˓→Integer(2), None)]})size()
Return the number of edges.
Note that num_edges() also returns the number of edges in 𝐺.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.size()
15>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.size()15

spanning_trees_count(root_vertex=None)
Return the number of spanning trees in a graph.
In the case of a digraph, counts the number of spanning out-trees rooted in root_vertex. Default is toset 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 thenumber of out-trees rooted at a specific vertex.
INPUT:• root_vertex – a vertex (default: None); the vertex that will be used as root for all spanning out-trees
if the graph is a directed graph. Otherwise, the first vertex returned by vertex_iterator() is used.
This argument is ignored if the graph is not a digraph.
See also:
spanning_trees() – enumerates all spanning trees of a graph
REFERENCES:• [1] http://mathworld.wolfram.com/MatrixTreeTheorem.html• [2] Lih-Hsing Hsu, Cheng-Kuan Lin, “Graph Theory and Interconnection Networks”
AUTHORS:• Anders Jonsson (2009-10-10)
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.spanning_trees_count()#␣(continues on next page)

376

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules
2000˓→>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.spanning_trees_count()
˓→needs sage.modules
2000

#␣

sage: n = 11
sage: G = graphs.CompleteGraph(n)sage: ST = G.spanning_trees_count()
˓→needs sage.modules
sage: ST == n ^ (n - 2)
˓→needs sage.modules
True>>> from sage.all import *>>> n = Integer(11)>>> G = graphs.CompleteGraph(n)>>> ST = G.spanning_trees_count()
˓→needs sage.modules>>> ST == n ** (n - Integer(2))˓→# needs sage.modules
True

#␣
#␣

#␣
␣

sage: # needs sage.modules
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)1sage: D.spanning_trees_count(2)2>>> from sage.all import *>>> # needs sage.modules>>> M = matrix(Integer(3), Integer(3), [Integer(0), Integer(1), Integer(0),␣
˓→Integer(0), Integer(0), Integer(1), Integer(1), Integer(1), Integer(0)])>>> D = DiGraph(M)>>> D.spanning_trees_count()1>>> D.spanning_trees_count(Integer(0))
1>>> D.spanning_trees_count(Integer(2))
2spectral_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
1.1. Generic graphs (common to directed/undirected)

377

Graph Theory, Release 10.4

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 forany 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
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>>> from sage.all import *>>> from sage.graphs.base.static_sparse_graph import spectral_radius>>> G = DiGraph([(Integer(0),Integer(0)),(Integer(0),Integer(1)),(Integer(1),˓→Integer(0))], loops=True)>>> phi = (RR(Integer(1)) + RR(Integer(5)).sqrt() ) / Integer(2)>>> phi # abs tol 1e-14
1.618033988749895>>> e_min, e_max = spectral_radius(G, RealNumber( 1e-14 ))>>> e_min, e_max# abs tol 1e-14(1.618033988749894, 1.618033988749896)>>> (e_max - e_min) # abs tol 1e-14
1e-14>>> e_min < phi < e_max
TrueThis 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))# needs sage.modules sage.rings.number_fieldsage: e_min < e < e_max˓→# needs sage.modules sage.rings.number_field sage.symbolicTrue␣

sage: G.spectral_radius() # abs tol 1e-9
(2.48119430408, 2.4811943041)

378

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),˓→Integer(2)),(Integer(1),Integer(3)),(Integer(2),Integer(4)),(Integer(3),˓→Integer(4))])>>> e_min, e_max = spectral_radius(G, RealNumber( 1e-14 ))>>> e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False))
˓→# needs sage.modules sage.rings.number_field>>> e_min < e < e_max
˓→# needs sage.modules sage.rings.number_field sage.symbolic
True>>> G.spectral_radius() # abs tol 1e-9
(2.48119430408, 2.4811943041)

A larger example:
sage: # needs sage.modules
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: px^201 - x^199 - 1
sage: r = p.roots(AA, multiplicities=False)[0]˓→# needs sage.rings.number_fieldsage: e_min < r < e_max˓→# needs sage.rings.number_field
True>>> from sage.all import *>>> # needs sage.modules>>> G = DiGraph()>>> G.add_edges((i,i+Integer(1)) for i in range(Integer(200)))>>> G.add_edge(Integer(200),Integer(0))>>> G.add_edge(Integer(1),Integer(0))>>> e_min, e_max = spectral_radius(G, RealNumber( 0.00001 ))>>> p = G.adjacency_matrix(sparse=True).charpoly()>>> px^201 - x^199 - 1>>> r = p.roots(AA, multiplicities=False)[Integer(0)]˓→# needs sage.rings.number_field>>> e_min < r < e_max
˓→# needs sage.rings.number_field
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)

1.1. Generic graphs (common to directed/undirected)

379

Graph Theory, Release 10.4>>> from sage.all import *>>> G = DiGraph(Integer(100000))>>> r = list(range(Integer(100000)))>>> while not G.is_strongly_connected():...
shuffle(r)...
G.add_edges(enumerate(r), loops=False)>>> spectral_radius(G, RealNumber( 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))˓→# needs sage.modules sage.rings.number_field
2.414213562373095?

␣>>> from sage.all import *>>> G = DiGraph(Integer(2),loops=True,multiedges=True)>>> G.add_edges([(Integer(0),Integer(0)),(Integer(0),Integer(0)),(Integer(0),˓→Integer(1)),(Integer(1),Integer(0))])>>> spectral_radius(G, RealNumber( 1e-14 )) # abs tol 1e-14(2.414213562373094, 2.414213562373095)>>> max(G.adjacency_matrix().eigenvalues(AA))˓→# needs sage.modules sage.rings.number_field
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)>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(3)),(Integer(2),˓→Integer(3))])>>> G.spectral_radius() # abs tol 1e-10(1.6180339887253428, 1.6180339887592732)>>> G = DiGraph([(Integer(0),Integer(1)),(Integer(0),Integer(3)),(Integer(2),˓→Integer(3)),(Integer(3),Integer(0)),(Integer(1),Integer(0)),(Integer(1),˓→Integer(2))])>>> G.spectral_radius() # abs tol 1e-10(1.5537739740270458, 1.553773974033029)>>> G = graphs.CompleteBipartiteGraph(Integer(1),Integer(3))(continues on next page)

380

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G.spectral_radius() # abs tol 1e-10(1.7320508075688772, 1.7320508075688774)

spectrum(laplacian=False)
Return a list of the eigenvalues of the adjacency matrix.
INPUT:• laplacian – boolean (default: False); if True, use the Laplacian matrix (see kirchhoff_matrix())
OUTPUT:
A list of the eigenvalues, including multiplicities, sorted with the largest eigenvalue first.
See also:
The method spectral_radius() returns floating point approximation of the maximum eigenvalue.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.spectrum()#␣˓→needs sage.modules sage.rings.number_field[3, 1, 1, 1, 1, 1, -2, -2, -2, -2]
sage: P.spectrum(laplacian=True)#␣˓→needs sage.modules sage.rings.number_field[5, 5, 5, 5, 2, 2, 2, 2, 2, 0]
sage: D = P.to_directed()sage: D.delete_edge(7, 9)
sage: D.spectrum()#␣˓→needs sage.modules sage.rings.number_field[2.9032119259..., 1, 1, 1, 1, 0.8060634335..., -1.7092753594..., -2, -2, -2]>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.spectrum()#␣˓→needs sage.modules sage.rings.number_field[3, 1, 1, 1, 1, 1, -2, -2, -2, -2]>>> P.spectrum(laplacian=True)#␣˓→needs sage.modules sage.rings.number_field[5, 5, 5, 5, 2, 2, 2, 2, 2, 0]>>> D = P.to_directed()>>> D.delete_edge(Integer(7), Integer(9))>>> D.spectrum()#␣˓→needs sage.modules sage.rings.number_field[2.9032119259..., 1, 1, 1, 1, 0.8060634335..., -1.7092753594..., -2, -2, -2]
sage: C = graphs.CycleGraph(8)sage: C.spectrum()#␣˓→needs sage.modules sage.rings.number_field[2, 1.4142135623..., 1.4142135623..., 0, 0, -1.4142135623..., -1.4142135623...
˓→, -2]>>> from sage.all import *>>> C = graphs.CycleGraph(Integer(8))>>> C.spectrum()#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

381

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules sage.rings.number_field[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()#␣˓→needs sage.modules sage.rings.number_field[1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...
˓→*I]>>> from sage.all import *>>> T = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(0)]})>>> T.spectrum()#␣˓→needs sage.modules sage.rings.number_field[1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...
˓→*I]

steiner_tree(vertices, weighted, solver=False, verbose=None, integrality_tolerance=0)
Return a tree of minimum weight connecting the given set of vertices.
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 asubset 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 (default: False); whether to consider the graph as weighted, and use eachedge’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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
Note:• This problem being defined on undirected graphs, the orientation is not considered if the current graphis actually a digraph.
• The graph is assumed not to have multiple edges.
ALGORITHM:

382

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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: first5 = g.vertices(sort=True)[:5]
sage: st = g.steiner_tree(first5)
˓→needs sage.numerical.mip
sage: st.is_tree()
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(30), RealNumber( .5 ))>>> first5 = g.vertices(sort=True)[:Integer(5)]>>> st = g.steiner_tree(first5)
˓→needs sage.numerical.mip>>> st.is_tree()
˓→needs sage.numerical.mip
True

#␣
#␣

#␣
#␣

And all the 5 vertices are contained in this tree
sage: all(v in st for v in first5)
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> all(v in st for v in first5)
˓→needs sage.numerical.mip
True

#␣

#␣

An exception is raised when the problem is impossible, i.e. if the given vertices are not all included in thesame connected component:
sage: g = 2 * graphs.PetersenGraph()
sage: st = g.steiner_tree([5, 15])
Traceback (most recent call last):...
EmptySetError: the given vertices do not all belong to the same connected␣
˓→component. This problem has no solution !
>>> from sage.all import *>>> g = Integer(2) * graphs.PetersenGraph()>>> st = g.steiner_tree([Integer(5), Integer(15)])
Traceback (most recent call last):...
EmptySetError: the given vertices do not all belong to the same connected␣
˓→component. This problem has no solution !

1.1. Generic graphs (common to directed/undirected)

383

Graph Theory, Release 10.4

strong_product(other)
Return the strong product of self and other.
The strong product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) = 𝑉 (𝐺) × 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥))
is an edge of 𝐿 iff either :• (𝑢, 𝑤) is an edge of 𝐺 and 𝑣 = 𝑥, or• (𝑣, 𝑥) is an edge of 𝐻 and 𝑢 = 𝑤, or• (𝑢, 𝑤) is an edge of 𝐺 and (𝑣, 𝑥) is an edge of 𝐻.
In other words, the edges of the strong product is the union of the edges of the tensor and Cartesian products.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)sage: C = graphs.CycleGraph(5)sage: S = C.strong_product(Z); S
Graph on 10 vertices
sage: S.plot()# long time
˓→needs sage.plot
Graphics object consisting of 36 graphics primitives>>> from sage.all import *>>> Z = graphs.CompleteGraph(Integer(2))>>> C = graphs.CycleGraph(Integer(5))>>> S = C.strong_product(Z); S
Graph on 10 vertices>>> S.plot()# long time
˓→needs sage.plot
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
˓→needs sage.plot
Graphics object consisting of 1701 graphics primitives>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> P = graphs.PetersenGraph()>>> S = D.strong_product(P); S
Graph on 200 vertices>>> S.plot()# long time
˓→needs sage.plot
Graphics object consisting of 1701 graphics primitives

#␣

#␣

#␣

#␣

subdivide_edge(*args)
Subdivide an edge 𝑘 times.
INPUT:
The following forms are all accepted to subdivide 8 times the edge between vertices 1 and 2 labeled with
"my_label".
• G.subdivide_edge( 1, 2, 8 )384

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• 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 pairu,vEXAMPLES:
Subdividing 5 times an edge in a path of length 3 makes it a path of length 8:
sage: g = graphs.PathGraph(3)sage: edge = next(g.edge_iterator())
sage: g.subdivide_edge(edge, 5)
sage: g.is_isomorphic(graphs.PathGraph(8))
True>>> from sage.all import *>>> g = graphs.PathGraph(Integer(3))>>> edge = next(g.edge_iterator())>>> g.subdivide_edge(edge, Integer(5))>>> g.is_isomorphic(graphs.PathGraph(Integer(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(g.edges(sort=True))[(0, 1, label1 ), (1, 2, label2 )]>>> from sage.all import *>>> g = Graph()>>> g.add_edge(Integer(0), Integer(1), "label1")>>> g.add_edge(Integer(1), Integer(2), "label2")>>> print(g.edges(sort=True))[(0, 1, label1 ), (1, 2, label2 )]Specifying the label:sage: g.subdivide_edge(0, 1, "label1", 3)
sage: print(g.edges(sort=True))[(0, 3, label1 ), (1, 2, label2 ), (1, 5,
˓→5,label1 )]label1 ), (3, 4,label1 ), (4,␣>>> from sage.all import *>>> g.subdivide_edge(Integer(0), Integer(1), "label1", Integer(3))>>> print(g.edges(sort=True))[(0, 3, label1 ), (1, 2, label2 ), (1, 5, label1 ), (3, 4, label1 ), (4,␣˓→5,label1 )]The lazy way:

1.1. Generic graphs (common to directed/undirected)

385

Graph Theory, Release 10.4

sage: g.subdivide_edge(1, 2, "label2", 5)sage: print(g.edges(sort=True))[(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 )]>>> from sage.all import *>>> g.subdivide_edge(Integer(1), Integer(2), "label2", Integer(5))>>> print(g.edges(sort=True))[(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>>> from sage.all import *>>> g.subdivide_edge(Integer(0),Integer(1),Integer(1),Integer(1),Integer(1),˓→Integer(1),Integer(1),Integer(1),Integer(1),Integer(1),Integer(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>>> from sage.all import *>>> g.subdivide_edge(Integer(0), Integer(1), "fake_label", Integer(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)
Subdivide 𝑘 times edges from an iterable container.
For more information on the behaviour of this method, please refer to the documentation of subdivide_edge().
INPUT:• edges – a list of edges• k – integer; common length of the subdivisions

386

Chapter 1. Graph objects and methods

Graph Theory, Release 10.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>>> from sage.all import *>>> paths = [Integer(2), Integer(5), Integer(9)]>>> paths = map(graphs.PathGraph, paths)>>> g = Graph()>>> for P in paths:...
g = g + P

Subdividing edges in each of them will only change their lengths:
sage: edges = [next(P.edge_iterator()) for P in g.connected_components_
˓→subgraphs()]
sage: k = 6
sage: g.subdivide_edges(edges, k)>>> from sage.all import *>>> edges = [next(P.edge_iterator()) for P in g.connected_components_
˓→subgraphs()]>>> k = Integer(6)>>> 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>>> from sage.all import *>>> paths2 = [Integer(2) + k, Integer(5) + k, Integer(9) + k]>>> paths2 = map(graphs.PathGraph, paths2)>>> g2 = Graph()>>> for P in paths2:...
g2 = g2 + P>>> g.is_isomorphic(g2)
True

See also:• subdivide_edge() – subdivides one edge

1.1. Generic graphs (common to directed/undirected)

387

Graph Theory, Release 10.4

subgraph(vertices=None, edges=None, inplace=False, vertex_property=None, edge_property=None,algorithm=None, immutable=None)
Return 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 notspecified, returns the subgraph induced by the vertices.
INPUT:• inplace – boolean (default: False); using inplace=True will simply delete the extra vertices
and edges from the current graph. This will modify the graph.
• vertices – a single vertex or an iterable container of vertices, e.g. a list, set, graph, file or numeric
array. If not passed (i.e., None), defaults to the entire graph.
• edges – as with vertices, edges can be a single edge or an iterable container of edges (e.g., a list,
set, file, numeric array, etc.). By default (edges=None), all edges are assumed and the returned graphis an induced subgraph. In the case of multiple edges, specifying an edge as (𝑢, 𝑣) means to keep alledges (𝑢, 𝑣), regardless of the label.
• vertex_property – function (default: None); a function that inputs a vertex and outputs a boolean
value, i.e., a vertex v in vertices is kept if vertex_property(v) == True• edge_property – function (default: None); a function that inputs an edge and outputs a boolean
value, i.e., a edge e in edges is kept if edge_property(e) == True
• algorithm – string (default: None); one of the following:– If algorithm="delete" or inplace=True, then the graph is constructed by deleting edges
and vertices– If algorithm="add", then the graph is constructed by building a new graph from the appropriate
vertices and edges. Implies inplace=False.
– If algorithm=None, then the algorithm is chosen based on the number of vertices in the subgraph.
• immutable – boolean (default: None); whether to create a mutable/immutable subgraph. immutable=None (default) means that the graph and its subgraph will behave the same way.
EXAMPLES:
sage: G = graphs.CompleteGraph(9)sage: H = G.subgraph([0, 1, 2]); H
Subgraph of (Complete graph): Graph on 3 vertices
sage: G
Complete graph: Graph on 9 vertices
sage: J = G.subgraph(edges=[(0, 1)])
sage: J.edges(sort=True, labels=False)[(0, 1)]
sage: set(J) == set(G)Truesage: G.subgraph([0, 1, 2], inplace=True); G
Subgraph of (Complete graph): Graph on 3 vertices
sage: G.subgraph() == G
True>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(9))>>> H = G.subgraph([Integer(0), Integer(1), Integer(2)]); H
Subgraph of (Complete graph): Graph on 3 vertices(continues on next page)

388

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G
Complete graph: Graph on 9 vertices>>> J = G.subgraph(edges=[(Integer(0), Integer(1))])>>> J.edges(sort=True, labels=False)[(0, 1)]>>> set(J) == set(G)True>>> G.subgraph([Integer(0), Integer(1), Integer(2)], inplace=True); G
Subgraph of (Complete graph): Graph on 3 vertices>>> G.subgraph() == G
True
sage: D = digraphs.Complete(9)sage: H = D.subgraph([0, 1, 2]); H
Subgraph of (Complete digraph): Digraph on 3 vertices
sage: H = D.subgraph(edges=[(0, 1), (0, 2)])sage: H.edges(sort=True, labels=False)[(0, 1), (0, 2)]
sage: set(H) == set(D)True
sage: D
Complete digraph: Digraph on 9 vertices
sage: D.subgraph([0, 1, 2], inplace=True); D
Subgraph of (Complete digraph): Digraph on 3 vertices
sage: D.subgraph() == D
True>>> from sage.all import *>>> D = digraphs.Complete(Integer(9))>>> H = D.subgraph([Integer(0), Integer(1), Integer(2)]); H
Subgraph of (Complete digraph): Digraph on 3 vertices>>> H = D.subgraph(edges=[(Integer(0), Integer(1)), (Integer(0), Integer(2))])>>> H.edges(sort=True, labels=False)[(0, 1), (0, 2)]>>> set(H) == set(D)
True
>>> D
Complete digraph: Digraph on 9 vertices>>> D.subgraph([Integer(0), Integer(1), Integer(2)], inplace=True); D
Subgraph of (Complete digraph): Digraph on 3 vertices>>> D.subgraph() == DTrue

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(sort=True)[(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(sort=True)[(0, 1, a )]sage: J.vertices(sort=True)[0, 1](continues on next page)

1.1. Generic graphs (common to directed/undirected)

389

Graph Theory, Release 10.4

(continued from previous page)

sage: G.subgraph(vertices=G) == G
True>>> from sage.all import *>>> G = Graph(multiedges=True, sparse=True)>>> G.add_edges([(Integer(0), Integer(1), a ), (Integer(0), Integer(1), b ),˓→ (Integer(1), Integer(0),c ), (Integer(0), Integer(2), d ), (Integer(0),␣
˓→Integer(2),e ), (Integer(2), Integer(0), f ), (Integer(1), Integer(2), g˓→ )])>>> G.subgraph(edges=[(Integer(0), Integer(1)), (Integer(0), Integer(2), d ),␣˓→(Integer(0), Integer(2),not in graph )]).edges(sort=True)[(0, 1, a ), (0, 1, b ), (0, 1, c ), (0, 2, d )]>>> J = G.subgraph(vertices=[Integer(0), Integer(1)], edges=[(Integer(0),␣
˓→Integer(1),a ), (Integer(0), Integer(2), c )])>>> J.edges(sort=True)[(0, 1, a )]>>> J.vertices(sort=True)[0, 1]>>> G.subgraph(vertices=G) == G
True
sage: D = DiGraph(multiedges=True, sparse=True)
sage: D.add_edges([(0, 1, a ), (0, 1, b ), (1, 0,
˓→ e ), (2, 0,f ), (1, 2, g )])sage: D.subgraph(edges=[(0, 1), (0, 2, d ), (0, 2,
˓→edges(sort=True)[(0, 1, a ), (0, 1, b ), (0, 2, d )]sage: H = D.subgraph(vertices=[0, 1], edges=[(0, 1,
sage: H.edges(sort=True)[(0, 1, a )]sage: H.vertices(sort=True)[0, 1]c ), (0, 2,d ), (0, 2,

not in graph )]).

a ), (0, 2,

c )])>>> from sage.all import *>>> D = DiGraph(multiedges=True, sparse=True)>>> D.add_edges([(Integer(0), Integer(1), a ), (Integer(0), Integer(1), b ),˓→ (Integer(1), Integer(0),c ), (Integer(0), Integer(2), d ), (Integer(0),␣
˓→Integer(2),e ), (Integer(2), Integer(0), f ), (Integer(1), Integer(2), g˓→ )])>>> D.subgraph(edges=[(Integer(0), Integer(1)), (Integer(0), Integer(2), d ),˓→ (Integer(0), Integer(2),not in graph )]).edges(sort=True)[(0, 1, a ), (0, 1, b ), (0, 2, d )]>>> H = D.subgraph(vertices=[Integer(0), Integer(1)], edges=[(Integer(0),␣
˓→Integer(1),a ), (Integer(0), Integer(2), c )])>>> H.edges(sort=True)[(0, 1, a )]>>> H.vertices(sort=True)[0, 1]

Using the property arguments:
sage: P = graphs.PetersenGraph()
sage: S = P.subgraph(vertex_property=lambda v: not (v % 2))
sage: S.vertices(sort=True)[0, 2, 4, 6, 8]

390

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> S = P.subgraph(vertex_property=lambda v: not (v % Integer(2)))>>> S.vertices(sort=True)[0, 2, 4, 6, 8]
sage: C = graphs.CubeGraph(2)sage: S = C.subgraph(edge_property=(lambda e: e[0][0] == e[1][0]))sage: C.edges(sort=True)[( 00 , 01 , None), ( 00 , 10 , None), ( 01 , 11 , None), ( 10 ,˓→None)]sage: S.edges(sort=True)[( 00 , 01 , None), ( 10 , 11 , None)]11 ,␣>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(2))>>> S = C.subgraph(edge_property=(lambda e: e[Integer(0)][Integer(0)] ==␣
˓→e[Integer(1)][Integer(0)]))>>> C.edges(sort=True)[( 00 , 01 , None), ( 00 , 10 , None), ( 01 , 11 , None), ( 10 , 11 ,␣˓→None)]>>> S.edges(sort=True)[( 00 , 01 , None), ( 10 , 11 , None)]

The algorithm is not specified, then a reasonable choice is made for speed:
sage: g = graphs.PathGraph(1000)
sage: g.subgraph(list(range(10))) # uses the add
Subgraph of (Path graph): Graph on 10 vertices

algorithm>>> from sage.all import *>>> g = graphs.PathGraph(Integer(1000))>>> g.subgraph(list(range(Integer(10)))) # uses the
Subgraph of (Path graph): Graph on 10 vertices

addalgorithm

subgraph_search(G, induced=False)
Return a copy of G in self.
INPUT:• G – the (di)graph whose copy we are looking for in self
• induced – boolean (default: False); whether or not to search for an induced copy of G in self
OUTPUT:
If induced=False, return a copy of G in this graph. Otherwise, return an induced copy of G in self. If
G is the empty graph, return the empty graph since it is a subgraph of every graph. Now suppose G is not theempty graph. If there is no copy (induced or otherwise) of G in self, we return None.
Note: The vertex labels and the edge labels in the graph are ignored.
See also:• subgraph_search_count() – counts the number of copies of 𝐻 inside of 𝐺
• subgraph_search_iterator() – iterator over the copies of 𝐻 inside of 𝐺
1.1. Generic graphs (common to directed/undirected)

391

Graph Theory, Release 10.4

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
˓→needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices
sage: h1.vertices(sort=True); h1.edges(sort=True, labels=False)
˓→needs sage.modules[0, 1, 2, 3, 4][(0, 1), (1, 2), (2, 3), (3, 4)]
sage: I1 = g.subgraph_search(graphs.PathGraph(5), induced=True); I1
˓→needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices
sage: I1.vertices(sort=True); I1.edges(sort=True, labels=False)
˓→needs sage.modules[0, 1, 2, 3, 8][(0, 1), (1, 2), (2, 3), (3, 8)]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> h1 = g.subgraph_search(graphs.PathGraph(Integer(5))); h1˓→# needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices>>> h1.vertices(sort=True); h1.edges(sort=True, labels=False)#␣˓→needs sage.modules[0, 1, 2, 3, 4][(0, 1), (1, 2), (2, 3), (3, 4)]>>> I1 = g.subgraph_search(graphs.PathGraph(Integer(5)), induced=True); I1
˓→# needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices>>> I1.vertices(sort=True); I1.edges(sort=True, labels=False)#␣˓→needs sage.modules[0, 1, 2, 3, 8][(0, 1), (1, 2), (2, 3), (3, 8)]

#␣

#␣

#␣

#␣

␣

␣

It also contains the claw 𝐾1,3 :sage: # needs sage.modules
sage: h2 = g.subgraph_search(graphs.ClawGraph()); h2
Subgraph of (Petersen graph): Graph on 4 vertices
sage: h2.vertices(sort=True); h2.edges(sort=True, labels=False)[0, 1, 4, 5][(0, 1), (0, 4), (0, 5)]
sage: I2 = g.subgraph_search(graphs.ClawGraph(), induced=True); I2
Subgraph of (Petersen graph): Graph on 4 vertices
sage: I2.vertices(sort=True); I2.edges(sort=True, labels=False)[0, 1, 4, 5][(0, 1), (0, 4), (0, 5)]>>> from sage.all import *>>> # needs sage.modules>>> h2 = g.subgraph_search(graphs.ClawGraph()); h2(continues on next page)392

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Subgraph of (Petersen graph): Graph on 4 vertices>>> h2.vertices(sort=True); h2.edges(sort=True, labels=False)[0, 1, 4, 5][(0, 1), (0, 4), (0, 5)]>>> I2 = g.subgraph_search(graphs.ClawGraph(), induced=True); I2
Subgraph of (Petersen graph): Graph on 4 vertices>>> I2.vertices(sort=True); I2.edges(sort=True, labels=False)[0, 1, 4, 5][(0, 1), (0, 4), (0, 5)]

Of course the induced copies are isomorphic to the graphs we were looking for:sage: I1.is_isomorphic(graphs.PathGraph(5))˓→needs sage.modules
True
sage: I2.is_isomorphic(graphs.ClawGraph())˓→needs sage.modules
True

#␣

#␣

>>> from sage.all import *>>> I1.is_isomorphic(graphs.PathGraph(Integer(5)))˓→# needs sage.modules
True>>> I2.is_isomorphic(graphs.ClawGraph())˓→needs sage.modules
True

␣

#␣

However, the Petersen graph does not contain a subgraph isomorphic to 𝐾3 :sage: g.subgraph_search(graphs.CompleteGraph(3)) is None˓→needs sage.modules
True

#␣

>>> from sage.all import *>>> g.subgraph_search(graphs.CompleteGraph(Integer(3))) is None˓→# needs sage.modules
True␣

Nor does it contain a nonempty induced subgraph isomorphic to 𝑃6 :sage: g.subgraph_search(graphs.PathGraph(6), induced=True) is None˓→needs sage.modules
True>>> from sage.all import *>>> g.subgraph_search(graphs.PathGraph(Integer(6)), induced=True) is None˓→# needs sage.modules
True

#␣

␣

The empty graph is a subgraph of every graph:
sage: g.subgraph_search(graphs.EmptyGraph())˓→needs sage.modules
Graph on 0 vertices
sage: g.subgraph_search(graphs.EmptyGraph(), induced=True)#␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

393

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules
Graph on 0 vertices˓→>>> from sage.all import *>>> g.subgraph_search(graphs.EmptyGraph())˓→needs sage.modules
Graph on 0 vertices>>> g.subgraph_search(graphs.EmptyGraph(), induced=True)
˓→needs sage.modules
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)˓→needs sage.modules
sage: s.edges(sort=True, labels=False)
˓→needs sage.modules[( a , b ), ( b , c )]#␣#␣>>> from sage.all import *>>> k3 = graphs.CompleteGraph(Integer(3)); p3 = graphs.PathGraph(Integer(3))>>> k3.relabel(list( abc ))>>> s = k3.subgraph_search(p3)#␣˓→needs sage.modules>>> s.edges(sort=True, labels=False)#␣˓→needs sage.modules[( 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˓→needs sage.modules
True

#␣

>>> from sage.all import *>>> k3 = graphs.CompleteGraph(Integer(3)); p3 = graphs.PathGraph(Integer(3))>>> k3.relabel(list( abc ))>>> k3.subgraph_search(p3, induced=True) is None#␣˓→needs sage.modules
True

If the graph has labels, the labels are just ignored:sage: g.set_vertex(0, foo )sage: c = g.subgraph_search(graphs.PathGraph(5))˓→needs sage.modules
sage: c.get_vertices()
˓→needs sage.modules{0: foo , 1: None, 2: None, 3: None, 4: None}

394

#␣
#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g.set_vertex(Integer(0), foo )>>> c = g.subgraph_search(graphs.PathGraph(Integer(5)))˓→# needs sage.modules>>> c.get_vertices()
˓→needs sage.modules{0: foo , 1: None, 2: None, 3: None, 4: None}␣#␣subgraph_search_count(G, induced=False)
Return the number of labelled occurrences of G in self.
INPUT:• G – the (di)graph whose copies we are looking for in self
• induced – boolean (default: False); whether or not to count induced copies of G in self
Note: The vertex labels and the edge labels in the graph are ignored.
ALGORITHM:
See the documentation of SubgraphSearch.
See also:• subgraph_search() – finds a subgraph isomorphic to 𝐻 inside of a graph 𝐺• subgraph_search_iterator() – iterator over 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))˓→needs sage.modules
240>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.subgraph_search_count(graphs.PathGraph(Integer(5)))˓→# needs sage.modules
240

#␣

␣

Requiring these subgraphs be induced:
sage: g.subgraph_search_count(graphs.PathGraph(5), induced=True)
˓→needs sage.modules
120>>> from sage.all import *>>> g.subgraph_search_count(graphs.PathGraph(Integer(5)), induced=True)˓→# needs sage.modules
120

#␣

␣

If we define the graph 𝑇𝑘 (the transitive tournament on 𝑘 vertices) as the graph on {0, ..., 𝑘 − 1} such that𝑖𝑗 ∈ 𝑇𝑘 if 𝑖 < 𝑗, how many directed triangles can be found in 𝑇5 ? The answer is of course 0:

1.1. Generic graphs (common to directed/undirected)

395

Graph Theory, Release 10.4

sage: T5 = digraphs.TransitiveTournament(5)sage: T5.subgraph_search_count(digraphs.Circuit(3))˓→needs sage.modules0#␣>>> from sage.all import *>>> T5 = digraphs.TransitiveTournament(Integer(5))>>> T5.subgraph_search_count(digraphs.Circuit(Integer(3)))˓→# needs sage.modules
0

If we count instead the number of 𝑇3 in 𝑇5 , we expect the answer to be

␣

(︀5)︀

3 :

sage: T3 = digraphs.TransitiveTournament(3)sage: T5.subgraph_search_count(T3)˓→needs sage.modules
10
sage: binomial(5,3)˓→needs sage.symbolic
10
sage: T3.is_isomorphic(T5.subgraph(vertices=[0, 1, 2]))
˓→needs sage.modules
True

#␣

#␣

#␣

>>> from sage.all import *>>> T3 = digraphs.TransitiveTournament(Integer(3))>>> T5.subgraph_search_count(T3)˓→needs sage.modules
10>>> binomial(Integer(5),Integer(3))˓→# needs sage.symbolic
10>>> T3.is_isomorphic(T5.subgraph(vertices=[Integer(0), Integer(1),␣
˓→Integer(2)]))# needs sage.modules
True

#␣

␣

The empty graph is a subgraph of every graph:
sage: g.subgraph_search_count(graphs.EmptyGraph())˓→needs sage.modules
1>>> from sage.all import *>>> g.subgraph_search_count(graphs.EmptyGraph())˓→needs sage.modules
1

#␣

#␣

If the graph has vertex labels or edge labels, the label is just ignored:sage: g.set_vertex(0, foo )sage: g.subgraph_search_count(graphs.PathGraph(5))˓→needs sage.modules
240>>> from sage.all import *>>> g.set_vertex(Integer(0),

#␣

foo )
(continues on next page)

396

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> g.subgraph_search_count(graphs.PathGraph(Integer(5)))˓→# needs sage.modules
240␣

subgraph_search_iterator(G, induced=False, return_graphs=True)
Return 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
• return_graphs – boolean (default: True); whether to return (di)graphs or only the list of verticesof the found (di)graphs
Note: The vertex labels and the edge labels in the graph are ignored.
ALGORITHM:
See the documentation of SubgraphSearch.
OUTPUT:
Iterator over the labelled copies of G in self, as lists or (di)graphs. For each value (𝑣1 , 𝑣2 , ..., 𝑣𝑘 ) returned,
the first vertex of 𝐺 is associated with 𝑣1 , the second with 𝑣2 , etc.
Note: This method works on Graph, DiGraph and BipartiteGraph.
See also:• subgraph_search() – finds a 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: P3 = graphs.PathGraph(3)sage: for p in g.subgraph_search_iterator(P3, return_graphs=False):
˓→needs sage.modules....:
print(p)[0, 1, 2][1, 2, 3][2, 1, 0][2, 3, 4][3, 2, 1][4, 3, 2]
sage: for p in g.subgraph_search_iterator(P3, return_graphs=True):
˓→needs sage.modules....:
print(p)Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)#␣#␣(continues on next page)

1.1. Generic graphs (common to directed/undirected)

397

Graph Theory, Release 10.4

(continued from previous page)

Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
sage: all(h.is_isomorphic(P3) for h in g.subgraph_search_iterator(P3))
˓→needs sage.modules
True>>> from sage.all import *>>> g = graphs.PathGraph(Integer(5))>>> P3 = graphs.PathGraph(Integer(3))>>> for p in g.subgraph_search_iterator(P3, return_graphs=False):
˓→needs sage.modules...
print(p)[0, 1, 2][1, 2, 3][2, 1, 0][2, 3, 4][3, 2, 1][4, 3, 2]>>> for p in g.subgraph_search_iterator(P3, return_graphs=True):
˓→needs sage.modules...
print(p)Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)
Subgraph of (Path graph)>>> all(h.is_isomorphic(P3) for h in g.subgraph_search_iterator(P3))
˓→needs sage.modules
True

#␣

#␣

#␣

#␣

If the graph has vertex labels or edge labels, the label is just ignored:sage: g.set_vertex(0, foo )sage: for p in g.subgraph_search_iterator(P3, return_graphs=False):
˓→needs sage.modules....:
print(p)[0, 1, 2][1, 2, 3][2, 1, 0][2, 3, 4][3, 2, 1][4, 3, 2]>>> from sage.all import *>>> g.set_vertex(Integer(0), foo )>>> for p in g.subgraph_search_iterator(P3, return_graphs=False):
˓→needs sage.modules...
print(p)[0, 1, 2][1, 2, 3][2, 1, 0][2, 3, 4][3, 2, 1][4, 3, 2]

398

#␣

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Search for induced subgraphs:
sage: H = graphs.HouseGraph()
sage: P4 = graphs.PathGraph(4)sage: all(h.is_isomorphic(P4)˓→needs sage.modules....:
for h in H.subgraph_search_iterator(P4, induced=True))Truesage: sum(1 for h in H.subgraph_search_iterator(P4, induced=True))
˓→needs sage.modules4
sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=False))
˓→needs sage.modules
20

#␣

#␣

#␣

>>> from sage.all import *>>> H = graphs.HouseGraph()>>> P4 = graphs.PathGraph(Integer(4))>>> all(h.is_isomorphic(P4)#␣˓→needs sage.modules...
for h in H.subgraph_search_iterator(P4, induced=True))
True>>> sum(Integer(1) for h in H.subgraph_search_iterator(P4, induced=True))␣˓→# needs sage.modules
4>>> sum(Integer(1) for h in H.subgraph_search_iterator(P4, induced=False))␣˓→# needs sage.modules
20

Search for subdigraphs:
sage: H = digraphs.Complete(5)sage: P4 = digraphs.Path(4)sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=True))
˓→needs sage.modules0sage: sum(1 for _ in H.subgraph_search_iterator(P4, induced=False))
˓→needs sage.modules
120>>> from sage.all import *>>> H = digraphs.Complete(Integer(5))>>> P4 = digraphs.Path(Integer(4))>>> sum(Integer(1) for _ in H.subgraph_search_iterator(P4, induced=True))˓→# needs sage.modules0>>> sum(Integer(1) for _ in H.subgraph_search_iterator(P4, induced=False))˓→# needs sage.modules
120

#␣

#␣

␣

␣

This method also works for bipartite graphs:
sage: K33 = BipartiteGraph(graphs.CompleteBipartiteGraph(3, 3))
sage: K22 = BipartiteGraph(graphs.CompleteBipartiteGraph(2, 2))
sage: sum(1 for _ in K33.subgraph_search_iterator(K22))
˓→needs sage.modules
72

1.1. Generic graphs (common to directed/undirected)

#␣

399

Graph Theory, Release 10.4>>> from sage.all import *>>> K33 = BipartiteGraph(graphs.CompleteBipartiteGraph(Integer(3),␣
˓→Integer(3)))>>> K22 = BipartiteGraph(graphs.CompleteBipartiteGraph(Integer(2),␣
˓→Integer(2)))>>> sum(Integer(1) for _ in K33.subgraph_search_iterator(K22))˓→# needs sage.modules
72␣

symmetric_edge_polytope(backend=None)
Return the symmetric edge polytope of self.
The symmetric edge polytope (SEP) of a Graph on 𝑛 vertices is the polytope in 𝑛 defined as the convex hullof 𝑒𝑖 − 𝑒𝑗 and 𝑒𝑗 − 𝑒𝑖 for each edge (𝑖, 𝑗). Here 𝑒1 , . . . , 𝑒𝑛 denotes the standard basis.
INPUT:• backend – string or None (default); the backend to use; see sage.geometry.polyhedron.
constructor.Polyhedron()
EXAMPLES:The SEP of a 4-cycle is a cube:
sage: G = graphs.CycleGraph(4)sage: P = G.symmetric_edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 8 vertices
sage: P.is_combinatorially_isomorphic(polytopes.cube())#␣˓→needs sage.geometry.polyhedron
True>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> P = G.symmetric_edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 8 vertices>>> P.is_combinatorially_isomorphic(polytopes.cube())#␣˓→needs sage.geometry.polyhedron
True

The SEP of a complete graph on 4 vertices is a cuboctahedron:sage: G = graphs.CompleteGraph(4)sage: P = G.symmetric_edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 12 vertices
sage: P.is_combinatorially_isomorphic(polytopes.cuboctahedron())#␣˓→needs sage.geometry.polyhedron
True>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> P = G.symmetric_edge_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 12 vertices>>> P.is_combinatorially_isomorphic(polytopes.cuboctahedron())#␣(continues on next page)

400

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.geometry.polyhedron
True˓→

The SEP of a graph with edges on 𝑛 vertices has dimension 𝑛 minus the number of connected components:
sage: n = randint(5, 12)
sage: G = Graph()
sage: while not G.num_edges():
˓→needs networkx....:
G = graphs.RandomGNP(n, 0.2)
sage: P = G.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: P.ambient_dim() == n˓→needs networkx sage.geometry.polyhedron
True
sage: P.dim() == n - G.connected_components_number()˓→needs networkx sage.geometry.polyhedron
True

#␣

#␣
#␣

#␣

>>> from sage.all import *>>> n = randint(Integer(5), Integer(12))>>> G = Graph()>>> while not G.num_edges():
˓→needs networkx...
G = graphs.RandomGNP(n, RealNumber( 0.2 ))>>> P = G.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> P.ambient_dim() == n˓→needs networkx sage.geometry.polyhedron
True>>> P.dim() == n - G.connected_components_number()˓→needs networkx sage.geometry.polyhedron
True

#␣

#␣
#␣

#␣

The SEP of a graph is isomorphic to the subdirect sum of its connected components SEP’s:
sage: n = randint(3, 6)
sage: G1 = graphs.RandomGNP(n, 0.2)
˓→needs networkx
sage: n = randint(3, 6)
sage: G2 = graphs.RandomGNP(n, 0.2)
˓→needs networkx
sage: G = G1.disjoint_union(G2)˓→needs networkx
sage: P = G.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: P1 = G1.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: P2 = G2.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2))
˓→needs networkx sage.geometry.polyhedron
True

#␣

#␣
#␣
#␣
#␣
#␣
#␣

>>> from sage.all import *>>> n = randint(Integer(3), Integer(6))(continues on next page)

1.1. Generic graphs (common to directed/undirected)

401Graph Theory, Release 10.4

(continued from previous page)>>> G1 = graphs.RandomGNP(n, RealNumber( 0.2 ))˓→# needs networkx>>> n = randint(Integer(3), Integer(6))>>> G2 = graphs.RandomGNP(n, RealNumber( 0.2 ))˓→# needs networkx>>> G = G1.disjoint_union(G2)˓→needs networkx>>> P = G.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> P1 = G1.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> P2 = G2.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> P.is_combinatorially_isomorphic(P1.subdirect_sum(P2))
˓→needs networkx sage.geometry.polyhedron
True

␣

␣
#␣
#␣
#␣
#␣
#␣

All trees on 𝑛 vertices have isomorphic SEPs:
sage: n = randint(4, 10)
sage: G1 = graphs.RandomTree(n)sage: G2 = graphs.RandomTree(n)sage: P1 = G1.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedronsage: P2 = G2.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedronsage: P1.is_combinatorially_isomorphic(P2)˓→needs sage.geometry.polyhedron
True

#␣
#␣
#␣

>>> from sage.all import *>>> n = randint(Integer(4), Integer(10))>>> G1 = graphs.RandomTree(n)>>> G2 = graphs.RandomTree(n)>>> P1 = G1.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedron>>> P2 = G2.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedron>>> P1.is_combinatorially_isomorphic(P2)˓→needs sage.geometry.polyhedron
True

#␣
#␣
#␣

However, there are still many different SEPs:
sage: len(list(graphs(5)))
34
sage: polys = []sage: for G in graphs(5):˓→needs sage.geometry.polyhedron....:
P = G.symmetric_edge_polytope()....:
for P1 in polys:....:
if P.is_combinatorially_isomorphic(P1):
....:
break
....:
else:
....:
polys.append(P)sage: len(polys)#␣#␣(continues on next page)402

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.geometry.polyhedron˓→25>>> from sage.all import *>>> len(list(graphs(Integer(5))))34>>> polys = []>>> for G in graphs(Integer(5)):˓→# needs sage.geometry.polyhedron...
P = G.symmetric_edge_polytope()...
for P1 in polys:...
if P.is_combinatorially_isomorphic(P1):
...
break
...
else:
...
polys.append(P)>>> len(polys)
˓→needs sage.geometry.polyhedron
25

␣

#␣

A non-trivial example of two graphs with isomorphic SEPs:
sage: G1 = graphs.CycleGraph(4)sage: G1.add_edges([[0, 5], [5, 2], [1, 6], [6, 2]])sage: G2 = copy(G1)sage: G1.add_edges([[2, 7], [7, 3]])sage: G2.add_edges([[0, 7], [7, 3]])sage: G1.is_isomorphic(G2)False
sage: P1 = G1.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedronsage: P2 = G2.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedronsage: P1.is_combinatorially_isomorphic(P2)˓→needs sage.geometry.polyhedron
True>>> from sage.all import *>>> G1 = graphs.CycleGraph(Integer(4))>>> G1.add_edges([[Integer(0), Integer(5)], [Integer(5), Integer(2)],␣
˓→[Integer(1), Integer(6)], [Integer(6), Integer(2)]])>>> G2 = copy(G1)>>> G1.add_edges([[Integer(2), Integer(7)], [Integer(7), Integer(3)]])>>> G2.add_edges([[Integer(0), Integer(7)], [Integer(7), Integer(3)]])>>> G1.is_isomorphic(G2)
False>>> P1 = G1.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedron>>> P2 = G2.symmetric_edge_polytope()
˓→needs sage.geometry.polyhedron>>> P1.is_combinatorially_isomorphic(P2)˓→needs sage.geometry.polyhedron
True

#␣
#␣
#␣

#␣
#␣
#␣

Apparently, glueing two graphs together on a vertex gives isomorphic SEPs:

1.1. Generic graphs (common to directed/undirected)

403

Graph Theory, Release 10.4

sage: n = randint(3, 7)
sage: g1 = graphs.RandomGNP(n, 0.2)
˓→needs networkx
sage: g2 = graphs.RandomGNP(n, 0.2)
˓→needs networkx
sage: G = g1.disjoint_union(g2)˓→needs networkx
sage: H = copy(G)˓→needs networkx
sage: G.merge_vertices(((0, randrange(n)), (1, randrange(n))))˓→needs networkx
sage: H.merge_vertices(((0, randrange(n)), (1, randrange(n))))˓→needs networkx
sage: PG = G.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: PH = H.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedronsage: PG.is_combinatorially_isomorphic(PH)˓→needs networkx sage.geometry.polyhedron
True>>> from sage.all import *>>> n = randint(Integer(3), Integer(7))>>> g1 = graphs.RandomGNP(n, RealNumber( 0.2 ))˓→# needs networkx>>> g2 = graphs.RandomGNP(n, RealNumber( 0.2 ))˓→# needs networkx>>> G = g1.disjoint_union(g2)˓→needs networkx>>> H = copy(G)˓→needs networkx>>> G.merge_vertices(((Integer(0), randrange(n)), (Integer(1),␣
˓→randrange(n))))# needs networkx>>> H.merge_vertices(((Integer(0), randrange(n)), (Integer(1),␣
˓→randrange(n))))# needs networkx>>> PG = G.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> PH = H.symmetric_edge_polytope()
˓→needs networkx sage.geometry.polyhedron>>> PG.is_combinatorially_isomorphic(PH)˓→needs networkx sage.geometry.polyhedron
True

#␣
#␣
#␣
#␣
#␣
#␣
#␣
#␣
#␣

␣
␣
#␣
#␣

#␣
#␣
#␣

szeged_index(G, algorithm=None)
Return the Szeged index of the graph 𝐺.
Let 𝐺 = (𝑉, 𝐸) be a connected graph, and for any 𝑢𝑣 ∈ 𝐸, let 𝑁𝑢 (𝑢𝑣) = {𝑤 ∈ 𝑉 : 𝑑(𝑢, 𝑤) < 𝑑(𝑣, 𝑤)}
and 𝑛𝑢 (𝑢𝑣) = |𝑁𝑢 (𝑢𝑣)|. The Szeged index of 𝐺 is then defined as [KRG1996]∑︁`𝑛𝑢 (𝑢𝑣) × 𝑛𝑣 (𝑢𝑣)`𝑢𝑣∈𝐸(𝐺)See the Wikipedia article Szeged_index for more details.
INPUT:• G – a Sage graph• algorithm – string (default: None); algorithm to use among:
404

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

– "low" – algorithm with time complexity in 𝑂(𝑛𝑚) and space complexity in 𝑂(𝑚). This implementation is currently valid only for simple (without loops or multiple edges) connected graphs.
– "high" – algorithm with time complexity in 𝑂(𝑛𝑚) and space complexity in 𝑂(𝑛2 ). It cannot be
used on graphs with more than 65536 = 216 vertices.
By default (None), the "low" algorithm is used for graphs and the "high" algorithm for digraphs.
Note: As the graph is converted to a short_digraph, the complexity for the case algorithm == "high"has an extra 𝑂(𝑚 + 𝑛) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph. If algorithm == "low",
the extra complexity is 𝑂(𝑛 + 𝑚 log 𝑚) for SparseGraph and 𝑂(𝑛2 log 𝑚) for DenseGraph (because
init_short_digraph is called with sort_neighbors=True).
EXAMPLES:
True for any connected graph [KRG1996]:
sage: from sage.graphs.distances_all_pairs import szeged_index
sage: g = graphs.PetersenGraph()
sage: g.wiener_index() <= szeged_index(g)True>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import szeged_index>>> g = graphs.PetersenGraph()>>> g.wiener_index() <= szeged_index(g)True

True for all trees [KRG1996]:
sage: g = Graph()
sage: g.add_edges(graphs.CubeGraph(5).min_spanning_tree())
sage: g.wiener_index() == szeged_index(g)True>>> from sage.all import *>>> g = Graph()>>> g.add_edges(graphs.CubeGraph(Integer(5)).min_spanning_tree())>>> g.wiener_index() == szeged_index(g)TrueCheck that both algorithms return same value:
sage: # long time, needs networkx
sage: G = graphs.RandomBarabasiAlbert(100, 2)
sage: a = szeged_index(G, algorithm= low )sage: b = szeged_index(G, algorithm= high )sage: a == b
True>>> from sage.all import *>>> # long time, needs networkx>>> G = graphs.RandomBarabasiAlbert(Integer(100), Integer(2))>>> a = szeged_index(G, algorithm= low )>>> b = szeged_index(G, algorithm= high )(continues on next page)

1.1. Generic graphs (common to directed/undirected)

405

Graph Theory, Release 10.4

(continued from previous page)>>> a == b
True

The Szeged index of a directed circuit of order 𝑛 is (𝑛 − 1)2 :sage: [digraphs.Circuit(n).szeged_index() for n in range(1, 8)][0, 1, 4, 9, 16, 25, 36]>>> from sage.all import *>>> [digraphs.Circuit(n).szeged_index() for n in range(Integer(1),␣
˓→Integer(8))][0, 1, 4, 9, 16, 25, 36]

tensor_product(other)
Return the tensor product of self and other.
The tensor product of 𝐺 and 𝐻 is the graph 𝐿 with vertex set 𝑉 (𝐿) equal to the Cartesian product of thevertices 𝑉 (𝐺) and 𝑉 (𝐻), and ((𝑢, 𝑣), (𝑤, 𝑥)) is an edge iff - (𝑢, 𝑤) is an edge of self, and - (𝑣, 𝑥) is an edgeof other.
The tensor product is also known as the categorical product and the Kronecker product (referring to the
Kronecker matrix product). See the Wikipedia article Kronecker_product.
EXAMPLES:
sage: Z = graphs.CompleteGraph(2)sage: C = graphs.CycleGraph(5)sage: T = C.tensor_product(Z); T
Graph on 10 vertices
sage: T.size()
10
sage: T.plot()# long time
˓→needs sage.plot
Graphics object consisting of 21 graphics primitives>>> from sage.all import *>>> Z = graphs.CompleteGraph(Integer(2))>>> C = graphs.CycleGraph(Integer(5))>>> T = C.tensor_product(Z); T
Graph on 10 vertices>>> T.size()
10>>> T.plot()# long time
˓→needs sage.plot
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
˓→needs sage.plot
Graphics object consisting of 1101 graphics primitives

406

#␣

#␣

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> P = graphs.PetersenGraph()>>> T = D.tensor_product(P); T
Graph on 200 vertices>>> T.size()
900>>> T.plot()# long time
˓→needs sage.plot
Graphics object consisting of 1101 graphics primitives#␣

to_dictionary(edge_labels=False, multiple_edges=False)
Return the graph as a dictionary.
INPUT:• edge_labels – boolean (default: False); whether to include edge labels in the output• multiple_edges – boolean (default: False); whether to include multiple edges in the output
OUTPUT:
The output depends on the input:• If edge_labels == False and multiple_edges == False, the output is a dictionary
associating to each vertex the list of its neighbors.
• If edge_labels == False and multiple_edges == True, the output is a dictionary thesame as previously with one difference: the neighbors are listed with multiplicity.
• If edge_labels == True and multiple_edges == False, the output is a dictionary
associating to each vertex 𝑢 [a dictionary associating to each vertex 𝑣 incident to 𝑢 the label of edge(𝑢, 𝑣)].
• If edge_labels == True and multiple_edges == True, the output is a dictionary associating to each vertex 𝑢 [a dictionary associating to each vertex 𝑣 incident to 𝑢 [the list of labels of alledges 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],(continues on next page)

1.1. Generic graphs (common to directed/undirected)

407

Graph Theory, Release 10.4

(continued from previous page)

4: [0, 3, 9], 5: [0, 7, 8],
6: [1, 8, 9], 7: [2, 5, 9],
8: [3, 5, 6], 9: [4, 6, 7]}
sage: graphs.PetersenGraph().to_dictionary(edge_labels=True){0: {1: None, 4: None, 5: None},
1: {0: None, 2: None, 6: None},
2: {1: None, 3: None, 7: None},
3: {2: None, 4: None, 8: None},
4: {0: None, 3: None, 9: None},
5: {0: None, 7: None, 8: None},
6: {1: None, 8: None, 9: None},
7: {2: None, 5: None, 9: None},
8: {3: None, 5: None, 6: None},
9: {4: None, 6: None, 7: None}}sage: graphs.PetersenGraph().to_dictionary(edge_labels=True,multiple_
˓→edges=True){0: {1: [None], 4: [None], 5: [None]},1: {0: [None], 2: [None], 6: [None]},2: {1: [None], 3: [None], 7: [None]},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]}}>>> from sage.all import *>>> g = graphs.PetersenGraph().to_dictionary()>>> [(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])]>>> 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]}>>> graphs.PetersenGraph().to_dictionary(edge_labels=True){0: {1: None, 4: None, 5: None},
1: {0: None, 2: None, 6: None},
2: {1: None, 3: None, 7: None},
3: {2: None, 4: None, 8: None},
4: {0: None, 3: None, 9: None},
5: {0: None, 7: None, 8: None},
6: {1: None, 8: None, 9: None},
7: {2: None, 5: None, 9: None},
8: {3: None, 5: None, 6: None},(continues on next page)

408

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

9: {4: None, 6: None, 7: None}}>>> 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)
Return a simple version of the self.
In particular, loops and multiple edges are removed, and the graph might optionally be converted to an undirected graph.
INPUT:• to_undirected – boolean (default: True); if True, the graph is also converted to an undirectedgraph• keep_label – string (default: any ); if there are multiple edges with different labels, this variable
defines which label should be kept:–

any – any label–

min – the smallest label–

max – the largest label

Warning:
min and max only works if the labels can be compared. A TypeError might beraised when working with non-comparable objects.
• immutable – boolean (default: Non); whether to create a mutable/immutable copy.
mutable=None (default) means that the graph and its copy will behave the same way.

im-

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(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (2, 3), (3, 2)]
sage: H = G.to_simple()sage: H.edges(sort=True, 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(sort=True)(continues on next page)

1.1. Generic graphs (common to directed/undirected)

409

Graph Theory, Release 10.4

(continued from previous page)[(2, 3, 1), (3, 2, None)]sage: G.to_simple(to_undirected=False, keep_label= max ).edges(sort=True)[(2, 3, 2), (3, 2, None)]>>> from sage.all import *>>> G = DiGraph(loops=True, multiedges=True, sparse=True)>>> G.add_edges([(Integer(0), Integer(0), None), (Integer(1), Integer(1),␣
˓→None), (Integer(2), Integer(2), None),...
(Integer(2), Integer(3), Integer(1)), (Integer(2),␣
˓→Integer(3), Integer(2)), (Integer(3), Integer(2), None)])>>> G.edges(sort=True, labels=False)[(0, 0), (1, 1), (2, 2), (2, 3), (2, 3), (3, 2)]>>> H = G.to_simple()>>> H.edges(sort=True, labels=False)[(2, 3)]>>> H.is_directed()
False>>> H.allows_loops()
False>>> H.allows_multiple_edges()
False>>> G.to_simple(to_undirected=False, keep_label= min ).edges(sort=True)[(2, 3, 1), (3, 2, None)]>>> G.to_simple(to_undirected=False, keep_label= max ).edges(sort=True)[(2, 3, 2), (3, 2, None)]transitive_closure(loops=True)
Return the transitive closure of the (di)graph.
The transitive closure of a graph 𝐺 has an edge (𝑥, 𝑦) if and only if there is a path between 𝑥 and 𝑦 in 𝐺.
The transitive closure of any (strongly) connected component of a (di)graph is a complete graph. The transitive
closure of a directed acyclic graph is a directed acyclic graph representing the full partial order.
Note: If the (di)graph allows loops, its transitive closure will by default have one loop edge per vertex. Thiscan be prevented by disallowing loops in the (di)graph (self.allow_loops(False)).
EXAMPLES:
sage: g = graphs.PathGraph(4)sage: g.transitive_closure()
Transitive closure of Path graph: Graph on 4 vertices
sage: g.transitive_closure().is_isomorphic(graphs.CompleteGraph(4))
Truesage: g = DiGraph({0: [1, 2], 1: [3], 2: [4, 5]})sage: g.transitive_closure().edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 3), (2, 4), (2, 5)]>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4))>>> g.transitive_closure()
Transitive closure of Path graph: Graph on 4 vertices>>> g.transitive_closure().is_isomorphic(graphs.CompleteGraph(Integer(4)))
True>>> g = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
(continues on next page)

410

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[Integer(3)], Integer(2): [Integer(4), Integer(5)]})>>> g.transitive_closure().edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 3), (2, 4), (2, 5)]˓→On an immutable digraph:
sage: digraphs.Path(5).copy(immutable=True).transitive_closure()
Transitive closure of Path: Digraph on 5 vertices>>> from sage.all import *>>> digraphs.Path(Integer(5)).copy(immutable=True).transitive_closure()
Transitive closure of Path: Digraph on 5 vertices

The transitive closure of a (di)graph allowing loops has by default a loop edge per vertex. Parameter loops
allows to prevent that:
sage: G = digraphs.Circuit(3)sage: G.transitive_closure().loop_edges(labels=False)[]
sage: G.allow_loops(True)
sage: G.transitive_closure().loop_edges(labels=False)[(0, 0), (1, 1), (2, 2)]>>> from sage.all import *>>> G = digraphs.Circuit(Integer(3))>>> G.transitive_closure().loop_edges(labels=False)[]>>> G.allow_loops(True)>>> G.transitive_closure().loop_edges(labels=False)[(0, 0), (1, 1), (2, 2)]
sage: G = graphs.CycleGraph(3)sage: G.transitive_closure().loop_edges(labels=False)[]
sage: G.allow_loops(True)
sage: G.transitive_closure().loop_edges(labels=False)[(0, 0), (1, 1), (2, 2)]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> G.transitive_closure().loop_edges(labels=False)[]>>> G.allow_loops(True)>>> G.transitive_closure().loop_edges(labels=False)[(0, 0), (1, 1), (2, 2)]transitive_reduction()
Return a transitive reduction of a graph.
A transitive reduction 𝐻 of 𝐺 has a path from 𝑥 to 𝑦 if and only if there was a path from 𝑥 to 𝑦 in 𝐺. Deletingany edge of 𝐻 destroys this property. A transitive reduction is not unique in general. A transitive reduction
has the same transitive closure as the original graph.
A transitive reduction of a complete graph is a tree. A transitive reduction of a tree is itself.
EXAMPLES:
1.1. Generic graphs (common to directed/undirected)

411

Graph Theory, Release 10.4

sage: g = graphs.PathGraph(4)sage: g.transitive_reduction() == gTruesage: g = graphs.CompleteGraph(5)sage: h = g.transitive_reduction(); h.size()4
sage: g = DiGraph({0: [1, 2], 1: [2, 3, 4, 5], 2: [4, 5]})sage: g.transitive_reduction().size()
5>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4))>>> g.transitive_reduction() == g
True>>> g = graphs.CompleteGraph(Integer(5))>>> h = g.transitive_reduction(); h.size()4>>> g = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(2), Integer(3), Integer(4), Integer(5)], Integer(2): [Integer(4),␣
˓→Integer(5)]})>>> g.transitive_reduction().size()
5

traveling_salesman_problem(use_edge_labels, maximize=False, solver=False,
constraint_generation=None, verbose=None, verbose_constraints=0,
integrality_tolerance=False)
Solve 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 sometime before returning its result.
INPUT:• use_edge_labels – boolean (default: False); whether to solve the weighted traveling salesman
problem where the weight of an edge is defined by its label (a label set to None or {} being considered
as a weight of 1), or the non-weighted version (i.e., the Hamiltonian cycle problem)• maximize – boolean (default: False); whether to compute a minimum (default) or a maximum(when maximize == True) weight tour (or Hamiltonian cycle). This parameter is considered only
if use_edge_labels == True.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• constraint_generation – boolean (default: None); whether to use constraint generation whensolving the Mixed Integer Linear Program.
When constraint_generation = None, constraint generation is used whenever the graph hasa density larger than 70%.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• verbose_constraints – boolean (default: False); whether to display which constraints are being
generated

412

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
A solution to the TSP, as a Graph object whose vertex set is 𝑉 (𝐺), and whose edges are only those of thesolution.
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(); tsp
˓→needs sage.numerical.mip
TSP from Heawood graph: Graph on 14 vertices>>> from sage.all import *>>> g = graphs.HeawoodGraph()>>> tsp = g.traveling_salesman_problem(); tsp
˓→needs sage.numerical.mip
TSP from Heawood graph: Graph on 14 vertices#␣#␣The solution to the TSP has to be connected:
sage: tsp.is_connected()
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> tsp.is_connected()
˓→needs sage.numerical.mip
True

#␣

#␣

It must also be a 2-regular graph:
sage: tsp.is_regular(k=2)˓→needs sage.numerical.mip
True>>> from sage.all import *>>> tsp.is_regular(k=Integer(2))˓→# needs sage.numerical.mip
True

#␣

␣

And obviously it is a subgraph of the Heawood graph:
sage: tsp.is_subgraph(g, induced=False)
˓→needs sage.numerical.mip
True

#␣

1.1. Generic graphs (common to directed/undirected)

413

Graph Theory, Release 10.4>>> from sage.all import *>>> tsp.is_subgraph(g, induced=False)
˓→needs sage.numerical.mip
True

#␣

On the other hand, the Petersen Graph is known not to be Hamiltonian:sage: g = graphs.PetersenGraph()
sage: tsp = g.traveling_salesman_problem()˓→needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: the given graph is not Hamiltonian>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> tsp = g.traveling_salesman_problem()˓→needs sage.numerical.mip
Traceback (most recent call last):...
EmptySetError: the given graph is not Hamiltonian#␣#␣One easy way to change it is obviously to add to this graph the edges corresponding to a Hamiltonian cycle.
If we do this by setting the cost of these new edges to 2, while the others are set to 1, we notice that not all
the edges we added are used in the optimal solution
sage: for u, v in g.edge_iterator(labels=None):....:g.set_edge_label(u, v, 1)
sage: cycle = graphs.CycleGraph(10)sage: for u,v in cycle.edges(labels=None, sort=False):....:
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)
˓→needs sage.numerical.mip
sage: sum( tsp.edge_labels() ) < 2 * 10
˓→needs sage.numerical.mip
True

#␣
#␣

>>> from sage.all import *>>> for u, v in g.edge_iterator(labels=None):...
g.set_edge_label(u, v, Integer(1))>>> cycle = graphs.CycleGraph(Integer(10))>>> for u,v in cycle.edges(labels=None, sort=False):...
if not g.has_edge(u, v):...
g.add_edge(u, v)...
g.set_edge_label(u, v, Integer(2))>>> tsp = g.traveling_salesman_problem(use_edge_labels=True)
˓→needs sage.numerical.mip>>> sum( tsp.edge_labels() ) < Integer(2) * Integer(10)˓→# needs sage.numerical.mip
True

414

#␣
␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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, sort=False):....:
g.set_edge_label(u,v,1/2)
sage: tsp = g.traveling_salesman_problem(use_edge_labels=True)
˓→needs sage.numerical.mip
sage: sum(tsp.edge_labels()) == (1/2) * 10
˓→needs sage.numerical.mip
True

#␣
#␣

>>> from sage.all import *>>> for u, v in cycle.edges(labels=None, sort=False):...
g.set_edge_label(u,v,Integer(1)/Integer(2))>>> tsp = g.traveling_salesman_problem(use_edge_labels=True)
˓→needs sage.numerical.mip>>> sum(tsp.edge_labels()) == (Integer(1)/Integer(2)) * Integer(10)˓→# needs sage.numerical.mip
True

#␣
␣

Search for a minimum and a maximum weight Hamiltonian cycle:
sage: # needs sage.numerical.mip
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>>> from sage.all import *>>> # needs sage.numerical.mip>>> G = Graph([(Integer(0), Integer(1), Integer(1)), (Integer(0), Integer(2),␣
˓→Integer(2)), (Integer(0), Integer(3), Integer(1)), (Integer(1), Integer(2),␣
˓→Integer(1)), (Integer(1), Integer(3), Integer(2)), (Integer(2), Integer(3),␣
˓→Integer(1))])>>> tsp = G.traveling_salesman_problem(use_edge_labels=True,...
maximize=False)>>> print(sum(tsp.edge_labels()))
4>>> tsp = G.traveling_salesman_problem(use_edge_labels=True,...
maximize=True)>>> print(sum(tsp.edge_labels()))
6

triangles_count(algorithm=None)
Return the number of triangles in the (di)graph.
For digraphs, we count the number of directed circuit of length 3.
INPUT:• algorithm – string (default: None); specifies the algorithm to use (note that only iter is available
for directed graphs):
1.1. Generic graphs (common to directed/undirected)

415

Graph Theory, Release 10.4–

sparse_copy – counts the triangles in a sparse copy of the graph (see sage.graphs.
base.static_sparse_graph). Calls static_sparse_graph.triangles_count–dense_copy – counts the triangles in a dense copy of the graph (see sage.graphs.base.
static_dense_graph). Calls static_dense_graph.triangles_count–matrix uses the trace of the cube of the adjacency matrix–

iter iterates over the pairs of neighbors of each vertex. No copy of the graph is performed– None – for undirected graphs, uses "sparse_copy" or "dense_copy" depending on whether
the graph is stored as dense or sparse. For directed graphs, uses iter .
EXAMPLES:
The Petersen graph is triangle free and thus:
sage: G = graphs.PetersenGraph()
sage: G.triangles_count()0>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.triangles_count()0

Any triple of vertices in the complete graph induces a triangle so we have:sage: G = graphs.CompleteGraph(15)sage: G.triangles_count() == binomial(15, 3)
˓→needs sage.symbolic
True

#␣

>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(15))>>> G.triangles_count() == binomial(Integer(15), Integer(3))˓→# needs sage.symbolicTrue␣The 2-dimensional DeBruijn graph of 2 symbols has 2 directed 𝐶3 :sage: G = digraphs.DeBruijn(2,2)˓→needs sage.combinat
sage: G.triangles_count()
˓→needs sage.combinat
2

#␣
#␣

>>> from sage.all import *>>> G = digraphs.DeBruijn(Integer(2),Integer(2))˓→# needs sage.combinat>>> G.triangles_count()
˓→needs sage.combinat2␣#␣The directed 𝑛-cycle is trivially triangle free for 𝑛 > 3:sage: G = digraphs.Circuit(10)sage: G.triangles_count()#␣(continues on next page)

416

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules˓→0>>> from sage.all import *>>> G = digraphs.Circuit(Integer(10))>>> G.triangles_count()
˓→needs sage.modules
0#␣union(other, immutable=None)
Return the union of self and other.
If the graphs have common vertices, the common vertices will be identified.
If one of the two graphs allows loops (or multiple edges), the resulting graph will allow loops (or multiple
edges).
If both graphs are weighted the resulting graphs is weighted.
If both graphs are immutable, the resulting graph is immutable, unless requested otherwise.
INPUT:• immutable – boolean (default: None); whether to create a mutable/immutable union.
mutable=None (default) means that the graphs and their union will behave the same way.

im-

See also:• disjoint_union()• join()EXAMPLES:
sage: G = graphs.CycleGraph(3)sage: H = graphs.CycleGraph(4)sage: J = G.union(H); J
Graph on 4 vertices
sage: J.vertices(sort=True)[0, 1, 2, 3]
sage: J.edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (1, 2), (2, 3)]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> H = graphs.CycleGraph(Integer(4))>>> J = G.union(H); J
Graph on 4 vertices>>> J.vertices(sort=True)[0, 1, 2, 3]>>> J.edges(sort=True, labels=False)[(0, 1), (0, 2), (0, 3), (1, 2), (2, 3)]vertex_boundary(vertices1, vertices2=None)
Return a list of all vertices in the external boundary of vertices1, intersected with vertices2.
If vertices2 is None, then vertices2 is the complement of vertices1. This is much faster if
vertices1 is smaller than vertices2.

1.1. Generic graphs (common to directed/undirected)

417

Graph Theory, Release 10.4

The external boundary of a set of vertices is the union of the neighborhoods of each vertex in the set. Notethat in this implementation, since vertices2 defaults to the complement of vertices1, if a vertex 𝑣
has a loop, then vertex_boundary(v) will not contain 𝑣.
In a digraph, the external boundary of a vertex 𝑣 are those vertices 𝑢 with an arc (𝑣, 𝑢).
EXAMPLES:
sage: G = graphs.CubeGraph(4)sage: l = [ 0111 , 0000 , 0001 , 0011 , 0010 , 0101 ,˓→ 1101 ,1011 , 1001 ]sage: sorted(G.vertex_boundary([ 0000 , 1111 ], l))[ 0001 , 0010 , 0100 , 0111 , 1011 , 1101 ]>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(4))>>> l = [ 0111 , 0000 , 0001 , 0011 , 0010 , 0101 ,˓→ ,1011 , 1001 ]>>> sorted(G.vertex_boundary([ 0000 , 1111 ], l))[ 0001 , 0010 , 0100 , 0111 , 1011 , 1101 ]

0100 ,

0100 ,

1111 ,

1111 ,

1101

sage: D = DiGraph({0: [1, 2], 3: [0]})sage: D.vertex_boundary([0])[1, 2]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(3):␣
˓→[Integer(0)]})>>> D.vertex_boundary([Integer(0)])[1, 2]

vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, verbose=0,
integrality_tolerance=0.001)
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 graphis strongly 𝑘-connected if there are 𝑘 vertex disjoint paths between any two vertices 𝑢, 𝑣). If you do notwant to consider strong connectivity, the best is probably to convert your DiGraph object to a Graphobject, and compute the connectivity of this other graph.
• By convention, a complete graph on 𝑛 vertices is 𝑛 − 1 connected. In this case, no certificate can begiven as there is no pair of vertices split by a cut of order 𝑘 − 1. For this reason, the certificates returnedin this situation are empty.
INPUT:• G – the input Sage (Di)Graph• value_only – boolean (default: True)– When set to True (default), only the value is returned.
– When set to False, both the value and a minimum vertex cut are returned.
418

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• sets – boolean (default: False); whether to also return the two
sets of vertices that are disconnected by the cut (implies value_only=False)• k – integer (default: None); when specified, check if the vertex connectivity of the (di)graph is larger
or equal to 𝑘. The method thus outputs a boolean only.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic application on a PappusGraph:
sage: from sage.graphs.connectivity import vertex_connectivity
sage: g = graphs.PappusGraph()
sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
3
sage: g.vertex_connectivity()˓→# needs sage.numerical.mip
3>>> from sage.all import *>>> from sage.graphs.connectivity import vertex_connectivity>>> g = graphs.PappusGraph()>>> vertex_connectivity(g)˓→ # needs sage.numerical.mip
3>>> g.vertex_connectivity()
˓→ # needs sage.numerical.mip
3

␣

␣

␣

␣

In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is ofcardinality 1:
sage: g = graphs.GridGraph([ 3,3 ])sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True)˓→# needs sage.numerical.mip
sage: len(setA) == 1 or len(setB) == 1
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.GridGraph([ Integer(3),Integer(3) ])>>> [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True)
˓→ # needs sage.numerical.mip>>> len(setA) == Integer(1) or len(setB) == Integer(1)˓→# needs sage.numerical.mip
True

␣
␣

␣
␣

A vertex cut in a tree is any internal vertex:

1.1. Generic graphs (common to directed/undirected)

419

Graph Theory, Release 10.4

sage: tree = graphs.RandomTree(15)sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False)˓→# needs sage.numerical.mip
sage: tree.degree(cut_vertex) > 1
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> tree = graphs.RandomTree(Integer(15))>>> val, [cut_vertex] = vertex_connectivity(tree, value_only=False)
˓→ # needs sage.numerical.mip>>> tree.degree(cut_vertex) > Integer(1)˓→# needs sage.numerical.mip
True

␣
␣

␣
␣

When value_only = True, this function is optimized for small connectivity values and does not needto build a linear program.
It is the case for connected graphs which are not connected:
sage: g = 2 * graphs.PetersenGraph()
sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
0␣>>> from sage.all import *>>> g = Integer(2) * graphs.PetersenGraph()>>> vertex_connectivity(g)˓→ # needs sage.numerical.mip
0␣

Or if they are just 1-connected:
sage: g = graphs.PathGraph(10)sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
1

␣>>> from sage.all import *>>> g = graphs.PathGraph(Integer(10))>>> vertex_connectivity(g)˓→ # needs sage.numerical.mip
1␣For directed graphs, the strong connectivity is tested through the dedicated function:
sage: g = digraphs.ButterflyGraph(3)sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
0>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(3))>>> vertex_connectivity(g)˓→ # needs sage.numerical.mip
0

420

␣

␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

A complete graph on 10 vertices is 9-connected:
sage: g = graphs.CompleteGraph(10)sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
9>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(10))>>> vertex_connectivity(g)˓→ # needs sage.numerical.mip9␣␣

A complete digraph on 10 vertices is 9-connected:
sage: g = DiGraph(graphs.CompleteGraph(10))
sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
9>>> from sage.all import *>>> g = DiGraph(graphs.CompleteGraph(Integer(10)))>>> vertex_connectivity(g)˓→ # needs sage.numerical.mip
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)
˓→# needs sage.numerical.mip
True
sage: vertex_connectivity(g, k=4)
˓→# needs sage.numerical.mip
False>>> from sage.all import *>>> g = graphs.PappusGraph()>>> vertex_connectivity(g, k=Integer(3))˓→# needs sage.numerical.mip
True>>> vertex_connectivity(g, k=Integer(4))˓→# needs sage.numerical.mip
False

␣

␣

␣

␣

vertex_cut(s, t, value_only, vertices=True, solver=False, verbose=None, integrality_tolerance=0)
Return 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 obtained byremoving 𝑈 from self is disconnected. For more information, see the Wikipedia article Cut_(graph_theory).
INPUT:• value_only – boolean (default: True); whether to return only the size of the minimum cut, or toalso return the set 𝑈 of vertices of the cut• vertices – boolean (default: False); whether to also return the two sets of vertices that are disconnected by the cut. Implies value_only set to False.
1.1. Generic graphs (common to directed/undirected)

421

Graph Theory, Release 10.4

• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
Real number or tuple, depending on the given arguments (examples are given below).
EXAMPLES:
A basic application in the Pappus graph:
sage: g = graphs.PappusGraph()
sage: g.vertex_cut(1, 16, value_only=True)
˓→# needs sage.numerical.mip
3>>> from sage.all import *>>> g = graphs.PappusGraph()>>> g.vertex_cut(Integer(1), Integer(16), value_only=True)˓→# needs sage.numerical.mip
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)
˓→# needs sage.numerical.mip
sage: print(value)
˓→# needs sage.numerical.mip
8
sage: vertices == list(range(2, 10))
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.CompleteBipartiteGraph(Integer(2), Integer(8))>>> [value, vertices] = g.vertex_cut(Integer(0), Integer(1), value_
˓→only=False)# needs sage.numerical.mip>>> print(value)
˓→needs sage.numerical.mip
8>>> vertices == list(range(Integer(2), Integer(10)))˓→# needs sage.numerical.mip
True

#␣

␣

Clearly, in this case the two sides of the cut are singletons:
sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True)
˓→# needs sage.numerical.mip
sage: len(set1) == 1
˓→# needs sage.numerical.mip
True(continues on next page)422

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: len(set2) == 1
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> [value, vertices, [set1, set2]] = g.vertex_cut(Integer(0), Integer(1),␣
˓→vertices=True)# needs sage.numerical.mip>>> len(set1) == Integer(1)˓→# needs sage.numerical.mip
True>>> len(set2) == Integer(1)˓→# needs sage.numerical.mip
True

␣

␣

vertex_disjoint_paths(s, t, solver, verbose=None, integrality_tolerance=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 numberof pairwise vertex-independent paths from 𝑠 to 𝑡.
This function returns a list of such paths.
INPUT:• s, t – two vertices of the graph.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
In a complete bipartite graphsage: g = graphs.CompleteBipartiteGraph(2, 3)
sage: g.vertex_disjoint_paths(0, 1)
˓→needs sage.numerical.mip[[0, 2, 1], [0, 3, 1], [0, 4, 1]]>>> from sage.all import *>>> g = graphs.CompleteBipartiteGraph(Integer(2), Integer(3))>>> g.vertex_disjoint_paths(Integer(0), Integer(1))˓→# needs sage.numerical.mip[[0, 2, 1], [0, 3, 1], [0, 4, 1]]#␣␣vertex_iterator(vertices=None, degree=None, vertex_property=None)
Return 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)graph1.1. Generic graphs (common to directed/undirected)

423

Graph Theory, Release 10.4

• degree – a nonnegative integer (default: None); a vertex v is kept if degree(v) == degree• vertex_property – function (default: None); a function that inputs a vertex and outputs a boolean
value, i.e., a vertex v is kept if vertex_property(v) == True
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: for v in P.vertex_iterator():....:print(v)
0
1
2
...
8
9
>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> for v in P.vertex_iterator():...
print(v)
0
1
2
...
8
9
sage: G = graphs.TetrahedralGraph()
sage: for i in G:....:
print(i)01
2
3>>> from sage.all import *>>> G = graphs.TetrahedralGraph()>>> for i in G:...
print(i)0123sage: H = graphs.PathGraph(5)sage: prop = lambda l: l % 3 == 1
sage: for v in H.vertex_iterator(degree=1, vertex_property=prop):....:
print(v)
4>>> from sage.all import *>>> H = graphs.PathGraph(Integer(5))>>> prop = lambda l: l % Integer(3) == Integer(1)>>> for v in H.vertex_iterator(degree=Integer(1), vertex_property=prop):...
print(v)4424

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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(sort=False)# 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>>> from sage.all import *>>> timeit V = P.vertices(sort=False)# not tested
100000 loops, best of 3: 8.85 [micro]s per loop>>> timeit V = list(P.vertex_iterator())# not tested
100000 loops, best of 3: 5.74 [micro]s per loop

vertices(sort=False, key=None, degree=None, vertex_property=None)
Return a list of the vertices.
INPUT:• sort – boolean (default: False); whether to sort vertices according the ordering specified with parameter key. If False (default), vertices are not sorted.
• key – a function (default: None); a function that takes a vertex as its one argument and returns a valuethat can be used for comparisons in the sorting algorithm (we must have sort=True)• degree – a nonnegative integer (default: None); a vertex v is kept if degree(v) == degree• vertex_property – function (default: None); a function that inputs a vertex and outputs a boolean
value, i.e., a vertex v is kept if vertex_property(v) == TrueOUTPUT:
The list of vertices of the (di)graph.
Warning: 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 toguarantee a total order for the sorting of the edges, use the key argument, as illustrated in the examples
below.
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

If you do not care about sorted output and you are concerned about the time taken to sort, consider thefollowing alternative:
sage: # not tested
sage: timeit V = P.vertices(sort=True)
625 loops, best of 3: 3.86 [micro]s per loop
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

425

Graph Theory, Release 10.4

(continued from previous page)

sage: timeit V = P.vertices(sort=False)
625 loops, best of 3: 2.06 [micro]s per loop
sage: timeit V = list(P.vertex_iterator())
625 loops, best of 3: 2.05 [micro]s per loop
sage: timeit( V = list(P) )625 loops, best of 3: 1.98 [micro]s per loop>>> from sage.all import *>>> # not tested>>> timeit V = P.vertices(sort=True)
625 loops, best of 3: 3.86 [micro]s per loop>>> timeit V = P.vertices(sort=False)
625 loops, best of 3: 2.06 [micro]s per loop>>> timeit V = list(P.vertex_iterator())
625 loops, best of 3: 2.05 [micro]s per loop>>> timeit( V = list(P) )625 loops, best of 3: 1.98 [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(sort=True)[0, 1, 2, 3, 4, ... 22, 23, 24, 25, 26]
sage: H.vertices(sort=True, key=lambda x: -x)[26, 25, 24, 23, 22, ... 4, 3, 2, 1, 0]>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(3), Integer(3), labels=False)>>> H.vertices(sort=True)[0, 1, 2, 3, 4, ... 22, 23, 24, 25, 26]>>> H.vertices(sort=True, key=lambda x: -x)[26, 25, 24, 23, 22, ... 4, 3, 2, 1, 0]
sage: G = graphs.HanoiTowerGraph(3, 3)
sage: G.vertices(sort=True)[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), ... (2, 2, 1), (2, 2, 2)]
sage: G.vertices(sort=True, key = lambda x: (x[1], x[2], x[0]))[(0, 0, 0), (1, 0, 0), (2, 0, 0), (0, 0, 1), ... (1, 2, 2), (2, 2, 2)]>>> from sage.all import *>>> G = graphs.HanoiTowerGraph(Integer(3), Integer(3))>>> G.vertices(sort=True)[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), ... (2, 2, 1), (2, 2, 2)]>>> G.vertices(sort=True, key = lambda x: (x[Integer(1)], x[Integer(2)],␣
˓→x[Integer(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 arepolynomials, and use the discriminant function to provide an ordering. Note that since functions are first-classobjects in Python, we can specify precisely the function from the Sage library that we wish to use as the key:
sage: # needs sage.libs.flint
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: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_(continues on next page)

426

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

rational_flint
sage: dsc = Polynomial_rational_flint.discriminantsage: verts = K.vertices(sort=True, key=dsc); verts[t^2 + 2, t^2, 5*t, 4*t^2 - 6]sage: [x.discriminant() for x in verts][-8, 0, 1, 96]˓→>>> from sage.all import *>>> # needs sage.libs.flint>>> t = polygen(QQ, t )>>> K = Graph({Integer(5)*t: [t**Integer(2)], t**Integer(2):␣˓→[t**Integer(2)+Integer(2)], t**Integer(2)+Integer(2):␣
˓→[Integer(4)*t**Integer(2)-Integer(6)], Integer(4)*t**Integer(2)-Integer(6):␣
˓→[Integer(5)*t]})>>> from sage.rings.polynomial.polynomial_rational_flint import Polynomial_
˓→rational_flint>>> dsc = Polynomial_rational_flint.discriminant>>> verts = K.vertices(sort=True, key=dsc); verts[t^2 + 2, t^2, 5*t, 4*t^2 - 6]>>> [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 – boolean (default: None); if it is provided, then the weightedness flag is set accordingly. This is
not allowed for immutable graphs.
Note: Changing the weightedness flag changes the ==-class of a graph and is thus not allowed for immutablegraphs.
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 forthe presence of edges:
sage: G = Graph({0: {1:sage: H = Graph({0: {1:sage: G == H
Truea }}, sparse=True)b }}, sparse=True)>>> from sage.all import *>>> G = Graph({Integer(0): {Integer(1):>>> H = Graph({Integer(0): {Integer(1):>>> G == H
Truea }}, sparse=True)b }}, sparse=True)

Now one is weighted and the other is not, and thus the graphs are not equal:
sage: G.weighted(True)
sage: H.weighted()(continues on next page)

1.1. Generic graphs (common to directed/undirected)

427

Graph Theory, Release 10.4

(continued from previous page)

False
sage: G == H
False>>> from sage.all import *>>> G.weighted(True)>>> H.weighted()
False>>> G == H
False

However, if both are weighted, then we finally compare ‘a’ to ‘b’:sage: H.weighted(True)
sage: G == H
False>>> from sage.all import *>>> H.weighted(True)>>> G == H
False

weighted_adjacency_matrix(sparse, vertices=True, default_weight=None, base_ring=None, **kwds)
Return the weighted adjacency matrix of the graph.
By default, each vertex is represented by its position in the list returned by method vertices().
INPUT:• sparse – boolean (default: True); whether to use a sparse or a dense matrix• vertices – list, None, or True (default: None);– when a list, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering ofvertices,– when None, the 𝑖-th row and column of the matrix correspond to the 𝑖-th vertex in the ordering
given by GenericGraph.vertices() with sort=True.
– when True, construct an endomorphism of a free module instead of a matrix, where the module’sbasis is indexed by the vertices.
If the vertices are not comparable, the keyword vertices must be used to specify an ordering, or a
TypeError exception will be raised.
• default_weight – (default: None); specifies the weight to replace any None edge label. When not
specified an error is raised if the label of an edge is None.
• base_ring – a ring (default: determined from the weights); the base ring of the matrix space to use.
• **kwds – other keywords to pass to matrix()
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˓→needs sage.modules[0 1 3 4]#␣(continues on next page)

428

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[1 0 2 0][3 2 0 0][4 0 0 0]
sage: H = Graph(data=M, format= weighted_adjacency_matrix , sparse=True)
˓→needs sage.modules
sage: H == G˓→needs sage.modules
True
sage: G.weighted_adjacency_matrix(vertices=[3, 2, 1, 0])
˓→needs sage.modules[0 0 0 4][0 0 2 3][0 2 0 1][4 3 1 0]

#␣
#␣

#␣

>>> from sage.all import *>>> G = Graph(sparse=True, weighted=True)>>> G.add_edges([(Integer(0), Integer(1), Integer(1)), (Integer(1),␣
˓→Integer(2), Integer(2)), (Integer(0), Integer(2), Integer(3)), (Integer(0),␣
˓→Integer(3), Integer(4))])>>> M = G.weighted_adjacency_matrix(); M#␣˓→needs sage.modules[0 1 3 4][1 0 2 0][3 2 0 0][4 0 0 0]>>> H = Graph(data=M, format= weighted_adjacency_matrix , sparse=True)#␣˓→needs sage.modules>>> H == G#␣˓→needs sage.modules
True>>> G.weighted_adjacency_matrix(vertices=[Integer(3), Integer(2), Integer(1),␣
˓→Integer(0)])# needs sage.modules[0 0 0 4][0 0 2 3][0 2 0 1][4 3 1 0]

Using a different matrix implementation:
sage: M = G.weighted_adjacency_matrix(sparse=False, base_ring=ZZ,
˓→needs numpy sage.modules....:
implementation= numpy ); M
[0 1 3 4][1 0 2 0][3 2 0 0][4 0 0 0]>>> from sage.all import *>>> M = G.weighted_adjacency_matrix(sparse=False, base_ring=ZZ,
˓→needs numpy sage.modules...
implementation= numpy ); M
[0 1 3 4][1 0 2 0][3 2 0 0][4 0 0 0]

1.1. Generic graphs (common to directed/undirected)

#␣

#␣

429

Graph Theory, Release 10.4

As an immutable matrix:
sage: M = G.weighted_adjacency_matrix(immutable=True); M˓→needs sage.modules[0 1 3 4][1 0 2 0][3 2 0 0][4 0 0 0]
sage: M[2, 2] = 1
˓→needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).

#␣#␣>>> from sage.all import *>>> M = G.weighted_adjacency_matrix(immutable=True); M˓→needs sage.modules[0 1 3 4][1 0 2 0][3 2 0 0][4 0 0 0]>>> M[Integer(2), Integer(2)] = Integer(1)˓→# needs sage.modules
Traceback (most recent call last):...
ValueError: matrix is immutable; please change a copy instead(i.e., use copy(M) to change a copy of M).

#␣␣Creating a module morphism:
sage: # needs sage.modules
sage: G = Graph(sparse=True, weighted=True)
sage: G.add_edges([( A , B , 1), ( B , C , 2), ( A , C , 3), ( A ,˓→4)])
sage: phi = G.weighted_adjacency_matrix(vertices=True); phi
Generic endomorphism ofFree module generated by { A , B , C , D } over Integer Ringsage: print(phi._unicode_art_matrix())
A B C DA⎛0 1 3 4⎞B⎜1 0 2 0⎟
C⎜3 2 0 0⎟
D⎝4 0 0 0⎠>>> from sage.all import *>>> # needs sage.modules>>> G = Graph(sparse=True, weighted=True)>>> G.add_edges([( A , B , Integer(1)), ( B , C , Integer(2)), ( A ,˓→Integer(3)), ( A ,D , Integer(4))])>>> phi = G.weighted_adjacency_matrix(vertices=True); phi
Generic endomorphism ofFree module generated by { A , B , C , D } over Integer Ring>>> print(phi._unicode_art_matrix())
A B C DA⎛0 1 3 4⎞B⎜1 0 2 0⎟

D ,␣

C ,␣

(continues on next page)

430

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)C⎜3 2 0 0⎟
D⎝4 0 0 0⎠

wiener_index(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the Wiener index of self.
The graph is expected to have no cycles of negative weight.
∑︀
The Wiener index of a undirected graph 𝐺 is 𝑊 (𝐺) = 12 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣) where 𝑑(𝑢, 𝑣) denotes the distance
between vertices 𝑢 and 𝑣 (see [KRG1996]).
The Wiener index∑︀ of a directed graph 𝐺 is defined as the sum of the distances between each pairs of vertices,
i.e., 𝑊 (𝐺) = 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣).
For more information on the input variables and more examples, we refer to shortest_paths() andshortest_path_all_pairs(), which have very similar input variables.
INPUT:• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• algorithm – string (default: None); one of the following algorithms:– 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 algorithm. 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:∗

Bellman-Ford_Boost : the Bellman-Ford algorithm, implemented in Boost.

∗Johnson_Boost : the Johnson algorithm, implemented in Boost.

∗

Floyd-Warshall-Python – the Python implementation of the Floyd-Warshall algorithm. 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.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
Note: Some algorithms (e.g., Boost algorithms) use floating point numbers for internal computations. Whenever the solution is integral, we try to convert the returned value to an integer.
EXAMPLES:

1.1. Generic graphs (common to directed/undirected)

431

Graph Theory, Release 10.4

sage: G = Graph( { 0: {1: None}, 1: {2: None}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}
˓→ }, sparse=True)
sage: G.wiener_index()
15
sage: G.wiener_index(weight_function=lambda e:(e[2] if e[2] is not None else␣
˓→1))20
sage: G.wiener_index(weight_function=lambda e:(e[2] if e[2] is not None else␣˓→200))
820
sage: G.wiener_index(algorithm= BFS )15
sage: G.wiener_index(algorithm= Floyd-Warshall-Cython )15
sage: G.wiener_index(algorithm= Floyd-Warshall-Python )15
sage: G.wiener_index(algorithm= Dijkstra_Boost )15
sage: G.wiener_index(algorithm= Bellman-Ford_Boost )15
sage: G.wiener_index(algorithm= Johnson_Boost )15
sage: G.wiener_index(algorithm= Dijkstra_NetworkX )#␣˓→needs networkx
15>>> from sage.all import *>>> G = Graph( { Integer(0): {Integer(1): None}, Integer(1): {Integer(2):␣
˓→None}, Integer(2): {Integer(3): Integer(1)}, Integer(3): {Integer(4):␣
˓→Integer(2)}, Integer(4): {Integer(0): Integer(2)} }, sparse=True)>>> G.wiener_index()
15>>> G.wiener_index(weight_function=lambda e:(e[Integer(2)] if e[Integer(2)]␣
˓→is not None else Integer(1)))
20>>> G.wiener_index(weight_function=lambda e:(e[Integer(2)] if e[Integer(2)]␣
˓→is not None else Integer(200)))
820>>> G.wiener_index(algorithm= BFS )15>>> G.wiener_index(algorithm= Floyd-Warshall-Cython )15>>> G.wiener_index(algorithm= Floyd-Warshall-Python )15>>> G.wiener_index(algorithm= Dijkstra_Boost )15>>> G.wiener_index(algorithm= Bellman-Ford_Boost )15>>> G.wiener_index(algorithm= Johnson_Boost )15>>> G.wiener_index(algorithm= Dijkstra_NetworkX )#␣˓→needs networkx
15

Wiener index of complete (di)graphs:

432

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: n = 5
sage: g = graphs.CompleteGraph(n)sage: g.wiener_index() == (n * (n - 1)) / 2
True
sage: g = digraphs.Complete(n)sage: g.wiener_index() == n * (n - 1)
True>>> from sage.all import *>>> n = Integer(5)>>> g = graphs.CompleteGraph(n)>>> g.wiener_index() == (n * (n - Integer(1))) / Integer(2)True>>> g = digraphs.Complete(n)>>> g.wiener_index() == n * (n - Integer(1))
True

Wiener index of circuit digraphs:
sage: n = 7
sage: g = digraphs.Circuit(n)sage: w = lambda x: (x*x*(x-1))/2
sage: g.wiener_index(algorithm= Dijkstra_Boost ) == w(n)True>>> from sage.all import *>>> n = Integer(7)>>> g = digraphs.Circuit(n)>>> w = lambda x: (x*x*(x-Integer(1)))/Integer(2)>>> g.wiener_index(algorithm= Dijkstra_Boost ) == w(n)True

Wiener index of a graph of order 1:
sage: Graph(1).wiener_index()
0>>> from sage.all import *>>> Graph(Integer(1)).wiener_index()
0

The Wiener index is not defined on the empty graph:
sage: Graph().wiener_index()
Traceback (most recent call last):...
ValueError: Wiener index is not defined for the empty graph>>> from sage.all import *>>> Graph().wiener_index()
Traceback (most recent call last):...
ValueError: Wiener index is not defined for the empty graph1.1. Generic graphs (common to directed/undirected)

433

Graph Theory, Release 10.4

sage.graphs.generic_graph.graph_isom_equivalent_non_edge_labeled_graph(g, partition=None,standard_label=None,
return_relabeling=False,
return_edge_labels=False,
inplace=False,
ignore_edge_labels=False)
Helper function for canonical labeling of edge labeled (di)graphs.
Translates to a bipartite incidence-structure type graph appropriate for computing canonical labels of edge labeled
and/or multi-edge graphs. Note that this is actually computationally equivalent to implementing a change on an
inner loop of the main algorithm – namely making the refinement procedure sort for each label.
If the graph is a multigraph, it is translated to a non-multigraph, where each instance of multiple edges is converted
to a single edge labeled with a list [[label1, multiplicity], [label2, multiplicity], .
..] describing how many edges of each label were originally there. Then in either case we are working on agraph without multiple edges. At this point, we create another (partially bipartite) graph, whose left vertices are
the original vertices of the graph, and whose right vertices represent the labeled edges. Any unlabeled edges in theoriginal graph are also present in the new graph, and – this is the bipartite aspect – for every labeled edge 𝑒 from 𝑣
to 𝑤 in the original graph, there is an edge between the right vertex corresponding to 𝑒 and each of the left vertices
corresponding to 𝑣 and 𝑤. We partition the left vertices as they were originally, and the right vertices by common
labels: only automorphisms taking edges to like-labeled edges are allowed, and this additional partition information
enforces this on the new graph.
INPUT:• g – Graph or DiGraph• partition – list (default: None); a partition of the vertices as a list of lists of vertices. If given, thepartition of the vertices is as well relabeled• standard_label – (default: None); edges in g with this label are preserved in the new graph• return_relabeling – boolean (default: False); whether to return a dictionary containing the relabeling• return_edge_labels – boolean (default: False); whether the different edge_labels are returned(useful if inplace is True)• inplace – boolean (default: False); whether the input (di)graph g is modified or the return a new(di)graph. Note that attributes of g are not copied for speed issues, only edges and vertices.
• ignore_edge_labels – boolean (default: False): if True, ignore edge labels, so when constructing
the new graph, only multiple edges are replaced with vertices. Labels on multiple edges are ignored – only
the multiplicity is relevant, so multiple edges with the same multiplicity in the original graph correspond toright vertices in the same partition in the new graph.
OUTPUT:• if inplace is False: the unlabeled graph without multiple edges

434

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• the partition of the vertices• if return_relabeling is True: a dictionary containing the relabeling• if return_edge_labels is True: the list of (former) edge labels is returned
EXAMPLES:
sage: from sage.graphs.generic_graph import graph_isom_equivalent_non_edge_
˓→labeled_graphsage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edges((0, 1, i) for i in range(10))
sage: G.add_edge(1,2, string )sage: G.add_edge(2,123)
sage: graph_isom_equivalent_non_edge_labeled_graph(G, partition=[[0,123],[1,2]])[Graph on 6 vertices, [[1, 0], [2, 3], [5], [4]]]sage: g, part = graph_isom_equivalent_non_edge_labeled_graph(G)sage: g, sorted(part)(Graph on 6 vertices, [[0, 1, 2, 3], [4], [5]])sage: g.edges(sort=True)[(0, 3, None), (1, 4, None), (2, 4, None), (2, 5, None), (3, 5, None)]sage: g = graph_isom_equivalent_non_edge_labeled_graph(G, standard_label= string ,....:return_edge_labels=True)
sage: g[0]Graph on 6 vertices
sage: g[0].edges(sort=True)[(0, 5, None), (1, 4, None), (2, 3, None), (2, 4, None), (3, 5, None)]sage: g[1][[0, 1, 2, 3], [4], [5]]sage: g[2][[[ string , 1]], [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1],
˓→ [8, 1], [9, 1]], [[None, 1]]]
sage: graph_isom_equivalent_non_edge_labeled_graph(G, inplace=True)[[[0, 1, 2, 3], [5], [4]]]sage: G.edges(sort=True)[(0, 3, None), (1, 4, None), (2, 4, None), (2, 5, None), (3, 5, None)]sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edges((0, 1) for i in range(10))
sage: G.add_edge(1, 2, a )sage: G.add_edge(1, 3, b )sage: G.add_edge(2, 3, b )sage: graph_isom_equivalent_non_edge_labeled_graph(G)[0]Graph on 8 vertices
sage: graph_isom_equivalent_non_edge_labeled_graph(G, ignore_edge_labels=True)[0]Graph on 5 vertices
sage: G = Graph(multiedges=True,sparse=True)
sage: G.add_edges((0, 1, i) for i in range(5))
sage: G.add_edges((0, 2, i+10) for i in range(5))
sage: G.add_edges((0, 3) for i in range(4))
sage: g0 = graph_isom_equivalent_non_edge_labeled_graph(G)sage: g1 = graph_isom_equivalent_non_edge_labeled_graph(G, ignore_edge_
˓→labels=True)
sage: g0
(continues on next page)

1.1. Generic graphs (common to directed/undirected)

435

Graph Theory, Release 10.4

(continued from previous page)[Graph on 7 vertices, [[0, 1, 2, 3], [4], [5], [6]]]sage: g1
[Graph on 7 vertices, [[0, 1, 2, 3], [6], [4, 5]]]>>> from sage.all import *>>> from sage.graphs.generic_graph import graph_isom_equivalent_non_edge_labeled_
˓→graph>>> G = Graph(multiedges=True,sparse=True)>>> G.add_edges((Integer(0), Integer(1), i) for i in range(Integer(10)))>>> G.add_edge(Integer(1),Integer(2), string )>>> G.add_edge(Integer(2),Integer(123))>>> graph_isom_equivalent_non_edge_labeled_graph(G, partition=[[Integer(0),˓→Integer(123)],[Integer(1),Integer(2)]])[Graph on 6 vertices, [[1, 0], [2, 3], [5], [4]]]>>> g, part = graph_isom_equivalent_non_edge_labeled_graph(G)>>> g, sorted(part)(Graph on 6 vertices, [[0, 1, 2, 3], [4], [5]])>>> g.edges(sort=True)[(0, 3, None), (1, 4, None), (2, 4, None), (2, 5, None), (3, 5, None)]>>> g = graph_isom_equivalent_non_edge_labeled_graph(G, standard_label= string ,...
return_edge_labels=True)>>> g[Integer(0)]Graph on 6 vertices>>> g[Integer(0)].edges(sort=True)[(0, 5, None), (1, 4, None), (2, 3, None), (2, 4, None), (3, 5, None)]>>> g[Integer(1)][[0, 1, 2, 3], [4], [5]]>>> g[Integer(2)][[[ string , 1]], [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1],
˓→ [8, 1], [9, 1]], [[None, 1]]]>>> graph_isom_equivalent_non_edge_labeled_graph(G, inplace=True)[[[0, 1, 2, 3], [5], [4]]]>>> G.edges(sort=True)[(0, 3, None), (1, 4, None), (2, 4, None), (2, 5, None), (3, 5, None)]>>> G = Graph(multiedges=True,sparse=True)>>> G.add_edges((Integer(0), Integer(1)) for i in range(Integer(10)))>>> G.add_edge(Integer(1), Integer(2), a )>>> G.add_edge(Integer(1), Integer(3), b )>>> G.add_edge(Integer(2), Integer(3), b )>>> graph_isom_equivalent_non_edge_labeled_graph(G)[Integer(0)]Graph on 8 vertices>>> graph_isom_equivalent_non_edge_labeled_graph(G, ignore_edge_
˓→labels=True)[Integer(0)]Graph on 5 vertices>>> G = Graph(multiedges=True,sparse=True)>>> G.add_edges((Integer(0), Integer(1), i) for i in range(Integer(5)))>>> G.add_edges((Integer(0), Integer(2), i+Integer(10)) for i in␣
˓→range(Integer(5)))>>> G.add_edges((Integer(0), Integer(3)) for i in range(Integer(4)))>>> g0 = graph_isom_equivalent_non_edge_labeled_graph(G)(continues on next page)

436

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> g1 = graph_isom_equivalent_non_edge_labeled_graph(G, ignore_edge_labels=True)>>> g0[Graph on 7 vertices, [[0, 1, 2, 3], [4], [5], [6]]]>>> g1[Graph on 7 vertices, [[0, 1, 2, 3], [6], [4, 5]]]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:• pos3d – a 3D layout of the vertices• 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))
˓→needs sage.plot
sage: type(T)˓→needs sage.plot<class sage.plot.plot3d.tachyon.Tachyon >sage: type(p)˓→needs sage.plot<... dict >>>> from sage.all import *>>> G = graphs.TetrahedralGraph()>>> from sage.graphs.generic_graph import tachyon_vertex_plot>>> T,p = tachyon_vertex_plot(G, pos3d=G.layout(dim=Integer(3)))˓→# needs sage.plot>>> type(T)˓→needs sage.plot<class sage.plot.plot3d.tachyon.Tachyon >>>> type(p)˓→needs sage.plot<... dict >

#␣
#␣

#␣

␣
#␣

#␣

1.2 Undirected graphs
This module implements functions and operations involving undirected graphs.
Algorithmically hard stuff

1.2. Undirected graphs437

Graph Theory, Release 10.4

convexity_properties()
has_homomorphism_to()
independent_set()
independent_set_of_representatives()
is_perfect()matching_polynomial()
minor()
pathwidth()rank_decomposition()
topological_minor()treelength()treewidth()tutte_polynomial()vertex_cover()Return a ConvexityProperties object corresponding to self.
Checks whether there is a homomorphism between two graphs.
Return a maximum independent set.
Return an independent set of representatives.
Tests whether the graph is perfect.
Computes the matching polynomial of the graph 𝐺.
Return the vertices of a minor isomorphic to 𝐻 in the current graph.
Compute the pathwidth of self (and provides a decomposition)
Compute an optimal rank-decomposition of the given graph.
Return a topological 𝐻-minor from self if one exists.
Compute the treelength of 𝐺 (and provide a decomposition).
Compute the treewidth of 𝑔 (and provide a decomposition).
Return the Tutte polynomial of the graph 𝐺.
Return a minimum vertex cover of self represented by a set of vertices.

Basic methods
bipartite_color()
bipartite_double()bipartite_sets()
graph6_string()
is_directed()join()
sparse6_string()
to_directed()
to_undirected()
write_to_eps()

Return a dictionary with vertices as the keys and the color class as the values.
Return the (extended) bipartite double of this graph.
Return (𝑋, 𝑌 ) where 𝑋 and 𝑌 are the nodes in each bipartite set of graph 𝐺.
Return the graph6 representation of the graph as an ASCII string.
Since graph is undirected, returns False.
Return the join of self and other.
Return the sparse6 representation of the graph as an ASCII string.
Return a directed version of the graph.
Since the graph is already undirected, simply returns a copy of itself.
Write a plot of the graph to filename in eps format.

Clique-related methods

438

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

all_cliques()
Iterator over the cliques in graph.
atoms_and_clique_sep- Return the atoms of the decomposition of 𝐺 by clique minimal separators.
arators()
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 graphclique_polynomial()
Return the clique polynomial of self.
cliques_containReturn the cliques containing each vertex, represented as a dictionary of lists of
ing_vertex()
lists, keyed by vertex.
cliques_get_clique_bi- Return the vertex-clique bipartite graph of self.
partite()cliques_get_max_clique_graph()
Return the clique graph.
cliques_maximal()
Return the list of all maximal cliques.
cliques_maximum()
Return 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.
cliques_verReturn a dictionary of sizes of the largest maximal cliques containing each vertex,
tex_clique_number()
keyed by vertex.
fracReturn the fractional clique number of the graph.
tional_clique_number()Coloring
chromatic_index()
chromatic_number()chromatic_polynomial()
chromatic_quasisymmetric_function()
chromatic_symmetric_function()coloring()
fractional_chromatic_index()
fractional_chromatic_number()

Return the chromatic index of the graph.
Return the minimal number of colors needed to color the vertices of the graph.
Compute the chromatic polynomial of the graph G.
Return the chromatic quasisymmetric function of self.
Return the chromatic symmetric function of self.
Return the first (optimal) proper vertex-coloring found.
Return the fractional chromatic index of the graph.
Return the fractional chromatic number of the graph.

Connectivity, orientations, trees

1.2. Undirected graphs439

Graph Theory, Release 10.4

acyclic_orientations()
bounded_outdegree_orientation()bridges()cleave()degree_constrained_subgraph()
ear_decomposition()gomory_hu_tree()is_triconnected()
minimum_outdegree_orientation()orientations()
random_orientation()random_spanning_tree()spanning_trees()
spqr_tree()strong_orientation()strong_orientations_iterator()

Return an iterator over all acyclic orientations of an undirected graph 𝐺.
Computes an orientation of self such that every vertex 𝑣 has out-degree lessthan 𝑏(𝑣)Return an iterator over the bridges (or cut edges).
Return the connected subgraphs separated by the input vertex cut.
Returns a degree-constrained subgraph.
Return an Ear decomposition of the graph.
Return a Gomory-Hu tree of self.
Check whether the graph is triconnected.
Returns an orientation of self with the smallest possible maximum outdegree.
Return an iterator over orientations of self.
Return a random orientation of a graph 𝐺.
Return a random spanning tree of the graph.
Return an iterator over all spanning trees of the graph 𝑔.
Return an SPQR-tree representing the triconnected components of the graph.
Returns a strongly connected orientation of the current graph.
Return an iterator over all strong orientations of a graph 𝐺.

Distances
center()centrality_degree()diameter()distance_graph()eccentricity()
hyperbolicity()
periphery()radius()Return the set of vertices in the center of the graph.
Return the degree centrality of a vertex.
Return the diameter of the 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 theoriginal graph.
Return the eccentricity of vertex (or vertices) v.
Return the hyperbolicity of the graph or an approximation of this value.
Return the set of vertices in the periphery of the graph.
Return the radius of the graph.

Domination
is_dominating()
is_redundant()
minimal_dominating_sets()
private_neighbors()

Check whether dom is a dominating set of G.
Check whether dom has redundant vertices.
Return an iterator over the minimal dominating sets of a graph.
Return the private neighbors of a vertex with respect to other vertices.

Expansion properties

440

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

cheeger_constant()
edge_isoperimetric_number()vertex_isoperimetric_number()

Return the cheeger constant of the graph.
Return the edge-isoperimetric number of the graph.
Return the vertex-isoperimetric number of the graph.

Graph properties
apex_vertices()
is_antipodal()
is_apex()is_arc_transitive()
is_asteroidal_triple_free()is_biconnected()
is_block_graph()
is_cactus()
is_cartesian_product()is_circumscribable()is_cograph()
is_comparability()
is_distance_regular()is_edge_transitive()
is_even_hole_free()is_forest()
is_half_transitive()
is_inscribable()
is_line_graph()
is_long_antihole_free()is_long_hole_free()
is_odd_hole_free()is_overfull()
is_partial_cube()
is_path()is_permutation()
is_polyhedral()
is_prime()
is_semi_symmetric()
is_split()
is_strongly_regular()is_tree()
is_triangle_free()is_weakly_chordal()

Return the list of apex vertices.
Check whether this graph is antipodal.
Test if the graph is apex.
Check if self is an arc-transitive graph
Test if the input graph is asteroidal triple-free
Test if the graph is biconnected.
Return whether this graph is a block graph.
Check whether the graph is cactus graph.
Test whether the graph is a Cartesian product.
Test whether the graph is the graph of a circumscribed polyhedron.
Check whether the graph is cograph.
Tests whether the graph is a comparability graph
Test if the graph is distance-regular
Check if self is an edge transitive graph.
Tests whether self contains an induced even hole.
Tests if the graph is a forest, i.e. a disjoint union of trees.
Check if self is a half-transitive graph.
Test whether the graph is the graph of an inscribed polyhedron.
Check whether the graph 𝑔 is a line graph.
Tests whether the given graph contains an induced subgraph that is isomorphic tothe complement of a cycle of length at least 5.
Tests whether g contains an induced cycle of length at least 5.
Tests whether self contains an induced odd hole.
Tests whether the current graph is overfull.
Test whether the given graph is a partial cube.
Check whether self is a path.
Tests whether the graph is a permutation graph.
Check whether the graph is the graph of the polyhedron.
Test whether the current graph is prime.
Check if self is semi-symmetric.
Returns True if the graph is a Split graph, False otherwise.
Check whether the graph is strongly regular.
Tests if the graph is a tree
Check whether self is triangle-free
Tests whether the given graph is weakly chordal, i.e., the graph and its complement
have no induced cycle of length at least 5.

Leftovers

1.2. Undirected graphs441

Graph Theory, Release 10.4

antipodal_graph()arboricity()
common_neighbors_matrix()
cores()
effective_resistance()
effective_resistance_matrix()
folded_graph()geodetic_closure()
has_perfect_matching()
ihara_zeta_function_inverse()
is_factor_critical()
kirchhoff_symanzik_polynomial()
least_effective_resistance()
lovasz_theta()
magnitude_function()matching()
maximum_average_degree()modular_decomposition()
most_common_neighbors()
perfect_matchings()
seidel_adjacency_matrix()
seidel_switching()
two_factor_petersen()twograph()

Return the antipodal graph of self.
Return the arboricity of the graph and an optional certificate.
Return a matrix of numbers of common neighbors between each pairs.
Return the core number for each vertex in an ordered list.
Return the effective resistance between nodes 𝑖 and 𝑗.
Return a matrix whose (𝑖 , 𝑗) entry gives the effective resistance between vertices
𝑖 and 𝑗.
Return the antipodal fold of this graph.
Return the geodetic closure of the set of vertices 𝑆 in 𝐺.
Return whether this graph has a perfect matching. INPUT:
Compute the inverse of the Ihara zeta function of the graph.
Check whether this graph is factor-critical.
Return the Kirchhoff-Symanzik polynomial of a graph.
Return a list of pairs of nodes with the least effective resistance.
Return the value of Lovász theta-function of graph.
Return the magnitude function of the graph as a rational function.
Return a maximum weighted matching of the graph represented by the list of its
edges.
Return the Maximum Average Degree (MAD) of the current graph.
Return the modular decomposition of the current graph.
Return vertex pairs with maximal number of common neighbors.
Return an iterator over all perfect matchings of the graph.
Return the Seidel adjacency matrix of self.
Return the Seidel switching of self w.r.t. subset of vertices s.
Return a decomposition of the graph into 2-factors.
Return the two-graph of self

Traversals
lex_M()
maximum_cardinality_search()
maximum_cardinality_search_M()

Return an ordering of the vertices according the LexM graph traversal.
Return an ordering of the vertices according a maximum cardinality search.
Return the ordering and the edges of the triangulation produced by MCS-M.

Unsorted
bandwidth()
cutwidth()442

Compute the bandwidth of an undirected graph.
Return the cutwidth of the graph and the corresponding vertex ordering.

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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, fixedplotting bugs (2007-01-23): basic tutorial, edge labels, loops, multiple edges and arcs (2007-02-07): graph6
and sparse6 formats, matrix input• Emily Kirkmann (2007-02-11): added graph_border option to plot and show
• Robert L. Miller (2007-02-12): vertex color-maps, graph boundaries, graph6
helper functions in Cython• Robert L. Miller Sage Days 3 (2007-02-17-21): 3d plotting in Tachyon• Robert L. Miller (2007-02-25): display a partition• Robert L. Miller (2007-02-28): associate arbitrary objects to vertices, edge
and arc label display (in 2d), edge coloring• Robert L. Miller (2007-03-21): Automorphism group, isomorphism check,canonical label• Robert L. Miller (2007-06-07-09): NetworkX function wrapping• Michael W. Hansen (2007-06-09): Topological sort generation• Emily Kirkman, Robert L. Miller Sage Days 4: Finished wrapping NetworkX• Emily Kirkman (2007-07-21): Genus (including circular planar, all embeddings
and all planar embeddings), all paths, interior paths• Bobby Moretti (2007-08-12): fixed up plotting of graphs with edge colors
differentiated by label• Jason Grout (2007-09-25): Added functions, bug fixes, and general enhancements• Robert L. Miller (Sage Days 7): Edge labeled graph isomorphism• Tom Boothby (Sage Days 7): Miscellaneous awesomeness• Tom Boothby (2008-01-09): Added graphviz output• David Joyner (2009-2): Fixed docstring bug related to GAP.
• Stephen Hartke (2009-07-26): Fixed bug in blocks_and_cut_vertices() thatcaused an incorrect result when the vertex 0 was a cut vertex.
• Stephen Hartke (2009-08-22): Fixed bug in blocks_and_cut_vertices() where thelist 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 andlong-hole-free / long-antihole-free graphs• Alexandre P. Zuge (2013-07): added join operation.
• Amritanshu Prasad (2014-08): added clique polynomial
1.2. Undirected graphs443

Graph Theory, Release 10.4

• Julian Rüth (2018-06-21): upgrade to NetworkX 2• David Coudert (2018-10-07): cleaning• Amanda Francis, Caitlin Lienkaemper, Kate Collins, Rajat Mittal (2019-03-10): methods for computing effective
resistance• Amanda Francis, Caitlin Lienkaemper, Kate Collins, Rajat Mittal (2019-03-19): most_common_neighbors andcommon_neighbors_matrix added.
• Jean-Florent Raymond (2019-04): is_redundant, is_dominating,private_neighbors

1.2.1 Graph Format
Supported formats
Sage Graphs can be created from a wide range of inputs. A few examples are covered here.
• 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()˓→# needs sage.plot>>> from sage.all import *>>> d = {Integer(0): [Integer(1),Integer(4),Integer(5)], Integer(1):␣
˓→[Integer(2),Integer(6)], Integer(2): [Integer(3),Integer(7)],␣
˓→Integer(3): [Integer(4),Integer(8)], Integer(4): [Integer(9)], \5: [7, 8], 6: [8,9], 7: [9]}>>> G = Graph(d); G
Graph on 10 vertices>>> G.plot().show()# or G.show()˓→# needs sage.plot

␣␣• A NetworkX graph:
sage: # needs networkx
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]>>> from sage.all import *>>> # needs networkx>>> import networkx>>> K = networkx.complete_bipartite_graph(Integer(12),Integer(7))>>> G = Graph(K)>>> 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:

444

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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()˓→# needs sage.plot␣>>> from sage.all import *>>> s = :I AKGsaOs cI]Gb~>>> G = Graph(s, sparse=True); G
Looped multi-graph on 10 vertices>>> G.plot().show()# or G.show()˓→# needs sage.plot

␣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>>> from sage.all import *>>> 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()˓→# needs sage.plot>>> from sage.all import *>>> G = Graph( Ihe\\n@GUA )>>> G.plot().show()# or G.show()˓→# needs sage.plot␣␣• 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: # needs sage.modules
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]
(continues on next page)1.2. Undirected graphs445

Graph Theory, Release 10.4

(continued from previous page)[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()˓→# needs sage.plot# or G.show()␣>>> from sage.all import *>>> # needs sage.modules>>> M = Matrix([(Integer(0),Integer(1),Integer(0),Integer(0),Integer(1),˓→Integer(1),Integer(0),Integer(0),Integer(0),Integer(0)), (Integer(1),˓→Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(1),˓→Integer(0),Integer(0),Integer(0)),...
(Integer(0),Integer(1),Integer(0),Integer(1),Integer(0),˓→Integer(0),Integer(0),Integer(1),Integer(0),Integer(0)), (Integer(0),˓→Integer(0),Integer(1),Integer(0),Integer(1),Integer(0),Integer(0),˓→Integer(0),Integer(1),Integer(0)),...
(Integer(1),Integer(0),Integer(0),Integer(1),Integer(0),˓→Integer(0),Integer(0),Integer(0),Integer(0),Integer(1)), (Integer(1),˓→Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),˓→Integer(1),Integer(1),Integer(0)), (Integer(0),Integer(1),Integer(0),˓→Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),˓→Integer(1)),...
(Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),˓→Integer(1),Integer(0),Integer(0),Integer(0),Integer(1)), (Integer(0),˓→Integer(0),Integer(0),Integer(1),Integer(0),Integer(1),Integer(1),˓→Integer(0),Integer(0),Integer(0)), (Integer(0),Integer(0),Integer(0),˓→Integer(0),Integer(1),Integer(0),Integer(1),Integer(1),Integer(0),˓→Integer(0))])>>> 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]>>> G = Graph(M); G
Graph on 10 vertices>>> G.plot().show()# or G.show()˓→ # needs sage.plot␣• incidence matrix: In an incidence matrix, each row represents a vertex andeach column represents an edge.
sage: # needs sage.modules
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),(continues on next page)

446

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)....:( 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()˓→# needs sage.plot
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

␣>>> from sage.all import *>>> # needs sage.modules>>> M = Matrix([(-Integer(1), Integer(0), Integer(0), Integer(0), Integer(1),␣
˓→Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),-Integer(1),␣
˓→Integer(0), Integer(0), Integer(0), Integer(0)),...
( Integer(1),-Integer(1), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0), Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),˓→Integer(1), Integer(0), Integer(0), Integer(0)),...
( Integer(0), Integer(1),-Integer(1), Integer(0), Integer(0),␣
˓→Integer(0), Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0),-Integer(1), Integer(0), Integer(0)),...
( Integer(0), Integer(0), Integer(1),-Integer(1), Integer(0),␣
˓→Integer(0), Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0), Integer(0),-Integer(1), Integer(0)),...
( Integer(0), Integer(0), Integer(0), Integer(1),-Integer(1),␣
˓→Integer(0), Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0), Integer(0), Integer(0),-Integer(1)),...
( Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),˓→Integer(1), Integer(0), Integer(0), Integer(0), Integer(1), Integer(1),␣
˓→Integer(0), Integer(0), Integer(0), Integer(0)),...
( Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0), Integer(0), Integer(1),-Integer(1), Integer(0), Integer(0),␣
˓→Integer(1), Integer(0), Integer(0), Integer(0)),...
( Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(1),-Integer(1), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0), Integer(1), Integer(0), Integer(0)),...
( Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0), Integer(0), Integer(0), Integer(1),-Integer(1), Integer(0),␣
˓→Integer(0), Integer(0), Integer(1), Integer(0)),...
( Integer(0), Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0), Integer(1),-Integer(1), Integer(0), Integer(0), Integer(0),␣
(continues on next page)1.2. Undirected graphs447

Graph Theory, Release 10.4

(continued from previous page)

Integer(0), Integer(0), Integer(0), Integer(1))])>>> 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]>>> G = Graph(M); G
Graph on 10 vertices>>> G.plot().show()# or G.show()˓→ # needs sage.plot>>> DiGraph(matrix(Integer(2), [Integer(0),Integer(0),-Integer(1),˓→Integer(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)]); g
Graph on 5 vertices>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(3)), (Integer(3), Integer(8)), (Integer(5),␣
˓→Integer(2))]); g
Graph on 5 vertices• an igraph Graph:
sage: import igraphsage: g = Graph(igraph.Graph([(1,3),(3,2),(0,2)]))sage: gGraph on 4 vertices# optional - python_igraph# optional - python_igraph# optional - python_igraph>>> from sage.all import *>>> import igraph# optional - python_igraph>>> g = Graph(igraph.Graph([(Integer(1),Integer(3)),(Integer(3),Integer(2)),˓→(Integer(0),Integer(2))]))# optional - python_igraph>>> g# optional - python_igraph
Graph on 4 vertices

448

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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][2, 2, 2, 2][3, 3, 2, 2][3, 3, 3, 3]>>> from sage.all import *>>> for g in graphs(Integer(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][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 graphwith chromatic number bigger than three:sage: for g in graphs():....:
if g.chromatic_number() > 3:
....:
break
sage: g.is_isomorphic(graphs.CompleteGraph(4))
True>>> from sage.all import *>>> for g in graphs():...
if g.chromatic_number() > Integer(3):
...
break
>>> g.is_isomorphic(graphs.CompleteGraph(Integer(4)))
True

For some commonly used graphs to play with, type:sage: graphs.[tab]# not tested>>> from sage.all import *>>> 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
1.2. Undirected graphs449

Graph Theory, Release 10.4

graphs.
sage: G = graphs.PetersenGraph()
sage: G.plot().show()# or G.show()˓→needs sage.plot
sage: G.degree_histogram()[0, 0, 0, 10]
sage: G.adjacency_matrix()
˓→needs sage.modules[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]#␣#␣>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.plot().show()# or G.show()˓→needs sage.plot>>> G.degree_histogram()[0, 0, 0, 10]>>> G.adjacency_matrix()
˓→needs sage.modules[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()˓→needs sage.plot
sage: S.density()
1/2#␣>>> from sage.all import *>>> S = G.subgraph([Integer(0),Integer(1),Integer(2),Integer(3)])>>> S.plot().show()# or S.show()˓→needs sage.plot>>> 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)˓→needs sage.plot

450

#␣

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = GraphQuery(display_cols=[ graph6 ], num_vertices=Integer(7),␣
˓→diameter=Integer(5))>>> L = G.get_graphs_list()>>> graphs_list.show_graphs(L)˓→needs sage.plot#␣

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:
sage: M = Matrix([[0,0], [0,0]])˓→needs sage.modules
sage: G = Graph({ 0 : { M : None } })˓→needs sage.modules
Traceback (most recent call last):...
TypeError: mutable matrices are unhashable>>> from sage.all import *>>> M = Matrix([[Integer(0),Integer(0)], [Integer(0),Integer(0)]])˓→# needs sage.modules>>> G = Graph({ Integer(0) : { M : None } })˓→
# needs sage.modules
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 thatassociation:
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(sort=True)[0, 1, 2, 3]
sage: T.set_vertices(d)sage: T.get_vertex(1)Flower Snark: Graph on 20 vertices>>> from sage.all import *>>> d = {Integer(0) : graphs.DodecahedralGraph(), Integer(1) : graphs.FlowerSnark(), \2 : graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }>>> d[Integer(2)]Moebius-Kantor Graph: Graph on 16 vertices>>> T = graphs.TetrahedralGraph()>>> T.vertices(sort=True)[0, 1, 2, 3]>>> T.set_vertices(d)(continues on next page)1.2. Undirected graphs451

Graph Theory, Release 10.4

(continued from previous page)>>> T.get_vertex(Integer(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 searchparameter keywords broken down by their designated table names, typesage: graph_db_info(){...}>>> from sage.all import *>>> graph_db_info(){...}

For more details on data types or keyword input, entersage: GraphQuery?

# not tested>>> from sage.all import *>>> 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
>>> from sage.all import *>>> Q = GraphQuery(display_cols=[ graph6 ],num_vertices=Integer(7),␣
˓→diameter=Integer(5))>>> Q.show()
Graph6-------------------F? po
F?gqg
F@?]O
F@OKg
F@R@o
FA_pW
FEOhW
FGC{o
FIAHo

452

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Show each graph as you iterate through the results:
sage: for g in Q:
˓→needs sage.plot....:
show(g)>>> from sage.all import *>>> for g in Q:
˓→needs sage.plot...
show(g)#␣#␣

1.2.5 Visualization
To see a graph 𝐺 you are working with, there are three main options. You can view the graph in two dimensions via
matplotlib with show().
sage: G = graphs.RandomGNP(15,.3)
sage: G.show()˓→needs sage.plot>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(15),RealNumber( .3 ))>>> G.show()˓→needs sage.plot#␣#␣

And you can view it in three dimensions via jmol with show3d().
sage: G.show3d()
˓→needs sage.plot>>> from sage.all import *>>> G.show3d()
˓→needs sage.plot#␣#␣

Or it can be rendered with LATEX. This requires the right additions to a standard TEX installation. Then standard Sagecommands, 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_graphsage: check_tkz_graph() # random - depends on TeX installation
sage: latex(G)\begin{tikzpicture}...
\end{tikzpicture}>>> from sage.all import *>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> latex(G)\begin{tikzpicture}...
\end{tikzpicture}

1.2. Undirected graphs453

Graph Theory, Release 10.4

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>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> {G:Integer(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)>>> G_immutable = Graph(G, immutable=True)>>> G_immutable == G
True>>> {G_immutable:Integer(1)}[G_immutable]
1

1.2.7 Methods
class sage.graphs.graph.Graph(data=None, pos=None, loops=None, format=None, weighted=None,
data_structure='sparse', vertex_labels=True, name=None,
multiedges=None, convert_empty_dict_labels_to_None=None,sparse=True, immutable=False, hash_labels=None)
Bases: 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 byreading the documentation of graph, generic_graph, and digraph.
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.

454

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

To
bypassauto-detection,
preferformat= vertices_and_edges ).

the

more

explicit

Graph([V,E],

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 ofneighbors 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:[ a1 , a2 ], 3:[ b ]} ,3:{2:[ c ]}}).

{2:

7. Graph(a_symmetric_matrix) – return a graph with given (weighted) adjacency matrix (see documentation 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 contains 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 documentationof graph6_string() or sparse6_string()).
11. Graph(a_seidel_matrix, format= seidel_adjacency_matrix ) – return a graphwith 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 asquare:{0: [-1,-1],
1: [ 1,-1],
2: [ 1, 1],
3: [-1, 1]}• name – (must be an explicitly named parameter, i.e.,
name="complete") gives the graph a name• loops – boolean (default: None); whether to allow loops (ignored
if data is an instance of the Graph class)• multiedges – boolean (default: None); whether to allow multiple
edges (ignored if data is an instance of the Graph class).
• weighted – boolean (default: None); whether graph thinks of itself as weighted or not.
weighted().
1.2. Undirected graphs

See

455

Graph Theory, Release 10.4

• format – if set to None (default), Graph tries to guess input’s format. To avoid this possibly time-consuming step, one of the following values can be specified (see description above):"int", "graph6", "sparse6", "rule", "list_of_edges", "dict_of_lists","dict_of_dicts", "adjacency_matrix", "weighted_adjacency_matrix", "seidel_adjacency_matrix", "incidence_matrix", "NX", "igraph".
• sparse – boolean (default: True); sparse=True is an alias for data_structure="sparse", andsparse=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 thesparse backend and smaller in memory, and it is immutable, so that the resulting graphs can be usedas dictionary keys).
• immutable – boolean (default: False); whether to create a immutable graph. Note that immutable=True is actually a shortcut for data_structure= static_sparse . Set to False
by default.
• hash_labels – boolean (default: None); whether to include edge labels during hashing. This parameter
defaults to True if the graph is weighted. This parameter is ignored if the graph is mutable. Beware thattrying to hash unhashable labels will raise an error.
• vertex_labels – boolean (default: True); whether to allow any object as a vertex (slower), or only the
integers 0, ..., 𝑛 − 1, where 𝑛 is the number of vertices.
• convert_empty_dict_labels_to_None – this arguments sets the default
edge labels used by NetworkX (empty dictionaries) to be replaced by None, the default Sage edge label.
It is set to True iff a NetworkX graph is on the input.
EXAMPLES:
We illustrate the first seven input formats (the other two involve packages that are currently not standard in Sage):
1. An integer giving the number of vertices:sage: g = Graph(5); g
Graph on 5 vertices
sage: g.vertices(sort=True)[0, 1, 2, 3, 4]
sage: g.edges(sort=False)[]>>> from sage.all import *>>> g = Graph(Integer(5)); g
Graph on 5 vertices>>> g.vertices(sort=True)[0, 1, 2, 3, 4]>>> g.edges(sort=False)[]

2. A dictionary of dictionaries:
sage: g = Graph({0:{1: x ,2: z ,3: a }, 2:{5: out }}); g
Graph on 5 vertices

456

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph({Integer(0):{Integer(1): x ,Integer(2): z ,Integer(3): a },␣
˓→Integer(2):{Integer(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.:
sage: a, b, c, d, e, f = sorted(SymmetricGroup(3))˓→# needs sage.groups
sage: Graph({b: {d: c , e: p }, c: {d: p , e: c }})˓→# needs sage.groups
Graph on 4 vertices>>> from sage.all import *>>> a, b, c, d, e, f = sorted(SymmetricGroup(Integer(3)))˓→# needs sage.groups>>> Graph({b: {d: c , e: p }, c: {d: p , e: c }})˓→# needs sage.groups
Graph on 4 vertices␣␣␣

3. A dictionary of lists:
sage: g = Graph({0:[1,2,3], 2:[4]}); g
Graph on 5 vertices>>> from sage.all import *>>> g = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(2):[Integer(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()])˓→# needs sage.rings.finite_rings
sage: g.vertices(sort=True)
˓→# needs sage.rings.finite_rings[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: g.adjacency_matrix()
˓→# needs sage.modules sage.rings.finite_rings[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]

1.2. Undirected graphs457

Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph([GF(Integer(13)), lambda i,j: i!=j and (i-j).is_square()])˓→# needs sage.rings.finite_rings>>> g.vertices(sort=True)
˓→needs sage.rings.finite_rings[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]>>> g.adjacency_matrix()
˓→needs sage.modules sage.rings.finite_rings[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(sort=True, labels=false),....:
lambda i,j: len(set(i).intersection(set(j)))>0],....:
loops=False)
sage: line_graph.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: line_graph.adjacency_matrix()
˓→# needs sage.modules[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]>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4))>>> line_graph = Graph([g.edges(sort=True, labels=false),...
lambda i,j: len(set(i).intersection(set(j)))>˓→Integer(0)],...
loops=False)>>> line_graph.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]>>> line_graph.adjacency_matrix()
˓→needs sage.modules[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:

458

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: s = :I AKGsaOs cI]Gb~
sage: Graph(s, sparse=True)
Looped multi-graph on 10 vertices>>> from sage.all import *>>> s = :I AKGsaOs cI]Gb~>>> Graph(s, sparse=True)
Looped multi-graph on 10 vertices
sage: G = Graph( G????? )sage: G = Graph("G ?G?C")
Traceback (most recent call last):...
RuntimeError: the string seems corrupt: valid characters are?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ abcdefghijklmnopqrstuvwxyz{|}~sage: G = Graph( G?????? )Traceback (most recent call last):...
RuntimeError: the string (G??????) seems corrupt: for n = 8, the string is␣˓→too long>>> from sage.all import *>>> G = Graph( G????? )>>> G = Graph("G ?G?C")
Traceback (most recent call last):...
RuntimeError: the string seems corrupt: valid characters are?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ abcdefghijklmnopqrstuvwxyz{|}~>>> 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{|}~>>> from sage.all import *>>> 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\nsage: graphs_list.from_sparse6(s)[Looped multi-graph on 10 vertices,
Looped multi-graph on 10 vertices,
Looped multi-graph on 10 vertices]

1.2. Undirected graphs459

Graph Theory, Release 10.4>>> from sage.all import *>>> s = :IgMoqoCUOqeb\n:I AKGsaOs cI]Gb~\n:I EDOAEQ?PccSsge\\N\n>>> 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˓→# needs sage.modules[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)˓→# needs sage.modules
Graph on 10 vertices␣␣>>> from sage.all import *>>> M = graphs.PetersenGraph().am(); M
˓→# needs sage.modules[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]>>> Graph(M)˓→# needs sage.modules
Graph on 10 vertices
sage: Graph(matrix([[1,2], [2,4]]), loops=True, sparse=True)˓→# needs sage.modules
Looped multi-graph on 2 vertices

␣sage: M = Matrix([[0,1,-1], [1,0,-1/2], [-1,-1/2,0]]); M˓→# needs sage.modules
[
0
1
-1]
[
1
0 -1/2][ -1 -1/2
0]
sage: G = Graph(M, sparse=True); G˓→# needs sage.modules
Graph on 3 vertices␣␣(continues on next page)

460

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.weighted()˓→# needs sage.modules
True␣>>> from sage.all import *>>> Graph(matrix([[Integer(1),Integer(2)], [Integer(2),Integer(4)]]),␣
˓→loops=True, sparse=True)# needs sage.modules
Looped multi-graph on 2 vertices>>> M = Matrix([[Integer(0),Integer(1),-Integer(1)], [Integer(1),˓→Integer(0),-Integer(1)/Integer(2)], [-Integer(1),-Integer(1)/Integer(2),˓→Integer(0)]]); M# needs sage.modules
[
0
1
-1]
[
1
0 -1/2][ -1 -1/2
0]>>> G = Graph(M, sparse=True); G
˓→# needs sage.modules
Graph on 3 vertices>>> G.weighted()
˓→# needs sage.modules
True• an incidence matrix:
sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0,˓→# needs sage.modules....:
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)˓→# needs sage.modules
Graph on 6 vertices

␣sage: Graph(Matrix([[1],[1],[1]]))˓→# needs sage.modules
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]]))˓→# needs sage.modules
Graph on 3 vertices

␣sage: M = Matrix([[0,1,-1], [1,0,-1], [-1,-1,0]]); M˓→# needs sage.modules[ 0 1 -1]
[ 1 0 -1][-1 -1 0]
sage: Graph(M, sparse=True)˓→# needs sage.modules
Graph on 3 vertices

␣

␣

␣

␣

(continues on next page)1.2. Undirected graphs461

Graph Theory, Release 10.4

(continued from previous page)

sage: M = Matrix([[0,1,1], [1,0,1], [-1,-1,0]]); M˓→# needs sage.modules[ 0 1 1]
[ 1 0 1][-1 -1 0]
sage: Graph(M)˓→# needs sage.modules
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␣␣>>> from sage.all import *>>> M = Matrix(Integer(6), [-Integer(1),Integer(0),Integer(0),Integer(0),˓→Integer(1), Integer(1),-Integer(1),Integer(0),Integer(0),Integer(0),␣
˓→Integer(0),Integer(1),-Integer(1),Integer(0),Integer(0),␣˓→# needs sage.modules...
Integer(0),Integer(0),Integer(1),-Integer(1),˓→Integer(0), Integer(0),Integer(0),Integer(0),Integer(1),-Integer(1),␣
˓→Integer(0),Integer(0),Integer(0),Integer(0),Integer(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]>>> Graph(M)˓→# needs sage.modules
Graph on 6 vertices>>> Graph(Matrix([[Integer(1)],[Integer(1)],[Integer(1)]]))
˓→# needs sage.modules
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>>> Graph(Matrix([[Integer(1)],[Integer(1)],[Integer(0)]]))
˓→# needs sage.modules
Graph on 3 vertices>>> M = Matrix([[Integer(0),Integer(1),-Integer(1)], [Integer(1),˓→Integer(0),-Integer(1)], [-Integer(1),-Integer(1),Integer(0)]]); M˓→# needs sage.modules[ 0 1 -1]
[ 1 0 -1][-1 -1 0]>>> Graph(M, sparse=True)
˓→# needs sage.modules
Graph on 3 vertices>>> M = Matrix([[Integer(0),Integer(1),Integer(1)], [Integer(1),˓→Integer(0),Integer(1)], [-Integer(1),-Integer(1),Integer(0)]]); M˓→# needs sage.modules[ 0 1 1]
[ 1 0 1][-1 -1 0]

␣

␣

␣

␣

(continues on next page)462

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> Graph(M)˓→# needs sage.modules
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 Issue #9714 is fixed:
sage: # needs sage.modules
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); MI[2 1 1 0 0 0]
[0 1 1 2 2 0]
[0 0 0 0 0 2]
sage: Graph(MI).edges(sort=True, labels=None)[(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)]
sage: M = Matrix([[1], [-1]]); M˓→# needs sage.modules
[ 1]
[-1]
sage: Graph(M).edges(sort=True)˓→# needs sage.modules[(0, 1, None)]␣␣>>> from sage.all import *>>> # needs sage.modules>>> MA = Matrix([[Integer(1),Integer(2),Integer(0)], [Integer(0),˓→Integer(2),Integer(0)], [Integer(0),Integer(0),Integer(1)]])>>> GA = Graph(MA, format= adjacency_matrix )>>> MI = GA.incidence_matrix(oriented=False); MI[2 1 1 0 0 0]
[0 1 1 2 2 0]
[0 0 0 0 0 2]>>> Graph(MI).edges(sort=True, labels=None)[(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)]>>> M = Matrix([[Integer(1)], [-Integer(1)]]); M˓→# needs sage.modules
[ 1]
[-1]
>>> Graph(M).edges(sort=True)˓→# needs sage.modules[(0, 1, None)]␣␣

7. A Seidel adjacency matrix:
sage: from sage.combinat.matrices.hadamard_matrix import (˓→# needs sage.combinat sage.modules....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd)
sage: m = rshcd(16,1) - matrix.identity(16)˓→# needs sage.combinat sage.modules
sage: Graph(m,(continues on next page)1.2. Undirected graphs463

Graph Theory, Release 10.4

(continued from previous page)# needs sage.combinat sage.modules....:
format="seidel_adjacency_matrix").is_strongly_
˓→regular(parameters=True)(16, 6, 2, 2)
˓→>>> from sage.all import *>>> from sage.combinat.matrices.hadamard_matrix import (˓→needs sage.combinat sage.modules... regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd)>>> m = rshcd(Integer(16),Integer(1)) - matrix.identity(Integer(16))˓→# needs sage.combinat sage.modules>>> Graph(m,˓→needs sage.combinat sage.modules...
format="seidel_adjacency_matrix").is_strongly_
˓→regular(parameters=True)(16, 6, 2, 2)

#␣

␣
#␣

8. List of edges, or labelled edges:
sage: g = Graph([(1, 3), (3, 8), (5, 2)]); g
Graph on 5 vertices
sage: g = Graph([(1, 2, "Peace"), (7, -9, "and"), (77, 2, "Love")]); 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 )]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(3)), (Integer(3), Integer(8)),␣
˓→(Integer(5), Integer(2))]); g
Graph on 5 vertices>>> g = Graph([(Integer(1), Integer(2), "Peace"), (Integer(7), -Integer(9),˓→"and"), (Integer(77), Integer(2), "Love")]); g
Graph on 5 vertices>>> g = Graph([(Integer(0), Integer(2), 0 ), (Integer(0), Integer(2), 1 ),␣
˓→(Integer(3), Integer(3),
2 )],
...
loops=True, multiedges=True)>>> g.loops()[(3, 3, 2 )]9. A NetworkX MultiGraph:
sage: import networkx
˓→# needs networkx
sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]})˓→# needs networkx
sage: Graph(g)˓→# needs networkx
Multi-graph on 5 vertices>>> from sage.all import *>>> import networkx#␣(continues on next page)464

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs networkx>>> g = networkx.MultiGraph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(2):[Integer(4)]})# needs networkx>>> Graph(g)#␣˓→needs networkx
Multi-graph on 5 vertices
˓→

10. A NetworkX graph:
sage: import networkx
˓→# needs networkx
sage: g = networkx.Graph({0:[1,2,3], 2:[4]})˓→# needs networkx
sage: DiGraph(g)˓→# needs networkx
Digraph on 5 vertices>>> from sage.all import *>>> import networkx#␣˓→needs networkx>>> g = networkx.Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(2):[Integer(4)]})# needs networkx>>> DiGraph(g)#␣˓→needs networkx
Digraph on 5 vertices

11. An igraph Graph (see also igraph_graph()):
sage: import igraphsage: g = igraph.Graph([(0, 1), (0, 2)])sage: Graph(g)Graph on 3 vertices# optional - python_igraph# optional - python_igraph# optional - python_igraph>>> from sage.all import *>>> import igraph# optional - python_igraph>>> g = igraph.Graph([(Integer(0), Integer(1)), (Integer(0), Integer(2))])
˓→optional - python_igraph>>> 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 , ifavailable:
sage: # optional - python_igraphsage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={ name :[ a , b , c ]})sage: Graph(g).vertices(sort=True)[ a , b , c ]sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={ label :[ a , b , c ]})sage: Graph(g).vertices(sort=True)[0, 1, 2]>>> from sage.all import *>>> # optional - python_igraph>>> g = igraph.Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2))],␣
˓→vertex_attrs={ name :[ a , b , c ]})(continues on next page)1.2. Undirected graphs465

Graph Theory, Release 10.4

(continued from previous page)>>> Graph(g).vertices(sort=True)[ a , b , c ]>>> g = igraph.Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2))],␣
˓→vertex_attrs={ label :[ a , b , c ]})>>> Graph(g).vertices(sort=True)[0, 1, 2]

If the igraph Graph has edge attributes, they are used as edge labels:
sage: g = igraph.Graph([(0, 1), (0, 2)],#␣
˓→optional - python_igraph....:edge_attrs={ name : [ a , b ], weight : [1, 3]})sage: Graph(g).edges(sort=True)#␣˓→optional - python_igraph[(0, 1, { name : a , weight : 1}), (0, 2, { name : b , weight : 3})]>>> from sage.all import *>>> g = igraph.Graph([(Integer(0), Integer(1)), (Integer(0), Integer(2))],␣˓→# optional - python_igraph...
edge_attrs={ name : [ a , b ], weight : [Integer(1),␣
˓→Integer(3)]})>>> Graph(g).edges(sort=True)# optional␣˓→- python_igraph[(0, 1, { name : a , weight : 1}), (0, 2, { name : b , weight : 3})]

When defining an undirected graph from a function f, it is very important that f be symmetric. If it is not, anything
can happen:
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))
Truesage: 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>>> from sage.all import *>>> f_sym = lambda x,y: abs(x-y) == Integer(1)>>> f_nonsym = lambda x,y: (x-y) == Integer(1)>>> G_sym = Graph([[Integer(4),Integer(6),Integer(1),Integer(5),Integer(3),˓→Integer(7),Integer(2),Integer(0)], f_sym])>>> G_sym.is_isomorphic(graphs.PathGraph(Integer(8)))
True>>> G_nonsym = Graph([[Integer(4),Integer(6),Integer(1),Integer(5),Integer(3),˓→Integer(7),Integer(2),Integer(0)], f_nonsym])>>> G_nonsym.size()4>>> G_nonsym.is_isomorphic(G_sym)
False

By default, graphs are mutable and can thus not be used as a dictionary key:466

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> {G:Integer(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>>> from sage.all import *>>> G_imm = Graph(G, immutable=True)>>> H_imm = Graph(G, data_structure= static_sparse )>>> G_imm == H_imm == G
True>>> {G_imm:Integer(1)}[H_imm]
1

acyclic_orientations(G)Return an iterator over all acyclic orientations of an undirected graph 𝐺.
ALGORITHM:
The algorithm is based on [Sq1998]. It presents an efficient algorithm for listing the acyclic orientations ofa graph. The algorithm is shown to require O(n) time per acyclic orientation generated, making it the mostefficient known algorithm for generating acyclic orientations.
The function uses a recursive approach to generate acyclic orientations of the graph. It reorders the vertices and edges of the graph, creating a new graph with updated labels. Then, it iteratively generates acyclicorientations by considering subsets of edges and checking whether they form upsets in a corresponding poset.
INPUT:• G – an undirected graph.
OUTPUT:• An iterator over all acyclic orientations of the input graph.
Note: The function assumes that the input graph is undirected and the edges are unlabelled.
EXAMPLES:

1.2. Undirected graphs

467

Graph Theory, Release 10.4

To count number acyclic orientations for a graph:
sage: g = Graph([(0, 3), (0, 4), (3, 4), (1, 3), (1, 2), (2, 3), (2, 4)])sage: it = g.acyclic_orientations()
sage: len(list(it))
54>>> from sage.all import *>>> g = Graph([(Integer(0), Integer(3)), (Integer(0), Integer(4)),␣
˓→(Integer(3), Integer(4)), (Integer(1), Integer(3)), (Integer(1),␣
˓→Integer(2)), (Integer(2), Integer(3)), (Integer(2), Integer(4))])>>> it = g.acyclic_orientations()>>> len(list(it))
54

Test for arbitary vertex labels:
sage: g_str = Graph([( abc , def ), ( ghi ,˓→ uvw ), ( uvw ,abc ), ( uvw , ghi )])sage: it = g_str.acyclic_orientations()
sage: len(list(it))
42>>> from sage.all import *>>> g_str = Graph([( abc , def ), ( ghi ,˓→ uvw ), ( uvw ,abc ), ( uvw , ghi )])>>> it = g_str.acyclic_orientations()>>> len(list(it))
42

def ), ( xyz ,def ), ( xyz ,abc ), ( xyz ,abc ), ( xyz ,all_cliques(graph, min_size=0, max_size=0)
Iterator over the cliques in graph.
A clique is an induced complete subgraph. This method is an iterator over all the cliques with size in between
min_size and max_size. By default, this method returns only maximum cliques. Each yielded clique isrepresented by a list of vertices.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraphto an undirected graph.
INPUT:• min_size – integer (default: 0); minimum size of reported cliques. When set to 0 (default), thismethod searches for maximum cliques. In such case, parameter max_size must also be set to 0.
• max_size – integer (default: 0); maximum size of reported cliques. When set to 0 (default), themaximum size of the cliques is unbounded. When min_size is set to 0, this parameter must be set to0.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
sage: G = graphs.CompleteGraph(5)sage: list(sage.graphs.cliquer.all_cliques(G))(continues on next page)

468

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[[0, 1, 2, 3, 4]]
sage: list(sage.graphs.cliquer.all_cliques(G, 2, 3))[[3, 4],[2, 3],[2, 3, 4],[2, 4],[1, 2],[1, 2, 3],[1, 2, 4],[1, 3],[1, 3, 4],[1, 4],[0, 1],[0, 1, 2],[0, 1, 3],[0, 1, 4],[0, 2],[0, 2, 3],[0, 2, 4],[0, 3],[0, 3, 4],[0, 4]]
sage: G.delete_edge([1,3])
sage: list(sage.graphs.cliquer.all_cliques(G))[[0, 2, 3, 4], [0, 1, 2, 4]]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> list(sage.graphs.cliquer.all_cliques(G))[[0, 1, 2, 3, 4]]>>> list(sage.graphs.cliquer.all_cliques(G, Integer(2), Integer(3)))[[3, 4],[2, 3],[2, 3, 4],[2, 4],[1, 2],[1, 2, 3],[1, 2, 4],[1, 3],[1, 3, 4],[1, 4],[0, 1],[0, 1, 2],[0, 1, 3],[0, 1, 4],[0, 2],[0, 2, 3],[0, 2, 4],[0, 3],[0, 3, 4],[0, 4]]>>> G.delete_edge([Integer(1),Integer(3)])>>> list(sage.graphs.cliquer.all_cliques(G))[[0, 2, 3, 4], [0, 1, 2, 4]]

1.2. Undirected graphs469

Graph Theory, Release 10.4

Todo: Use the re-entrant functionality of Cliquer [NO2003] to avoid storing all cliques.
antipodal_graph()
Return the antipodal graph of self.
The antipodal graph of a graph 𝐺 has the same vertex set of 𝐺 and two vertices are adjacent if their distancein 𝐺 is equal to the diameter of 𝐺.
OUTPUT:
A new graph. self is not touched.
EXAMPLES:
sage: G = graphs.JohnsonGraph(10, 5)
sage: G.antipodal_graph()
Antipodal graph of Johnson graph with parameters 10,5: Graph on 252 vertices
sage: G = graphs.HammingGraph(8, 2)
sage: G.antipodal_graph()
Antipodal graph of Hamming Graph with parameters 8,2: Graph on 256 vertices>>> from sage.all import *>>> G = graphs.JohnsonGraph(Integer(10), Integer(5))>>> G.antipodal_graph()
Antipodal graph of Johnson graph with parameters 10,5: Graph on 252 vertices>>> G = graphs.HammingGraph(Integer(8), Integer(2))>>> G.antipodal_graph()
Antipodal graph of Hamming Graph with parameters 8,2: Graph on 256 vertices

The antipodal graph of a disconnected graph is its complement:
sage: G = Graph(5)sage: H = G.antipodal_graph()
sage: H.is_isomorphic(G.complement())
True>>> from sage.all import *>>> G = Graph(Integer(5))>>> H = G.antipodal_graph()>>> H.is_isomorphic(G.complement())
True

apex_vertices(k=None)
Return the list of apex vertices.
A graph is apex if it can be made planar by the removal of a single vertex. The deleted vertex is called an
apex of the graph, and a graph may have more than one apex. For instance, in the minimal nonplanar graphs
𝐾5 or 𝐾3,3 , every vertex is an apex. The apex graphs include graphs that are themselves planar, in which caseagain 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 connectedcomponent and that this component is apex. See the Wikipedia article Apex_graph for more information.
See also:• is_apex()• is_planar()
470

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

INPUT:• k – integer (default: None); when set to None, the method returns the list of all apex of the graph,possibly empty if the graph is not apex. When set to a positive integer, the method ends as soon as 𝑘apex vertices are found.
OUTPUT:
By default, the method returns the list of all apex of the graph. When parameter k is set to a positive integer,
the returned list is bounded to 𝑘 apex vertices.
EXAMPLES:
𝐾5 and 𝐾3,3 are apex graphs, and each of their vertices is an apex:
sage: G = graphs.CompleteGraph(5)sage: G.apex_vertices()[0, 1, 2, 3, 4]
sage: G = graphs.CompleteBipartiteGraph(3,3)
sage: G.is_apex()Truesage: G.apex_vertices()[0, 1, 2, 3, 4, 5]
sage: G.apex_vertices(k=3)[0, 1, 2]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G.apex_vertices()[0, 1, 2, 3, 4]>>> G = graphs.CompleteBipartiteGraph(Integer(3),Integer(3))>>> G.is_apex()
True>>> G.apex_vertices()[0, 1, 2, 3, 4, 5]>>> G.apex_vertices(k=Integer(3))[0, 1, 2]

A4
𝑡𝑖𝑚𝑒𝑠4-grid is apex and each of its vertices is an apex. When adding a universal vertex, the resulting graphis apex and the universal vertex is the unique apex vertex
sage: G = graphs.Grid2dGraph(4,4)
sage: set(G.apex_vertices()) == set(G.vertices(sort=False))
True
sage: G.add_edges([( universal ,v) for v in G])
sage: G.apex_vertices()[ universal ]>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(4),Integer(4))>>> set(G.apex_vertices()) == set(G.vertices(sort=False))
True>>> G.add_edges([( universal ,v) for v in G])>>> G.apex_vertices()[ universal ]The Petersen graph is not apex:

1.2. Undirected graphs471

Graph Theory, Release 10.4

sage: G = graphs.PetersenGraph()
sage: G.apex_vertices()[]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> 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()[]>>> from sage.all import *>>> M = graphs.Grid2dGraph(Integer(3),Integer(3))>>> K5 = graphs.CompleteGraph(Integer(5))>>> (M+K5).apex_vertices()[9, 10, 11, 12, 13]>>> (M+K5+K5).apex_vertices()[]

Neighbors of an apex of degree 2 are apex:
sage: G = graphs.Grid2dGraph(5,5)
sage: v = (666, 666)
sage: G.add_path([(1, 1), v, (3, 3)])sage: G.is_planar()False
sage: G.degree(v)2sage: sorted(G.apex_vertices())[(1, 1), (2, 2), (3, 3), (666, 666)]>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(5),Integer(5))>>> v = (Integer(666), Integer(666))>>> G.add_path([(Integer(1), Integer(1)), v, (Integer(3), Integer(3))])>>> G.is_planar()
False>>> G.degree(v)2>>> sorted(G.apex_vertices())[(1, 1), (2, 2), (3, 3), (666, 666)]

arboricity(certificate=False)
Return the arboricity of the graph and an optional certificate.
The arboricity is the minimum number of forests that covers the graph.
See Wikipedia article Arboricity
INPUT:

472

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• certificate – boolean (default: False); whether to return a certificate.
OUTPUT:
When certificate = True, then the function returns (𝑎, 𝐹 ) where 𝑎 is the arboricity and 𝐹 is a listof 𝑎 disjoint forests that partitions the edge set of 𝑔. The forests are represented as subgraphs of the originalgraph.
If certificate = False, the function returns just a integer indicating the arboricity.
ALGORITHM:
Represent the graph as a graphical matroid, then apply matroid sage.matroid.partition() algorithm from the matroids module.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: a, F = G.arboricity(True)
˓→needs sage.modules
sage: a˓→needs sage.modules2
sage: all([f.is_forest() for f in F])
˓→needs sage.modules
True
sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size()
˓→needs sage.modules
True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> a, F = G.arboricity(True)
˓→needs sage.modules>>> a˓→needs sage.modules
2>>> all([f.is_forest() for f in F])
˓→needs sage.modules
True>>> len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size()
˓→needs sage.modules
True

#␣
#␣

#␣

#␣

#␣
#␣

#␣

#␣

atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=False)
Return the atoms of the decomposition of 𝐺 by clique minimal separators.
Let 𝐺 = (𝑉, 𝐸) be a graph. A set 𝑆 ⊂ 𝑉 is a clique separator if 𝐺[𝑆] is a clique and the graph 𝐺 ∖ 𝑆 has atleast 2 connected components. Let 𝐶 ⊂ 𝑉 be the vertices of a connected component of 𝐺 ∖ 𝑆. The graph
𝐺[𝐶 + 𝑆] is an atom if it has no clique separator.
This method implements the algorithm proposed in [BPS2010], that improves upon the algorithm proposed
in [TY1984], for computing the atoms and the clique minimal separators of a graph. This algorithm is basedon the maximum_cardinality_search_M() graph traversal and has time complexity in 𝑂(|𝑉 |·|𝐸|).
Note: As the graph is converted to a short_digraph (with sort_neighbors=True), the complexity has
an extra 𝑂(|𝑉 | + |𝐸| log |𝐸|) for SparseGraph and 𝑂(|𝑉 |2 log |𝐸|) for DenseGraph.

1.2. Undirected graphs473

Graph Theory, Release 10.4

If the graph is not connected, we insert empty separators between the lists of separators of each connectedcomponents. See the examples below for more details.
INPUT:• G – a Sage graph• tree – boolean (default: False); whether to return the result as a directed tree in which internal nodes
are clique separators and leaves are the atoms of the decomposition. Since a clique separator is repeated
when its removal partition the graph into 3 or more connected components, vertices are labels by tuples(𝑖, 𝑆), where 𝑆 is the set of vertices of the atom or the clique separator, and 0 ≤ 𝑖 ≤ |𝑇 |.
• rooted_tree – boolean (default: False); whether to return the result as a LabelledRootedTree. When tree is True, this parameter is ignored.
• separators – boolean (default: False); whether to also return the complete list of separators considered during the execution of the algorithm. When tree or rooted_tree is True, this parameteris ignored.
OUTPUT:• By default, return a tuple (𝐴, 𝑆𝑐 ), where 𝐴 is the list of atoms of the graph in the order of discovery, and
𝑆𝑐 is the list of clique separators, with possible repetitions, in the order the separator has been considered.
If furthermore separators is True, return a tuple (𝐴, 𝑆ℎ , 𝑆𝑐 ), where 𝑆𝑐 is the list of consideredseparators of the graph in the order they have been considered.
• When tree is True, format the result as a directed tree
• When rooted_tree is True and tree is False, format the output as a LabelledRootedTree
EXAMPLES:
Example of [BPS2010]:
sage: G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],....:d : [ e , f , j , k ], e : [ g ],....:f : [ g , j , k ], g : [ j , k ], h : [ i , j ],....:i : [ k ], j : [ k ]})sage: atoms, cliques = G.atoms_and_clique_separators()
sage: sorted(sorted(a) for a in atoms)[[ a , b , c , k ],[ c , d , j , k ],[ d , e , f , g , j , k ],[ h , i , j , k ]]sage: sorted(sorted(c) for c in cliques)[[ c , k ], [ d , j , k ], [ j , k ]]sage: T = G.atoms_and_clique_separators(tree=True)
sage: T.is_tree()True
sage: T.diameter() == len(atoms)Truesage: all(u[1] in atoms for u in T if T.degree(u) == 1)
True
sage: all(u[1] in cliques for u in T if T.degree(u) != 1)
True>>> from sage.all import *>>> G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],...
d : [ e , f , j , k ], e : [ g ],...
f : [ g , j , k ], g : [ j , k ], h : [ i , j ],...
i : [ k ], j : [ k ]})(continues on next page)474

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> atoms, cliques = G.atoms_and_clique_separators()>>> sorted(sorted(a) for a in atoms)[[ a , b , c , k ],[ c , d , j , k ],[ d , e , f , g , j , k ],[ h , i , j , k ]]>>> sorted(sorted(c) for c in cliques)[[ c , k ], [ d , j , k ], [ j , k ]]>>> T = G.atoms_and_clique_separators(tree=True)>>> T.is_tree()True>>> T.diameter() == len(atoms)
True>>> all(u[Integer(1)] in atoms for u in T if T.degree(u) == Integer(1))
True>>> all(u[Integer(1)] in cliques for u in T if T.degree(u) != Integer(1))
True

A graph without clique separator:
sage: G = graphs.CompleteGraph(5)sage: G.atoms_and_clique_separators()([{0, 1, 2, 3, 4}], [])sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True)){0, 1, 2, 3, 4}>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G.atoms_and_clique_separators()([{0, 1, 2, 3, 4}], [])>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True)){0, 1, 2, 3, 4}

Graphs with several biconnected components:
sage: G = graphs.PathGraph(4)sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))____{2}____//{2, 3}__{1}__//{1, 2} {0, 1}
sage: G = graphs.WindmillGraph(3, 4)
sage: G.atoms_and_clique_separators()([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))________{0}________//{0, 1, 2}_______{0}______//{0, 3, 4}____{0}___//{0, 8, 7} {0, 5, 6}

1.2. Undirected graphs475

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))____{2}____//{2, 3}__{1}__//{1, 2} {0, 1}>>> G = graphs.WindmillGraph(Integer(3), Integer(4))>>> G.atoms_and_clique_separators()([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))________{0}________//{0, 1, 2}_______{0}______//{0, 3, 4}____{0}___//{0, 8, 7} {0, 5, 6}

When the removal of a clique separator results in 𝑘 > 2 connected components, this separator is repeated𝑘 − 1 times, but the repetitions are not necessarily contiguous:
sage: G = Graph(2)sage: for i in range(5):....:G.add_cycle([0, 1, G.add_vertex()])
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))_________{0, 1}_____//{0, 1, 4}________{0, 1}_____//{0, 1, 2}_______{0, 1}___//{0, 1, 3}____{0, 1}//{0, 1, 5} {0, 1, 6}
sage: G = graphs.StarGraph(3)sage: G.subdivide_edges(G.edges(sort=False), 2)
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{5}______//{1, 5}______{7}______//{2, 7}______{9}______//{9, 3}______{6}______//{6, 7}______{4}_____//{4, 5}_____{0}_____//{0, 6}____{8}____//{8, 9}__{0}__//{0, 8} {0, 4}

476

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph(Integer(2))>>> for i in range(Integer(5)):...
G.add_cycle([Integer(0), Integer(1), G.add_vertex()])>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))_________{0, 1}_____//{0, 1, 4}________{0, 1}_____//{0, 1, 2}_______{0, 1}___//{0, 1, 3}____{0, 1}//{0, 1, 5} {0, 1, 6}>>> G = graphs.StarGraph(Integer(3))>>> G.subdivide_edges(G.edges(sort=False), Integer(2))>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{5}______//{1, 5}______{7}______//{2, 7}______{9}______//{9, 3}______{6}______//{6, 7}______{4}_____//{4, 5}_____{0}_____//{0, 6}____{8}____//{8, 9}__{0}__//{0, 8} {0, 4}

If the graph is not connected, we insert empty separators between the lists of separators of each connectedcomponents. For instance, let 𝐺 be a graph with 3 connected components. The method returns the list
𝑆𝑐 = [𝑆0 , · · · , 𝑆𝑖 , . . . , 𝑆𝑗 , . . . , 𝑆𝑘−1 ] of 𝑘 clique separators, where 𝑖 and 𝑗 are the indexes of the inserted
empty separators and 0 ≤ 𝑖 < 𝑗 < 𝑘 − 1. The method also returns the list 𝐴 = [𝐴0 , . . . , 𝑆𝑘 ] of the𝑘 + 1 atoms, with 𝑘 + 1 ≥ 3. The lists of atoms and clique separators of each of the connected components
are respectively [𝐴0 , . . . , 𝐴𝑖 ] and [𝑆0 , . . . , 𝑆𝑖−1 ], [𝐴𝑖+1 , . . . , 𝐴𝑗 ] and [𝑆𝑖+1 , . . . , 𝑆𝑗−1 ], and [𝐴𝑗+1 , . . . , 𝐴𝑘 ]and [𝑆𝑗+1 , . . . , 𝑆𝑘−1 ]. One can check that for each connected component, we get one atom more than cliqueseparators:
sage: G = graphs.PathGraph(3) * 3
sage: A, Sc = G.atoms_and_clique_separators()
sage: A[{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]
sage: Sc[{1}, {}, {4}, {}, {7}]sage: i , j = [i for i, s in enumerate(Sc) if not s]sage: i, j
(1, 3)
sage: A[:i+1], Sc[:i]([{1, 2}, {0, 1}], [{1}])sage: A[i+1:j+1], Sc[i+1:j](continues on next page)1.2. Undirected graphs

477

Graph Theory, Release 10.4

(continued from previous page)([{4, 5}, {3, 4}], [{4}])sage: A[j+1:], Sc[j+1:]([{8, 7}, {6, 7}], [{7}])sage: I = [-1, i, j, len(Sc)]sage: for i, j in zip(I[:-1], I[1:]):....:
print(A[i+1:j+1], Sc[i+1:j])[{1, 2}, {0, 1}] [{1}][{4, 5}, {3, 4}] [{4}][{8, 7}, {6, 7}] [{7}]sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}>>> from sage.all import *>>> G = graphs.PathGraph(Integer(3)) * Integer(3)>>> A, Sc = G.atoms_and_clique_separators()>>> A[{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]>>> Sc[{1}, {}, {4}, {}, {7}]>>> i , j = [i for i, s in enumerate(Sc) if not s]>>> i, j(1, 3)>>> A[:i+Integer(1)], Sc[:i]([{1, 2}, {0, 1}], [{1}])>>> A[i+Integer(1):j+Integer(1)], Sc[i+Integer(1):j]([{4, 5}, {3, 4}], [{4}])>>> A[j+Integer(1):], Sc[j+Integer(1):]([{8, 7}, {6, 7}], [{7}])>>> I = [-Integer(1), i, j, len(Sc)]>>> for i, j in zip(I[:-Integer(1)], I[Integer(1):]):...
print(A[i+Integer(1):j+Integer(1)], Sc[i+Integer(1):j])[{1, 2}, {0, 1}] [{1}][{4, 5}, {3, 4}] [{4}][{8, 7}, {6, 7}] [{7}]>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}

478

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Loops and multiple edges are ignored:sage: G.allow_loops(True)
sage: G.add_edges([(u, u) for u in G])
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}>>> from sage.all import *>>> G.allow_loops(True)>>> G.add_edges([(u, u) for u in G])>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edges(sort=False))>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}

We can check that the returned list of separators is valid:
sage: G = graphs.RandomGNP(50, .1)
sage: while not G.is_connected():....:G = graphs.RandomGNP(50, .1)
sage: _, separators, _ = G.atoms_and_clique_separators(separators=True)
sage: for S in separators:....:
H = G.copy()....:
H.delete_vertices(S)....:if H.is_connected():....:raise ValueError("something goes wrong")>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(50), RealNumber( .1 ))>>> while not G.is_connected():...
G = graphs.RandomGNP(Integer(50), RealNumber( .1 ))>>> _, separators, _ = G.atoms_and_clique_separators(separators=True)>>> for S in separators:...
H = G.copy()...
H.delete_vertices(S)(continues on next page)1.2. Undirected graphs479

Graph Theory, Release 10.4

(continued from previous page)

...
...

if H.is_connected():raise ValueError("something goes wrong")

bandwidth(G, k=None)
Compute the bandwidth of an undirected graph.
For a definition of the bandwidth of a graph, see the documentation of the bandwidth module.
INPUT:• G – a graph• k – integer (default: None); set to an integer value to test whether 𝑏𝑤(𝐺) ≤ 𝑘, or to None (default) tocompute 𝑏𝑤(𝐺)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])˓→# needs sage.modules[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])˓→# needs sage.modules[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]␣␣(continues on next page)

480

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[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]>>> from sage.all import *>>> from sage.graphs.graph_decompositions.bandwidth import bandwidth>>> G = graphs.PetersenGraph()>>> bandwidth(G,Integer(3))
False>>> bandwidth(G)(5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2])>>> G.adjacency_matrix(vertices=[Integer(0), Integer(4), Integer(5),␣
˓→Integer(8), Integer(1), Integer(9), Integer(3), Integer(7), Integer(6),␣
˓→Integer(2)])# needs sage.modules[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]>>> G = graphs.ChvatalGraph()>>> bandwidth(G)(6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2])>>> G.adjacency_matrix(vertices=[Integer(0), Integer(5), Integer(9),␣
˓→Integer(4), Integer(10), Integer(1), Integer(6), Integer(11), Integer(3),␣
˓→Integer(8), Integer(7), Integer(2)])# needs sage.modules[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]

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.

1.2. Undirected graphs481

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.CycleGraph(Integer(4)).bipartite_color(){0: 1, 1: 0, 2: 1, 3: 0}>>> graphs.CycleGraph(Integer(5)).bipartite_color()
Traceback (most recent call last):...
RuntimeError: Graph is not bipartite.

bipartite_double(extended=False)
Return the (extended) bipartite double of this graph.
The bipartite double of a graph 𝐺 has vertex set {(𝑣, 0), (𝑣, 1) : 𝑣 ∈ 𝐺} and for any edge (𝑢, 𝑣) in 𝐺 it hasedges ((𝑢, 0), (𝑣, 1)) and ((𝑢, 1), (𝑣, 0)). Note that this is the tensor product of 𝐺 with 𝐾2 .
The extended bipartite double of 𝐺 is the bipartite double of 𝐺 after added all edges ((𝑣, 0), (𝑣, 1)) for all
vertices 𝑣.
INPUT:• extended – boolean (default: False); Whether to return the extended bipartite double, or only the
bipartite double (default)
OUTPUT:
A graph; self is left untouched.
EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: H = G.bipartite_double()sage: G == graphs.PetersenGraph() # G is left invariant
Truesage: H.order() == 2 * G.order()True
sage: H.size() == 2 * G.size()
True
sage: H.is_bipartite()True
sage: H.bipartite_sets() == (set([(v, 0) for v in G]),....: set([(v, 1) for v in G]))
True
sage: H.is_isomorphic(G.tensor_product(graphs.CompleteGraph(2)))
True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> H = G.bipartite_double()>>> G == graphs.PetersenGraph() # G is left invariant
True>>> H.order() == Integer(2) * G.order()True>>> H.size() == Integer(2) * G.size()
True>>> H.is_bipartite()True>>> H.bipartite_sets() == (set([(v, Integer(0)) for v in G]),... set([(v, Integer(1)) for v in G]))
True
(continues on next page)482

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> H.is_isomorphic(G.tensor_product(graphs.CompleteGraph(Integer(2))))
True

Behaviour with disconnected graphs:
sage: G1 = graphs.PetersenGraph()
sage: G2 = graphs.HoffmanGraph()
sage: G = G1.disjoint_union(G2)sage: H = G.bipartite_double()sage: H1 = G1.bipartite_double()sage: H2 = G2.bipartite_double()sage: H.is_isomorphic(H1.disjoint_union(H2))
True>>> from sage.all import *>>> G1 = graphs.PetersenGraph()>>> G2 = graphs.HoffmanGraph()>>> G = G1.disjoint_union(G2)>>> H = G.bipartite_double()>>> H1 = G1.bipartite_double()>>> H2 = G2.bipartite_double()>>> H.is_isomorphic(H1.disjoint_union(H2))
True

See also:
Wikipedia article Bipartite_double_cover, WolframAlpha Bipartite Double, [VDKT2016] p. 20 for the extended bipartite double.
bipartite_sets()
Return (𝑋, 𝑌 ) where 𝑋 and 𝑌 are the nodes in each bipartite set of graph 𝐺.
Fails with an error if graph is not bipartite.
EXAMPLES:
sage: graphs.CycleGraph(4).bipartite_sets()({0, 2}, {1, 3})
sage: graphs.CycleGraph(5).bipartite_sets()
Traceback (most recent call last):...
RuntimeError: Graph is not bipartite.
>>> from sage.all import *>>> graphs.CycleGraph(Integer(4)).bipartite_sets()({0, 2}, {1, 3})>>> graphs.CycleGraph(Integer(5)).bipartite_sets()
Traceback (most recent call last):...
RuntimeError: Graph is not bipartite.

bounded_outdegree_orientation(bound, solver, verbose=None, integrality_tolerance=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 :1.2. Undirected graphs483

Graph Theory, Release 10.4

• An integer 𝑘. In this case, computes an orientation whose maximum out-degree is less than 𝑘.
• A dictionary associating to each vertex its associated maximum out-degree.
• A function associating to each vertex its associated maximum out-degree.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
A DiGraph representing the orientation if it exists. A ValueError exception is raised otherwise.
ALGORITHM:
The problem is solved through a maximum flow :Given a graph 𝐺, we create a DiGraph 𝐷 defined on 𝐸(𝐺) ∪ 𝑉 (𝐺) ∪ {𝑠, 𝑡}. We then link 𝑠 to all of 𝑉 (𝐺)(these edges having a capacity equal to the bound associated to each element of 𝑉 (𝐺)), and all the elementsof 𝐸(𝐺) to 𝑡 . We then link each 𝑣 ∈ 𝑉 (𝐺) to each of its incident edges in 𝐺. A maximum integer flow ofvalue |𝐸(𝐺)| 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 ⌉:sage: g = graphs.RandomGNP(40, .4)
sage: b = lambda v: integer_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>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(40), RealNumber( .4 ))>>> b = lambda v: integer_ceil(g.degree(v)/Integer(2))>>> D = g.bounded_outdegree_orientation(b)>>> 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>>> from sage.all import *>>> g = graphs.ChvatalGraph()>>> D = g.bounded_outdegree_orientation(Integer(2))>>> 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.

484

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = graphs.RandomGNP(40, .4) sage: mad = g.maximum_average_degree() # needs sage.numerical.mip
Hence this is possible
sage: d = g.bounded_outdegree_orientation(integer_ceil(mad/2))
˓→needs sage.numerical.mip#␣>>> from sage.all import *>>> d = g.bounded_outdegree_orientation(integer_ceil(mad/Integer(2)))˓→# needs sage.numerical.mip

␣While this is not:sage: try:
˓→needs sage.numerical.mip....:
g.bounded_outdegree_orientation(integer_ceil(mad/2-1))....:
print("Error")....: except ValueError:
....:
pass

#␣

>>> from sage.all import *>>> try:
˓→needs sage.numerical.mip...
g.bounded_outdegree_orientation(integer_ceil(mad/Integer(2)˓→Integer(1)))...
print("Error")... except ValueError:
...
pass

#␣

bridges(G, labels=True)
Return an iterator over the bridges (or cut edges).
A bridge is an edge whose deletion disconnects the undirected graph. A disconnected graph has no bridge.
INPUT:• labels – boolean (default: True); if False, each bridge is a tuple (𝑢, 𝑣) of vertices
EXAMPLES:
sage: 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)Truesage: list(bridges(g))[(1, 10, None)]sage: list(g.bridges())[(1, 10, None)]>>> from sage.all import *>>> from sage.graphs.connectivity import bridges>>> from sage.graphs.connectivity import is_connected>>> g = Integer(2) * graphs.PetersenGraph()>>> g.add_edge(Integer(1), Integer(10))>>> is_connected(g)(continues on next page)1.2. Undirected graphs

485

Graph Theory, Release 10.4

(continued from previous page)True>>> list(bridges(g))[(1, 10, None)]>>> list(g.bridges())[(1, 10, None)]

Every edge of a tree is a bridge:
sage: g = graphs.RandomTree(100)sage: sum(1 for _ in g.bridges()) == 99
True>>> from sage.all import *>>> g = graphs.RandomTree(Integer(100))>>> sum(Integer(1) for _ in g.bridges()) == Integer(99)Truecenter(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the set of vertices in the center of the graph.
The center is the set of vertices whose eccentricity is equal to the radius of the graph, i.e., achieving theminimum eccentricity.
For more information and examples on how to use input variables, see shortest_paths() and eccentricity()
INPUT:• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); see method eccentricity() for the list of available algorithms• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:Is Central African Republic in the center of Africa in graph theoretic sense? Yes:sage: A = graphs.AfricaMap(continental=True)
sage: sorted(A.center())[ Cameroon , Central Africa ]>>> from sage.all import *>>> A = graphs.AfricaMap(continental=True)>>> sorted(A.center())[ Cameroon , Central Africa ]Some other graphs. Center can be the whole graph:
sage: G = graphs.DiamondGraph()
sage: G.center()(continues on next page)

486

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[1, 2]
sage: P = graphs.PetersenGraph()
sage: P.subgraph(P.center()) == P
True
sage: S = graphs.StarGraph(19)sage: S.center()[0]>>> from sage.all import *>>> G = graphs.DiamondGraph()>>> G.center()[1, 2]>>> P = graphs.PetersenGraph()>>> P.subgraph(P.center()) == P
True>>> S = graphs.StarGraph(Integer(19))>>> S.center()[0]

centrality_degree(v=None)
Return the degree centrality of a vertex.
The degree centrality of a vertex 𝑣 is its degree, divided by |𝑉 (𝐺)| − 1. For more information, see the
Wikipedia article Centrality.
INPUT:• v – a vertex (default: None); set to None (default) to get a dictionary associating each vertex with its
centrality degree.
See also:• centrality_closeness()• centrality_betweenness()
EXAMPLES:
sage: (graphs.ChvatalGraph()).centrality_degree(){0: 4/11, 1: 4/11, 2: 4/11, 3: 4/11, 4: 4/11, 5: 4/11,
6: 4/11, 7: 4/11, 8: 4/11, 9: 4/11, 10: 4/11, 11: 4/11}
sage: D = graphs.DiamondGraph()
sage: D.centrality_degree(){0: 2/3, 1: 1, 2: 1, 3: 2/3}
sage: D.centrality_degree(v=1)
1>>> from sage.all import *>>> (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}>>> D = graphs.DiamondGraph()>>> D.centrality_degree(){0: 2/3, 1: 1, 2: 1, 3: 2/3}>>> D.centrality_degree(v=Integer(1))
1

1.2. Undirected graphs487

Graph Theory, Release 10.4

cheeger_constant(g)Return the cheeger constant of the graph.
The Cheeger constant of a graph 𝐺 = (𝑉, 𝐸) is the minimum of |𝜕𝑆|/|𝑉 𝑜𝑙(𝑆)| where 𝑉 𝑜𝑙(𝑆) is the sumof degrees of element in 𝑆, 𝜕𝑆 is the edge boundary of 𝑆 (number of edges with one end in 𝑆 and one end
in 𝑉 ∖ 𝑆) and the minimum is taken over all non-empty subsets 𝑆 of vertices so that |𝑉 𝑜𝑙(𝑆)| ≤ |𝐸|.
See also:
Alternative but similar quantities can be obtained via the methods edge_isoperimetric_number()and vertex_isoperimetric_number().
EXAMPLES:
sage: graphs.PetersenGraph().cheeger_constant()
1/3>>> from sage.all import *>>> graphs.PetersenGraph().cheeger_constant()
1/3

The Cheeger constant of a cycle on 𝑛 vertices is 1/⌊𝑛/2⌋:
sage: [graphs.CycleGraph(k).cheeger_constant() for k in range(2,10)][1, 1, 1/2, 1/2, 1/3, 1/3, 1/4, 1/4]>>> from sage.all import *>>> [graphs.CycleGraph(k).cheeger_constant() for k in range(Integer(2),˓→Integer(10))][1, 1, 1/2, 1/2, 1/3, 1/3, 1/4, 1/4]

The Cheeger constant of a complete graph on 𝑛 vertices is ⌈𝑛/2⌉/(𝑛 − 1):sage: [graphs.CompleteGraph(k).cheeger_constant() for k in range(2,10)][1, 1, 2/3, 3/4, 3/5, 2/3, 4/7, 5/8]>>> from sage.all import *>>> [graphs.CompleteGraph(k).cheeger_constant() for k in range(Integer(2),˓→Integer(10))][1, 1, 2/3, 3/4, 3/5, 2/3, 4/7, 5/8]

For complete bipartite:sage: [graphs.CompleteBipartiteGraph(i,j).cheeger_constant() for i in range(2,˓→7) for j in range(2, i)][3/5, 1/2, 3/5, 5/9, 4/7, 5/9, 1/2, 5/9, 1/2, 5/9]>>> from sage.all import *>>> [graphs.CompleteBipartiteGraph(i,j).cheeger_constant() for i in␣
˓→range(Integer(2),Integer(7)) for j in range(Integer(2), i)][3/5, 1/2, 3/5, 5/9, 4/7, 5/9, 1/2, 5/9, 1/2, 5/9]

More examples:sage: G = Graph([(0, 1), (0, 3), (0, 8), (1, 4), (1, 6), (2, 4), (2, 7), (2,␣
˓→9),
....:
(3, 6), (3, 8), (4, 9), (5, 6), (5, 7), (5, 8), (7, 9)])(continues on next page)

488

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.cheeger_constant()
1/6
sage: G = Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (3,␣˓→4), (3, 5)])sage: G.cheeger_constant()
1/2
sage: Graph([[1,2,3,4],[(1,2),(3,4)]]).cheeger_constant()
0>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1)), (Integer(0), Integer(3)),␣
˓→(Integer(0), Integer(8)), (Integer(1), Integer(4)), (Integer(1),␣
˓→Integer(6)), (Integer(2), Integer(4)), (Integer(2), Integer(7)),␣
˓→(Integer(2), Integer(9)),...
(Integer(3), Integer(6)), (Integer(3), Integer(8)),␣
˓→(Integer(4), Integer(9)), (Integer(5), Integer(6)), (Integer(5),␣
˓→Integer(7)), (Integer(5), Integer(8)), (Integer(7), Integer(9))])>>> G.cheeger_constant()
1/6>>> G = Graph([(Integer(0), Integer(1)), (Integer(0), Integer(2)),␣
˓→(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(1),␣
˓→Integer(4)), (Integer(1), Integer(5)), (Integer(2), Integer(3)),␣
˓→(Integer(3), Integer(4)), (Integer(3), Integer(5))])>>> G.cheeger_constant()
1/2>>> Graph([[Integer(1),Integer(2),Integer(3),Integer(4)],[(Integer(1),˓→Integer(2)),(Integer(3),Integer(4))]]).cheeger_constant()
0chromatic_index(solver, verbose=None, integrality_tolerance=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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
This method is a frontend for method sage.graphs.graph_coloring.edge_coloring() thatuses 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()

1.2. Undirected graphs489

Graph Theory, Release 10.4

• 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()
5sage: graphs.CompleteGraph(6).chromatic_index()
5>>> from sage.all import *>>> graphs.CompleteGraph(Integer(4)).chromatic_index()3>>> graphs.CompleteGraph(Integer(5)).chromatic_index()
5>>> graphs.CompleteGraph(Integer(6)).chromatic_index()
5

The path 𝑃𝑛 with 𝑛 ≥ 2 has chromatic index 2:
sage: graphs.PathGraph(5).chromatic_index()
˓→needs sage.numerical.mip2#␣>>> from sage.all import *>>> graphs.PathGraph(Integer(5)).chromatic_index()˓→# needs sage.numerical.mip
2

␣

The windmill graph with parameters 𝑘, 𝑛 has chromatic index (𝑘 − 1)𝑛:sage: k,n = 3,4
sage: G = graphs.WindmillGraph(k,n)
sage: G.chromatic_index() == (k-1)*n˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> k,n = Integer(3),Integer(4)>>> G = graphs.WindmillGraph(k,n)>>> G.chromatic_index() == (k-Integer(1))*n˓→# needs sage.numerical.mip
True␣

chromatic_number(algorithm, solver='DLX', verbose=None, integrality_tolerance=0)
Return the minimal number of colors needed to color the vertices of the graph.
INPUT:• algorithm – string (default: "DLX"); one of the following algorithms:– "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.

490

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

– "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.
– "MILP": the chromatic number is computed using a mixed integer linear program. The performance of this implementation is affected by whether optional MILP solvers have been installed (seethe MILP module, or Sage’s tutorial on Linear Programming).
– "parallel": all the above algorithms are executed in parallel and the result is returned as soon
as one algorithm ends. Observe that the speed of the above algorithms depends on the size andstructure of the graph.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
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")
3sage: G.chromatic_number(algorithm="MILP")
3
sage: G.chromatic_number(algorithm="CP")˓→needs sage.libs.flint3
sage: G.chromatic_number(algorithm="parallel")3#␣>>> from sage.all import *>>> G = Graph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(1):␣
˓→[Integer(2)]})>>> G.chromatic_number(algorithm="DLX")
3>>> G.chromatic_number(algorithm="MILP")
3>>> G.chromatic_number(algorithm="CP")#␣˓→needs sage.libs.flint
3>>> G.chromatic_number(algorithm="parallel")3

A bipartite graph has (by definition) chromatic number 2:
sage: graphs.RandomBipartite(50,50,0.7).chromatic_number()˓→needs numpy2#␣>>> from sage.all import *>>> graphs.RandomBipartite(Integer(50),Integer(50),RealNumber( 0.7 )).
˓→chromatic_number()# needs numpy
2

1.2. Undirected graphs491

Graph Theory, Release 10.4

A complete multipartite graph with 𝑘 parts has chromatic number 𝑘:sage: all(graphs.CompleteMultipartiteGraph([5]*i).chromatic_number() == i....:for i in range(2, 5))
True>>> from sage.all import *>>> all(graphs.CompleteMultipartiteGraph([Integer(5)]*i).chromatic_number()␣
˓→== i...
for i in range(Integer(2), Integer(5)))
True

The complete graph has the largest chromatic number from all the graphs of order 𝑛. Namely its chromatic
number is 𝑛:
sage: all(graphs.CompleteGraph(i).chromatic_number() == i for i in range(10))
True>>> from sage.all import *>>> all(graphs.CompleteGraph(i).chromatic_number() == i for i in␣
˓→range(Integer(10)))True

The Kneser graph with parameters (𝑛, 2) for 𝑛 > 3 has chromatic number 𝑛 − 2:sage: all(graphs.KneserGraph(i,2).chromatic_number() == i-2 for i in range(4,
˓→6))
True
>>> from sage.all import *>>> all(graphs.KneserGraph(i,Integer(2)).chromatic_number() == i-Integer(2)␣
˓→for i in range(Integer(4),Integer(6)))
True

The Flower Snark graph has chromatic index 4 hence its line graph has chromatic number 4:
sage: graphs.FlowerSnark().line_graph().chromatic_number()4>>> from sage.all import *>>> graphs.FlowerSnark().line_graph().chromatic_number()4

chromatic_polynomial(G, return_tree_basis=False, algorithm='C', cache=None)
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 thechromatic polynomial of G is equal to that of G’ minus that of G’’.
INPUT:• G – a Sage graph• return_tree_basis – boolean (default: False); not used yet

492

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• algorithm – string (default: "C"); the algorithm to use among– "C", an implementation in C by Robert Miller and Gordon Royle.
– "Python", an implementation in Python using caching to avoid recomputing the chromatic polynomial of a graph that has already been seen. This seems faster on some dense graphs.
• cache – dictionary (default: None); this parameter is used only for algorithm "Python". It is adictionary keyed by canonical labelings of graphs and used to cache the chromatic polynomials of thegraphs generated by the algorithm. In other words, it avoids computing twice the chromatic polynomialof isometric graphs. One will be created automatically if not provided.
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 time0>>> from sage.all import *>>> graphs.CycleGraph(Integer(4)).chromatic_polynomial()x^4 - 4*x^3 + 6*x^2 - 3*x>>> graphs.CycleGraph(Integer(3)).chromatic_polynomial()x^3 - 3*x^2 + 2*x>>> graphs.CubeGraph(Integer(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>>> 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>>> graphs.CompleteBipartiteGraph(Integer(3),Integer(3)).chromatic_
˓→polynomial()x^6 - 9*x^5 + 36*x^4 - 75*x^3 + 78*x^2 - 31*x>>> for i in range(Integer(2),Integer(7)):(continues on next page)1.2. Undirected graphs493

Graph Theory, Release 10.4

(continued from previous page)...
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>>> graphs.CycleGraph(Integer(5)).chromatic_polynomial().factor()(x - 2) * (x - 1) * x * (x^2 - 2*x + 2)>>> graphs.OctahedralGraph().chromatic_polynomial().factor()(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)>>> graphs.WheelGraph(Integer(5)).chromatic_polynomial().factor()(x - 2) * (x - 1) * x * (x^2 - 5*x + 7)>>> graphs.WheelGraph(Integer(6)).chromatic_polynomial().factor()(x - 3) * (x - 2) * (x - 1) * x * (x^2 - 4*x + 5)>>> __tmp__=var("x"); C = symbolic_expression(graphs.LCFGraph(Integer(24),␣
˓→[Integer(12),Integer(7),-Integer(7)], Integer(8)).chromatic_polynomial()).
˓→function(x)# long time (6s on sage.math, 2011)>>> C(Integer(2)) # long time0

By definition, the chromatic number of a graph G is the least integer k such that the chromatic polynomial of
G is strictly positive at k:sage: G = graphs.PetersenGraph()
sage: P = G.chromatic_polynomial()
sage: min(i for i in range(11) if P(i) > 0) == G.chromatic_number()True
sage: G = graphs.RandomGNP(10,0.7)
sage: P = G.chromatic_polynomial()
sage: min(i for i in range(11) if P(i) > 0) == G.chromatic_number()True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> P = G.chromatic_polynomial()>>> min(i for i in range(Integer(11)) if P(i) > Integer(0)) == G.chromatic_
˓→number()
True>>> G = graphs.RandomGNP(Integer(10),RealNumber( 0.7 ))>>> P = G.chromatic_polynomial()>>> min(i for i in range(Integer(11)) if P(i) > Integer(0)) == G.chromatic_
˓→number()
True

Check that algorithms "C" and "Python" return the same results:
sage: G = graphs.RandomGNP(8, randint(1, 9)*0.1)
sage: c = G.chromatic_polynomial(algorithm= C )sage: p = G.chromatic_polynomial(algorithm= Python )sage: c == p
True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(8), randint(Integer(1),␣
(continues on next page)494

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

Integer(9))*RealNumber( 0.1 ))>>> c = G.chromatic_polynomial(algorithm= C )>>> p = G.chromatic_polynomial(algorithm= Python )>>> c == pTrue˓→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 firstdescribed in [SW2012]. We use the equivalent definition given in [BC2018]:∑︁
𝑋𝐺 (𝑡) =𝑡asc(𝜎) 𝑀|𝜎1 |,...,|𝜎𝑛 | ,𝜎=(𝜎1 ,...,𝜎𝑛 )where we sum over all ordered set partitions of the vertex set of 𝐺 such that each block 𝜎𝑖 is an independent(i.e., stable) set of 𝐺, and where asc(𝜎) denotes the number of edges {𝑢, 𝑣} of 𝐺 such that 𝑢 < 𝑣 and 𝑣
appears in a later part of 𝜎 than 𝑢.
INPUT:• t – (optional) the parameter 𝑡; uses the variable 𝑡 in [𝑡] by default• R – (optional) the base ring for the quasisymmetric functions; uses the parent of 𝑡 by default
EXAMPLES:
sage: # needs sage.combinat sage.modules
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]>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> G = Graph([[Integer(1),Integer(2),Integer(3)], [[Integer(1),Integer(3)],␣
˓→[Integer(2),Integer(3)]]])>>> G.chromatic_quasisymmetric_function()(2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1]>>> G = graphs.PathGraph(Integer(4))>>> 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]>>> 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](continues on next page)1.2. Undirected graphs495

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphs.CompleteGraph(Integer(4))>>> 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()
˓→needs sage.combinat sage.modules
False

#␣

>>> from sage.all import *>>> G = Graph([[Integer(1),Integer(2)], [Integer(1),Integer(5)], [Integer(3),˓→Integer(4)], [Integer(3),Integer(5)]])>>> G.chromatic_quasisymmetric_function().is_symmetric()#␣˓→needs sage.combinat sage.modules
False

We check that at 𝑡 = 1, we recover the usual chromatic symmetric function:
sage: p = SymmetricFunctions(QQ).p()
˓→needs sage.combinat sage.modules
sage: G = graphs.CycleGraph(5)sage: XG = G.chromatic_quasisymmetric_function(t=1); XG
˓→needs sage.combinat sage.modules
120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1]+ 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1]+ 10*M[2, 1, 2] + 10*M[2, 2, 1]
sage: p(XG.to_symmetric_function())˓→needs sage.combinat sage.modules
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
˓→needs sage.combinat sage.modules
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())˓→needs sage.combinat sage.modules
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]>>> from sage.all import *>>> p = SymmetricFunctions(QQ).p()
˓→needs sage.combinat sage.modules>>> G = graphs.CycleGraph(Integer(5))>>> XG = G.chromatic_quasisymmetric_function(t=Integer(1)); XG˓→# needs sage.combinat sage.modules
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]>>> p(XG.to_symmetric_function())˓→needs sage.combinat sage.modules
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]

#␣

#␣

#␣

␣

#␣

(continues on next page)

496

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphs.ClawGraph()>>> XG = G.chromatic_quasisymmetric_function(t=Integer(1)); XG˓→# needs sage.combinat sage.modules
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]>>> p(XG.to_symmetric_function())˓→needs sage.combinat sage.modules
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]␣#␣chromatic_symmetric_function(R=None)
Return the chromatic symmetric function of self.
Let 𝐺 be a graph. The chromatic symmetric function 𝑋𝐺 was described in [Sta1995], specifically Theorem
2.5 states that∑︁𝑋𝐺 =(−1)|𝐹 | 𝑝𝜆(𝐹 ) ,𝐹 ⊆𝐸(𝐺)

where 𝜆(𝐹 ) is the partition of the sizes of the connected components of the subgraph induced by the edges
𝐹 and 𝑝𝜇 is the powersum symmetric function.
INPUT:• R – (optional) the base ring for the symmetric functions; this uses

by default

ALGORITHM:
We traverse a binary tree whose leaves correspond to subsets of edges, and whose internal vertices at depth 𝑑correspond to a choice of whether to include the 𝑑-th edge in a given subset. The components of the induced
subgraph are incrementally updated using a disjoint-set forest. If the next edge would introduce a cycle to thesubset, we prune the branch as the terms produced by the two subtrees cancel in this case.
EXAMPLES:
sage: s = SymmetricFunctions(ZZ).s()
˓→needs sage.combinat sage.modules
sage: G = graphs.CycleGraph(5)sage: XG = G.chromatic_symmetric_function(); XG
˓→needs sage.combinat sage.modules
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)˓→needs sage.combinat sage.modules
30*s[1, 1, 1, 1, 1] + 10*s[2, 1, 1, 1] + 10*s[2, 2, 1]>>> from sage.all import *>>> s = SymmetricFunctions(ZZ).s()
˓→needs sage.combinat sage.modules>>> G = graphs.CycleGraph(Integer(5))>>> XG = G.chromatic_symmetric_function(); XG
˓→needs sage.combinat sage.modules
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]>>> s(XG)
˓→needs sage.combinat sage.modules
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:

1.2. Undirected graphs497

Graph Theory, Release 10.4

sage: G = graphs.ClawGraph()
sage: XG = G.chromatic_symmetric_function(); XG
˓→needs sage.combinat sage.modules
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]sage: s(XG)˓→needs sage.combinat sage.modules
8*s[1, 1, 1, 1] + 5*s[2, 1, 1] - s[2, 2] + s[3, 1]>>> from sage.all import *>>> G = graphs.ClawGraph()>>> XG = G.chromatic_symmetric_function(); XG
˓→needs sage.combinat sage.modules
p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4]>>> s(XG)
˓→needs sage.combinat sage.modules
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: # needs sage.combinat sage.modules
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)sage: G3.delete_edge([1,3])
sage: XG3 = G3.chromatic_symmetric_function()sage: XG == XG1 + XG2 - XG3
True>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> G = Graph([[Integer(1),Integer(2)],[Integer(1),Integer(3)],[Integer(2),˓→Integer(3)]])>>> XG = G.chromatic_symmetric_function()>>> G1 = copy(G)>>> G1.delete_edge([Integer(1),Integer(2)])>>> XG1 = G1.chromatic_symmetric_function()>>> G2 = copy(G)>>> G2.delete_edge([Integer(1),Integer(3)])>>> XG2 = G2.chromatic_symmetric_function()>>> G3 = copy(G1)>>> G3.delete_edge([Integer(1),Integer(3)])>>> XG3 = G3.chromatic_symmetric_function()>>> XG == XG1 + XG2 - XG3
Truecleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0, integrality_tolerance=0.001)
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:
498

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• G – a Graph.
• cut_vertices – iterable container of 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 inG.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT: A 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 notconnected 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(sort=True), f1.edges(sort=True)([0, 1], [])>>> from sage.all import *>>> from sage.graphs.connectivity import cleave>>> G = Graph(Integer(2))>>> for _ in range(Integer(3)):...
G.add_clique([Integer(0), Integer(1), G.add_vertex(), G.add_vertex()])>>> S1,C1,f1 = cleave(G, cut_vertices=[Integer(0), Integer(1)])>>> [g.order() for g in S1][4, 4, 4]>>> C1.order(), C1.size()(2, 4)>>> f1.vertices(sort=True), f1.edges(sort=True)([0, 1], [])1.2. Undirected graphs499

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> G.subgraph([Integer(0), Integer(1)]).complement() == Graph([[Integer(0),␣
˓→Integer(1)], []])
True>>> S2,C2,f2 = cleave(G, cut_vertices=[Integer(0), Integer(1)], virtual_
˓→edges=False)>>> (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(sort=True), f1.edges(sort=True)([0, 1], [(0, 1, None)])>>> from sage.all import *>>> G.delete_edge(Integer(0), Integer(1))>>> S1,C1,f1 = cleave(G, cut_vertices=[Integer(0), Integer(1)])>>> [g.order() for g in S1][4, 4, 4]>>> C1.order(), C1.size()(2, 3)>>> f1.vertices(sort=True), f1.edges(sort=True)([0, 1], [(0, 1, None)])If virtual_edges == False and the cut vertices are not connected by an edge:
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(sort=True), f2.edges(sort=True)([0, 1], [])sage: (S1 == S2, C1 == C2, f1 == f2)(False, False, False)>>> from sage.all import *>>> G.subgraph([Integer(0), Integer(1)]).complement() == Graph([[Integer(0),␣
˓→Integer(1)], []])
False>>> S2,C2,f2 = cleave(G, cut_vertices=[Integer(0), Integer(1)], virtual_(continues on next page)

500

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)edges=False)>>> [g.order() for g in S2][4, 4, 4]>>> C2.order(), C2.size()(2, 0)>>> f2.vertices(sort=True), f2.edges(sort=True)([0, 1], [])>>> (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.edge_iterator())
sage: G.add_edges([(0, 1), (0, 1), (0, 1)])
sage: S,C,f = cleave(G, cut_vertices=[0, 1])
sage: for g in S:....:
print(g.edges(sort=True, labels=0))[(0, 1), (0, 1), (0, 1), (0, 2), (0, 2), (0, 3), (0, 3), (1, 2), (1, 2), (1,␣˓→3), (1, 3), (2, 3), (2, 3)][(0, 1), (0, 1), (0, 1), (0, 4), (0, 4), (1, 4), (1, 4)]>>> from sage.all import *>>> G = graphs.CompleteBipartiteGraph(Integer(2), Integer(3))>>> G.add_edge(Integer(2), Integer(3))>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edge_iterator())>>> G.add_edges([(Integer(0), Integer(1)), (Integer(0), Integer(1)),␣
˓→(Integer(0), Integer(1))])>>> S,C,f = cleave(G, cut_vertices=[Integer(0), Integer(1)])>>> for g in S:...
print(g.edges(sort=True, labels=Integer(0)))[(0, 1), (0, 1), (0, 1), (0, 2), (0, 2), (0, 3), (0, 3), (1, 2), (1, 2), (1,␣˓→3), (1, 3), (2, 3), (2, 3)][(0, 1), (0, 1), (0, 1), (0, 4), (0, 4), (1, 4), (1, 4)]clique_complex()
Return the clique complex of self.
This is the largest simplicial complex on the vertices of self whose 1-skeleton is self.
This is only makes sense for undirected simple graphs.
EXAMPLES:
sage: g = Graph({0:[1,2],1:[2],4:[]})
sage: g.clique_complex()
Simplicial complex with vertex set (0, 1, 2, 4) and facets {(4,), (0, 1, 2)}
sage: h = Graph({0:[1,2,3,4],1:[2,3,4],2:[3]})sage: x = h.clique_complex()
sage: xSimplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0,␣
˓→1, 2, 3)}
sage: i = x.graph()(continues on next page)1.2. Undirected graphs

501Graph Theory, Release 10.4

(continued from previous page)

sage: i==h
True
sage: x==i.clique_complex()True>>> from sage.all import *>>> g = Graph({Integer(0):[Integer(1),Integer(2)],Integer(1):[Integer(2)],
˓→Integer(4):[]})>>> g.clique_complex()
Simplicial complex with vertex set (0, 1, 2, 4) and facets {(4,), (0, 1, 2)}>>> h = Graph({Integer(0):[Integer(1),Integer(2),Integer(3),Integer(4)],
˓→Integer(1):[Integer(2),Integer(3),Integer(4)],Integer(2):[Integer(3)]})>>> x = h.clique_complex()>>> x
Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0,␣
˓→1, 2, 3)}>>> i = x.graph()>>> i==hTrue>>> x==i.clique_complex()Trueclique_maximum(algorithm, solver='Cliquer', verbose=None, integrality_tolerance=0)
Return the vertex set of a maximal order complete subgraph.
INPUT:• algorithm – the algorithm to be used :– If algorithm = "Cliquer" (default), wraps the C program Cliquer [NO2003].
– 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.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
Parameters solver and verbose are used only when algorithm="MILP".
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:

502

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> C = graphs.PetersenGraph()>>> C.clique_maximum()[7, 9]>>> C = Graph( DJ{ )>>> C.clique_maximum()[1, 2, 3, 4]

Through a Linear Program:
sage: len(C.clique_maximum(algorithm="MILP"))4>>> from sage.all import *>>> len(C.clique_maximum(algorithm="MILP"))4

clique_number(algorithm, cliques='Cliquer', solver=None, verbose=None, integrality_tolerance=0)
Return the order of the largest clique of the graphThis is also called as the clique number.
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph toan undirected graph.
INPUT:• algorithm – the algorithm to be used :– If algorithm = "Cliquer", wraps the C program Cliquer [NO2003].
– If algorithm = "networkx", uses the NetworkX’s implementation of the Bron and Kerbosch
Algorithm [BK1973].
– If algorithm = "MILP", the problem is solved through a Mixed Integer Linear Program.
(see MixedIntegerLinearProgram)– If algorithm = "mcqd", uses the MCQD solver (http://insilab.org/maxclique/). Note that the
MCQD package must be installed.
• cliques – an optional list of cliques that can be input if already computed. Ignored unless algorithm=="networkx".
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.

1.2. Undirected graphs503

Graph Theory, Release 10.4

• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
ALGORITHM:
This function is based on Cliquer [NO2003] and [BK1973].
EXAMPLES:
sage: C = Graph( DJ{ )sage: C.clique_number()4
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
˓→needs sage.plot
sage: G.clique_number()3>>> from sage.all import *>>> C = Graph( DJ{ )>>> C.clique_number()4>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> 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>>> from sage.all import *>>> all(graphs.CompleteGraph(i).clique_number() == i for i in␣
˓→range(Integer(1),Integer(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>>> from sage.all import *>>> all((i*graphs.CompleteGraph(Integer(1))).clique_number() == Integer(1)...
for i in range(Integer(1),Integer(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

504

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> all((i*graphs.CompleteMultipartiteGraph(i*[Integer(5)])).clique_number()␣
˓→== i...
for i in range(Integer(1),Integer(6)))
Trueclique_polynomial(t=None)
Return the clique polynomial of self.
This is the polynomial where the coefficient of 𝑡𝑛 is the number of cliques in the graph with 𝑛 vertices. The
constant term of the clique polynomial is always taken to be one.
EXAMPLES:
sage: g = Graph()
sage: g.clique_polynomial()
1
sage: g = Graph({0:[1]})sage: g.clique_polynomial()t^2 + 2*t + 1
sage: g = graphs.CycleGraph(4)sage: g.clique_polynomial()
4*t^2 + 4*t + 1>>> from sage.all import *>>> g = Graph()>>> g.clique_polynomial()
1>>> g = Graph({Integer(0):[Integer(1)]})>>> g.clique_polynomial()t^2 + 2*t + 1>>> g = graphs.CycleGraph(Integer(4))>>> 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: # needs networkx
sage: C = Graph( DJ{ )sage: C.cliques_containing_vertex(){0: [[0, 4]],
1: [[1, 2, 3, 4]],
2: [[1, 2, 3, 4]],
(continues on next page)1.2. Undirected graphs505

Graph Theory, Release 10.4

(continued from previous page)3: [[1, 2, 3, 4]],
4: [[0, 4], [1, 2, 3, 4]]}sage: C.cliques_containing_vertex(4)[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_containing_vertex([0, 1]){0: [[0, 4]], 1: [[1, 2, 3, 4]]}sage: E = C.cliques_maximal(); 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: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
˓→needs sage.plot
sage: G.cliques_containing_vertex()
˓→needs networkx{0: [[0, 1, 2], [0, 1, 3]],
1: [[0, 1, 2], [0, 1, 3]],
2: [[0, 1, 2]],
3: [[0, 1, 3]]}#␣#␣>>> from sage.all import *>>> # needs networkx>>> C = Graph( DJ{ )>>> C.cliques_containing_vertex(){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]]}>>> C.cliques_containing_vertex(Integer(4))[[0, 4], [1, 2, 3, 4]]>>> C.cliques_containing_vertex([Integer(0), Integer(1)]){0: [[0, 4]], 1: [[1, 2, 3, 4]]}>>> E = C.cliques_maximal(); E[[0, 4], [1, 2, 3, 4]]>>> 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]]}>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> G.cliques_containing_vertex()
˓→needs networkx{0: [[0, 1, 2], [0, 1, 3]],
1: [[0, 1, 2], [0, 1, 3]],
2: [[0, 1, 2]],
3: [[0, 1, 3]]}

506

␣
#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Since each clique of a 2 dimensional grid corresponds to an edge, the number of cliques in which a vertex is
involved equals its degree:
sage: # needs networkx
sage: F = graphs.Grid2dGraph(2,3)
sage: d = F.cliques_containing_vertex()sage: all(F.degree(u) == len(cliques) for u,cliques in d.items())
True
sage: d = F.cliques_containing_vertex(vertices=[(0, 1)])
sage: list(d)[(0, 1)]
sage: sorted(sorted(x for x in L) for L in d[(0, 1)])[[(0, 0), (0, 1)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]]>>> from sage.all import *>>> # needs networkx>>> F = graphs.Grid2dGraph(Integer(2),Integer(3))>>> d = F.cliques_containing_vertex()>>> all(F.degree(u) == len(cliques) for u,cliques in d.items())
True>>> d = F.cliques_containing_vertex(vertices=[(Integer(0), Integer(1))])>>> list(d)[(0, 1)]>>> sorted(sorted(x for x in L) for L in d[(Integer(0), Integer(1))])[[(0, 0), (0, 1)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]]cliques_get_clique_bipartite(**kwds)
Return the vertex-clique bipartite graph of self.
In the returned bipartite graph, the left vertices are the vertices of self and the right vertices represent
the maximal cliques of self. There is an edge from vertex 𝑣 to clique 𝐶 in the bipartite graph if and only
if 𝑣 belongs to 𝐶.
Note: Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an
undirected graph.
EXAMPLES:
sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG
Bipartite graph on 36 vertices
sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False)
˓→needs sage.plot
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
˓→needs sage.plot
sage: G.cliques_get_clique_bipartite()
Bipartite graph on 6 vertices
sage: G.cliques_get_clique_bipartite().show(figsize=[2,2])
˓→needs sage.plot

#␣

#␣

#␣

>>> from sage.all import *>>> CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG
Bipartite graph on 36 vertices>>> CBG.show(figsize=[Integer(2),Integer(2)], vertex_size=Integer(20), vertex_
˓→labels=False)# needs sage.plot(continues on next page)1.2. Undirected graphs507

Graph Theory, Release 10.4

(continued from previous page)>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> G.cliques_get_clique_bipartite()
Bipartite graph on 6 vertices>>> G.cliques_get_clique_bipartite().show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot

␣␣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: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG
Graph on 24 vertices
sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False)
˓→needs sage.plot
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
˓→needs sage.plot
sage: G.cliques_get_max_clique_graph()
Graph on 2 vertices
sage: G.cliques_get_max_clique_graph().show(figsize=[2,2])
˓→needs sage.plot

#␣

#␣

#␣

>>> from sage.all import *>>> MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG
Graph on 24 vertices>>> MCG.show(figsize=[Integer(2),Integer(2)], vertex_size=Integer(20), vertex_
˓→labels=False)# needs sage.plot>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])␣˓→# needs sage.plot>>> G.cliques_get_max_clique_graph()
Graph on 2 vertices>>> G.cliques_get_max_clique_graph().show(figsize=[Integer(2),Integer(2)])␣˓→# needs sage.plot

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:

508

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• algorithm – can be set to "native" (default) to use Sage’s own implementation, or to "NetworkX" to use NetworkX’ implementation of the Bron and Kerbosch Algorithm [BK1973].
Note: This method sorts its output before returning it. If you prefer to save the extra time, you can callsage.graphs.independent_sets.IndependentSets directly.

Note: Sage’s implementation of the enumeration of maximal independent sets is not much faster than
NetworkX’ (expect a 2x speedup), which is surprising as it is written in Cython. This being said, the algorithm
from NetworkX appears to be slightly different from this one, and that would be a good thing to explore if
one wants to improve the implementation.
ALGORITHM:
This function is based on NetworkX’s implementation of the Bron and Kerbosch Algorithm [BK1973].
EXAMPLES:
sage: graphs.ChvatalGraph().cliques_maximal()[[0, 1], [0, 4], [0, 6], [0, 9], [1, 2], [1, 5], [1, 7], [2, 3],[2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10],[5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]]sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2, 2])
˓→needs sage.plot
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]]>>> from sage.all import *>>> 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]]>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2), Integer(2)])˓→# needs sage.plot>>> G.cliques_maximal()[[0, 1, 2], [0, 1, 3]]>>> C = graphs.PetersenGraph()>>> 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]]>>> C = Graph( DJ{ )>>> C.cliques_maximal()[[0, 4], [1, 2, 3, 4]]#␣␣Comparing the two implementations:1.2. Undirected graphs509

Graph Theory, Release 10.4

sage: g = graphs.RandomGNP(20,.7)
sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX")))˓→needs networkx
sage: s2 = Set(map(Set, g.cliques_maximal(algorithm="native")))sage: s1 == s2
˓→needs networkx
True>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(20),RealNumber( .7 ))>>> s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX")))˓→needs networkx>>> s2 = Set(map(Set, g.cliques_maximal(algorithm="native")))>>> s1 == s2
˓→needs networkx
True

#␣

#␣

#␣

#␣

cliques_maximum(graph)
Return the vertex sets of ALL the maximum complete subgraphs.
Returns the list of all maximum cliques, with each clique represented by a list of vertices. A clique is aninduced complete subgraph, and a maximum clique is one of maximal order.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraphto an undirected graph.
ALGORITHM:
This function is based on Cliquer [NO2003].
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])˓→# needs sage.plot
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]]␣>>> from sage.all import *>>> 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]]>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})(continues on next page)

510

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> G.cliques_maximum()[[0, 1, 2], [0, 1, 3]]>>> C = graphs.PetersenGraph()>>> 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]]>>> C = Graph( DJ{ )>>> 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(); E[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_number_of(cliques=E){0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
sage: F = graphs.Grid2dGraph(2,3)
sage: F.cliques_number_of(){(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2}
sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]){(0, 1): 3, (1, 2): 2}
sage: F.cliques_number_of(vertices=(0, 1))3
sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
˓→needs sage.plot
sage: G.cliques_number_of(){0: 2, 1: 2, 2: 1, 3: 1}#␣>>> from sage.all import *>>> C = Graph( DJ{ )>>> C.cliques_number_of(){0: 1, 1: 1, 2: 1, 3: 1, 4: 2}>>> E = C.cliques_maximal(); E[[0, 4], [1, 2, 3, 4]]>>> C.cliques_number_of(cliques=E){0: 1, 1: 1, 2: 1, 3: 1, 4: 2}(continues on next page)1.2. Undirected graphs

511

Graph Theory, Release 10.4

(continued from previous page)>>> F = graphs.Grid2dGraph(Integer(2),Integer(3))>>> F.cliques_number_of(){(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2}>>> F.cliques_number_of(vertices=[(Integer(0), Integer(1)), (Integer(1),␣
˓→Integer(2))]){(0, 1): 3, (1, 2): 2}>>> F.cliques_number_of(vertices=(Integer(0), Integer(1)))
3>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> 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.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraphto an undirected graph.
INPUT:• algorithm – either cliquer or networkx– cliquer – This wraps the C program Cliquer [NO2003].
– networkx – This function is based on NetworkX’s implementation of the Bron and Kerbosch
Algorithm [BK1973].
• vertices – the vertices toalgorithm== networkx .

inspect(defaultisentiregraph).

Ignoredunless• cliques – list of cliques (if already computed). Ignored unless algorithm== networkx .
EXAMPLES:
sage: C = Graph( DJ{ )sage: C.cliques_vertex_clique_number()˓→needs sage.plot{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
sage: E = C.cliques_maximal(); E[[0, 4], [1, 2, 3, 4]]
sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx")
˓→needs networkx{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
sage: F = graphs.Grid2dGraph(2,3)
sage: F.cliques_vertex_clique_number(algorithm="networkx")
˓→needs networkx{(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)])
˓→needs sage.plot{(0, 1): 2, (1, 2): 2}

#␣

#␣

#␣

#␣

(continues on next page)

512

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
sage: G.show(figsize=[2,2])
˓→needs sage.plot
sage: G.cliques_vertex_clique_number()˓→needs sage.plot{0: 3, 1: 3, 2: 3, 3: 3}>>> from sage.all import *>>> C = Graph( DJ{ )>>> C.cliques_vertex_clique_number()˓→needs sage.plot{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}>>> E = C.cliques_maximal(); E[[0, 4], [1, 2, 3, 4]]>>> C.cliques_vertex_clique_number(cliques=E, algorithm="networkx")
˓→needs networkx{0: 2, 1: 4, 2: 4, 3: 4, 4: 4}>>> F = graphs.Grid2dGraph(Integer(2),Integer(3))>>> F.cliques_vertex_clique_number(algorithm="networkx")
˓→needs networkx{(0, 0): 2, (0, 1): 2, (0, 2): 2, (1, 0): 2, (1, 1): 2, (1, 2): 2}>>> F.cliques_vertex_clique_number(vertices=[(Integer(0), Integer(1)),␣
˓→(Integer(1), Integer(2))])# needs sage.plot{(0, 1): 2, (1, 2): 2}>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> G.cliques_vertex_clique_number()˓→needs sage.plot{0: 3, 1: 3, 2: 3, 3: 3}

#␣
#␣

#␣

#␣

#␣

␣
#␣

coloring(algorithm, hex_colors='DLX', solver=False, verbose=None, integrality_tolerance=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 – boolean (default: False); if True, return a dictionary which can easily be used forplotting.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
1.2. Undirected graphs513

Graph Theory, Release 10.4

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")
sage: Q = G.coloring(algorithm="DLX")
sage: def are_equal_colorings(A, B):....:
return Set(map(Set, A)) == Set(map(Set, B))
sage: are_equal_colorings(P, [[1, 2, 3], [0, 5, 6], [4]])Truesage: are_equal_colorings(P, Q)
True
sage: # needs sage.plot
sage: G.plot(partition=P)
Graphics object consisting of 16 graphics primitives
sage: G.coloring(hex_colors=True, algorithm="MILP"){ #0000ff : [4], #00ff00 : [0, 6, 5], #ff0000 : [2, 1, 3]}
sage: H = G.coloring(hex_colors=True, algorithm="DLX"); H{ #0000ff : [4], #00ff00 : [1, 2, 3], #ff0000 : [0, 5, 6]}
sage: G.plot(vertex_colors=H)
Graphics object consisting of 16 graphics primitives>>> from sage.all import *>>> G = Graph("Fooba")>>> P = G.coloring(algorithm="MILP")>>> Q = G.coloring(algorithm="DLX")>>> def are_equal_colorings(A, B):...
return Set(map(Set, A)) == Set(map(Set, B))>>> are_equal_colorings(P, [[Integer(1), Integer(2), Integer(3)], [Integer(0),˓→ Integer(5), Integer(6)], [Integer(4)]])True>>> are_equal_colorings(P, Q)
True>>> # needs sage.plot>>> G.plot(partition=P)
Graphics object consisting of 16 graphics primitives>>> G.coloring(hex_colors=True, algorithm="MILP"){ #0000ff : [4], #00ff00 : [0, 6, 5], #ff0000 : [2, 1, 3]}>>> H = G.coloring(hex_colors=True, algorithm="DLX"); H{ #0000ff : [4], #00ff00 : [1, 2, 3], #ff0000 : [0, 5, 6]}>>> G.plot(vertex_colors=H)
Graphics object consisting of 16 graphics primitives

common_neighbors_matrix(vertices, nonedgesonly=None, base_ring=True, **kwds)
Return a matrix of numbers of common neighbors between each pairs.
The (𝑖, 𝑗) entry of the matrix gives the number of common neighbors between vertices 𝑖 and 𝑗.
This method is only valid for simple (no loops, no multiple edges) graphs.
INPUT:• nonedgesonly – boolean (default: True); if True, assigns 0 value to adjacent vertices.
• vertices – list (default: None); the ordering of the vertices defining how they should appear in thematrix. By default, the ordering given by GenericGraph.vertices() is used.
514

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

4
1

0

6

3

2

5

1.2. Undirected graphs

515

Graph Theory, Release 10.4

• base_ring – a ring (default: None); the base ring of the matrix space to use• **kwds – other keywords to pass to matrix()
OUTPUT: matrix
EXAMPLES:
The common neighbors matrix for a straight linear 2-tree counting only non-adjacent vertex pairs
sage: G1 = Graph()
sage: G1.add_edges([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G1.common_neighbors_matrix(nonedgesonly=True)#␣˓→needs sage.modules[0 0 0 2 1 0]
[0 0 0 0 2 1]
[0 0 0 0 0 2]
[2 0 0 0 0 0]
[1 2 0 0 0 0]
[0 1 2 0 0 0]>>> from sage.all import *>>> G1 = Graph()>>> G1.add_edges([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),˓→Integer(2)),(Integer(1),Integer(3)),(Integer(3),Integer(5)),(Integer(2),˓→Integer(4)),(Integer(2),Integer(3)),(Integer(3),Integer(4)),(Integer(4),˓→Integer(5))])>>> G1.common_neighbors_matrix(nonedgesonly=True)#␣˓→needs sage.modules[0 0 0 2 1 0]
[0 0 0 0 2 1]
[0 0 0 0 0 2]
[2 0 0 0 0 0]
[1 2 0 0 0 0]
[0 1 2 0 0 0]

We now show the common neighbors matrix which includes adjacent vertices
sage: G1.common_neighbors_matrix(nonedgesonly=False)
˓→needs sage.modules[0 1 1 2 1 0]
[1 0 2 1 2 1]
[1 2 0 2 1 2]
[2 1 2 0 2 1]
[1 2 1 2 0 1]
[0 1 2 1 1 0]>>> from sage.all import *>>> G1.common_neighbors_matrix(nonedgesonly=False)
˓→needs sage.modules[0 1 1 2 1 0]
[1 0 2 1 2 1]
[1 2 0 2 1 2]
[2 1 2 0 2 1]
[1 2 1 2 0 1]
[0 1 2 1 1 0]#␣#␣

The common neighbors matrix for a fan on 6 vertices counting only non-adjacent vertex pairs

516

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.common_neighbors_matrix()#␣˓→needs sage.modules[0 0 0 0 0 0 0]
[0 0 0 2 1 1 1]
[0 0 0 0 2 1 1]
[0 2 0 0 0 2 1]
[0 1 2 0 0 0 1]
[0 1 1 2 0 0 1]
[0 1 1 1 1 1 0]>>> from sage.all import *>>> H = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(0),˓→Integer(3)),(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(0),˓→Integer(6)),(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(4)),(Integer(4),Integer(5))])>>> H.common_neighbors_matrix()#␣˓→needs sage.modules[0 0 0 0 0 0 0]
[0 0 0 2 1 1 1]
[0 0 0 0 2 1 1]
[0 2 0 0 0 2 1]
[0 1 2 0 0 0 1]
[0 1 1 2 0 0 1]
[0 1 1 1 1 1 0]

A different base ring:sage: H.common_neighbors_matrix(base_ring=RDF)
˓→needs sage.modules[0.0 0.0 0.0 0.0 0.0 0.0 0.0]
[0.0 0.0 0.0 2.0 1.0 1.0 1.0]
[0.0 0.0 0.0 0.0 2.0 1.0 1.0]
[0.0 2.0 0.0 0.0 0.0 2.0 1.0]
[0.0 1.0 2.0 0.0 0.0 0.0 1.0]
[0.0 1.0 1.0 2.0 0.0 0.0 1.0]
[0.0 1.0 1.0 1.0 1.0 1.0 0.0]

#␣>>> from sage.all import *>>> H.common_neighbors_matrix(base_ring=RDF)
˓→needs sage.modules[0.0 0.0 0.0 0.0 0.0 0.0 0.0]
[0.0 0.0 0.0 2.0 1.0 1.0 1.0]
[0.0 0.0 0.0 0.0 2.0 1.0 1.0]
[0.0 2.0 0.0 0.0 0.0 2.0 1.0]
[0.0 1.0 2.0 0.0 0.0 0.0 1.0]
[0.0 1.0 1.0 2.0 0.0 0.0 1.0]
[0.0 1.0 1.0 1.0 1.0 1.0 0.0]

#␣

It is an error to input anything other than a simple graph:
sage: G = Graph([(0,0)], loops=True)
sage: G.common_neighbors_matrix()
˓→needs sage.modules
Traceback (most recent call last):...
ValueError: This method is not known to work on graphs with loops.

#␣(continues on next page)1.2. Undirected graphs

517

Graph Theory, Release 10.4

(continued from previous page)

Perhaps this method can be updated to handle them, but in themeantime if you want to use it please disallow loops using
allow_loops().
>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(0))], loops=True)>>> G.common_neighbors_matrix()
˓→needs sage.modules
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 themeantime if you want to use it please disallow loops using
allow_loops().

#␣

See also:• most_common_neighbors() – returns node pairs with most shared neighbors
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 ofthe 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: # needs sage.numerical.mip
sage: g = graphs.PetersenGraph()
sage: g.convexity_properties().hull([1, 3])[1, 2, 3]
sage: g.convexity_properties().hull([3, 7])[2, 3, 7]>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.PetersenGraph()>>> g.convexity_properties().hull([Integer(1), Integer(3)])[1, 2, 3]>>> g.convexity_properties().hull([Integer(3), Integer(7)])[2, 3, 7]

is a terrible waste of computations, while
sage: # needs sage.numerical.mip
sage: g = graphs.PetersenGraph()
sage: CP = g.convexity_properties()
sage: CP.hull([1, 3])(continues on next page)

518

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[1, 2, 3]
sage: CP.hull([3, 7])[2, 3, 7]>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.PetersenGraph()>>> CP = g.convexity_properties()>>> CP.hull([Integer(1), Integer(3)])[1, 2, 3]>>> CP.hull([Integer(3), Integer(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 atleast 𝑘.
• 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, 𝛿 * (𝐺) = 𝑘 − 1
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 [BZ2003].
INPUT:• k – integer (default: None);– 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.

1.2. Undirected graphs519

Graph Theory, Release 10.4

• with_labels – boolean (default: False); 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.
See also:• Graph cores is also a notion related to graph homomorphisms. For this second meaning, see Graph.
has_homomorphism_to().
• Wikipedia article Degeneracy_(graph_theory)
EXAMPLES:
sage: (graphs.FruchtGraph()).cores()[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
sage: (graphs.FruchtGraph()).cores(with_labels=True){0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3}
sage: # needs sage.modules
sage: set_random_seed(0)sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1)
sage: b = Graph(20)sage: b.add_edges(a.nonzero_positions(), loops=False)
sage: cores = b.cores(with_labels=True); cores{0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3,
11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
sage: [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]>>> from sage.all import *>>> (graphs.FruchtGraph()).cores()[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]>>> (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}>>> # needs sage.modules>>> set_random_seed(Integer(0))>>> a = random_matrix(ZZ, Integer(20), x=Integer(2), sparse=True,␣
˓→density=RealNumber( .1 ))>>> b = Graph(Integer(20))>>> b.add_edges(a.nonzero_positions(), loops=False)>>> 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}>>> [v for v,c in cores.items() if c >= Integer(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)
˓→needs networkx
sage: ordering, core = g.cores(2)˓→needs networkx
sage: len(core) == 0
˓→needs networkx
True

520

#␣
#␣
#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.RandomLobster(Integer(20), RealNumber( .5 ), RealNumber( .5 ))␣˓→# needs networkx>>> ordering, core = g.cores(Integer(2))␣˓→# needs networkx>>> len(core) == Integer(0)␣˓→# needs networkx
True

Checking the cores of a bull graph:
sage: G = graphs.BullGraph()
sage: G.cores(with_labels=True){0: 2, 1: 2, 2: 2, 3: 1, 4: 1}
sage: G.cores(k=2)([3, 4], [0, 1, 2])>>> from sage.all import *>>> G = graphs.BullGraph()>>> G.cores(with_labels=True){0: 2, 1: 2, 2: 2, 3: 1, 4: 1}>>> G.cores(k=Integer(2))([3, 4], [0, 1, 2])

Graphs with multiple edges:
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: G.cores(with_labels=True){0: 4, 1: 4, 2: 4, 3: 2, 4: 2}
sage: G.cores(k=4)([3, 4], [0, 1, 2])>>> from sage.all import *>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edges(sort=False))>>> G.cores(with_labels=True){0: 4, 1: 4, 2: 4, 3: 2, 4: 2}>>> G.cores(k=Integer(4))([3, 4], [0, 1, 2])

cutwidth(G, algorithm='exponential', cut_off=0, solver=None, verbose=False, integrality_tolerance=0.001)
Return the cutwidth of the graph and the corresponding vertex ordering.
INPUT:• G – a Graph or a DiGraph• algorithm – string (default: "exponential"); 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 – integer (default: 0); 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.

1.2. Undirected graphs521

Graph Theory, Release 10.4

• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – boolean (default: False); whether to display information on the computations.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Cutwidth of a 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>>> from sage.all import *>>> from sage.graphs.graph_decompositions.cutwidth import cutwidth>>> G = graphs.CompleteGraph(Integer(5))>>> cw,L = cutwidth(G); cw
6>>> K = graphs.CompleteGraph(Integer(6))>>> cw,L = cutwidth(K); cw
9>>> cw,L = cutwidth(K+K); cw
9The 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>>> from sage.all import *>>> from sage.graphs.graph_decompositions.cutwidth import cutwidth>>> G = graphs.Grid2dGraph(Integer(3),Integer(3))>>> cw,L = cutwidth(G); cw
4>>> G = graphs.Grid2dGraph(Integer(3),Integer(5))>>> cw,L = cutwidth(G); cw
4degree_constrained_subgraph(bounds, solver, verbose=None, integrality_tolerance=0)
Returns a degree-constrained subgraph.

522

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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) corresponding
to the values (𝑓 (𝑣), 𝑔(𝑣)).
– A function associating to each vertex a pair of real values (min,max) corresponding to the values(𝑓 (𝑣), 𝑔(𝑣)).
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:• When a solution exists, this method outputs the degree-constrained 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: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)
˓→needs sage.numerical.mip
sage: m.size()
˓→needs sage.numerical.mip
3>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6))>>> bounds = lambda x: [Integer(1),Integer(1)]>>> m = g.degree_constrained_subgraph(bounds=bounds)
˓→needs sage.numerical.mip>>> m.size()
˓→needs sage.numerical.mip
3

#␣
#␣

#␣
#␣

diameter(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the diameter of the graph.

1.2. Undirected graphs523

Graph Theory, Release 10.4

The diameter is defined to be the maximum distance between two vertices. It is infinite if the graph is notconnected.
For more information and examples on how to use input variables, see shortest_paths() and eccentricity()
INPUT:• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); one of the following algorithms:–

BFS : the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False.

–

Floyd-Warshall-Cython : a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False and v is None.

–

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.

–

Dijkstra_NetworkX : the Dijkstra algorithm, implemented in NetworkX. It works withweighted graphs, but no negative weight is allowed.

–

DHV – diameter computation is done using the algorithm proposed in [Dragan2018].
Works only for non-negative edge weights.
For more information see method sage.
graphs.distances_all_pairs.diameter_DHV() and sage.graphs.base.
boost_graph.diameter_DHV().

–

standard , 2sweep , multi-sweep , iFUB : these algorithms are implemented 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 for unweighted graphs,
Dijkstra_Boost if all weights are positive, Johnson_Boost otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:
The more symmetric a graph is, the smaller (diameter - radius) is:
sage: G = graphs.BarbellGraph(9, 3)
sage: G.radius()
3
sage: G.diameter()
6524

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.BarbellGraph(Integer(9), Integer(3))>>> G.radius()
3>>> G.diameter()6
sage: G = graphs.OctahedralGraph()
sage: G.radius()
2
sage: G.diameter()2>>> from sage.all import *>>> G = graphs.OctahedralGraph()>>> G.radius()
2>>> G.diameter()2

distance_graph(dist)
Return the graph on the same vertex set as the original graph but vertices are adjacent in the returned graphif and only if they are at specified distances in the original graph.
INPUT:• dist – a nonnegative integer or a list of nonnegative integers; specified distance(s) for the connecting
vertices. Infinity may be used here to describe vertex pairs in separate components.
OUTPUT:The returned value is an undirected graph. The vertex set is identical to the calling graph, but edges of the
returned graph join vertices whose distance in the calling graph are present in the input dist. Loops will
only be present if distance 0 is included. If the original graph has a position dictionary specifying locations ofvertices 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()
˓→needs sage.modules[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]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(3))>>> H = G.cartesian_product(graphs.CompleteGraph(Integer(2)))>>> K = H.distance_graph(Integer(2))>>> K.am()#␣#␣(continues on next page)1.2. Undirected graphs525

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules[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() commandto 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))
Falsesage: H = G.distance_graph(list(range(1,d+1)))
sage: H.is_isomorphic(graphs.CompleteGraph(n))
True>>> from sage.all import *>>> G = graphs.OddGraph(Integer(4))>>> d = G.diameter()>>> n = G.num_verts()>>> H = G.distance_graph(list(range(d+Integer(1))))>>> H.is_isomorphic(graphs.CompleteGraph(n))
False>>> H = G.distance_graph(list(range(Integer(1),d+Integer(1))))>>> H.is_isomorphic(graphs.CompleteGraph(n))
True

A complete collection of distance graphs will have adjacency matrices that sum to the matrix of all ones:sage: P = graphs.PathGraph(20)sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)])
˓→needs sage.modules
sage: all_ones == matrix(ZZ, 20, 20, [1]*400)
˓→needs sage.modules
True>>> from sage.all import *>>> P = graphs.PathGraph(Integer(20))>>> all_ones = sum([P.distance_graph(i).am() for i in range(Integer(20))])˓→# needs sage.modules>>> all_ones == matrix(ZZ, Integer(20), Integer(20),␣
˓→[Integer(1)]*Integer(400))# needs sage.
˓→modules
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)(continues on next page)

526

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.is_isomorphic(H)
True>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(4))>>> H = G.distance_graph(Integer(3))>>> G.is_isomorphic(H)
True

The graph of eight-bit strings, adjacent if different in an odd number of bits:
sage: # long time, needs sage.symbolic
sage: G = graphs.CubeGraph(8)sage: H = G.distance_graph([1,3,5,7])
sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]])
sage: degrees.append(2^8)
sage: degrees == H.degree_histogram()True>>> from sage.all import *>>> # long time, needs sage.symbolic>>> G = graphs.CubeGraph(Integer(8))>>> H = G.distance_graph([Integer(1),Integer(3),Integer(5),Integer(7)])>>> degrees = [Integer(0)]*sum([binomial(Integer(8),j) for j in [Integer(1),˓→Integer(3),Integer(5),Integer(7)]])>>> degrees.append(Integer(2)**Integer(8))>>> degrees == H.degree_histogram()
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()
˓→needs sage.modules[0 0 0 1 1]
[0 0 0 1 1]
[0 0 0 1 1]
[1 1 1 0 0]
[1 1 1 0 0]
sage: L.is_isomorphic(graphs.CompleteBipartiteGraph(3, 2))
True>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(3))>>> H = G.disjoint_union(graphs.CompleteGraph(Integer(2)))>>> L = H.distance_graph(Infinity)>>> L.am()
˓→needs sage.modules[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]#␣#␣(continues on next page)1.2. Undirected graphs

527

Graph Theory, Release 10.4

(continued from previous page)>>> L.is_isomorphic(graphs.CompleteBipartiteGraph(Integer(3), Integer(2)))
True

AUTHOR:Rob Beezer, 2009-11-25, Issue #7533
ear_decomposition()
Return an Ear decomposition of the graph.
An ear of an undirected graph 𝐺 is a path 𝑃 where the two endpoints of the path may coincide (i.e., forma cycle), but where otherwise no repetition of edges or vertices is allowed, so every internal vertex of 𝑃 has
degree two in 𝑃 .
An ear decomposition of an undirected graph 𝐺 is a partition of its set of edges into a sequence of ears, suchthat the one or two endpoints of each ear belong to earlier ears in the sequence and such that the internalvertices 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].
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]]>>> from sage.all import *>>> g = Graph( LlCG{O@?GBOMW? )>>> 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.CycleGraph(4)sage: g.ear_decomposition()[[0, 3, 2, 1, 0]]528

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(4))>>> g.ear_decomposition()[[0, 3, 2, 1, 0]]

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]]>>> from sage.all import *>>> G = Graph()>>> G.add_cycle([Integer(0),Integer(1),Integer(2)])>>> G.add_edge(Integer(0),Integer(3))>>> G.add_cycle([Integer(3),Integer(4),Integer(5),Integer(6)])>>> G.ear_decomposition()[[0, 2, 1, 0], [3, 6, 5, 4, 3]]

The ear decomposition of a multigraph with loops is the same as the ear decomposition of the underlying
simple graph:
sage: g = graphs.BullGraph()
sage: g.allow_multiple_edges(True)
sage: g.add_edges(g.edges(sort=False))
sage: g.allow_loops(True)
sage: u = g.random_vertex()sage: g.add_edge(u, u)
sage: gBull graph: Looped multi-graph on 5 vertices
sage: h = g.to_simple()sage: g.ear_decomposition() == h.ear_decomposition()
True>>> from sage.all import *>>> g = graphs.BullGraph()>>> g.allow_multiple_edges(True)>>> g.add_edges(g.edges(sort=False))>>> g.allow_loops(True)>>> u = g.random_vertex()>>> g.add_edge(u, u)>>> gBull graph: Looped multi-graph on 5 vertices>>> h = g.to_simple()>>> g.ear_decomposition() == h.ear_decomposition()Trueeccentricity(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_path_all_pairs(),

1.2. Undirected graphs529

Graph Theory, Release 10.4

shortest_path_lengths() and shortest_paths()
INPUT:• v – either a single vertex or a list of vertices. If it is not specified, then it is taken to be all vertices.
• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); one of the following algorithms:–

BFS – the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False.

–

DHV – the computation is done using the algorithm proposed in [Dragan2018]. Works only
if self has non-negative edge weights and v is None or v should contain all verticesof self. For more information see method sage.graphs.distances_all_pairs.
eccentricity() and sage.graphs.base.boost_graph.eccentricity_DHV().

–

Floyd-Warshall-Cython – a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False and v is None or v should contain all vertices of self.

–

Floyd-Warshall-Python – a Python implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
However, v must be None or v should contain all vertices of self.

–

Dijkstra_NetworkX – the Dijkstra algorithm, implemented in NetworkX. It works withweighted graphs, but no negative weight is allowed.

–

Dijkstra_Boost – the Dijkstra algorithm, implemented in Boost (works only with positive
weights).

–

Johnson_Boost – the Johnson algorithm, implemented in Boost (works also with negative
weights, if there is no negative cycle). Works only if v is None or v should contain all verticesof self.

–

From_Dictionary – uses the (already computed) distances, that are provided by input variable dist_dict.

– None (default): Sage chooses the best algorithm: From_Dictionary if dist_dict is
not None, BFS for unweighted graphs, Dijkstra_Boost if all weights are positive,
Johnson_Boost otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
• dist_dict – a dictionary (default: None); a dict of dicts of distances (used only if
algorithm== From_Dictionary )• with_labels – boolean (default: False); whether to return a list or a dictionary keyed by vertices.
EXAMPLES:
sage: G = graphs.KrackhardtKiteGraph()
sage: G.eccentricity()[4, 4, 4, 4, 4, 3, 3, 2, 3, 4]
sage: G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: G.eccentricity(7)(continues on next page)

530

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)2
sage: G.eccentricity([7,8,9])[2, 3, 4]
sage: G.eccentricity([7, 8, 9], with_labels=True) == {8: 3, 9: 4, 7: 2}
Truesage: 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 )#␣˓→needs 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]
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]
sage: G.eccentricity(by_weight=False, algorithm= DHV )[1, 1, 1]
sage: G.eccentricity(by_weight=True, algorithm= DHV )[2.0, 1.0, 2.0]>>> from sage.all import *>>> G = graphs.KrackhardtKiteGraph()>>> G.eccentricity()[4, 4, 4, 4, 4, 3, 3, 2, 3, 4]>>> G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> G.eccentricity(Integer(7))
2>>> G.eccentricity([Integer(7),Integer(8),Integer(9)])[2, 3, 4]>>> G.eccentricity([Integer(7), Integer(8), Integer(9)], with_labels=True) ==˓→{Integer(8): Integer(3), Integer(9): Integer(4), Integer(7): Integer(2)}True>>> G = Graph({Integer(0): [], Integer(1): [], Integer(2): [Integer(1)]})>>> G.eccentricity()[+Infinity, +Infinity, +Infinity]>>> G = Graph({Integer(0):[]})>>> G.eccentricity(with_labels=True){0: 0}>>> G = Graph({Integer(0):[], Integer(1):[]})>>> G.eccentricity(with_labels=True)(continues on next page)1.2. Undirected graphs

531

Graph Theory, Release 10.4

(continued from previous page){0: +Infinity, 1: +Infinity}>>> G = Graph([(Integer(0), Integer(1), Integer(1)), (Integer(1), Integer(2),␣
˓→Integer(1)), (Integer(0), Integer(2), Integer(3))])>>> G.eccentricity(algorithm= BFS )[1, 1, 1]>>> G.eccentricity(algorithm= Floyd-Warshall-Cython )[1, 1, 1]>>> G.eccentricity(by_weight=True, algorithm= Dijkstra_NetworkX )#␣˓→needs networkx[2, 1, 2]>>> G.eccentricity(by_weight=True, algorithm= Dijkstra_Boost )[2, 1, 2]>>> G.eccentricity(by_weight=True, algorithm= Johnson_Boost )[2, 1, 2]>>> G.eccentricity(by_weight=True, algorithm= Floyd-Warshall-Python )[2, 1, 2]>>> G.eccentricity(dist_dict=G.shortest_path_all_pairs(by_˓→weight=True)[Integer(0)])[2, 1, 2]>>> G.eccentricity(by_weight=False, algorithm= DHV )[1, 1, 1]>>> G.eccentricity(by_weight=True, algorithm= DHV )[2.0, 1.0, 2.0]

edge_isoperimetric_number(g)Return the edge-isoperimetric number of the graph.
The edge-isoperimetric number of a graph 𝐺 = (𝑉, 𝐸) is also sometimes called the isoperimetric number. It
is defined as the minimum of |𝜕𝑆|/|𝑆| where 𝜕𝑆 is the edge boundary of 𝑆 (number of edges with one end
in 𝑆 and one end in 𝑉 ∖ 𝑆) and the minimum is taken over all subsets of vertices whose cardinality does notexceed half the size |𝑉 | of the graph.
See also:
Alternative but similar quantities can be obtained via the methods cheeger_constant() and vertex_isoperimetric_number().
EXAMPLES:
The edge-isoperimetric number of a complete graph on 𝑛 vertices is ⌈𝑛/2⌉:
sage: [graphs.CompleteGraph(n).edge_isoperimetric_number() for n in range(2,˓→10)][1, 2, 2, 3, 3, 4, 4, 5]>>> from sage.all import *>>> [graphs.CompleteGraph(n).edge_isoperimetric_number() for n in␣˓→range(Integer(2),Integer(10))][1, 2, 2, 3, 3, 4, 4, 5]

The edge-isoperimetric constant of a cycle on 𝑛 vertices is 2/⌊𝑛/2⌋:
sage: [graphs.CycleGraph(n).edge_isoperimetric_number() for n in range(2,15)][1, 2, 1, 1, 2/3, 2/3, 1/2, 1/2, 2/5, 2/5, 1/3, 1/3, 2/7]>>> from sage.all import *>>> [graphs.CycleGraph(n).edge_isoperimetric_number() for n in␣(continues on next page)532

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

range(Integer(2),Integer(15))][1, 2, 1, 1, 2/3, 2/3, 1/2, 1/2, 2/5, 2/5, 1/3, 1/3, 2/7]˓→In general, for 𝑑-regular graphs the edge-isoperimetric number is 𝑑 times larger than the Cheeger constant of
the graph:
sage: g = graphs.RandomRegular(3, 10)˓→# needs networkx
sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3
˓→# needs networkx
True

␣
␣

>>> from sage.all import *>>> g = graphs.RandomRegular(Integer(3), Integer(10))˓→# needs networkx>>> g.edge_isoperimetric_number() == g.cheeger_constant() * Integer(3)˓→# needs networkx
True

␣
␣

And the edge-isoperimetric constant of a disconnected graph is 0:
sage: Graph([[1,2,3,4],[(1,2),(3,4)]]).edge_isoperimetric_number()0>>> from sage.all import *>>> Graph([[Integer(1),Integer(2),Integer(3),Integer(4)],[(Integer(1),˓→Integer(2)),(Integer(3),Integer(4))]]).edge_isoperimetric_number()0effective_resistance(i, j, base_ring)
Return the effective resistance between nodes 𝑖 and 𝑗.
The resistance distance between vertices 𝑖 and 𝑗 of a simple connected graph 𝐺 is defined as the effective
resistance between the two vertices on an electrical network constructed from 𝐺 replacing each edge of thegraph by a unit (1 ohm) resistor.
See the Wikipedia article Resistance_distance for more information.
INPUT:• i, j – vertices of the graph• base_ring – a ring (default: None); the base ring of the matrix space to use
OUTPUT: rational number denoting resistance between nodes 𝑖 and 𝑗
EXAMPLES:
Effective resistances in a straight linear 2-tree on 6 vertices
sage: # needs sage.modules
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G.effective_resistance(0,1)
34/55
sage: G.effective_resistance(0,3)
49/55
sage: G.effective_resistance(1,4)
9/11(continues on next page)1.2. Undirected graphs533

Graph Theory, Release 10.4

(continued from previous page)

sage: G.effective_resistance(0,5)
15/11>>> from sage.all import *>>> # needs sage.modules>>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),˓→Integer(2)),(Integer(1),Integer(3)),(Integer(3),Integer(5)),(Integer(2),˓→Integer(4)),(Integer(2),Integer(3)),(Integer(3),Integer(4)),(Integer(4),˓→Integer(5))])>>> G.effective_resistance(Integer(0),Integer(1))
34/55>>> G.effective_resistance(Integer(0),Integer(3))
49/55>>> G.effective_resistance(Integer(1),Integer(4))
9/11>>> G.effective_resistance(Integer(0),Integer(5))
15/11Effective resistances in a fan on 6 vertices
sage: # needs sage.modules
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.effective_resistance(1,5)
6/5
sage: H.effective_resistance(1,3)
49/55
sage: H.effective_resistance(1,1)
0>>> from sage.all import *>>> # needs sage.modules>>> H = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(0),˓→Integer(3)),(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(0),˓→Integer(6)),(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(4)),(Integer(4),Integer(5))])>>> H.effective_resistance(Integer(1),Integer(5))
6/5>>> H.effective_resistance(Integer(1),Integer(3))
49/55>>> H.effective_resistance(Integer(1),Integer(1))
0Using a different base ring:sage: H.effective_resistance(1, 5, base_ring=RDF)
˓→needs numpy sage.modules
1.2000000000000000
sage: H.effective_resistance(1, 1, base_ring=RDF)
˓→needs sage.modules
0.0# abs tol 1e-14#␣#␣>>> from sage.all import *>>> H.effective_resistance(Integer(1), Integer(5), base_ring=RDF)
˓→1e-14# needs numpy sage.modules
1.2000000000000000# abs tol␣(continues on next page)534

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> H.effective_resistance(Integer(1), Integer(1), base_ring=RDF)˓→# needs sage.modules
0.0␣

See also:• effective_resistance_matrix() – a similar method giving a matrix full of all effective resistances between all nodes• least_effective_resistance() – gives node pairs with least effective resistances• See Wikipedia article Resistance_distance for more details.
effective_resistance_matrix(vertices, nonedgesonly=None, base_ring=True, **kwds)
Return a matrix whose (𝑖 , 𝑗) entry gives the effective resistance between vertices 𝑖 and 𝑗.
The resistance distance between vertices 𝑖 and 𝑗 of a simple connected graph 𝐺 is defined as the effective
resistance between the two vertices on an electrical network constructed from 𝐺 replacing each edge of thegraph by a unit (1 ohm) resistor.
By default, the matrix returned is over the rationals.
INPUT:• nonedgesonly – boolean (default: True); if True assign zero resistance to pairs of adjacent vertices.
• vertices – list (default: None); the ordering of the vertices defining how they should appear in thematrix. By default, the ordering given by GenericGraph.vertices() is used.
• base_ring – a ring (default: None); the base ring of the matrix space to use• **kwds – other keywords to pass to matrix()
OUTPUT: matrix
EXAMPLES:
The effective resistance matrix for a straight linear 2-tree counting only non-adjacent vertex pairs
sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G.effective_resistance_matrix()
˓→needs sage.modules[
000 49/55 59/55 15/11][
00
0
0 9/11 59/55]
[
0
0
0
0
0 49/55][49/5500000][59/55 9/11
00
00]
[15/11 59/55 49/55
0
0
0]

#␣

>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),˓→Integer(2)),(Integer(1),Integer(3)),(Integer(3),Integer(5)),(Integer(2),˓→Integer(4)),(Integer(2),Integer(3)),(Integer(3),Integer(4)),(Integer(4),˓→Integer(5))])>>> G.effective_resistance_matrix()#␣˓→needs sage.modules[
000 49/55 59/55 15/11][
00
0
0 9/11 59/55]
[
0
0
0
0
0 49/55](continues on next page)1.2. Undirected graphs535

Graph Theory, Release 10.4

(continued from previous page)[49/5500[59/55 9/11
0
[15/11 59/55 49/55

0
0
0

0
0
0

0]
0]
0]

The same effective resistance matrix, this time including adjacent vertices
sage: G.effective_resistance_matrix(nonedgesonly=False)
˓→needs sage.modules[
0 34/55 34/55 49/55 59/55 15/11][34/55
0 26/55 31/55 9/11 59/55][34/55 26/55
0 5/11 31/55 49/55][49/55 31/55 5/11
0 26/55 34/55][59/55 9/11 31/55 26/55
0 34/55][15/11 59/55 49/55 34/55 34/55
0]>>> from sage.all import *>>> G.effective_resistance_matrix(nonedgesonly=False)
˓→needs sage.modules[
0 34/55 34/55 49/55 59/55 15/11][34/55
0 26/55 31/55 9/11 59/55][34/55 26/55
0 5/11 31/55 49/55][49/55 31/55 5/11
0 26/55 34/55][59/55 9/11 31/55 26/55
0 34/55][15/11 59/55 49/55 34/55 34/55
0]

#␣

#␣

This example illustrates the common neighbors matrix for a fan on 6 vertices counting only non-adjacentvertex pairs
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.effective_resistance_matrix()#␣˓→needs sage.modules
[
0
0
0
0
0
0
0]
[
0
0
0 49/55 56/55
6/5 89/55]
[
0
0
0
0
4/5 56/55 81/55][
0 49/55000 49/55 16/11][
0 56/55
4/5
0
0
0 81/55][
0
6/5 56/55 49/55
00 89/55][
0 89/55 81/55 16/11 81/55 89/55
0]>>> from sage.all import *>>> H = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(0),˓→Integer(3)),(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(0),˓→Integer(6)),(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(4)),(Integer(4),Integer(5))])>>> H.effective_resistance_matrix()#␣˓→needs sage.modules
[
0
0
0
0
0
0
0]
[
0
0
0 49/55 56/55
6/5 89/55]
[
0
0
0
0
4/5 56/55 81/55][
0 49/55000 49/55 16/11][
0 56/55
4/5
0
0
0 81/55][
0
6/5 56/55 49/55
00 89/55][
0 89/55 81/55 16/11 81/55 89/55
0]

A different base ring:

536

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent()
˓→needs numpy sage.modules
Real Double Field#␣>>> from sage.all import *>>> H.effective_resistance_matrix(base_ring=RDF)[Integer(0), Integer(0)].
˓→parent()# needs numpy sage.modules
Real Double Field

See also:• least_effective_resistance() – gives node pairs with least effective resistances• effective_resistance() – computes effective resistance for a single node pair
• See Wikipedia article Resistance_Distance for more details.
folded_graph(check=False)
Return the antipodal fold of this graph.
Given an antipodal graph 𝐺 let 𝐺𝑑 be its distance-𝑑 graph. Then the folded graph of 𝐺 has a vertex for eachmaximal clique of 𝐺𝑑 and two cliques are adjacent if there is an edge in 𝐺 connecting the two.
See also:
sage.graphs.graph.is_antipodal()
INPUT:• check – boolean (default: False); whether to check if the graph is antipodal. If check is True andthe graph is not antipodal, then return False.
OUTPUT:
This function returns a new graph and self is not touched.
Note: The input is expected to be an antipodal graph. You can check that a graph is antipodal using sage.
graphs.graph.is_antipodal().
EXAMPLES:
sage: G = graphs.JohnsonGraph(10, 5)
sage: H = G.folded_graph(); H
Folded Johnson graph with parameters 10,5: Graph on 126 vertices
sage: Gd = G.distance_graph(G.diameter())
sage: all(i == 1 for i in Gd.degree())
Truesage: H.is_distance_regular(True)([25, 16, None], [None, 1, 4])>>> from sage.all import *>>> G = graphs.JohnsonGraph(Integer(10), Integer(5))>>> H = G.folded_graph(); H
Folded Johnson graph with parameters 10,5: Graph on 126 vertices>>> Gd = G.distance_graph(G.diameter())>>> all(i == Integer(1) for i in Gd.degree())
True(continues on next page)1.2. Undirected graphs

537

Graph Theory, Release 10.4

(continued from previous page)>>> H.is_distance_regular(True)([25, 16, None], [None, 1, 4])This method doesn’t check if the graph is antipodal:
sage: G = graphs.PetersenGraph()
sage: G.is_antipodal()False
sage: G.folded_graph() # some garbage
Folded Petersen graph: Graph on 2 vertices
sage: G.folded_graph(check=True)
False>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.is_antipodal()False>>> G.folded_graph() # some garbage
Folded Petersen graph: Graph on 2 vertices>>> G.folded_graph(check=True)
False

REFERENCES:
See [BCN1989] p. 438 or [Sam2012] for this definition of folded graph.
fractional_chromatic_index(G, solver='PPL', verbose_constraints=False, verbose=0)
Return the fractional chromatic index of the graph.
The fractional chromatic index is a relaxed version of edge-coloring. An edge coloring of a graph being
actually a covering of its edges into the smallest possible number of matchings, the fractional chromatic index
of a graph 𝐺 is the smallest real value 𝜒𝑓 (𝐺) such that there exists a list of matchings 𝑀1 , . . . , 𝑀𝑘 of 𝐺 andcoefficients 𝛼1 , . . . , 𝛼𝑘 with the property that each edge is covered by the matchings in the following relaxedway∑︁
∀𝑒 ∈ 𝐸(𝐺),𝛼𝑖 ≥ 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 bysage is actually:∑︁
Maximize :𝑟𝑒𝑒∈𝐸(𝐺)Such that :∀𝑀 matching ⊆ 𝐺,∑︁𝑟𝑣 ≤ 1𝑒∈𝑀

INPUT:• G – a graph• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, thedefault one is used. For more information on LP solvers and which default solver is used, see the method
solve of the class MixedIntegerLinearProgram.
538

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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 whenusing some non exact solvers as reported in Issue #23658 and Issue #23798.
• verbose_constraints – boolean (default: False); whether to display which constraints are being
generated• verbose – integer (default: 0); sets the level of verbosity of the LP solver
EXAMPLES:
The fractional chromatic index of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)sage: g.fractional_chromatic_index()˓→# needs sage.numerical.mip
5/2

␣>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.fractional_chromatic_index()
˓→# needs sage.numerical.mip
5/2

fractional_chromatic_number(G, solver='PPL', verbose=0, check_components=True,
check_bipartite=True)
Return the fractional chromatic number of the graph.
Fractional coloring is a relaxed version of vertex coloring with several equivalent definitions, such as the
optimum value in a linear relaxation of the integer program that gives the usual chromatic number. It is also
equal to the fractional clique number by LP-duality.
ALGORITHM:
The fractional chromatic number is computed via the usual Linear Program. The LP solved by sage is essentially,∑︁
Minimize :𝑥𝐼
𝐼∈ℐ(𝐺)Such that :∀𝑣 ∈ 𝑉 (𝐺),∑︁𝑥𝑣 ≥ 1𝐼∈ℐ(𝐺), 𝑣∈𝐼∀𝐼 ∈ ℐ(𝐺), 𝑥𝐼 ≥ 0
where ℐ(𝐺) is the set of maximal independent sets of 𝐺 (see Section 2.1 of [CFKPR2010] to know why it
is sufficient to consider maximal independent sets). As optional optimisations, we construct the LP on eachbiconnected component of 𝐺 (and output the maximum value), and avoid using the LP if G is bipartite (asthen the output must be 1 or 2).
Note: Computing the fractional chromatic number can be very slow. Since the variables of the LP are independent sets, in general the LP has size exponential in the order of the graph. In the current implementation
a list of all maximal independent sets is created and stored, which can be both slow and memory-hungry.
INPUT:
1.2. Undirected graphs539

Graph Theory, Release 10.4

• G – a graph• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, thedefault one is used. For more information on LP solvers and which default solver is used, see the method
solve of the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number,
although this may be slower that using other solvers.
• verbose – integer (default: 0); sets the level of verbosity of the LP solver• check_components – boolean (default: True); whether the method is called on each biconnectedcomponent of 𝐺
• check_bipartite – boolean (default: True); whether the graph is checked for bipartiteness. If thegraph is bipartite then we can avoid creating and solving the LP.
EXAMPLES:
The fractional chromatic number of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)sage: g.fractional_chromatic_number()˓→# needs sage.numerical.mip
5/2

␣>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.fractional_chromatic_number()˓→# needs sage.numerical.mip
5/2

fractional_clique_number(solver='PPL', verbose=0, check_components=True, check_bipartite=True)
Return the fractional clique number of the graph.
A fractional clique is a nonnegative weight function on the vertices of a graph such that the sum of the weights
over any independent set is at most 1. The fractional clique number is the largest total weight of a fractional
clique, which is equal to the fractional chromatic number by LP-duality.
ALGORITHM:
The fractional clique number is computed via the Linear Program for fractional chromatic number, seefractional_chromatic_number
INPUT:• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, thedefault one is used. For more information on LP solvers and which default solver is used, see the method
solve of the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number,
although this may be slower that using other solvers.
• verbose – integer (default: 0); sets the level of verbosity of the LP solver• check_components – boolean (default: True); whether the method is called on each biconnectedcomponent of 𝐺

540

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• check_bipartite – boolean (default: True); whether the graph is checked for bipartiteness. If thegraph is bipartite then we can avoid creating and solving the LP.
EXAMPLES:
The fractional clique number of a 𝐶7 is 7/3:
sage: g = graphs.CycleGraph(7)sage: g.fractional_clique_number()˓→needs sage.numerical.mip
7/3>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(7))>>> g.fractional_clique_number()˓→needs sage.numerical.mip
7/3

#␣

#␣

geodetic_closure(G, S)
Return the geodetic closure of the set of vertices 𝑆 in 𝐺.
The geodetic closure 𝑔(𝑆) of a subset of vertices 𝑆 of a graph 𝐺 is in [HLT1993] as the set of all vertices thatlie on a shortest 𝑢−𝑣 path for any pair of vertices 𝑢, 𝑣 ∈ 𝑆. We assume that 𝑔(∅) = ∅ and that 𝑔({𝑢}) = {𝑢}for any 𝑢 in 𝐺.
Warning: This operation is not a closure function. Indeed, a closure function must satisfy the property
that 𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋), which is not always the case here. The term closure is usedhere to follow the terminology of the domain. See for instance [HLT1993].
Here, we implement a simple algorithm to determine this set. Roughly, for each vertex 𝑢 ∈ 𝑆, the algorithm
first performs a breadth first search from 𝑢 to get distances, and then identifies the vertices of 𝐺 lying ona shortest path from 𝑢 to any 𝑣 ∈ 𝑆 using a reversal traversal from vertices in 𝑆. This algorithm has timecomplexity in 𝑂(|𝑆|(𝑛+𝑚)+(𝑛+𝑚 log 𝑚)) for SparseGraph, 𝑂(|𝑆|(𝑛+𝑚)+𝑛2 log 𝑚) for DenseGraph and space complexity in 𝑂(𝑛 + 𝑚) (the extra log factor is due to init_short_digraph being
called with sort_neighbors=True).
INPUT:• G – a Sage graph• S – a subset of vertices of 𝐺
EXAMPLES:
The vertices of the Petersen graph can be obtained by a geodetic closure of four of its vertices:sage: from sage.graphs.convexity_properties import geodetic_closure
sage: G = graphs.PetersenGraph()
sage: geodetic_closure(G, [0, 2, 8, 9])[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> from sage.all import *>>> from sage.graphs.convexity_properties import geodetic_closure>>> G = graphs.PetersenGraph()>>> geodetic_closure(G, [Integer(0), Integer(2), Integer(8), Integer(9)])[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The vertices of a 2D grid can be obtained by a geodetic closure of two vertices:
1.2. Undirected graphs541

Graph Theory, Release 10.4

sage: G = graphs.Grid2dGraph(4, 4)
sage: c = G.geodetic_closure([(0, 0), (3, 3)])sage: len(c) == G.order()True>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(4), Integer(4))>>> c = G.geodetic_closure([(Integer(0), Integer(0)), (Integer(3),␣
˓→Integer(3))])>>> len(c) == G.order()True

If two vertices belong to different connected components of a graph, their geodetic closure is trivial:sage: G = Graph([(0, 1), (2, 3)])sage: geodetic_closure(G, [0, 2])[0, 2]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1)), (Integer(2), Integer(3))])>>> geodetic_closure(G, [Integer(0), Integer(2)])[0, 2]The geodetic closure does not satisfy the closure function property that 𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋):sage: G = graphs.DiamondGraph()
sage: G.subdivide_edge((1, 2), 1)
sage: geodetic_closure(G, [0, 3])[0, 1, 2, 3]
sage: geodetic_closure(G, geodetic_closure(G, [0, 3]))[0, 1, 2, 3, 4]>>> from sage.all import *>>> G = graphs.DiamondGraph()>>> G.subdivide_edge((Integer(1), Integer(2)), Integer(1))>>> geodetic_closure(G, [Integer(0), Integer(3)])[0, 1, 2, 3]>>> geodetic_closure(G, geodetic_closure(G, [Integer(0), Integer(3)]))[0, 1, 2, 3, 4]

gomory_hu_tree(algorithm=None)
Return a Gomory-Hu tree of self.
Given a tree 𝑇 with labeled edges representing capacities, it is very easy to determine the maximum flow
between any pair of vertices : it is the minimal label on the edges of the unique path between them.
Given a graph 𝐺, a Gomory-Hu tree 𝑇 of 𝐺 is a tree with the same set of vertices, and such that the maximum
flow between any two vertices is the same in 𝐺 as in 𝑇 . See the Wikipedia article Gomory–Hu_tree. Note
that, in general, a graph admits more than one Gomory-Hu tree.
See also 15.4 (Gomory-Hu trees) from [Sch2003].
INPUT:• algorithm – select the algorithm used by the edge_cut() method. Refer to its documentation forallowed values and default behaviour.
OUTPUT:
542

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

A graph with labeled edges
EXAMPLES:
Taking the Petersen graph:
sage: g = graphs.PetersenGraph()
sage: t = g.gomory_hu_tree()>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> t = g.gomory_hu_tree()Obviously, this graph is a tree:
sage: t.is_tree()True>>> from sage.all import *>>> 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>>> from sage.all import *>>> (Integer(2)*g).gomory_hu_tree().is_forest()
True>>> (Integer(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(sort=False), 2))
True>>> from sage.all import *>>> all(t.flow(u,v) == g.flow(u,v) for u,v in Subsets(g.vertices(sort=False),␣
˓→Integer(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>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(20),RealNumber( .3 ))>>> t = g.gomory_hu_tree()(continues on next page)1.2. Undirected graphs543

Graph Theory, Release 10.4

(continued from previous page)>>> g.flow(Integer(0),Integer(1)) == t.flow(Integer(0),Integer(1))
True

And also the min cut:sage: g.edge_connectivity() == min(t.edge_labels()) or not g.is_connected()True>>> from sage.all import *>>> g.edge_connectivity() == min(t.edge_labels()) or not g.is_connected()
Truegraph6_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>>> from sage.all import *>>> G = graphs.KrackhardtKiteGraph()>>> G.graph6_string()
IvUqwK@?G

has_homomorphism_to(H, core, solver=False, verbose=None, integrality_tolerance=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 completegraph on 𝑘 elements.
For more information, see the Wikipedia article Graph_homomorphism.
INPUT:• H – the graph to which self should be sent.
• core – boolean (default: False; whether to minimize the size of the mapping’s image (see note below).
This is set to False by default.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.

544

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
Note: One can compute the core of a graph (with respect to homomorphism) with this method
sage: g = graphs.CycleGraph(10)sage: mapping = g.has_homomorphism_to(g, core=True)#␣˓→needs sage.numerical.mip
sage: print("The size of the core is {}".format(len(set(mapping.values())))) ␣˓→# needs sage.numerical.mip
The size of the core is 2>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(10))>>> mapping = g.has_homomorphism_to(g, core=True)#␣˓→needs sage.numerical.mip>>> print("The size of the core is {}".format(len(set(mapping.values()))))
˓→# needs sage.numerical.mip
The size of the core is 2␣

OUTPUT:
This method returns False when the homomorphism does not exist, and returns the homomorphism otherwise as a dictionary associating a vertex of 𝐻 to a vertex of 𝐺.
EXAMPLES:Is Petersen’s graph 3-colorable:
sage: P = graphs.PetersenGraph()
sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.has_homomorphism_to(graphs.CompleteGraph(Integer(3))) is not False˓→# needs sage.numerical.mip
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
˓→needs sage.numerical.mip
True
sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False
˓→needs sage.numerical.mip
True
sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False
˓→needs sage.numerical.mip
False

1.2. Undirected graphs

#␣

#␣

#␣

545

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(9))>>> g.has_homomorphism_to(graphs.CycleGraph(Integer(5))) is not False˓→# needs sage.numerical.mip
True>>> g.has_homomorphism_to(graphs.CycleGraph(Integer(7))) is not False˓→# needs sage.numerical.mip
True>>> g.has_homomorphism_to(graphs.CycleGraph(Integer(4))) is not False˓→# needs sage.numerical.mip
False

␣

␣

␣

has_perfect_matching(algorithm, solver='Edmonds', verbose=None, integrality_tolerance=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 maximal
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 variableb[e] on each edge 𝑒, and for each vertex 𝑣, require that the sum of the values of the edges incident
to 𝑣 is 1.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity: set to 0 by default, which means quiet (onlyuseful when algorithm == "LP_matching" or algorithm == "LP")• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:
A boolean.
EXAMPLES:
sage: graphs.PetersenGraph().has_perfect_matching()
˓→needs networkx
True
sage: graphs.WheelGraph(6).has_perfect_matching()
˓→needs networkx
True
sage: graphs.WheelGraph(5).has_perfect_matching()
˓→needs networkx
False
sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching")
˓→needs sage.numerical.mip
True
sage: graphs.WheelGraph(6).has_perfect_matching(algorithm="LP_matching")
˓→needs sage.numerical.mip
True
sage: graphs.WheelGraph(5).has_perfect_matching(algorithm="LP_matching")
False

#␣

#␣

#␣

#␣

#␣

(continues on next page)

546

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching")
˓→needs sage.numerical.mip
True
sage: graphs.WheelGraph(6).has_perfect_matching(algorithm="LP_matching")
˓→needs sage.numerical.mip
True
sage: graphs.WheelGraph(5).has_perfect_matching(algorithm="LP_matching")
False

#␣

#␣

>>> from sage.all import *>>> graphs.PetersenGraph().has_perfect_matching()#␣˓→needs networkx
True>>> graphs.WheelGraph(Integer(6)).has_perfect_matching()␣˓→# needs networkx
True>>> graphs.WheelGraph(Integer(5)).has_perfect_matching()␣˓→# needs networkx
False>>> graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching") #␣
˓→needs sage.numerical.mip
True>>> graphs.WheelGraph(Integer(6)).has_perfect_matching(algorithm="LP_matching˓→")# needs sage.numerical.mip
True>>> graphs.WheelGraph(Integer(5)).has_perfect_matching(algorithm="LP_matching
˓→")
False
>>> graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching") #␣
˓→needs sage.numerical.mip
True>>> graphs.WheelGraph(Integer(6)).has_perfect_matching(algorithm="LP_matching˓→")# needs sage.numerical.mip
True>>> graphs.WheelGraph(Integer(5)).has_perfect_matching(algorithm="LP_matching
˓→")
False

hyperbolicity(G, algorithm='BCCM', approximation_factor=None, additive_gap=None, verbose=False)
Return the hyperbolicity of the graph or an approximation of this value.
The hyperbolicity of a graph has been defined by Gromov [Gro1987] as follows: Let 𝑎, 𝑏, 𝑐, 𝑑 be vertices of
the graph, let 𝑆1 = 𝑑𝑖𝑠𝑡(𝑎, 𝑏) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐), 𝑆2 = 𝑑𝑖𝑠𝑡(𝑎, 𝑐) + 𝑑𝑖𝑠𝑡(𝑏, 𝑑), and 𝑆3 = 𝑑𝑖𝑠𝑡(𝑎, 𝑑) + 𝑑𝑖𝑠𝑡(𝑏, 𝑐),and let 𝑀1 and 𝑀2 be the two largest values among 𝑆1 , 𝑆2 , and 𝑆3 . We have ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) = |𝑀1 − 𝑀2 |,and the hyperbolicity of the graph is the maximum over all possible 4-tuples (𝑎, 𝑏, 𝑐, 𝑑) divided by 2. The
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 complexityin 𝑂(𝑛4 ).

1.2. Undirected graphs

547

Graph Theory, Release 10.4–

CCL is an exact algorithm proposed in [CCL2015]. It considers the 4-tuples in an ordering allowing to cut the search space as soon as a new lower bound is found (see the module’s documentation).
This algorithm can be turned into a approximation algorithm.

–

CCL+FA or CCL+ uses the notion of far-apart pairs as proposed in [Sot2011] to significantly
reduce the overall computation time of the CCL algorithm.

–

BCCM is an exact algorithm proposed in [BCCM2015]. It improves CCL+FA by cutting several 4-tuples (for more information, see the module’s documentation).

–

dom is an approximation with additive constant four. It computes the hyperbolicity of the verticesof 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 andthe best found solution is less than the approximation factor. When the approximation factor is 1.0,
the problem is solved optimally. This parameter is used only when the chosen algorithm is CCL ,CCL+FA , or BCCM .
• additive_gap – (default: None) When sets to a positive number, the function stop computations assoon 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 chosenalgorithm 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.Grid2dGraph(3, 3)
sage: L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)
sage: L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.Grid2dGraph(Integer(3), Integer(3))>>> L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)>>> L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)(continues on next page)

548

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(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: L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+ ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+FA ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= dom ); L,U(0, 1)
sage: sorted(C) # random[0, 1, 2, 6]>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.PetersenGraph()>>> L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+ ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+FA ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= dom ); L,U(0, 1)>>> sorted(C) # random[0, 1, 2, 6]

Asking for an approximation in a grid graph:
sage: from sage.graphs.hyperbolicity import hyperbolicity
sage: G = graphs.Grid2dGraph(2, 10)
sage: L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=1.5); L,U(1, 3/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+ , approximation_factor=1.5); L,˓→U(1, 1)
sage: L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=4); L,U(1, 4)
sage: L,C,U = hyperbolicity(G, algorithm= CCL , additive_gap=2); L,U(1, 3)
sage: L,C,U = hyperbolicity(G, algorithm= dom ); L,U(1, 5)

1.2. Undirected graphs549

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.Grid2dGraph(Integer(2), Integer(10))>>> L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=RealNumber(
˓→ 1.5 )); L,U(1, 3/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+ , approximation_
˓→factor=RealNumber( 1.5 )); L,U(1, 1)>>> L,C,U = hyperbolicity(G, algorithm= CCL , approximation_
˓→factor=Integer(4)); L,U(1, 4)>>> L,C,U = hyperbolicity(G, algorithm= CCL , additive_gap=Integer(2)); L,U(1, 3)>>> L,C,U = hyperbolicity(G, algorithm= dom ); L,U(1, 5)Asking for an approximation in a cycle graph:
sage: from sage.graphs.hyperbolicity import hyperbolicity
sage: G = graphs.CycleGraph(10)sage: L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=1.5); L,U(2, 5/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+FA , approximation_factor=1.5);␣
˓→L,U(2, 5/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+FA , additive_gap=1); L,U(2, 5/2)>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.CycleGraph(Integer(10))>>> L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=RealNumber(
˓→ 1.5 )); L,U(2, 5/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+FA , approximation_
˓→factor=RealNumber( 1.5 )); L,U(2, 5/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+FA , additive_gap=Integer(1)); L,U(2, 5/2)

Comparison of results:
sage: from sage.graphs.hyperbolicity import hyperbolicity
sage: for i in range(10):# long time˓→# needs networkx....:
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(continues on next page)

550

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: import random
sage: random.seed()sage: for i in range(10):# long time˓→# needs networkx....:
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(sort=True))>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> for i in range(Integer(10)):# long time˓→# needs networkx...
G = graphs.RandomBarabasiAlbert(Integer(100),Integer(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=Integer(2))...
if (not d1==d2==d3==d4==d5) or l3>d1 or u3<d1:...
print("That s not good!")>>> from sage.graphs.hyperbolicity import hyperbolicity>>> import random>>> random.seed()>>> for i in range(Integer(10)):# long time˓→# needs networkx...
n = random.randint(Integer(2), Integer(20))...
m = random.randint(Integer(0), n*(n-Integer(1)) / Integer(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=Integer(2))...
if (not d1==d2==d3==d4==d5) or l3>d1 or u3<d1:...
print("Error in graph ", cc.edges(sort=True))

␣

␣

␣

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: L,C,U = hyperbolicity(G); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)

1.2. Undirected graphs551

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.PetersenGraph() * Integer(2)>>> G.add_edge(Integer(0), Integer(11))>>> L,C,U = hyperbolicity(G); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)

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 ofthis 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 numberof edges, related to the adjacency matrix of the line graph, see for example Proposition 9 in [SS2008] andDef. 4.1 in [Ter2011].
The graph is first replaced by its 2-core, as this does not change the Ihara zeta function.
EXAMPLES:
sage: G = graphs.CompleteGraph(4)sage: factor(G.ihara_zeta_function_inverse())˓→needs sage.libs.pari sage.modules(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())˓→needs sage.libs.pari sage.modules(-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())˓→needs sage.libs.pari sage.modules(-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()
˓→needs sage.libs.pari sage.modules1#␣>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> factor(G.ihara_zeta_function_inverse())˓→needs sage.libs.pari sage.modules(2*t - 1) * (t + 1)^2 * (t - 1)^3 * (2*t^2 + t + 1)^3>>> G = graphs.CompleteGraph(Integer(5))>>> factor(G.ihara_zeta_function_inverse())˓→needs sage.libs.pari sage.modules(-1) * (3*t - 1) * (t + 1)^5 * (t - 1)^6 * (3*t^2 + t + 1)^4#␣#␣>>> G = graphs.PetersenGraph()(continues on next page)

552

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> factor(G.ihara_zeta_function_inverse())˓→needs sage.libs.pari sage.modules(-1) * (2*t - 1) * (t + 1)^5 * (t - 1)^6 * (2*t^2 + 2*t + 1)^4
* (2*t^2 - t + 1)^5>>> G = graphs.RandomTree(Integer(10))>>> G.ihara_zeta_function_inverse()
˓→needs sage.libs.pari sage.modules
1

#␣

#␣

REFERENCES:[HST2001]
independent_set(algorithm, value_only='Cliquer', reduction_rules=False, solver=True, verbose=None,
integrality_tolerance=0)
Return a maximum independent set.
An independent set of a graph is a set of pairwise non-adjacent vertices. A maximum independent set is anindependent set of maximum cardinality. It induces an empty subgraph.
Equivalently, an independent set is defined as the complement of a vertex cover.
For more information, see the Wikipedia article Independent_set_(graph_theory) and the Wikipedia article
Vertex_cover.
INPUT:• algorithm – the algorithm to be used
– If algorithm = "Cliquer" (default), the problem is solved using Cliquer [NO2003].
(see the Cliquer modules)– If algorithm = "MILP", the problem is solved through a Mixed Integer Linear Program.
(see MixedIntegerLinearProgram)• If algorithm = "mcqd", uses the MCQD solver (http://www.sicmm.org/ konc/maxclique/). Notethat 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().

Note: While Cliquer/MCAD are usually (and by far) the most efficient implementations, the MILP formulation sometimes proves faster on very “symmetrical” graphs.

1.2. Undirected graphs553

Graph Theory, Release 10.4

EXAMPLES:
Using Cliquer:
sage: C = graphs.PetersenGraph()
sage: C.independent_set()[0, 3, 6, 7]>>> from sage.all import *>>> C = graphs.PetersenGraph()>>> C.independent_set()[0, 3, 6, 7]

As a linear program:
sage: C = graphs.PetersenGraph()
sage: len(C.independent_set(algorithm="MILP"))˓→needs sage.numerical.mip
4#␣>>> from sage.all import *>>> C = graphs.PetersenGraph()>>> len(C.independent_set(algorithm="MILP"))˓→needs sage.numerical.mip
4

#␣

0

5
1

4
6

9

7

2
554

8

3
Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

independent_set_of_representatives(family, solver, verbose=None, integrality_tolerance=0)
Return an independent set of representatives.
Given a graph 𝐺 and a family 𝐹 = {𝐹𝑖 : 𝑖 ∈ [1, ..., 𝑘]} of subsets of g.vertices(sort=False),
an Independent Set of Representatives (ISR) is an assignation of a vertex 𝑣𝑖 ∈ 𝐹𝑖 to each set 𝐹𝑖 such that𝑣𝑖 ! = 𝑣𝑗 if 𝑖 < 𝑗 (they are representatives) and the set ∪𝑖 𝑣𝑖 is an independent set in 𝐺.
It generalizes, for example, graph coloring and graph list coloring.
(See [ABZ2007] for more information.)
INPUT:• family – A list of lists defining the family 𝐹 (actually, a Family of subsets of G.
vertices(sort=False)).
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:• 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]])
˓→# needs sage.numerical.mip[1, 4]>>> from sage.all import *>>> g = graphs.CompleteBipartiteGraph(Integer(3),Integer(3))>>> g.delete_edge(Integer(1),Integer(4))>>> g.independent_set_of_representatives([[Integer(0),Integer(1),Integer(2)],
˓→[Integer(3),Integer(4),Integer(5)]])# needs sage.numerical.
˓→mip[1, 4]The Petersen Graph is 3-colorable, which can be expressed as an independent set of representatives problem: take 3 disjoint copies of the Petersen Graph, each one representing one color. Then take as a partition of
the set of vertices the family defined by the three copies of each vertex. The ISR of such a family defines a
3-coloring:sage: # needs sage.numerical.mip
sage: g = 3 * graphs.PetersenGraph()
sage: n = g.order() / 3
sage: f = [[i, i + n, i + 2*n] for i in range(n)]sage: isr = g.independent_set_of_representatives(f)sage: c = [integer_floor(i / n) for i in isr]
sage: color_classes = [[], [], []]sage: for v, i in enumerate(c):(continues on next page)1.2. Undirected graphs

555

Graph Theory, Release 10.4

(continued from previous page)....:color_classes[i].append(v)sage: for classs in color_classes:....:
g.subgraph(classs).size() == 0
True
True
True
>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = Integer(3) * graphs.PetersenGraph()>>> n = g.order() / Integer(3)>>> f = [[i, i + n, i + Integer(2)*n] for i in range(n)]>>> isr = g.independent_set_of_representatives(f)>>> c = [integer_floor(i / n) for i in isr]>>> color_classes = [[], [], []]>>> for v, i in enumerate(c):...
color_classes[i].append(v)>>> for classs in color_classes:...
g.subgraph(classs).size() == Integer(0)
True
True
True

is_antipodal()
Check whether this graph is antipodal.
A graph 𝐺 of diameter 𝑑 is said to be antipodal if its distance-𝑑 graph is a disjoint union of cliques.
EXAMPLES:
sage: G = graphs.JohnsonGraph(10, 5)
sage: G.is_antipodal()Truesage: H = G.folded_graph()
sage: H.is_antipodal()False>>> from sage.all import *>>> G = graphs.JohnsonGraph(Integer(10), Integer(5))>>> G.is_antipodal()True>>> H = G.folded_graph()>>> H.is_antipodal()
False

REFERENCES:
See [BCN1989] p. 438 or [Sam2012] for this definition of antipodal graphs.
is_apex()
Test if the graph is apex.
A graph is apex if it can be made planar by the removal of a single vertex. The deleted vertex is called an
apex of the graph, and a graph may have more than one apex. For instance, in the minimal nonplanar graphs
𝐾5 or 𝐾3,3 , every vertex is an apex. The apex graphs include graphs that are themselves planar, in which caseagain every vertex is an apex. The null graph is also counted as an apex graph even though it has no vertex

556

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

to remove. If the graph is not connected, we say that it is apex if it has at most one non planar connectedcomponent and that this component is apex. See the Wikipedia article Apex_graph for more information.
See also:• apex_vertices()• is_planar()
EXAMPLES:
𝐾5 and 𝐾3,3 are apex graphs, and each of their vertices is an apex:
sage: G = graphs.CompleteGraph(5)sage: G.is_apex()Truesage: G = graphs.CompleteBipartiteGraph(3,3)
sage: G.is_apex()True>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G.is_apex()
True>>> G = graphs.CompleteBipartiteGraph(Integer(3),Integer(3))>>> G.is_apex()
True

The Petersen graph is not apex:
sage: G = graphs.PetersenGraph()
sage: G.is_apex()
False>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> 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()Truesage: (M+K5+K5).is_apex()
False>>> from sage.all import *>>> M = graphs.Grid2dGraph(Integer(3),Integer(3))>>> K5 = graphs.CompleteGraph(Integer(5))>>> (M+K5).is_apex()True>>> (M+K5+K5).is_apex()
False

is_arc_transitive()
Check if self is an arc-transitive graph1.2. Undirected graphs

557

Graph Theory, Release 10.4

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()
˓→needs sage.libs.gap
True
sage: G = graphs.GrayGraph()˓→needs networkx
sage: G.is_arc_transitive()
˓→needs networkx sage.libs.gap
False

#␣

#␣
#␣

>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.is_arc_transitive()
˓→needs sage.libs.gap
True>>> G = graphs.GrayGraph()˓→needs networkx>>> G.is_arc_transitive()
˓→needs networkx sage.libs.gap
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 thethird one is called an asteroidal triple. A graph is asteroidal triple-free (AT-free) if it contains no asteroidal
triples. See the module s documentation for more details.
This method returns True is the graph is AT-free and False otherwise.
INPUT:• G – a Graph• certificate – boolean (default: False); by default, this method returns True if the graph isasteroidal triple-free and False otherwise. When certificate==True, this method returns inaddition 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:

558

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G.is_asteroidal_triple_free()True>>> G.is_asteroidal_triple_free(certificate=True)(True, [])>>> LG = G.line_graph()>>> LG.is_asteroidal_triple_free()True>>> LLG = LG.line_graph()>>> 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])>>> from sage.all import *>>> from sage.graphs.asteroidal_triples import *>>> G = graphs.PetersenGraph()>>> G.is_asteroidal_triple_free()False>>> 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_graph1.2. Undirected graphs559

Graph Theory, Release 10.4

EXAMPLES:
sage: G = graphs.PetersenGraph()
sage: G.is_biconnected()Truesage: G.add_path([0, a , b ])sage: G.is_biconnected()False
sage: G.add_edge( b , 1)
sage: G.is_biconnected()True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.is_biconnected()
True>>> G.add_path([Integer(0), a , b ])>>> G.is_biconnected()
False>>> G.add_edge( b , Integer(1))>>> G.is_biconnected()
Trueis_block_graph()
Return whether this graph is a block graph.
A block graph is a connected graph in which every biconnected component (block) is a clique.
See also:• 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>>> from sage.all import *>>> G = graphs.RandomBlockGraph(Integer(6), Integer(2), kmax=Integer(4))>>> G.is_block_graph()(continues on next page)

560

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True>>> from sage.graphs.isgci import graph_classes>>> G in graph_classes.Block
True>>> graphs.CompleteGraph(Integer(4)).is_block_graph()
True>>> graphs.RandomTree(Integer(6)).is_block_graph()
True>>> graphs.PetersenGraph().is_block_graph()
False>>> Graph(Integer(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()
Truesage: 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()
Truesage: naphthalene.merge_vertices([1, 7])
sage: naphthalene.is_cactus()
False>>> from sage.all import *>>> g = Graph({Integer(1): [Integer(2)], Integer(2): [Integer(3), Integer(4)],
˓→ Integer(3): [Integer(4), Integer(5), Integer(6), Integer(7)], Integer(8):␣
˓→[Integer(3), Integer(5)], Integer(9): [Integer(6), Integer(7)]})>>> g.is_cactus()
True>>> c6 = graphs.CycleGraph(Integer(6))>>> naphthalene = c6 + c6>>> naphthalene.is_cactus() # Not connected
False>>> naphthalene.merge_vertices([Integer(0), Integer(6)])>>> naphthalene.is_cactus()
True>>> naphthalene.merge_vertices([Integer(1), Integer(7)])>>> naphthalene.is_cactus()
False

is_cartesian_product(g, certificate=False, relabeling=False)

1.2. Undirected graphs

561

Graph Theory, Release 10.4

Test whether the graph is a Cartesian product.
INPUT:• certificate – boolean (default: False); if certificate = False (default) the method only
returns True or False answers. If certificate = True, the True answers are replaced by thelist of the factors of the graph.
• relabeling – boolean (default: False); if relabeling = True (implies certificate =True), the method also returns a dictionary associating to each vertex its natural coordinates as a vertex
of a product graph. If 𝑔 is not a Cartesian product, None is returned instead.
See also:• sage.graphs.generic_graph.GenericGraph.cartesian_product()• graph_products – a module on graph products.
Note: This algorithm may run faster whenever the graph’s vertices are integers (see relabel()). Give ita try if it is too slow !
EXAMPLES:
The Petersen graph is prime:
sage: from sage.graphs.graph_decompositions.graph_products import is_
˓→cartesian_productsage: g = graphs.PetersenGraph()
sage: is_cartesian_product(g)False>>> from sage.all import *>>> from sage.graphs.graph_decompositions.graph_products import is_cartesian_
˓→product>>> g = graphs.PetersenGraph()>>> 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))
Truesage: p2.is_isomorphic(graphs.PathGraph(5))
True>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5),Integer(5))>>> p1, p2 = is_cartesian_product(g, certificate = True)>>> p1.is_isomorphic(graphs.PathGraph(Integer(5)))
True>>> p2.is_isomorphic(graphs.PathGraph(Integer(5)))
True

Forgetting the graph’s labels, then finding them back:562

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g.relabel()
sage: b,D = g.is_cartesian_product(g, relabeling=True)
sage: bTrue
sage: D # random isomorphism{0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
15: (5, 0), 16: (5, 1), 17: (5, 2), 18: (5, 3), 19: (5, 4),
20: (0, 0), 21: (0, 1), 22: (0, 2), 23: (0, 3), 24: (0, 4)}>>> from sage.all import *>>> g.relabel()>>> b,D = g.is_cartesian_product(g, relabeling=True)
>>> b
True
>>> D # random isomorphism{0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
15: (5, 0), 16: (5, 1), 17: (5, 2), 18: (5, 3), 19: (5, 4),
20: (0, 0), 21: (0, 1), 22: (0, 2), 23: (0, 3), 24: (0, 4)}

And of course, we find the factors back when we build a graph from a product:
sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
sage: g1, g2 = is_cartesian_product(g, certificate = True)
sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
True
sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
True>>> from sage.all import *>>> g = graphs.PetersenGraph().cartesian_product(graphs.
˓→CycleGraph(Integer(3)))>>> g1, g2 = is_cartesian_product(g, certificate = True)>>> any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
True>>> any( x.is_isomorphic(graphs.CycleGraph(Integer(3))) for x in [g1,g2])
True

is_circumscribable(solver='ppl', verbose=0)
Test whether the graph is the graph of a circumscribed polyhedron.
A polyhedron is circumscribed if all of its facets are tangent to a sphere. By a theorem of Rivin ([HRS1993]),
this can be checked by solving a linear program that assigns weights between 0 and 1/2 on each edge of thepolyhedron, so that the weights on any face add to exactly one and the weights on any non-facial cycle add tomore 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, thedefault 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:

1.2. Undirected graphs563

Graph Theory, Release 10.4

sage: C = graphs.CubeGraph(3)sage: C.is_circumscribable()
˓→needs sage.numerical.mip
True

#␣

sage: O = graphs.OctahedralGraph()
sage: O.is_circumscribable()
˓→needs sage.numerical.mip
True

#␣

sage: TT = polytopes.truncated_tetrahedron().graph()˓→needs sage.geometry.polyhedronsage: TT.is_circumscribable()
˓→needs sage.geometry.polyhedron sage.numerical.mip
False>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(3))>>> C.is_circumscribable()
˓→needs sage.numerical.mip
True

#␣
#␣

#␣

>>> O = graphs.OctahedralGraph()>>> O.is_circumscribable()
˓→needs sage.numerical.mip
True

#␣

>>> TT = polytopes.truncated_tetrahedron().graph()˓→needs sage.geometry.polyhedron>>> TT.is_circumscribable()
˓→needs sage.geometry.polyhedron sage.numerical.mip
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()
˓→needs sage.numerical.mip
False

#␣

>>> from sage.all import *>>> f = set(flatten(choice(O.faces())))>>> O.add_edges([[Integer(6), i] for i in f])>>> O.is_circumscribable()
˓→needs sage.numerical.mip
False

#␣

See also:• is_polyhedral()• is_inscribable()
Todo: Allow the use of other, inexact but faster solvers.

564

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

is_cograph()
Check whether the graph is cograph.
A cograph is defined recursively: the single-vertex graph is cograph, complement of cograph is cograph, anddisjoint 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()˓→needs sage.modules
False>>> from sage.all import *>>> graphs.HouseXGraph().is_cograph()
True>>> graphs.HouseGraph().is_cograph()˓→needs sage.modules
False

#␣

#␣

Todo: Implement faster recognition algorithm, as for instance the linear time recognition algorithm using
LexBFS proposed in [Bre2008].
is_comparability(g, algorithm='greedy', certificate=False, check=True, solver=None, verbose=0)
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 implementation is unable to return negative certificates ! When certificate = True, negativecertificates are always equal to None. True certificates are valid, though.
• certificate (boolean) – whether to return a certificate. Yes-answers the certificate is a transitiveorientation of 𝐺, and a no certificates is an odd cycle of sequentially forcing edges.
• check (boolean) – whether to check that the yes-certificates are indeed transitive. As it is very quickcompared 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, thedefault 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)

1.2. Undirected graphs

565

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.comparability import is_comparability>>> g = graphs.PetersenGraph()>>> is_comparability(g)False>>> is_comparability(graphs.CompleteGraph(Integer(5)), certificate=True)(True, Digraph on 5 vertices)

is_directed()
Since graph is undirected, returns False.
EXAMPLES:
sage: Graph().is_directed()
False>>> from sage.all import *>>> Graph().is_directed()
False

is_distance_regular(G, parameters=False)
Test if the graph is distance-regularA graph 𝐺 is distance-regular if for any integers 𝑗, 𝑘 the value of |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑗, 𝑥 ∈ 𝑉 (𝐺)} ∩ {𝑦 :𝑑𝐺 (𝑦, 𝑣) = 𝑗, 𝑦 ∈ 𝑉 (𝐺)}| is constant for any two vertices 𝑢, 𝑣 ∈ 𝑉 (𝐺) at distance 𝑖 from each other. In
particular 𝐺 is regular, of degree 𝑏0 (see below), as one can take 𝑢 = 𝑣.
Equivalently a graph is distance-regular if there exist integers 𝑏𝑖 , 𝑐𝑖 such that for any two vertices 𝑢, 𝑣 at
distance 𝑖 we have• 𝑏𝑖 = |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑖 + 1, 𝑥 ∈ 𝑉 (𝐺)} ∩ 𝑁𝐺 (𝑣)}|, 0 ≤ 𝑖 ≤ 𝑑 − 1• 𝑐𝑖 = |{𝑥 : 𝑑𝐺 (𝑥, 𝑢) = 𝑖 − 1, 𝑥 ∈ 𝑉 (𝐺)} ∩ 𝑁𝐺 (𝑣)}|, 1 ≤ 𝑖 ≤ 𝑑,where 𝑑 is the diameter of the graph. For more information on distance-regular graphs, see the Wikipedia
article Distance-regular_graph.
INPUT:• parameters – boolean (default: False); if set to True, the function returns the pair (b, c) oflists of integers instead of a boolean answer (see the definition above)
See also:• is_regular()• is_strongly_regular()
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.is_distance_regular()True
sage: g.is_distance_regular(parameters = True)([3, 2, None], [None, 1, 1])>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_distance_regular()(continues on next page)

566

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True>>> 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>>> from sage.all import *>>> graphs.CubeGraph(Integer(4)).is_distance_regular()True>>> graphs.OddGraph(Integer(5)).is_distance_regular()
True

Disconnected graph:
sage: (2*graphs.CubeGraph(4)).is_distance_regular()True>>> from sage.all import *>>> (Integer(2)*graphs.CubeGraph(Integer(4))).is_distance_regular()True

is_dominating(G, dom, focus=None)
Check whether dom is a dominating set of G.
We say that a set 𝐷 of vertices of a graph 𝐺 dominates a set 𝑆 if every vertex of 𝑆 either belongs to 𝐷 or isadjacent to a vertex of 𝐷. Also, 𝐷 is a dominating set of 𝐺 if it dominates 𝑉 (𝐺).
INPUT:• dom – iterable of vertices of G; the vertices of the supposed dominating set.
• focus – iterable of vertices of G (default: None); if specified, this method checks instead if dom
dominates the vertices in focus.
EXAMPLES:
sage: g = graphs.CycleGraph(5)sage: g.is_dominating([0,1], [4, 2])True
sage: g.is_dominating([0,1])
False>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.is_dominating([Integer(0),Integer(1)], [Integer(4), Integer(2)])
True>>> g.is_dominating([Integer(0),Integer(1)])
False

1.2. Undirected graphs

567

Graph Theory, Release 10.4

is_edge_transitive()
Check if self is an edge transitive graph.
A graph is edge-transitive if its automorphism group acts transitively on its edge set.
Equivalently, if there exists for any pair of edges 𝑢𝑣, 𝑢′ 𝑣 ′ ∈ 𝐸(𝐺) an automorphism 𝜑 of 𝐺 such that𝜑(𝑢𝑣) = 𝑢′ 𝑣 ′ (note this does not necessarily mean that 𝜑(𝑢) = 𝑢′ and 𝜑(𝑣) = 𝑣 ′ ).
See also:• Wikipedia article Edge-transitive_graph• is_arc_transitive()• is_half_transitive()• is_semi_symmetric()
EXAMPLES:
sage: P = graphs.PetersenGraph()
sage: P.is_edge_transitive()
˓→needs sage.libs.gap
True
sage: C = graphs.CubeGraph(3)sage: C.is_edge_transitive()
˓→needs sage.libs.gap
True
sage: G = graphs.GrayGraph()˓→needs networkx
sage: G.is_edge_transitive()
˓→needs networkx sage.libs.gap
True
sage: P = graphs.PathGraph(4)sage: P.is_edge_transitive()
˓→needs sage.libs.gap
False>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.is_edge_transitive()
˓→needs sage.libs.gap
True>>> C = graphs.CubeGraph(Integer(3))>>> C.is_edge_transitive()
˓→needs sage.libs.gap
True>>> G = graphs.GrayGraph()˓→needs networkx>>> G.is_edge_transitive()
˓→needs networkx sage.libs.gap
True>>> P = graphs.PathGraph(Integer(4))>>> P.is_edge_transitive()
˓→needs sage.libs.gap
False

#␣

#␣

#␣
#␣

#␣

#␣

#␣

#␣
#␣

#␣

is_even_hole_free(certificate=False)
Tests whether self contains an induced even hole.

568

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

A Hole is a cycle of length at least 4 (included). It is said to be even (resp. odd) if its length is even (resp.
odd).
Even-hole-free graphs always contain a bisimplicial vertex, which ensures that their chromatic number is at
most twice their clique number [ACHRS2008].
INPUT:• certificate – boolean (default: False); when certificate = False, this method only
returns True or False. If certificate = True, the subgraph found is returned instead ofFalse.
EXAMPLES:Is the Petersen Graph even-hole-free
sage: g = graphs.PetersenGraph()
sage: g.is_even_hole_free()
˓→needs sage.modules
False>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_even_hole_free()
˓→needs sage.modules
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()
˓→needs sage.modules
True>>> from sage.all import *>>> g = graphs.RandomIntervalGraph(Integer(20))>>> g.is_even_hole_free()
˓→needs sage.modules
True

#␣

#␣

It is clear, though, that a random Bipartite Graph which is not a forest has an even hole:sage: g = graphs.RandomBipartite(10, 10, .5)
˓→needs numpy
sage: g.is_even_hole_free() and not g.is_forest()
˓→needs numpy sage.modules
False

#␣
#␣

>>> from sage.all import *>>> g = graphs.RandomBipartite(Integer(10), Integer(10), RealNumber( .5 ))␣˓→# needs numpy>>> g.is_even_hole_free() and not g.is_forest()#␣˓→needs numpy sage.modules
False

We can check the certificate returned is indeed an even cycle:

1.2. Undirected graphs569

Graph Theory, Release 10.4

sage: if not g.is_forest():˓→needs numpy sage.modules....:
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 !
>>> from sage.all import *>>> if not g.is_forest():˓→needs numpy sage.modules...
cycle = g.is_even_hole_free(certificate=True)...
if cycle.order() % Integer(2) == Integer(1):...
print("Error !")...
if not cycle.is_isomorphic(...
graphs.CycleGraph(cycle.order())):...
print("Error !")...
>>> print("Everything is Fine !")Everything is Fine !

#␣#␣

is_factor_critical(matching, algorithm=None, solver='Edmonds', verbose=None,
integrality_tolerance=0)
Check whether this graph is factor-critical.
A graph of order 𝑛 is factor-critical if every subgraph of 𝑛 − 1 vertices have a perfect matching, hence 𝑛must be odd. See Wikipedia article Factor-critical_graph for more details.
This method implements the algorithm proposed in [LR2004] and we assume that a graph of order one isfactor-critical. The time complexity of the algorithm is linear if a near perfect matching is given as input(i.e., a matching such that all vertices but one are incident to an edge of the matching). Otherwise, the timecomplexity is dominated by the time needed to compute a maximum matching of the graph.
INPUT:• matching – (default: None); a near perfect matching of the graph, that is a matching such that all
vertices of the graph but one are incident to an edge of the matching. It can be given using any valid
input format of Graph.
If set to None, a matching is computed using the other parameters.
• algorithm – string (default: Edmonds); the algorithm to use to compute a maximum matching of
the graph among– "Edmonds" selects Edmonds’ algorithm as implemented in NetworkX– "LP" uses a Linear Program formulation of the matching problem• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity: set to 0 by default, which means quiet (onlyuseful when algorithm == "LP")

570

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
Odd length cycles and odd cliques of order at least 3 are factor-critical graphs:
sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)]#␣˓→needs networkx[True, True, True, True, True]
sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] ␣˓→# needs networkx[True, True, True, True, True]>>> from sage.all import *>>> [graphs.CycleGraph(Integer(2)*i + Integer(1)).is_factor_critical() for i␣˓→in range(Integer(5))]# needs networkx[True, True, True, True, True]>>> [graphs.CompleteGraph(Integer(2)*i + Integer(1)).is_factor_critical() for␣
˓→i in range(Integer(5))]# needs networkx[True, True, True, True, True]

More generally, every Hamiltonian graph with an odd number of vertices is factor-critical:
sage: G = graphs.RandomGNP(15, .2)
sage: G.add_path([0..14])
sage: G.add_edge(14, 0)
sage: G.is_hamiltonian()True
sage: G.is_factor_critical()˓→needs networkx
True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(15), RealNumber( .2 ))>>> G.add_path((ellipsis_range(Integer(0),Ellipsis,Integer(14))))>>> G.add_edge(Integer(14), Integer(0))>>> G.is_hamiltonian()
True>>> G.is_factor_critical()˓→needs networkx
True

#␣

#␣

Friendship graphs are non-Hamiltonian factor-critical graphs:
sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)]˓→# needs networkx[True, True, True, True]␣>>> from sage.all import *>>> [graphs.FriendshipGraph(i).is_factor_critical() for i in range(Integer(1),˓→ Integer(5))]# needs networkx[True, True, True, True]

Bipartite graphs are not factor-critical:

1.2. Undirected graphs571

Graph Theory, Release 10.4

sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5)
˓→needs numpy
sage: G.is_factor_critical()˓→needs numpy
False

#␣
#␣

>>> from sage.all import *>>> G = graphs.RandomBipartite(randint(Integer(1), Integer(10)),␣
˓→randint(Integer(1), Integer(10)), RealNumber( .5 ))# needs numpy>>> G.is_factor_critical()#␣˓→needs numpy
False

Graphs with even order are not factor critical:
sage: G = graphs.RandomGNP(10, .5)
sage: G.is_factor_critical()False>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(10), RealNumber( .5 ))>>> G.is_factor_critical()False

One can specify a matching:sage: F = graphs.FriendshipGraph(4)sage: M = F.matching()
˓→needs networkx
sage: F.is_factor_critical(matching=M)
˓→needs networkx
True
sage: F.is_factor_critical(matching=Graph(M))˓→needs networkx
True>>> from sage.all import *>>> F = graphs.FriendshipGraph(Integer(4))>>> M = F.matching()
˓→needs networkx>>> F.is_factor_critical(matching=M)
˓→needs networkx
True>>> F.is_factor_critical(matching=Graph(M))˓→needs networkx
True

#␣
#␣

#␣

#␣
#␣

#␣

is_forest(certificate=False, output='vertex')
Tests if the graph is a forest, i.e. a disjoint union of trees.
INPUT:• certificate – boolean (default: False); whether to return a certificate. The method only returns
boolean answers when certificate = False (default). When it is set to True, it either answers(True, None) when the graph is a forest or (False, cycle) when it contains a cycle.
• output – either vertex (default) or edge ; whether the certificate is given as a list of vertices(output = vertex ) or a list of edges (output = edge ).
572

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

EXAMPLES:
sage: seven_acre_wood = sum(graphs.trees(7), Graph())
sage: seven_acre_wood.is_forest()
True>>> from sage.all import *>>> seven_acre_wood = sum(graphs.trees(Integer(7)), Graph())>>> 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, [64, 69, 67, 65, 60])>>> from sage.all import *>>> g = graphs.RandomTree(Integer(30))>>> g.is_forest(certificate=True)(True, None)>>> (Integer(2)*g + graphs.PetersenGraph() + g).is_forest(certificate=True)(False, [64, 69, 67, 65, 60])

is_half_transitive()
Check if self is a half-transitive graph.
A graph is half-transitive if it is both vertex and edge transitive but not arc-transitive.
See also:• Wikipedia article half-transitive_graph• is_edge_transitive()• is_arc_transitive()• is_semi_symmetric()
EXAMPLES:
The Petersen Graph is not half-transitive:
sage: P = graphs.PetersenGraph()
sage: P.is_half_transitive()
˓→needs sage.libs.gap
False>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.is_half_transitive()
˓→needs sage.libs.gap
False

#␣

#␣

The smallest half-transitive graph is the Holt Graph:1.2. Undirected graphs573

Graph Theory, Release 10.4

sage: H = graphs.HoltGraph()
sage: H.is_half_transitive()
˓→needs sage.libs.gap
True

#␣

>>> from sage.all import *>>> H = graphs.HoltGraph()>>> H.is_half_transitive()
˓→needs sage.libs.gap
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, thedefault 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)
˓→needs sage.numerical.mip
False
sage: H.planar_dual().is_inscribable()# long time (> 1 sec)
˓→needs sage.numerical.mip
True

#␣

#␣

sage: C = graphs.CubeGraph(3)sage: C.is_inscribable()
˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> H = graphs.HerschelGraph()>>> H.is_inscribable()# long time (> 1 sec)
˓→needs sage.numerical.mip
False>>> H.planar_dual().is_inscribable()# long time (> 1 sec)
˓→needs sage.numerical.mip
True>>> C = graphs.CubeGraph(Integer(3))>>> C.is_inscribable()
˓→needs sage.numerical.mip
True

#␣

#␣

#␣

Cutting off a vertex from the cube yields an uninscribable graph:

574

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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()
˓→needs sage.numerical.mip
False>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(3))>>> v = next(C.vertex_iterator())>>> triangle = [_ + v for _ in C.neighbors(v)]>>> C.add_edges(Combinations(triangle, Integer(2)))>>> C.add_edges(zip(triangle, C.neighbors(v)))>>> C.delete_vertex(v)>>> C.is_inscribable()
˓→needs sage.numerical.mip
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()
˓→needs sage.numerical.mip
False

#␣

>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(3))>>> face = choice(C.faces())>>> C.add_edge([face[Integer(0)][Integer(0)], face[Integer(2)][Integer(0)]])>>> C.is_inscribable()#␣˓→needs sage.numerical.mip
False

See also:• is_polyhedral()• is_circumscribable()
is_line_graph(g, certificate=False)
Check whether the graph 𝑔 is a line graph.
INPUT:• certificate (boolean) – whether to return a certificate along with the boolean result. Here is what
happens when certificate = True:– If the graph is not a line graph, the method returns a pair (b, subgraph) where b is False andsubgraph 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 agraph whose line graph is the graph given as input, and isom is a map associating an edge of R toeach vertex of the graph.
1.2. Undirected graphs575

Graph Theory, Release 10.4

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>>> from sage.all import *>>> graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> graphs.PetersenGraph().is_line_graph()
False

This is indeed the subgraph returned:
sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1]˓→# needs sage.modules
sage: C.is_isomorphic(graphs.ClawGraph())˓→# needs sage.modules
True>>> from sage.all import *>>> C = graphs.PetersenGraph().is_line_graph(certificate=True)[Integer(1)]˓→# needs sage.modules>>> C.is_isomorphic(graphs.ClawGraph())˓→# needs sage.modules
True

␣
␣

␣

The house graph is a line graph:
sage: g = graphs.HouseGraph()
sage: g.is_line_graph()
True>>> from sage.all import *>>> g = graphs.HouseGraph()>>> g.is_line_graph()
True

576

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

But what is the graph whose line graph is the house ?:sage: # needs sage.modules
sage: is_line, R, isom = g.is_line_graph(certificate=True)
sage: R.sparse6_string():DaHI~
sage: R.show()˓→# needs sage.plot
sage: isom
{0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)}␣>>> from sage.all import *>>> # needs sage.modules>>> is_line, R, isom = g.is_line_graph(certificate=True)>>> R.sparse6_string():DaHI~>>> R.show()˓→# needs sage.plot>>> 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 cycleof 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 thiscase 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 areadjacent 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 andnever stored in memory.
The run time of this algorithm is 𝑂(𝑛 + 𝑚2 ) for SparseGraph and 𝑂(𝑛2 log 𝑚 + 𝑚2 ) for DenseGraph[NP2007] (where 𝑛 is the number of vertices and 𝑚 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

1.2. Undirected graphs

577

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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: rFalse
sage: a.complement().is_isomorphic(graphs.CycleGraph(6))
True>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6)).complement()>>> r,a = g.is_long_antihole_free(certificate=True)
>>> r
False
>>> a.complement().is_isomorphic(graphs.CycleGraph(Integer(6)))
True

is_long_hole_free(g, certificate=False)
Tests whether g contains an induced cycle of length at least 5.
INPUT:• certificate – boolean (default: False)
Whether to return a certificate. When certificate = True, then the function returns– (True, []) if g does not contain such a cycle. For this case, it is not known how to provide a
certificate.
– (False, Hole) if g contains an induced cycle of length at least 5. Hole returns this cycle.
If certificate = False, the function returns just True or False accordingly.
ALGORITHM:
This algorithm tries to find a cycle in the graph of all induced 𝑃4 of 𝑔, where two copies 𝑃 and 𝑃 ′ of 𝑃4 areadjacent 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 andnever stored in memory.
The run time of this algorithm is 𝑂(𝑛 + 𝑚2 ) for SparseGraph and 𝑂(𝑛2 + 𝑚2 ) for DenseGraph[NP2007] (where 𝑛 is the number of vertices and 𝑚 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>>> from sage.all import *>>> g = graphs.PetersenGraph()(continues on next page)

578

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> 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: rFalse
sage: Graph(h).is_isomorphic(graphs.CycleGraph(h.order()))
True>>> from sage.all import *>>> g = graphs.FlowerSnark()>>> r,h = g.is_long_hole_free(certificate=True)
>>> r
False
>>> 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[CCLSV2005], it is not known whether testing for one of these two cases independently is polynomial too.
INPUT:• certificate – boolean (default: False); when certificate = False, this method only
returns True or False. If certificate = True, the subgraph found is returned instead ofFalse.
EXAMPLES:Is the Petersen Graph odd-hole-free
sage: g = graphs.PetersenGraph()
sage: g.is_odd_hole_free()
˓→needs sage.modules
False>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_odd_hole_free()
˓→needs sage.modules
False

#␣

#␣

Which was to be expected, as its girth is 5
sage: g.girth()
5

1.2. Undirected graphs579

Graph Theory, Release 10.4>>> from sage.all import *>>> g.girth()5

We can check the certificate returned is indeed a 5-cycle:
sage: cycle = g.is_odd_hole_free(certificate=True)
˓→needs sage.modules
sage: cycle.is_isomorphic(graphs.CycleGraph(5))˓→needs sage.modules
True>>> from sage.all import *>>> cycle = g.is_odd_hole_free(certificate=True)
˓→needs sage.modules>>> cycle.is_isomorphic(graphs.CycleGraph(Integer(5)))˓→# needs sage.modules
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()
˓→needs sage.modules
True

#␣

>>> from sage.all import *>>> g = graphs.RandomIntervalGraph(Integer(20))>>> g.is_odd_hole_free()
˓→needs sage.modules
True

#␣

is_overfull()
Tests whether the current graph is overfull.
A graph 𝐺 on 𝑛 vertices and 𝑚 edges is said to be overfull if:• 𝑛 is odd• It satisfies 2𝑚 > (𝑛 − 1)Δ(𝐺), where Δ(𝐺) denotes the maximum degree among all vertices in 𝐺.
An overfull graph must have a chromatic index of Δ(𝐺) + 1.
EXAMPLES:
A complete graph of order 𝑛 > 1 is overfull if and only if 𝑛 is odd:
sage: graphs.CompleteGraph(6).is_overfull()
False
sage: graphs.CompleteGraph(7).is_overfull()True
sage: graphs.CompleteGraph(1).is_overfull()
False>>> from sage.all import *>>> graphs.CompleteGraph(Integer(6)).is_overfull()
False>>> graphs.CompleteGraph(Integer(7)).is_overfull()(continues on next page)

580

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True>>> graphs.CompleteGraph(Integer(1)).is_overfull()False

The claw graph is not overfull:sage: from sage.graphs.graph_coloring import edge_coloringsage: g = graphs.ClawGraph()
sage: gClaw graph: Graph on 4 vertices
sage: edge_coloring(g, value_only=True)
˓→needs sage.numerical_mip
3
sage: g.is_overfull()
False>>> from sage.all import *>>> from sage.graphs.graph_coloring import edge_coloring>>> g = graphs.ClawGraph()>>> g
Claw graph: Graph on 4 vertices>>> edge_coloring(g, value_only=True)
˓→needs sage.numerical_mip
3>>> g.is_overfull()
False

#␣

#␣

The Holt graph is an example of a overfull graph:
sage: G = graphs.HoltGraph()
sage: G.is_overfull()True>>> from sage.all import *>>> G = graphs.HoltGraph()>>> 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 timeComplete graphs of even order up to 100 are not overfull.
>>> from sage.all import *>>> def check_overfull_Kn_even(n):(continues on next page)1.2. Undirected graphs581

Graph Theory, Release 10.4

(continued from previous page)...
i = Integer(0)...
while i <= n:...
if graphs.CompleteGraph(i).is_overfull():...
print("A complete graph of even order cannot be overfull.")...
return...
i += Integer(2)...
print("Complete graphs of even order up to %s are not overfull." % n)...
>>> check_overfull_Kn_even(Integer(100)) # long timeComplete 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>>> from sage.all import *>>> Graph().is_overfull()
False>>> graphs.CompleteGraph(Integer(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 timeComplete graphs of odd order > 1 up to 100 are overfull.
>>> from sage.all import *>>> def check_overfull_Kn_odd(n):...
i = Integer(3)...
while i <= n:...
if not graphs.CompleteGraph(i).is_overfull():...
print("A complete graph of odd order > 1 must be overfull.")...
return...
i += Integer(2)...
print("Complete graphs of odd order > 1 up to %s are overfull." % n)...
>>> check_overfull_Kn_odd(Integer(100)) # long timeComplete 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(continues on next page)

582

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: from sage.graphs.graph_coloring import edge_coloringsage: max(g.degree()) + 1 == edge_coloring(g, value_only=True)
˓→needs sage.numerical_mip
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_overfull()
False>>> from sage.graphs.graph_coloring import edge_coloring>>> max(g.degree()) + Integer(1) == edge_coloring(g, value_only=True)˓→# needs sage.numerical_mip
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 labelledwith (0,1)-vectors of some fixed length such that the distance between any two vertices in the graph equals
the Hamming distance of their labels.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/ eppstein/PADS/), see also
[Epp2008]. The algorithm runs in 𝑂(𝑛2 ) time, where 𝑛 is the number of vertices. See the documentation ofpartial_cube for an overview of the algorithm.
INPUT:• certificate – boolean (default: False); this function returns True or False according to thegraph, 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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(10)).cartesian_product(graphs.
˓→CompleteGraph(Integer(2)))>>> g.is_partial_cube()True

1.2. Undirected graphs583

Graph Theory, Release 10.4

is_path()Check whether self is a path.
A connected graph of order 𝑛 ≥ 2 is a path if it is a tree (see is_tree()) with 𝑛 − 2 vertices of degree 2
and two of degree 1. By convention, a graph of order 1 without loops is a path, but the empty graph is not apath.
EXAMPLES:
sage: G = graphs.PathGraph(5) sage: G.is_path() True sage: H = graphs.CycleGraph(5) sage:
H.is_path() False sage: D = graphs.PathGraph(5).disjoint_union(graphs.CycleGraph(5)) sage:
D.is_path() False sage: E = graphs.EmptyGraph() sage: E.is_path() False sage: O = Graph([[1],[]]) sage: O.is_path() True sage: O.allow_loops(True) sage: O.add_edge(1, 1) sage: O.is_path()
False
is_perfect(certificate=False)
Tests whether the graph is perfect.
A graph 𝐺 is said to be perfect if 𝜒(𝐻) = 𝜔(𝐻) hold for any induced subgraph 𝐻 ⊆𝑖 𝐺 (and so for 𝐺 itself,too), where 𝜒(𝐻) represents the chromatic number of 𝐻, and 𝜔(𝐻) its clique number. The Strong Perfect
Graph Theorem [CRST2006] gives another characterization of perfect graphs:
A graph is perfect if and only if it contains no odd hole (cycle on an odd number 𝑘 of vertices, 𝑘 > 3) nor
any odd antihole (complement of a hole) as an induced subgraph.
INPUT:• certificate – boolean (default: False); whether to return a certificate.
OUTPUT:
When certificate = False, this function returns a boolean value. When certificate = True,
it returns a subgraph of self isomorphic to an odd hole or an odd antihole if any, and None otherwise.
EXAMPLES:
A Bipartite Graph is always perfect
sage: g = graphs.RandomBipartite(8,4,.5)
˓→needs numpy
sage: g.is_perfect()
˓→needs numpy sage.modules
True

#␣
#␣

>>> from sage.all import *>>> g = graphs.RandomBipartite(Integer(8),Integer(4),RealNumber( .5 ))˓→# needs numpy>>> g.is_perfect()
˓→needs numpy sage.modules
True

␣
#␣

So is the line graph of a bipartite graph:
sage: g = graphs.RandomBipartite(4,3,0.7)
˓→needs numpy
sage: g.line_graph().is_perfect()# long time
˓→needs numpy sage.modules
True

584

#␣
#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.RandomBipartite(Integer(4),Integer(3),RealNumber( 0.7 ))˓→# needs numpy>>> g.line_graph().is_perfect()# long time
˓→needs numpy sage.modules
True

␣
#␣

As well as the Cartesian product of two complete graphs:
sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3))
sage: g.is_perfect()#␣˓→needs sage.modules
True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(3)).cartesian_product(graphs.
˓→CompleteGraph(Integer(3)))>>> g.is_perfect()
˓→needs sage.modules
True

#␣

Interval Graphs, which are chordal graphs, too
sage: g = graphs.RandomIntervalGraph(7)sage: g.is_perfect()
˓→needs sage.modules
True

#␣

>>> from sage.all import *>>> g = graphs.RandomIntervalGraph(Integer(7))>>> g.is_perfect()
˓→needs sage.modules
True

#␣

The PetersenGraph, which is triangle-free and has chromatic number 3 is obviously not perfect:
sage: g = graphs.PetersenGraph()
sage: g.is_perfect()
˓→needs sage.modules
False>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_perfect()
˓→needs sage.modules
False

#␣

#␣

We can obtain an induced 5-cycle as a certificate:sage: g.is_perfect(certificate=True)
˓→needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices>>> from sage.all import *>>> g.is_perfect(certificate=True)#␣#␣(continues on next page)1.2. Undirected graphs585

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules
Subgraph of (Petersen graph): Graph on 5 vertices˓→

is_permutation(g, algorithm='greedy', certificate=False, check=True, solver=None, verbose=0)
Tests whether the graph is a permutation graph.
For more information on permutation graphs, refer to the documentation of the comparability module.
INPUT:• 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 implementation is unable to return negative certificates ! When certificate = True, negativecertificates 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 Permutation 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, thedefault 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>>> from sage.all import *>>> from sage.graphs.comparability import is_permutation>>> g = graphs.BullGraph()>>> _ , certif = is_permutation(g, certificate=True)>>> h = graphs.PermutationGraph(*certif)>>> h.is_isomorphic(g)True

Plotting the realization as an intersection graph of segments:

586

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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")˓→# needs sage.plot␣>>> from sage.all import *>>> true, perm = is_permutation(g, certificate=True)>>> p1 = Permutation([nn+Integer(1) for nn in perm[Integer(0)]])>>> p2 = Permutation([nn+Integer(1) for nn in perm[Integer(1)]])>>> p = p2 * p1.inverse()>>> p.show(representation="braid")
˓→# needs sage.plot

is_polyhedral()Check whether the graph is the graph of the polyhedron.
By a theorem of Steinitz (Satz 43, p. 77 of [St1922]), graphs of three-dimensional polyhedra are exactly thesimple 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]>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(3))>>> C.is_polyhedral()
True>>> K33=graphs.CompleteBipartiteGraph(Integer(3), Integer(3))>>> K33.is_polyhedral()False>>> graphs.CycleGraph(Integer(17)).is_polyhedral()False>>> [i for i in range(Integer(9)) if graphs.CompleteGraph(i).is_polyhedral()][4]

See also:• vertex_connectivity()• is_planar()• is_circumscribable()• is_inscribable()• Wikipedia article Polyhedral_graph1.2. Undirected graphs587

Graph Theory, Release 10.4

is_prime(algorithm=None)
Test whether the current graph is prime.
A graph is prime if all its modules are trivial (i.e. empty, all of the graph or singletons) – see modular_decomposition(). Use the 𝑂(𝑛3 ) algorithm of [HM1979].
EXAMPLES:
The Petersen Graph and the Bull Graph are both prime:
sage: graphs.PetersenGraph().is_prime()True
sage: graphs.BullGraph().is_prime()
True>>> from sage.all import *>>> graphs.PetersenGraph().is_prime()True>>> graphs.BullGraph().is_prime()
True

Though quite obviously, the disjoint union of them is not:sage: (graphs.PetersenGraph() + graphs.BullGraph()).is_prime()
False>>> from sage.all import *>>> (graphs.PetersenGraph() + graphs.BullGraph()).is_prime()
False

is_redundant(G, dom, focus=None)
Check whether dom has redundant vertices.
For a graph 𝐺 and sets 𝐷 and 𝑆 of vertices, we say that a vertex 𝑣 ∈ 𝐷 is redundant in 𝑆 if 𝑣 has no private
neighbor with respect to 𝐷 in 𝑆. In other words, there is no vertex in 𝑆 that is dominated by 𝑣 but not by
𝐷 ∖ {𝑣}.
INPUT:• dom – iterable of vertices of G; where we look for redundant vertices.
• focus – iterable of vertices of G (default: None); if specified, this method checks instead whether dom
has a redundant vertex in focus.
Warning: The assumption is made that focus (if provided) does not contain repeated vertices.
EXAMPLES:
sage: G = graphs.CubeGraph(3)sage: G.is_redundant([ 000 , 101 ], [ 011 ])Truesage: G.is_redundant([ 000 , 101 ])False>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(3))(continues on next page)

588

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G.is_redundant([ 000 ,True>>> G.is_redundant([ 000 ,False

101 ], [ 011 ])101 ])

is_semi_symmetric()
Check if self is semi-symmetric.
A graph is semi-symmetric if it is regular, edge-transitive but not vertex-transitive.
See also:• 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()
˓→needs sage.libs.gap
False>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.is_semi_symmetric()
˓→needs sage.libs.gap
False

#␣

#␣

The Gray graph is the smallest possible cubic semi-symmetric graph:
sage: G = graphs.GrayGraph()˓→needs networkx
sage: G.is_semi_symmetric()
˓→needs networkx sage.libs.gap
True>>> from sage.all import *>>> G = graphs.GrayGraph()˓→needs networkx>>> G.is_semi_symmetric()
˓→needs networkx sage.libs.gap
True

#␣
#␣

#␣
#␣

Another well known semi-symmetric graph is the Ljubljana graph:
sage: L = graphs.LjubljanaGraph()˓→needs networkx
sage: L.is_semi_symmetric()
˓→needs networkx sage.libs.gap
True1.2. Undirected graphs

#␣
#␣

589

Graph Theory, Release 10.4>>> from sage.all import *>>> L = graphs.LjubljanaGraph()˓→needs networkx>>> L.is_semi_symmetric()
˓→needs networkx sage.libs.gap
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 thatthe 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, asurvey” [BLS1999] page 203) :Given the degree sequence 𝑑1 ≥ ... ≥ 𝑑𝑛 of 𝐺, a graph is a split graph if and only if :𝜔∑︁

𝑑𝑖 = 𝜔(𝜔 − 1) +

𝑖=1

𝑛
∑︁

𝑑𝑖

𝑖=𝜔+1

where 𝜔 = 𝑚𝑎𝑥{𝑖 : 𝑑𝑖 ≥ 𝑖 − 1}.
EXAMPLES:
Split graphs are, in particular, chordal graphs. Hence, The Petersen graph can not be split:
sage: graphs.PetersenGraph().is_split()
False>>> from sage.all import *>>> 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>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(10))>>> sets = Subsets(Set(range(Integer(10))))>>> for i in range(Integer(10), Integer(25)):...
g.add_edges([(i,k) for k in sets.random_element()])>>> g.is_split()
True

Another characterisation of split graph states that a graph is a split graph if and only if does not contain the
4-cycle, 5-cycle or 2𝐾2 as an induced subgraph. Hence for the above graph we have:sage: forbidden_subgraphs = [graphs.CycleGraph(4),....:graphs.CycleGraph(5),(continues on next page)

590

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)....:2 * graphs.CompleteGraph(2)]sage: sum(g.subgraph_search_count(H, induced=True)
˓→needs sage.modules....:
for H in forbidden_subgraphs)0#␣>>> from sage.all import *>>> forbidden_subgraphs = [graphs.CycleGraph(Integer(4)),...
graphs.CycleGraph(Integer(5)),...
Integer(2) * graphs.CompleteGraph(Integer(2))]>>> sum(g.subgraph_search_count(H, induced=True)#␣˓→needs sage.modules...
for H in forbidden_subgraphs)0

is_strongly_regular(g, parameters=False)
Check whether the graph is strongly regular.
A simple graph 𝐺 is said to be strongly regular with parameters (𝑛, 𝑘, 𝜆, 𝜇) if and only if:• 𝐺 has 𝑛 vertices• 𝐺 is 𝑘-regular• Any two adjacent vertices of 𝐺 have 𝜆 common neighbors• Any two non-adjacent vertices of 𝐺 have 𝜇 common neighbors
By convention, the complete graphs, the graphs with no edges and the empty graph are not strongly regular.
See the Wikipedia article Strongly regular graph.
INPUT:• parameters – boolean (default: False); whether to return the quadruple (𝑛, 𝑘, 𝜆, 𝜇). If parameters = False (default), this method only returns True and False answers. If parameters =True, the True answers are replaced by quadruples (𝑛, 𝑘, 𝜆, 𝜇). See definition above.
EXAMPLES:Petersen’s graph is strongly regular:
sage: g = graphs.PetersenGraph()
sage: g.is_strongly_regular()True
sage: g.is_strongly_regular(parameters=True)(10, 3, 0, 1)>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_strongly_regular()True>>> 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()(continues on next page)1.2. Undirected graphs591

Graph Theory, Release 10.4

(continued from previous page)True
sage: g.is_strongly_regular(parameters=True)(16, 5, 0, 2)>>> from sage.all import *>>> g = graphs.ClebschGraph()>>> g.is_strongly_regular()True>>> 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>>> from sage.all import *>>> g = graphs.ChvatalGraph()>>> g.is_strongly_regular()
False

Complete graphs are not strongly regular. (Issue #14297)
sage: g = graphs.CompleteGraph(5)sage: g.is_strongly_regular()False>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> 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>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5)).complement()>>> g.is_strongly_regular()False

The empty graph is not strongly regular:
sage: g = graphs.EmptyGraph()
sage: g.is_strongly_regular()False>>> from sage.all import *>>> g = graphs.EmptyGraph()>>> g.is_strongly_regular()
False

592

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

If the input graph has loops or multiedges an exception is raised:sage: Graph([(1,1),(2,2)],loops=True).is_strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withloops. Perhaps this method can be updated to handle them, but in themeantime if you want to use it please disallow loops using
allow_loops().
sage: Graph([(1,2),(1,2)],multiedges=True).is_strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withmultiedges. Perhaps this method can be updated to handle them, but inthe meantime if you want to use it please disallow multiedges using
allow_multiple_edges().
>>> from sage.all import *>>> Graph([(Integer(1),Integer(1)),(Integer(2),Integer(2))],loops=True).is_˓→strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withloops. Perhaps this method can be updated to handle them, but in themeantime if you want to use it please disallow loops using
allow_loops().
>>> Graph([(Integer(1),Integer(2)),(Integer(1),Integer(2))],multiedges=True).
˓→is_strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withmultiedges. Perhaps this method can be updated to handle them, but inthe meantime if you want to use it please disallow multiedges using
allow_multiple_edges().

is_tree(certificate=False, output='vertex')
Tests if the graph is a tree
The empty graph is defined to be not a tree.
INPUT:• certificate – boolean (default: False); whether to return a certificate. The method only returns
boolean answers when certificate = False (default). When it is set to True, it either answers(True, None) when the graph is a tree or (False, cycle) when it contains a cycle. It returns(False, None) when the graph is empty or not connected.
• output – either vertex (default) or edge ; whether the certificate is given as a list of vertices(output = vertex ) or a list of edges (output = edge ).
When the certificate cycle is given as a list of edges, the edges are given as (𝑣𝑖 , 𝑣𝑖+1 , 𝑙) where 𝑣1 , 𝑣2 , . . . , 𝑣𝑛
are the vertices of the cycles (in their cyclic order).
EXAMPLES:
sage: all(T.is_tree() for T in graphs.trees(15))
True

1.2. Undirected graphs593

Graph Theory, Release 10.4>>> from sage.all import *>>> all(T.is_tree() for T in graphs.trees(Integer(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>>> from sage.all import *>>> g = graphs.RandomTree(Integer(30))>>> g.is_tree(certificate=True)(True, None)>>> g.add_edge(Integer(10),-Integer(1))>>> g.add_edge(Integer(11),-Integer(1))>>> isit, cycle = g.is_tree(certificate=True)>>> isit
False>>> -Integer(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)])>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(4))>>> 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, b ), (2, 1, a )])>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2), a ), (Integer(1), Integer(2),˓→multiedges=True)>>> G.is_tree(certificate=True)(False, [1, 2])>>> G.is_tree(certificate=True, output= edge )(False, [(1, 2, b ), (2, 1, a )])594b )],␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

is_triangle_free(algorithm='dense_graph', certificate=False)
Check whether self is triangle-free
INPUT:• algorithm – (default: dense_graph ) specifies the algorithm to use among:–

matrix – tests if the trace of the adjacency matrix is positive.

–

bitset – encodes adjacencies into bitsets and uses fast bitset operations to test if the input graphcontains a triangle. This method is generally faster than standard matrix multiplication.

–

dense_graph–static_dense_graph

use

the

implementationofsage.graphs.base.

• certificate – boolean (default: False); whether to return a triangle if one is found. This parameteris ignored when algorithm is matrix .
EXAMPLES:
The Petersen Graph is triangle-free:
sage: g = graphs.PetersenGraph()
sage: g.is_triangle_free()True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_triangle_free()Trueor a complete Bipartite Graph:
sage: G = graphs.CompleteBipartiteGraph(5,6)
sage: G.is_triangle_free(algorithm= matrix )˓→needs sage.modules
True
sage: G.is_triangle_free(algorithm= bitset )Truesage: G.is_triangle_free(algorithm= dense_graph )True>>> from sage.all import *>>> G = graphs.CompleteBipartiteGraph(Integer(5),Integer(6))>>> G.is_triangle_free(algorithm= matrix )˓→needs sage.modules
True>>> G.is_triangle_free(algorithm= bitset )True>>> G.is_triangle_free(algorithm= dense_graph )
True

#␣

#␣

a tripartite graph, though, contains many triangles:
sage: G = (3 * graphs.CompleteGraph(5)).complement()
sage: G.is_triangle_free(algorithm= matrix )˓→needs sage.modules
False
sage: G.is_triangle_free(algorithm= bitset )#␣(continues on next page)1.2. Undirected graphs595

Graph Theory, Release 10.4

(continued from previous page)

False
sage: G.is_triangle_free(algorithm= dense_graph )False>>> from sage.all import *>>> G = (Integer(3) * graphs.CompleteGraph(Integer(5))).complement()>>> G.is_triangle_free(algorithm= matrix )˓→needs sage.modules
False>>> G.is_triangle_free(algorithm= bitset )False>>> G.is_triangle_free(algorithm= dense_graph )
False

#␣

Asking for a certificate:sage: K4 = graphs.CompleteGraph(4)sage: K4.is_triangle_free(algorithm= dense_graph , certificate=True)(False, [0, 1, 2])
sage: K4.is_triangle_free(algorithm= bitset , certificate=True)(False, [0, 1, 2])>>> from sage.all import *>>> K4 = graphs.CompleteGraph(Integer(4))>>> K4.is_triangle_free(algorithm= dense_graph , certificate=True)(False, [0, 1, 2])>>> K4.is_triangle_free(algorithm= bitset , certificate=True)(False, [0, 1, 2])

is_triconnected(G)Check whether the graph is triconnected.
A triconnected graph is a connected graph on 3 or more vertices that is not broken into disconnected pieces
by deleting any pair of vertices.
EXAMPLES:
The Petersen graph is triconnected:
sage: G = graphs.PetersenGraph()
sage: G.is_triconnected()True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.is_triconnected()
True

But a 2D grid is not:sage: G = graphs.Grid2dGraph(3, 3)
sage: G.is_triconnected()
False>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(3), Integer(3))(continues on next page)

596

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G.is_triconnected()
False

By convention, a cycle of order 3 is triconnected:
sage: G = graphs.CycleGraph(3)sage: G.is_triconnected()True>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> G.is_triconnected()True

But cycles of order 4 and more are not:sage: [graphs.CycleGraph(i).is_triconnected() for i in range(4, 8)][False, False, False, False]>>> from sage.all import *>>> [graphs.CycleGraph(i).is_triconnected() for i in range(Integer(4),␣
˓→Integer(8))][False, False, False, False]

Comparing different methods on random graphs that are not always triconnected:
sage: G = graphs.RandomBarabasiAlbert(50, 3)˓→# needs networkx
sage: G.is_triconnected() == G.vertex_connectivity(k=3)˓→# needs networkx
True>>> from sage.all import *>>> G = graphs.RandomBarabasiAlbert(Integer(50), Integer(3))˓→# needs networkx>>> G.is_triconnected() == G.vertex_connectivity(k=Integer(3))˓→# needs networkx
True

␣
␣

␣
␣

See also:• is_connected()• is_biconnected()• spqr_tree()• Wikipedia article SPQR_tree
is_weakly_chordal(g, certificate=False)
Tests whether the given graph is weakly chordal, i.e., the graph and its complement have no induced cycle oflength 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, return1.2. Undirected graphs597

Graph Theory, Release 10.4

– (False, forbidden_subgraph) when the graph contains a forbidden subgraph H, thisgraph 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 ) for SparseGraphand 𝑂(𝑛2 log 𝑚 + 𝑚2 ) for DenseGraph (where 𝑛 is the number of vertices and 𝑚 is the number of edgesof 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: rFalse
sage: l = s.order()sage: s.is_isomorphic(graphs.CycleGraph(l))
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> r,s = g.is_weakly_chordal(certificate=True)
>>> r
False
>>> l = s.order()>>> s.is_isomorphic(graphs.CycleGraph(l))
Truejoin(other, labels='pairs', immutable=None)
Return the join of self and other.
INPUT:• labels – (defaults to ‘pairs’); if set to ‘pairs’, each element 𝑣 in the first graph will be named (0, 𝑣)
and each element 𝑢 in other will be named (1, 𝑢) in the result. If set to ‘integers’, the elements of theresult will be relabeled with consecutive integers.
• immutable – boolean (default: None); whether to create a mutable/immutable join.
mutable=None (default) means that the graphs and their join will behave the same way.

im-

See also:• union()• disjoint_union()
EXAMPLES:
sage: G = graphs.CycleGraph(3)sage: H = Graph(2)sage: J = G.join(H); J
Cycle graph join : Graph on 5 vertices
sage: J.vertices(sort=True)(continues on next page)

598

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]
sage: J = G.join(H, labels= integers ); J
Cycle graph join : Graph on 5 vertices
sage: J.vertices(sort=True)[0, 1, 2, 3, 4]
sage: J.edges(sort=True)[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None), (1, 2, None), (1, 3,␣
˓→None), (1, 4, None), (2, 3, None), (2, 4, None)]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> H = Graph(Integer(2))>>> J = G.join(H); J
Cycle graph join : Graph on 5 vertices>>> J.vertices(sort=True)[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]>>> J = G.join(H, labels= integers ); J
Cycle graph join : Graph on 5 vertices>>> J.vertices(sort=True)[0, 1, 2, 3, 4]>>> J.edges(sort=True)[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None), (1, 2, None), (1, 3,␣
˓→None), (1, 4, None), (2, 3, None), (2, 4, None)]sage: G = Graph(3)sage: G.name("Graph on 3 vertices")sage: H = Graph(2)sage: H.name("Graph on 2 vertices")sage: J = G.join(H); J
Graph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices
sage: J.vertices(sort=True)[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]
sage: J = G.join(H, labels= integers ); JGraph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices
sage: J.edges(sort=True)[(0, 3, None), (0, 4, None), (1, 3, None), (1, 4, None), (2, 3, None), (2, 4,␣
˓→None)]>>> from sage.all import *>>> G = Graph(Integer(3))>>> G.name("Graph on 3 vertices")>>> H = Graph(Integer(2))>>> H.name("Graph on 2 vertices")>>> J = G.join(H); J
Graph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices>>> J.vertices(sort=True)[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]>>> J = G.join(H, labels= integers ); JGraph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices>>> J.edges(sort=True)[(0, 3, None), (0, 4, None), (1, 3, None), (1, 4, None), (2, 3, None), (2, 4,␣
˓→None)]kirchhoff_symanzik_polynomial(name='t')
Return the Kirchhoff-Symanzik polynomial of a graph.

1.2. Undirected graphs599

Graph Theory, Release 10.4

This is a polynomial in variables 𝑡𝑒 (each of them representing an edge of the graph 𝐺) defined as a sum overall spanning trees:∑︁∏︁Ψ𝐺 (𝑡) =𝑡𝑒𝑇 ⊆𝑉𝑒̸∈𝐸(𝑇 )a spanning tree

This is also called the first Symanzik polynomial or the Kirchhoff polynomial.
INPUT:• name – name of the variables (default: t )OUTPUT:• a polynomial with integer coefficients
ALGORITHM:
This is computed here using a determinant, as explained in Section 3.1 of [Mar2009a].
As an intermediate step, one computes a cycle basis 𝒞 of 𝐺 and a rectangular |𝒞| × |𝐸(𝐺)| matrix with entries in {−1, 0, 1}, which describes which edge belong to which cycle of 𝒞 and theirrespective orientations.
More precisely, after fixing an arbitrary orientation for each edge 𝑒 ∈ 𝐸(𝐺) and each cycle 𝐶 ∈ 𝒞,
one gets a sign for every incident pair (edge, cycle) which is 1 if the orientation coincide and −1otherwise.
EXAMPLES:
For the cycle of length 5:
sage: G = graphs.CycleGraph(5)sage: G.kirchhoff_symanzik_polynomial()
˓→needs networkx sage.modules
t0 + t1 + t2 + t3 + t4

#␣>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(5))>>> G.kirchhoff_symanzik_polynomial()
˓→needs networkx sage.modules
t0 + t1 + t2 + t3 + t4

#␣

One can use another letter for variables:sage: G.kirchhoff_symanzik_polynomial(name= u )˓→needs networkx sage.modules
u0 + u1 + u2 + u3 + u4>>> from sage.all import *>>> G.kirchhoff_symanzik_polynomial(name= u )˓→needs networkx sage.modules
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()
˓→needs networkx sage.modules
t0*t1 + t0*t2 + t1*t2

600

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1), a ),(Integer(0),Integer(1), b ),˓→(Integer(0),Integer(1), c )], multiedges=True)>>> G.kirchhoff_symanzik_polynomial()
˓→needs networkx sage.modules
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()#␣˓→needs networkx sage.modules
t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(2), a ),(Integer(0),Integer(2), b ),˓→(Integer(0),Integer(1), c ),(Integer(1),Integer(2), d )], multiedges=True)>>> G.kirchhoff_symanzik_polynomial()#␣˓→needs networkx sage.modules
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()
˓→needs networkx sage.modules
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>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> G.kirchhoff_symanzik_polynomial()
˓→needs networkx sage.modules
t0*t1*t3 + t0*t2*t3 + t1*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4+ t1*t3*t4 + t2*t3*t4 + t0*t1*t5 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5+ t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5#␣#␣

REFERENCES:[Bro2011]
least_effective_resistance(nonedgesonly=True)
Return a list of pairs of nodes with the least effective resistance.
The resistance distance between vertices 𝑖 and 𝑗 of a simple connected graph 𝐺 is defined as the effective
resistance between the two vertices on an electrical network constructed from 𝐺 replacing each edge of thegraph by a unit (1 ohm) resistor.
INPUT:• nonedgesonly – Boolean (default: 𝑇 𝑟𝑢𝑒); if true, assign zero resistance to pairs of adjacent vertices
OUTPUT: list
EXAMPLES:
Pairs of non-adjacent nodes with least effective resistance in a straight linear 2-tree on 6 vertices:

1.2. Undirected graphs

601

Graph Theory, Release 10.4

sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G.least_effective_resistance()
˓→needs sage.modules[(1, 4)]#␣>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),˓→Integer(2)),(Integer(1),Integer(3)),(Integer(3),Integer(5)),(Integer(2),˓→Integer(4)),(Integer(2),Integer(3)),(Integer(3),Integer(4)),(Integer(4),˓→Integer(5))])>>> G.least_effective_resistance()#␣˓→needs sage.modules[(1, 4)]

Pairs of (adjacent or non-adjacent) nodes with least effective resistance in a straight linear 2-tree on 6 vertices
sage: G.least_effective_resistance(nonedgesonly=False)
˓→needs sage.modules[(2, 3)]>>> from sage.all import *>>> G.least_effective_resistance(nonedgesonly=False)
˓→needs sage.modules[(2, 3)]#␣#␣Pairs of non-adjacent nodes with least effective resistance in a fan on 6 vertices counting only non-adjacentvertex pairs
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.least_effective_resistance()#␣˓→needs sage.modules[(2, 4)]>>> from sage.all import *>>> H = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(0),˓→Integer(3)),(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(0),˓→Integer(6)),(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(4)),(Integer(4),Integer(5))])>>> H.least_effective_resistance()#␣˓→needs sage.modules[(2, 4)]

See also:• effective_resistance_matrix() – a similar method giving a matrix full of all effective resistances• effective_resistance() – compuetes effective resistance for a single node pair
• See Wikipedia article Resistance_distance for more details.
lex_M(triangulation=False, labels=False, initial_vertex=None, algorithm=None)
Return an ordering of the vertices according the LexM graph traversal.
LexM is a lexicographic ordering scheme that is a special type of breadth-first-search. LexM can also producea triangulation of the given graph. This functionality is implemented in this method. For more details on thealgorithms used see Sections 4 ( lex_M_slow ) and 5.3 ( lex_M_fast ) of [RTL76].
602

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Note: This method works only for undirected graphs.
INPUT:• triangulation – boolean (default: False); whether to return a list of edges that need to be addedin order to triangulate the graph• labels – boolean (default: False); whether to return the labels assigned to each vertex• initial_vertex – (default: None); the first vertex to consider• algorithm – string (default: None); one of the following algorithms:–

lex_M_slow : slower implementation of LexM traversal–

lex_M_fast : faster implementation of LexM traversal (works only when labels is set to
False)– None: Sage chooses the best algorithm:
lex_M_fast otherwise.

lex_M_slow

if labels is set to True,OUTPUT:
Depending on the values of the parameters triangulation and labels the method will return one ormore of the following (in that order):• an ordering of vertices of the graph according to LexM ordering scheme• the labels assigned to each vertex• a list of edges that when added to the graph will triangulate it
EXAMPLES:
LexM produces an ordering of the vertices:sage: g = graphs.CompleteGraph(6)sage: ord = g.lex_M(algorithm= lex_M_fast )sage: len(ord) == g.order()True
sage: set(ord) == set(g.vertices(sort=False))
True
sage: ord = g.lex_M(algorithm= lex_M_slow )sage: len(ord) == g.order()True
sage: set(ord) == set(g.vertices(sort=False))
True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> ord = g.lex_M(algorithm= lex_M_fast )>>> len(ord) == g.order()True>>> set(ord) == set(g.vertices(sort=False))
True>>> ord = g.lex_M(algorithm= lex_M_slow )>>> len(ord) == g.order()True>>> set(ord) == set(g.vertices(sort=False))
True

1.2. Undirected graphs603

Graph Theory, Release 10.4

Both algorithms produce a valid LexM ordering 𝛼 (i.e the neighbors of 𝛼(𝑖) in 𝐺[{𝛼(𝑖), ..., 𝛼(𝑛)}] induce aclique):sage: from sage.graphs.traversals import is_valid_lex_M_ordersage: G = graphs.PetersenGraph()
sage: ord, F = G.lex_M(triangulation=True, algorithm= lex_M_slow )sage: is_valid_lex_M_order(G, ord, F)
True
sage: ord, F = G.lex_M(triangulation=True, algorithm= lex_M_fast )sage: is_valid_lex_M_order(G, ord, F)
True>>> from sage.all import *>>> from sage.graphs.traversals import is_valid_lex_M_order>>> G = graphs.PetersenGraph()>>> ord, F = G.lex_M(triangulation=True, algorithm= lex_M_slow )>>> is_valid_lex_M_order(G, ord, F)
True>>> ord, F = G.lex_M(triangulation=True, algorithm= lex_M_fast )>>> is_valid_lex_M_order(G, ord, F)
True

LexM produces a triangulation of given graph:
sage: G = graphs.PetersenGraph()
sage: _, F = G.lex_M(triangulation=True)
sage: H = Graph(F, format= list_of_edges )sage: H.is_chordal()True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> _, F = G.lex_M(triangulation=True)>>> H = Graph(F, format= list_of_edges )>>> H.is_chordal()
True

LexM ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4,␣˓→5), (5, 6)])sage: g.lex_M()[6, 4, 5, 3, 2, 1]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)),␣
˓→(Integer(2), Integer(3)), (Integer(2), Integer(4)), (Integer(2),␣
˓→Integer(5)), (Integer(3), Integer(5)), (Integer(3), Integer(6)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))])>>> g.lex_M()[6, 4, 5, 3, 2, 1]

lovasz_theta(graph)
Return the value of Lovász theta-function of graph.
For a graph 𝐺 this function is denoted by 𝜃(𝐺), and it can be computed in polynomial time. Mathematically,

604

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

its most important property is the following:𝛼(𝐺) ≤ 𝜃(𝐺) ≤ 𝜒(𝐺)with 𝛼(𝐺) and 𝜒(𝐺) being, respectively, the maximum size of an independent set set of 𝐺 and thechromatic number of the complement 𝐺 of 𝐺.
For more information, see the Wikipedia article Lovász_number.
Note:• Implemented for undirected graphs only. Use to_undirected to convert a digraph to an undirected
graph.
• This function requires the optional package csdp, which you can install with sage -i csdp.
EXAMPLES:
sage: C = graphs.PetersenGraph()
sage: C.lovasz_theta()
4.0
sage: graphs.CycleGraph(5).lovasz_theta()
2.236068# optional - csdp
# optional - csdp>>> from sage.all import *>>> C = graphs.PetersenGraph()>>> C.lovasz_theta()# optional - csdp
4.0>>> graphs.CycleGraph(Integer(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 bya 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 adisjoint union is the sum of the magnitudes functions of the connected components. The magnitude functionof a Cartesian product is the product of the magnitudes functions of the factors.
EXAMPLES:
sage: g = Graph({1:[], 2:[]})
sage: g.magnitude_function()
˓→needs sage.modules2
sage: g = graphs.CycleGraph(4)sage: g.magnitude_function()
˓→needs sage.modules
4/(q^2 + 2*q + 1)
sage: g = graphs.CycleGraph(5)sage: m = g.magnitude_function(); m˓→needs sage.modules
5/(2*q^2 + 2*q + 1)

1.2. Undirected graphs

#␣

#␣

#␣

605

Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph({Integer(1):[], Integer(2):[]})>>> g.magnitude_function()
˓→needs sage.modules
2>>> g = graphs.CycleGraph(Integer(4))>>> g.magnitude_function()
˓→needs sage.modules
4/(q^2 + 2*q + 1)#␣#␣>>> g = graphs.CycleGraph(Integer(5))>>> m = g.magnitude_function(); m˓→needs sage.modules
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)˓→needs sage.modules
5 - 10*q + 10*q^2 - 20*q^4 + 40*q^5 - 40*q^6 + ...
>>> from sage.all import *>>> q = QQ[[ q ]].gen()>>> m(q)˓→needs sage.modules
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()
˓→needs sage.modules
sage: t = var( t )˓→needs sage.modules sage.symbolic
sage: m(exp(-t))˓→needs sage.modules sage.symbolic
6/(2*e^(-t) + 2*e^(-2*t) + e^(-3*t) + 1)

#␣
#␣
#␣

>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6))>>> m = g.magnitude_function()
˓→needs sage.modules>>> t = var( t )˓→needs sage.modules sage.symbolic>>> m(exp(-t))˓→needs sage.modules sage.symbolic
6/(2*e^(-t) + 2*e^(-2*t) + e^(-3*t) + 1)

#␣
#␣
#␣

REFERENCES:
matching(value_only, algorithm=False, use_edge_labels='Edmonds', solver=False, verbose=None,
integrality_tolerance=0)
Return a maximum weighted matching of the graph represented by the list of its edges.
For more information, see the Wikipedia article Matching_(graph_theory).

606

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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.
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 thematching 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 anedge has no label, 1 is assumed)– when set to False, each edge has weight 1• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity: set to 0 by default, which means quiet (onlyuseful when algorithm == "LP")• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT:• When value_only=False (default), this method returns an EdgesView containing the edges ofa maximum matching of 𝐺.
• When value_only=True, this method returns the sum of the weights (default: 1) of the edges of a
maximum matching of 𝐺. The type of the output may vary according to the type of the edge labels andthe algorithm used.
ALGORITHM:
The problem is solved using Edmond’s algorithm implemented in NetworkX, or using Linear Programming
depending on the value of algorithm.
EXAMPLES:
Maximum matching in a Pappus Graph:
sage: g = graphs.PappusGraph()
sage: g.matching(value_only=True)
˓→# needs sage.networkx
9

1.2. Undirected graphs

607

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PappusGraph()>>> g.matching(value_only=True)
˓→needs sage.networkx
9#␣Same test with the Linear Program formulation:
sage: g = graphs.PappusGraph()
sage: g.matching(algorithm="LP", value_only=True)
˓→# needs sage.numerical.mip
9>>> from sage.all import *>>> g = graphs.PappusGraph()>>> g.matching(algorithm="LP", value_only=True)
˓→needs sage.numerical.mip
9

#␣

0
6
1

5
7

8

12

11

13

17

14

16
15

10

2

4
9
3

matching_polynomial(G, complement=True, name=None)
Computes the matching polynomial of the graph 𝐺.
If 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings (matchings with 𝑘 edges) in 𝐺, then the matching polynomial

608

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

is defined as [God1993]:
𝜇(𝑥) =∑︁(−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘𝑘≥0INPUT:• complement – (default: True) whether to use Godsil’s duality theorem to compute the matching
polynomial from that of the graphs complement (see ALGORITHM).
• name – optional string for the variable name in the polynomial
Note: The complement option uses matching polynomials of complete graphs, which are cached. So
if you are crazy enough to try computing the matching polynomial on a graph with millions of vertices, you
might not want to use this option, since it will end up caching millions of polynomials of degree in the millions.
ALGORITHM:
The algorithm used is a recursive one, based on the following observation [God1993]:• If 𝑒 is an edge of 𝐺, 𝐺′ is the result of deleting the edge 𝑒, and 𝐺′′ is the result of deleting each vertex
in 𝑒, then the matching polynomial of 𝐺 is equal to that of 𝐺′ minus that of 𝐺′′ .
(the algorithm actually computes the signless matching polynomial, for which the recursion is the same
when one replaces the subtraction by an addition. It is then converted into the matching polynomial andreturned)
Depending on the value of complement, Godsil’s duality theorem [God1993] can also be used to compute
𝜇(𝑥) :∑︁𝜇(𝐺, 𝑥) =𝑝(𝐺, 𝑘)𝜇(𝐾𝑛−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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.matching_polynomial()x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6>>> g.matching_polynomial(complement=False)x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6>>> g.matching_polynomial(name= tom )tom^10 - 15*tom^8 + 75*tom^6 - 145*tom^4 + 90*tom^2 - 6(continues on next page)1.2. Undirected graphs609

Graph Theory, Release 10.4

(continued from previous page)>>> g = Graph()>>> L = [graphs.RandomGNP(Integer(8), RealNumber( .3 )) for i in␣
˓→range(Integer(1), Integer(6))]>>> 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))>>> from sage.all import *>>> for i in range(Integer(1), Integer(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))
1sage: matching_polynomial(graphs.CompleteGraph(1))
xsage: 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 - 15sage: 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

610

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.matchpoly import matching_polynomial>>> matching_polynomial(graphs.CompleteGraph(Integer(0)))
1>>> matching_polynomial(graphs.CompleteGraph(Integer(1)))
x>>> matching_polynomial(graphs.CompleteGraph(Integer(2)))
x^2 - 1>>> matching_polynomial(graphs.CompleteGraph(Integer(3)))
x^3 - 3*x>>> matching_polynomial(graphs.CompleteGraph(Integer(4)))
x^4 - 6*x^2 + 3>>> matching_polynomial(graphs.CompleteGraph(Integer(5)))
x^5 - 10*x^3 + 15*x>>> matching_polynomial(graphs.CompleteGraph(Integer(6)))
x^6 - 15*x^4 + 45*x^2 - 15>>> matching_polynomial(graphs.CompleteGraph(Integer(7)))
x^7 - 21*x^5 + 105*x^3 - 105*x>>> matching_polynomial(graphs.CompleteGraph(Integer(8)))
x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105>>> matching_polynomial(graphs.CompleteGraph(Integer(9)))
x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x>>> matching_polynomial(graphs.CompleteGraph(Integer(10)))x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945>>> matching_polynomial(graphs.CompleteGraph(Integer(11)))x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x>>> matching_polynomial(graphs.CompleteGraph(Integer(12)))x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395>>> matching_polynomial(graphs.CompleteGraph(Integer(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 - xsage: G = Graph({0:[], 1:[], 2:[]})
sage: matching_polynomial(G)x^3>>> from sage.all import *>>> G = Graph({Integer(0):[Integer(1),Integer(2)], Integer(1):[Integer(2)]})>>> matching_polynomial(G)x^3 - 3*x>>> G = Graph({Integer(0):[Integer(1),Integer(2)]})>>> matching_polynomial(G)x^3 - 2*x>>> G = Graph({Integer(0):[Integer(1)], Integer(2):[]})>>> matching_polynomial(G)x^3 - x>>> G = Graph({Integer(0):[], Integer(1):[], Integer(2):[]})>>> matching_polynomial(G)x^31.2. Undirected graphs611

Graph Theory, Release 10.4

sage: matching_polynomial(graphs.CompleteGraph(0), complement=False)1
sage: matching_polynomial(graphs.CompleteGraph(1), complement=False)xsage: 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 - 15sage: 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>>> from sage.all import *>>> matching_polynomial(graphs.CompleteGraph(Integer(0)), complement=False)1>>> matching_polynomial(graphs.CompleteGraph(Integer(1)), complement=False)x>>> matching_polynomial(graphs.CompleteGraph(Integer(2)), complement=False)x^2 - 1>>> matching_polynomial(graphs.CompleteGraph(Integer(3)), complement=False)x^3 - 3*x>>> matching_polynomial(graphs.CompleteGraph(Integer(4)), complement=False)x^4 - 6*x^2 + 3>>> matching_polynomial(graphs.CompleteGraph(Integer(5)), complement=False)x^5 - 10*x^3 + 15*x>>> matching_polynomial(graphs.CompleteGraph(Integer(6)), complement=False)x^6 - 15*x^4 + 45*x^2 - 15>>> matching_polynomial(graphs.CompleteGraph(Integer(7)), complement=False)x^7 - 21*x^5 + 105*x^3 - 105*x>>> matching_polynomial(graphs.CompleteGraph(Integer(8)), complement=False)x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105>>> matching_polynomial(graphs.CompleteGraph(Integer(9)), complement=False)x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x>>> matching_polynomial(graphs.CompleteGraph(Integer(10)), complement=False)x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945>>> matching_polynomial(graphs.CompleteGraph(Integer(11)), complement=False)x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x>>> matching_polynomial(graphs.CompleteGraph(Integer(12)), complement=False)x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395>>> matching_polynomial(graphs.CompleteGraph(Integer(13)), complement=False)(continues on next page)

612

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)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 degreeof 𝐺.
This can be computed in polynomial time.
INPUT:• value_only – boolean (default: True);– 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 solveof 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()
˓→needs sage.numerical.mip
sage: g.average_degree() <= mad_g
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(20),RealNumber( .3 ))>>> mad_g = g.maximum_average_degree()
˓→needs sage.numerical.mip>>> g.average_degree() <= mad_g
˓→needs sage.numerical.mip
True

#␣
#␣

#␣
#␣

Unlike the average degree, the 𝑀 𝑎𝑑 of the disjoint union of two graphs is the maximum of the 𝑀 𝑎𝑑 of eachgraphs:sage: h = graphs.RandomGNP(20,.3)
sage: mad_h = h.maximum_average_degree()
˓→needs sage.numerical.mip
sage: (g+h).maximum_average_degree() == max(mad_g, mad_h)
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> h = graphs.RandomGNP(Integer(20),RealNumber( .3 ))>>> mad_h = h.maximum_average_degree()
˓→needs sage.numerical.mip>>> (g+h).maximum_average_degree() == max(mad_g, mad_h)

#␣
#␣

#␣
#␣
(continues on next page)1.2. Undirected graphs613

Graph Theory, Release 10.4

(continued from previous page)needs sage.numerical.mip
True˓→The subgraph of a regular graph realizing the maximum average degree is always the whole graphsage: g = graphs.CompleteGraph(5)sage: mad_g = g.maximum_average_degree(value_only=False)
˓→needs sage.numerical.mip
sage: g.is_isomorphic(mad_g)
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> mad_g = g.maximum_average_degree(value_only=False)
˓→needs sage.numerical.mip>>> g.is_isomorphic(mad_g)
˓→needs sage.numerical.mip
True

#␣
#␣

#␣
#␣

This also works for complete bipartite graphs
sage: g = graphs.CompleteBipartiteGraph(3,4)
sage: mad_g = g.maximum_average_degree(value_only=False)
˓→needs sage.numerical.mip
sage: g.is_isomorphic(mad_g)
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.CompleteBipartiteGraph(Integer(3),Integer(4))>>> mad_g = g.maximum_average_degree(value_only=False)
˓→needs sage.numerical.mip>>> g.is_isomorphic(mad_g)
˓→needs sage.numerical.mip
True

#␣
#␣

#␣
#␣

maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None)
Return an ordering of the vertices according a maximum cardinality search.
Maximum cardinality search (MCS) is a graph traversal introduced in [TY1984]. It starts by assigning an
arbitrary vertex (or the specified initial_vertex) of 𝐺 the last position in the ordering 𝛼. Every vertex
keeps a weight equal to the number of its already processed neighbors (i.e., already added to 𝛼), and a vertexof largest such number is chosen at each step 𝑖 to be placed in position 𝑛 − 𝑖 in 𝛼. This ordering can becomputed in time 𝑂(𝑛 + 𝑚).
Time complexity is 𝑂(𝑛 + 𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number ofvertices and 𝑚 is the number of edges.
When the graph is chordal, the ordering returned by MCS is a perfect elimination ordering, like lex_BFS().
So this ordering can be used to recognize chordal graphs. See [He2006] for more details.
Note: The current implementation is for connected graphs only.
INPUT:
614

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• G – a Sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to also return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider
OUTPUT:
By default, return the ordering 𝛼 as a list. When tree is True, the method returns a tuple (𝛼, 𝑇 ), where 𝑇
is a directed tree with the same set of vertices as 𝐺 and a directed edge from 𝑢 to 𝑣 if 𝑢 was the first vertex
to see 𝑣.
EXAMPLES:
When specified, the initial_vertex is placed at the end of the ordering, unless parameter reverse
is True, in which case it is placed at the beginning:sage: G = graphs.PathGraph(4)sage: G.maximum_cardinality_search(initial_vertex=0)[3, 2, 1, 0]
sage: G.maximum_cardinality_search(initial_vertex=1)[0, 3, 2, 1]
sage: G.maximum_cardinality_search(initial_vertex=2)[0, 1, 3, 2]
sage: G.maximum_cardinality_search(initial_vertex=3)[0, 1, 2, 3]
sage: G.maximum_cardinality_search(initial_vertex=3, reverse=True)[3, 2, 1, 0]>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.maximum_cardinality_search(initial_vertex=Integer(0))[3, 2, 1, 0]>>> G.maximum_cardinality_search(initial_vertex=Integer(1))[0, 3, 2, 1]>>> G.maximum_cardinality_search(initial_vertex=Integer(2))[0, 1, 3, 2]>>> G.maximum_cardinality_search(initial_vertex=Integer(3))[0, 1, 2, 3]>>> G.maximum_cardinality_search(initial_vertex=Integer(3), reverse=True)[3, 2, 1, 0]

Returning the discovery tree:
sage: G = graphs.PathGraph(4)sage: _, T = G.maximum_cardinality_search(tree=True, initial_vertex=0)
sage: T.order(), T.size()(4, 3)
sage: T.edges(labels=False, sort=True)[(1, 0), (2, 1), (3, 2)]
sage: _, T = G.maximum_cardinality_search(tree=True, initial_vertex=3)
sage: T.edges(labels=False, sort=True)[(0, 1), (1, 2), (2, 3)]>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))(continues on next page)1.2. Undirected graphs615

Graph Theory, Release 10.4

(continued from previous page)>>> _, T = G.maximum_cardinality_search(tree=True, initial_vertex=Integer(0))>>> T.order(), T.size()(4, 3)>>> T.edges(labels=False, sort=True)[(1, 0), (2, 1), (3, 2)]>>> _, T = G.maximum_cardinality_search(tree=True, initial_vertex=Integer(3))>>> T.edges(labels=False, sort=True)[(0, 1), (1, 2), (2, 3)]maximum_cardinality_search_M(G, initial_vertex=None)
Return the ordering and the edges of the triangulation produced by MCS-M.
Maximum cardinality search M (MCS-M) is an extension of MCS (maximum_cardinality_search()) in the same way that Lex-M (lex_M()) is an extension of Lex-BFS (lex_BFS()).
That is, in MCS-M when 𝑢 receives number 𝑖 at step 𝑛 − 𝑖 + 1, it increments the weight of all unnumberedvertices 𝑣 for which there exists a path between 𝑢 and 𝑣 consisting only of unnumbered vertices with weightstrictly less than 𝑤− (𝑢) and 𝑤− (𝑣), where 𝑤− is the number of times a vertex has been reached during
previous iterations. See [BBHP2004] for the details of this 𝑂(𝑛𝑚) time algorithm.
If 𝐺 is not connected, the orderings of each of its connected components are added consecutively. Furthermore, if 𝐺 has 𝑘 connected components 𝐶𝑖 for 0 ≤ 𝑖 < 𝑘, 𝑋 contains at least one vertex of 𝐶𝑖 for each𝑖 ≥ 1. Hence, |𝑋| ≥ 𝑘 − 1. In particular, some isolated vertices (i.e., of degree 0) can appear in 𝑋 as forsuch a vertex 𝑥, we have that 𝐺 ∖ 𝑁 (𝑥) = 𝐺 is not connected.
INPUT:• G – a Sage graph• initial_vertex – (default: None); the first vertex to consider
OUTPUT: a tuple (𝛼, 𝐹, 𝑋), where• 𝛼 is the resulting ordering of the vertices. If an initial vertex is specified, it gets the last position in theordering 𝛼.
• 𝐹 is the list of edges of a minimal triangulation of 𝐺 according 𝛼• 𝑋 is a list of vertices such that for each 𝑥 ∈ 𝑋, the neighborhood of 𝑥 in 𝐺 is a separator (i.e., 𝐺 ∖ 𝑁 (𝑥)is not connected). Note that we may have 𝑁 (𝑥) = ∅ if 𝐺 is not connected and 𝑥 has degree 0.
EXAMPLES:
Chordal graphs have a perfect elimination ordering, and so the set 𝐹 of edges of the triangulation is empty:
sage: G = graphs.RandomChordalGraph(20)sage: alpha, F, X = G.maximum_cardinality_search_M(); F[]>>> from sage.all import *>>> G = graphs.RandomChordalGraph(Integer(20))>>> alpha, F, X = G.maximum_cardinality_search_M(); F[]

The cycle of order 4 is not chordal and so the triangulation has one edge:
sage: G = graphs.CycleGraph(4)sage: alpha, F, X = G.maximum_cardinality_search_M(); len(F)1616

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> alpha, F, X = G.maximum_cardinality_search_M(); len(F)1

The number of edges needed to triangulate of a cycle graph or order 𝑛 is 𝑛 − 3, independently of the initialvertex:sage: n = randint(3, 20)
sage: C = graphs.CycleGraph(n)sage: _, F, X = C.maximum_cardinality_search_M()
sage: len(F) == n - 3
True
sage: _, F, X = C.maximum_cardinality_search_M(initial_vertex=C.random_
˓→vertex())
sage: len(F) == n - 3
True>>> from sage.all import *>>> n = randint(Integer(3), Integer(20))>>> C = graphs.CycleGraph(n)>>> _, F, X = C.maximum_cardinality_search_M()>>> len(F) == n - Integer(3)True>>> _, F, X = C.maximum_cardinality_search_M(initial_vertex=C.random_vertex())>>> len(F) == n - Integer(3)TrueWhen an initial vertex is specified, it gets the last position in the ordering:sage: G = graphs.PathGraph(4)sage: G.maximum_cardinality_search_M(initial_vertex=0)([3, 2, 1, 0], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=1)([3, 2, 0, 1], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=2)([0, 1, 3, 2], [], [0, 1])
sage: G.maximum_cardinality_search_M(initial_vertex=3)([0, 1, 2, 3], [], [0, 1])>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.maximum_cardinality_search_M(initial_vertex=Integer(0))([3, 2, 1, 0], [], [2, 3])>>> G.maximum_cardinality_search_M(initial_vertex=Integer(1))([3, 2, 0, 1], [], [2, 3])>>> G.maximum_cardinality_search_M(initial_vertex=Integer(2))([0, 1, 3, 2], [], [0, 1])>>> G.maximum_cardinality_search_M(initial_vertex=Integer(3))([0, 1, 2, 3], [], [0, 1])

When 𝐺 is not connected, the orderings of each of its connected components are added consecutively, thevertices of the component containing the initial vertex occupying the last positions:sage: G = graphs.CycleGraph(4) * 2
sage: G.maximum_cardinality_search_M()[0](continues on next page)1.2. Undirected graphs

617

Graph Theory, Release 10.4

(continued from previous page)[5, 4, 6, 7, 2, 3, 1, 0]
sage: G.maximum_cardinality_search_M(initial_vertex=7)[0][2, 1, 3, 0, 5, 6, 4, 7]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4)) * Integer(2)>>> G.maximum_cardinality_search_M()[Integer(0)][5, 4, 6, 7, 2, 3, 1, 0]>>> G.maximum_cardinality_search_M(initial_vertex=Integer(7))[Integer(0)][2, 1, 3, 0, 5, 6, 4, 7]

Furthermore, if 𝐺 has 𝑘 connected components, 𝑋 contains at least one vertex per connected component,
except for the first one, and so at least 𝑘 − 1 vertices:sage: for k in range(1, 5):....:_, _, X = Graph(k).maximum_cardinality_search_M()....:
if len(X) < k - 1:....:
raise ValueError("something goes wrong")
sage: G = graphs.RandomGNP(10, .2)
sage: cc = G.connected_components(sort=False)
sage: _, _, X = G.maximum_cardinality_search_M()
sage: len(X) >= len(cc) - 1
True>>> from sage.all import *>>> for k in range(Integer(1), Integer(5)):...
_, _, X = Graph(k).maximum_cardinality_search_M()...
if len(X) < k - Integer(1):...
raise ValueError("something goes wrong")>>> G = graphs.RandomGNP(Integer(10), RealNumber( .2 ))>>> cc = G.connected_components(sort=False)>>> _, _, X = G.maximum_cardinality_search_M()>>> len(X) >= len(cc) - Integer(1)True

In the example of [BPS2010], the triangulation has 3 edges:
sage: G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],....:d : [ e , f , j , k ], e : [ g ],....:f : [ g , j , k ], g : [ j , k ], h : [ i , j ],....:i : [ k ], j : [ k ]})sage: _, F, _ = G.maximum_cardinality_search_M(initial_vertex= a )sage: len(F)3>>> from sage.all import *>>> G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],...
d : [ e , f , j , k ], e : [ g ],...
f : [ g , j , k ], g : [ j , k ], h : [ i , j ],...
i : [ k ], j : [ k ]})>>> _, F, _ = G.maximum_cardinality_search_M(initial_vertex= a )>>> len(F)3minimal_dominating_sets(G, to_dominate=None, work_on_copy=True, k=1)
Return an iterator over the minimal dominating sets of a graph.
618

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

INPUT:• G – a graph.
• to_dominate – vertex iterable or None (default: None); the set of vertices to be dominated.
• work_on_copy – boolean (default: True); whether or not to work on a copy of the input graph; if
set to False, the input graph will be modified (relabeled).
• k – a non-negative integer (default: 1); the domination distance
OUTPUT:
An iterator over the inclusion-minimal sets of vertices of G. If to_dominate is provided, return an iterator
over the inclusion-minimal sets of vertices that dominate the vertices of to_dominate.
ALGORITHM: The algorithm described in [BDHPR2019].
AUTHOR: Jean-Florent Raymond (2019-03-04) – initial version.
EXAMPLES:
sage: G = graphs.ButterflyGraph()
sage: ll = list(G.minimal_dominating_sets())
sage: pp = [{0, 1}, {1, 3}, {0, 2}, {2, 3}, {4}]sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x␣˓→in pp)True
sage: ll = list(G.minimal_dominating_sets([0,3]))
sage: pp = [{0}, {3}, {4}]sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x␣˓→in pp)True
sage: ll = list(G.minimal_dominating_sets([4]))sage: pp = [{4}, {0}, {1}, {2}, {3}]sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x␣˓→in pp)True>>> from sage.all import *>>> G = graphs.ButterflyGraph()>>> ll = list(G.minimal_dominating_sets())>>> pp = [{Integer(0), Integer(1)}, {Integer(1), Integer(3)}, {Integer(0),␣
˓→Integer(2)}, {Integer(2), Integer(3)}, {Integer(4)}]>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in␣
˓→pp)
True
>>> ll = list(G.minimal_dominating_sets([Integer(0),Integer(3)]))>>> pp = [{Integer(0)}, {Integer(3)}, {Integer(4)}]>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in␣
˓→pp)
True
>>> ll = list(G.minimal_dominating_sets([Integer(4)]))>>> pp = [{Integer(4)}, {Integer(0)}, {Integer(1)}, {Integer(2)}, {Integer(3)}˓→]>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in␣(continues on next page)1.2. Undirected graphs619

Graph Theory, Release 10.4

(continued from previous page)

pp)
True
˓→

sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets())
sage: pp = [{0, 2, 6},....:{0, 9, 3},....:{0, 8, 7},....:{1, 3, 7},....:{1, 4, 5},....:{8, 1, 9},....:{8, 2, 4},....:{9, 2, 5},....:{3, 5, 6},....:{4, 6, 7},....:{0, 8, 2, 9},....:{0, 3, 6, 7},....:{1, 3, 5, 9},....:{8, 1, 4, 7},....:{2, 4, 5, 6},....:{0, 1, 2, 3, 4},....:{0, 1, 2, 5, 7},....:{0, 1, 4, 6, 9},....:{0, 1, 5, 6, 8},....:{0, 8, 3, 4, 5},....:{0, 9, 4, 5, 7},....:{8, 1, 2, 3, 6},....:{1, 2, 9, 6, 7},....:{9, 2, 3, 4, 7},....:{8, 2, 3, 5, 7},....:{8, 9, 3, 4, 6},....:{8, 9, 5, 6, 7}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x␣˓→in pp)True>>> from sage.all import *>>> ll = list(graphs.PetersenGraph().minimal_dominating_sets())>>> pp = [{Integer(0), Integer(2), Integer(6)},...
{Integer(0), Integer(9), Integer(3)},...
{Integer(0), Integer(8), Integer(7)},...
{Integer(1), Integer(3), Integer(7)},...
{Integer(1), Integer(4), Integer(5)},...
{Integer(8), Integer(1), Integer(9)},...
{Integer(8), Integer(2), Integer(4)},...
{Integer(9), Integer(2), Integer(5)},...
{Integer(3), Integer(5), Integer(6)},...
{Integer(4), Integer(6), Integer(7)},...
{Integer(0), Integer(8), Integer(2), Integer(9)},...
{Integer(0), Integer(3), Integer(6), Integer(7)},...
{Integer(1), Integer(3), Integer(5), Integer(9)},...
{Integer(8), Integer(1), Integer(4), Integer(7)},...
{Integer(2), Integer(4), Integer(5), Integer(6)},...
{Integer(0), Integer(1), Integer(2), Integer(3), Integer(4)},...
{Integer(0), Integer(1), Integer(2), Integer(5), Integer(7)},...
{Integer(0), Integer(1), Integer(4), Integer(6), Integer(9)},...
{Integer(0), Integer(1), Integer(5), Integer(6), Integer(8)},(continues on next page)

620

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)...
{Integer(0), Integer(8), Integer(3), Integer(4), Integer(5)},...
{Integer(0), Integer(9), Integer(4), Integer(5), Integer(7)},...
{Integer(8), Integer(1), Integer(2), Integer(3), Integer(6)},...
{Integer(1), Integer(2), Integer(9), Integer(6), Integer(7)},...
{Integer(9), Integer(2), Integer(3), Integer(4), Integer(7)},...
{Integer(8), Integer(2), Integer(3), Integer(5), Integer(7)},...
{Integer(8), Integer(9), Integer(3), Integer(4), Integer(6)},...
{Integer(8), Integer(9), Integer(5), Integer(6), Integer(7)}]>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in␣
˓→pp)
True

Listing minimal distance-𝑘 dominating sets:
sage: G = graphs.Grid2dGraph(2, 3)
sage: list(G.minimal_dominating_sets(k=0))[{(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)}]sage: list(G.minimal_dominating_sets(k=1))[{(0, 0), (0, 2), (1, 1)},{(0, 1), (1, 1)},{(0, 0), (0, 1), (0, 2)},{(0, 2), (1, 0)},{(0, 0), (1, 2)},{(0, 1), (1, 0), (1, 2)},{(1, 0), (1, 1), (1, 2)}]sage: list(G.minimal_dominating_sets(k=2))[{(0, 0), (1, 2)},{(0, 2), (1, 2)},{(1, 0), (1, 2)},{(0, 1)},{(0, 0), (0, 2)},{(0, 2), (1, 0)},{(0, 0), (1, 0)},{(1, 1)}]
sage: list(G.minimal_dominating_sets(k=3))[{(0, 0)}, {(0, 1)}, {(0, 2)}, {(1, 0)}, {(1, 1)}, {(1, 2)}]>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(2), Integer(3))>>> list(G.minimal_dominating_sets(k=Integer(0)))[{(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)}]>>> list(G.minimal_dominating_sets(k=Integer(1)))[{(0, 0), (0, 2), (1, 1)},{(0, 1), (1, 1)},{(0, 0), (0, 1), (0, 2)},{(0, 2), (1, 0)},{(0, 0), (1, 2)},{(0, 1), (1, 0), (1, 2)},{(1, 0), (1, 1), (1, 2)}]>>> list(G.minimal_dominating_sets(k=Integer(2)))[{(0, 0), (1, 2)},{(0, 2), (1, 2)},{(1, 0), (1, 2)},{(0, 1)},{(0, 0), (0, 2)},{(0, 2), (1, 0)},(continues on next page)1.2. Undirected graphs621

Graph Theory, Release 10.4

(continued from previous page){(0, 0), (1, 0)},{(1, 1)}]>>> list(G.minimal_dominating_sets(k=Integer(3)))[{(0, 0)}, {(0, 1)}, {(0, 2)}, {(1, 0)}, {(1, 1)}, {(1, 2)}]

When parameter work_on_copy is False, the input graph is modified (relabeled):
sage: G = Graph([( A , B )])sage: _ = list(G.minimal_dominating_sets(work_on_copy=True))sage: set(G) == { A , B }True
sage: _ = list(G.minimal_dominating_sets(work_on_copy=False))
sage: set(G) == { A , B }False
sage: set(G) == {0, 1}
True>>> from sage.all import *>>> G = Graph([( A , B )])>>> _ = list(G.minimal_dominating_sets(work_on_copy=True))>>> set(G) == { A , B }True>>> _ = list(G.minimal_dominating_sets(work_on_copy=False))>>> set(G) == { A , B }False>>> set(G) == {Integer(0), Integer(1)}Trueminimum_outdegree_orientation(use_edge_labels, solver=False, verbose=None,
integrality_tolerance=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 [AMOZ2006].
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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
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()

⌈︁

𝑛𝑚
𝑛+𝑚

⌉︁
:
#␣

(continues on next page)

622

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.numerical.mip
sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4))
˓→needs sage.numerical.mip
True
˓→

#␣

>>> from sage.all import *>>> g = graphs.CompleteBipartiteGraph(Integer(3),Integer(4))>>> o = g.minimum_outdegree_orientation()#␣˓→needs sage.numerical.mip>>> max(o.out_degree()) == integer_ceil((Integer(4)*Integer(3))/˓→(Integer(3)+Integer(4)))# needs sage.numerical.mip
Trueminor(H, solver, verbose=None, induced=0, integrality_tolerance=False)
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 newgraph 𝐺′ , this new graph contains 𝐻 as a subgraph.
When parameter induced is True, this method returns an induced minor isomorphic to 𝐻, if it exists.
We say that a graph 𝐺 has an induced 𝐻-minor (or that it has a graph isomorphic to 𝐻 as an induced minor),if 𝐻 can be obtained from an induced subgraph of 𝐺 by contracting edges. Otherwise, 𝐺 is said to be
𝐻-induced minor-free.
For more information, see the Wikipedia article Minor_(graph_theory).
INPUT:• H – The minor to find for in the current graph.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
• induced – boolean (default: False); if True, returns an induced minor isomorphic to 𝐻 if it exists,and raises a ValueError otherwise.
OUTPUT:
A dictionary associating to each vertex of 𝐻 the set of vertices in the current graph representing it.
ALGORITHM:
Mixed Integer Linear Programming
COMPLEXITY:
Theoretically, when 𝐻 is fixed, testing for the existence of a 𝐻-minor is polynomial. The known algorithms
are highly exponential in 𝐻, though.
Note: This function can be expected to be very slow, especially where the minor does not exist.
EXAMPLES:

1.2. Undirected graphs623

Graph Theory, Release 10.4

Trying to find a minor isomorphic to 𝐾4 in the 4 × 4 grid:
sage: # needs sage.numerical.mip
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>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = graphs.GridGraph([Integer(4),Integer(4)])>>> h = graphs.CompleteGraph(Integer(4))>>> L = g.minor(h)>>> gg = g.subgraph(flatten(L.values(), max_level = Integer(1)))>>> _ = [gg.merge_vertices(l) for l in L.values() if len(l)>Integer(1)]>>> 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))˓→needs sage.numerical.mip# long time>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> K5_minor = g.minor(graphs.CompleteGraph(Integer(5)))˓→# needs sage.numerical.mip#␣# long time␣And even a 𝐾3,3 minor:
sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3))
˓→time, needs sage.numerical.mip# long␣

>>> from sage.all import *>>> K33_minor = g.minor(graphs.CompleteBipartiteGraph(Integer(3),Integer(3)))␣
˓→# long time, needs sage.numerical.mip(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 thiscase: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))˓→needs sage.numerical.mip
Traceback (most recent call last):...
ValueError: This graph has no minor isomorphic to H !

624

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(20), RealNumber( .5 ))>>> g = g.subgraph(edges=g.min_spanning_tree())>>> g.is_tree()True>>> L = g.minor(graphs.CompleteGraph(Integer(3)))˓→# needs sage.numerical.mip
Traceback (most recent call last):...
ValueError: This graph has no minor isomorphic to H !

␣Trying to find an induced minor isomorphic to 𝐶5 in a graph containing an induced 𝐶6 :sage: g = graphs.CycleGraph(6)sage: for i in range(randint(10, 30)):....:g.add_edge(randint(0, 5), g.add_vertex())
sage: h = graphs.CycleGraph(5)sage: L = g.minor(h, induced=True)
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>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6))>>> for i in range(randint(Integer(10), Integer(30))):...
g.add_edge(randint(Integer(0), Integer(5)), g.add_vertex())>>> h = graphs.CycleGraph(Integer(5))>>> L = g.minor(h, induced=True)>>> gg = g.subgraph(flatten(L.values(), max_level=Integer(1)))>>> _ = [gg.merge_vertices(l) for l in L.values() if len(l) > Integer(1)]>>> gg.is_isomorphic(h)Truemodular_decomposition(algorithm=None, style='tuple')
Return the modular decomposition of the current graph.
A module of an undirected graph is a subset of vertices such that every vertex outside the module is either
connected to all members of the module or to none of them. Every graph that has a nontrivial module can bepartitioned into modules, and the increasingly fine partitions into modules form a tree. The modular_decomposition function returns that tree, using an 𝑂(𝑛3 ) algorithm of [HM1979].
INPUT:• style – string (default: tuple ); specifies the output format:–

tuple – as nested tuples.

–

tree – as LabelledRootedTree.

OUTPUT:
A pair of two values (recursively encoding the decomposition) :• The type of the current module :– "PARALLEL"– "PRIME"– "SERIES"
1.2. Undirected graphs625

Graph Theory, Release 10.4

• The list of submodules (as list of pairs (type, list), recursively…) or the vertex’s name if themodule is a singleton.
Crash course on modular decomposition:
A module 𝑀 of a graph 𝐺 is a proper subset of its vertices such that for all 𝑢 ∈ 𝑉 (𝐺) − 𝑀, 𝑣, 𝑤 ∈ 𝑀 therelation 𝑢 ∼ 𝑣 ⇔ 𝑢 ∼ 𝑤 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 byvertex).
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 containedin the module) is adjacent to 𝑢. We can now independently (and recursively) study the structure of our module
𝑀 and the new graph 𝐺 − 𝑀 + {𝑣𝑀 }, without any loss of information.
Here are two very simple modules :• A connected component 𝐶 (or the union of some –but not all– of them) of a disconnected graph 𝐺, forinstance, 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 a non-anticonnected graph 𝐺, forthe 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 thecomplement of a disjoint union is called a Series composition. A graph whose only modules are singletons iscalled Prime.
For more information on modular decomposition, in particular for an explanation of the terms “Parallel,”“Prime” and “Series,” see the Wikipedia article Modular_decomposition.
You may also be interested in the survey from Michel Habib and Christophe Paul entitled “A survey on
Algorithmic aspects of modular decomposition” [HP2010].
EXAMPLES:
The Bull Graph is prime:
sage: graphs.BullGraph().modular_decomposition()(PRIME, [1, 2, 0, 3, 4])>>> from sage.all import *>>> graphs.BullGraph().modular_decomposition()(PRIME, [1, 2, 0, 3, 4])

The Petersen Graph too:sage: graphs.PetersenGraph().modular_decomposition()(PRIME, [1, 4, 5, 0, 2, 6, 3, 7, 8, 9])>>> from sage.all import *>>> graphs.PetersenGraph().modular_decomposition()(PRIME, [1, 4, 5, 0, 2, 6, 3, 7, 8, 9])This a clique on 5 vertices with 2 pendant edges, though, has a more interesting decomposition:
sage: g = graphs.CompleteGraph(5)sage: g.add_edge(0,5)
sage: g.add_edge(0,6)(continues on next page)

626

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: g.modular_decomposition()(SERIES, [(PARALLEL, [(SERIES, [1, 2, 3, 4]), 5, 6]), 0])>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> g.add_edge(Integer(0),Integer(5))>>> g.add_edge(Integer(0),Integer(6))>>> g.modular_decomposition()(SERIES, [(PARALLEL, [(SERIES, [1, 2, 3, 4]), 5, 6]), 0])We can choose output to be a LabelledRootedTree:sage: g.modular_decomposition(style= tree )SERIES[0[], PARALLEL[5[], 6[], SERIES[1[], 2[], 3[], 4[]]]]
sage: ascii_art(g.modular_decomposition(style= tree ))__SERIES//
0___PARALLEL
/ /
/
5 6
__SERIES/ / / /
1 2 3 4>>> from sage.all import *>>> g.modular_decomposition(style= tree )SERIES[0[], PARALLEL[5[], 6[], SERIES[1[], 2[], 3[], 4[]]]]>>> ascii_art(g.modular_decomposition(style= tree ))__SERIES//
0___PARALLEL
/ /
/
5 6
__SERIES/ / / /
1 2 3 4

ALGORITHM:
This function uses the algorithm of M. Habib and M. Maurer [HM1979].
See also:• is_prime() – Tests whether a graph is prime.
• LabelledRootedTree.
Note: A buggy implementation of linear time algorithm from [TCHP2008] was removed in Sage 9.7, seeIssue #25872.
most_common_neighbors(nonedgesonly=True)
Return vertex pairs with maximal number of common neighbors.
This method is only valid for simple (no loops, no multiple edges) graphs with order ≥ 2
INPUT:• nonedgesonly – boolean (default: True); if True, assigns 0 value to adjacent vertices.
1.2. Undirected graphs

627

Graph Theory, Release 10.4

OUTPUT: list of tuples of edge pairs
EXAMPLES:
The maximum common neighbor (non-adjacent) pairs for a straight linear 2-tree
sage: G1 = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)])
sage: G1.most_common_neighbors()
˓→needs sage.modules[(0, 3), (1, 4), (2, 5)]#␣>>> from sage.all import *>>> G1 = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),˓→Integer(2)),(Integer(1),Integer(3)),(Integer(3),Integer(5)),(Integer(2),˓→Integer(4)),(Integer(2),Integer(3)),(Integer(3),Integer(4)),(Integer(4),˓→Integer(5))])>>> G1.most_common_neighbors()#␣˓→needs sage.modules[(0, 3), (1, 4), (2, 5)]If we include non-adjacent pairs
sage: G1.most_common_neighbors(nonedgesonly=False)
˓→needs sage.modules[(0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4)]>>> from sage.all import *>>> G1.most_common_neighbors(nonedgesonly=False)
˓→needs sage.modules[(0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4)]#␣#␣

The common neighbors matrix for a fan on 6 vertices counting only non-adjacent vertex pairs
sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)])
sage: H.most_common_neighbors()#␣˓→needs sage.modules[(1, 3), (2, 4), (3, 5)]>>> from sage.all import *>>> H = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(0),˓→Integer(3)),(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(0),˓→Integer(6)),(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(4)),(Integer(4),Integer(5))])>>> H.most_common_neighbors()#␣˓→needs sage.modules[(1, 3), (2, 4), (3, 5)]

See also:• common_neighbors_matrix() – a similar method giving a matrix of number of common neighbors
orientations(data_structure=None, sparse=None)
Return an iterator over orientations of self.
An orientation of an undirected graph is a directed graph such that every edge is assigned a direction. Hence
there are 2𝑠 oriented digraphs for a simple graph with 𝑠 edges.

628

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

INPUT:• data_structure – one of "sparse", "static_sparse", or "dense"; see the documentation of Graph or DiGraph; default is the data structure of self
• sparse – boolean (default: None); sparse=True is an alias for data_structure="sparse",
and sparse=False is an alias for data_structure="dense". By default (None), guess themost suitable data structure.
Warning: This always considers multiple edges of graphs as distinguishable, and hence, may haverepeated digraphs.
See also:• strong_orientation()• strong_orientations_iterator()• nauty_directg()• random_orientation()
EXAMPLES:
sage: G = Graph([[1,2,3], [(1, 2,
˓→edges )sage: it = G.orientations()
sage: D = next(it)sage: D.edges(sort=True)[(1, 2, a ), (1, 3, b )]sage: D = next(it)sage: D.edges(sort=True)[(1, 2, a ), (3, 1, b )]a ), (1, 3,b )]], format= vertices_and_>>> from sage.all import *>>> G = Graph([[Integer(1),Integer(2),Integer(3)], [(Integer(1), Integer(2),˓→ a ), (Integer(1), Integer(3),b )]], format= vertices_and_edges )>>> it = G.orientations()>>> D = next(it)>>> D.edges(sort=True)[(1, 2, a ), (1, 3, b )]>>> D = next(it)>>> D.edges(sort=True)[(1, 2, a ), (3, 1, b )]pathwidth(k=None, certificate=False, algorithm='BAB', verbose=False, max_prefix_length=20,
max_prefix_number=1000000, solver=None)
Compute the pathwidth of self (and provides a decomposition)
INPUT:• k – integer (default: None); the width to be considered. When k is an integer, the method checks thatthe graph has pathwidth ≤ 𝑘. If k is None (default), the method computes the optimal pathwidth.
• certificate – boolean (default: False); whether to return the path-decomposition itself• algorithm – string (default: "BAB"); algorithm to use among:

1.2. Undirected graphs629

Graph Theory, Release 10.4

– "BAB" – Use a branch-and-bound algorithm. This algorithm has no size restriction but could takea very long time on large graphs. It can also be used to test is the input graph has pathwidth ≤ 𝑘, inwhich 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 ofgraphs 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 (default: False); whether to display information on the computations• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing
too many prefixes. This parameter is used only when algorithm=="BAB".
• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used
to prevent using too much memory. This parameter is used only when algorithm=="BAB".
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
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: sorted(decomp, key=str)[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}]>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6))>>> g.pathwidth()2>>> pw, decomp = g.pathwidth(certificate=True)>>> sorted(decomp, key=str)[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {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)(continues on next page)

630

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True
sage: g.pathwidth(k=6, certificate=True)(True, Graph on 5 vertices)>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.pathwidth()5>>> g.pathwidth(k=Integer(2))
False>>> g.pathwidth(k=Integer(6))
True>>> g.pathwidth(k=Integer(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 anedge 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: for m in G.perfect_matchings():....:
print(sorted(m))[((0, 0), (0, 1)), ((0, 2), (1, 2)), ((1, 0), (1, 1))][((0, 0), (1, 0)), ((0, 1), (0, 2)), ((1, 1), (1, 2))][((0, 0), (1, 0)), ((0, 1), (1, 1)), ((0, 2), (1, 2))]sage: G = graphs.CompleteGraph(4)sage: for m in G.perfect_matchings(labels=True):....:
print(sorted(m))[(0, 1, None), (2, 3, None)][(0, 2, None), (1, 3, None)][(0, 3, None), (1, 2, None)]sage: G = Graph([[1,-1, a ], [2,-2, b ], [1,-2, x ], [2,-1, y ]])sage: sorted(sorted(m) for m in 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]˓→needs sage.libs.flint
sage: len(list(G.perfect_matchings())) == mpc
˓→needs sage.libs.flint
True

#␣
#␣

(continues on next page)1.2. Undirected graphs631

Graph Theory, Release 10.4

(continued from previous page)

sage: G = graphs.PetersenGraph().copy(immutable=True)
sage: [sorted(m) for m in G.perfect_matchings()][[(0, 1), (2, 3), (4, 9), (5, 7), (6, 8)],[(0, 1), (2, 7), (3, 4), (5, 8), (6, 9)],[(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())[]>>> from sage.all import *>>> G=graphs.GridGraph([Integer(2),Integer(3)])>>> for m in G.perfect_matchings():...
print(sorted(m))[((0, 0), (0, 1)), ((0, 2), (1, 2)), ((1, 0), (1, 1))][((0, 0), (1, 0)), ((0, 1), (0, 2)), ((1, 1), (1, 2))][((0, 0), (1, 0)), ((0, 1), (1, 1)), ((0, 2), (1, 2))]>>> G = graphs.CompleteGraph(Integer(4))>>> for m in G.perfect_matchings(labels=True):...
print(sorted(m))[(0, 1, None), (2, 3, None)][(0, 2, None), (1, 3, None)][(0, 3, None), (1, 2, None)]>>> G = Graph([[Integer(1),-Integer(1), a ], [Integer(2),-Integer(2),˓→[Integer(1),-Integer(2), x ], [Integer(2),-Integer(1), y ]])>>> sorted(sorted(m) for m in G.perfect_matchings(labels=True))[[(-2, 1, x ), (-1, 2, y )], [(-2, 2, b ), (-1, 1, a )]]b ],␣>>> G = graphs.CompleteGraph(Integer(8))>>> mpc = G.matching_polynomial().coefficients(sparse=False)[Integer(0)]˓→# needs sage.libs.flint>>> len(list(G.perfect_matchings())) == mpc
˓→needs sage.libs.flint
True

␣
#␣

>>> G = graphs.PetersenGraph().copy(immutable=True)>>> [sorted(m) for m in G.perfect_matchings()][[(0, 1), (2, 3), (4, 9), (5, 7), (6, 8)],[(0, 1), (2, 7), (3, 4), (5, 8), (6, 9)],[(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)]]>>> list(Graph().perfect_matchings())[[]](continues on next page)

632

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphs.CompleteGraph(Integer(5))>>> list(G.perfect_matchings())[]

periphery(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the set of vertices in the periphery of the graph.
The periphery is the set of vertices whose eccentricity is equal to the diameter of the graph, i.e., achieving
the maximum eccentricity.
For more information and examples on how to use input variables, see shortest_paths() and eccentricity()
INPUT:• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); see method eccentricity() for the list of available algorithms• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:
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()0sage: G.periphery()[0]>>> from sage.all import *>>> G = graphs.DiamondGraph()>>> G.periphery()[0, 3]>>> P = graphs.PetersenGraph()>>> P.subgraph(P.periphery()) == P
True>>> S = graphs.StarGraph(Integer(19))>>> S.periphery()[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]>>> G = Graph()(continues on next page)1.2. Undirected graphs633

Graph Theory, Release 10.4

(continued from previous page)>>> G.periphery()[]>>> G.add_vertex()0>>> G.periphery()[0]

private_neighbors(G, vertex, dom)
Return the private neighbors of a vertex with respect to other vertices.
A private neighbor of a vertex 𝑣 with respect to a vertex subset 𝐷 is a closed neighbor of 𝑣 that is not dominatedby a vertex of 𝐷 ∖ {𝑣}.
INPUT:• vertex – a vertex of G.
• dom – iterable of vertices of G; the vertices possibly stealing private neighbors from vertex.
OUTPUT:
Return the closed neighbors of vertex that are not closed neighbors of any other vertex of dom.
EXAMPLES:
sage: g = graphs.PathGraph(5)sage: list(g.private_neighbors(1, [1, 3, 4]))
[1, 0]
sage: list(g.private_neighbors(1, [3, 4]))
[1, 0]
sage: list(g.private_neighbors(1, [3, 4, 0]))[]>>> from sage.all import *>>> g = graphs.PathGraph(Integer(5))>>> list(g.private_neighbors(Integer(1), [Integer(1), Integer(3),␣
˓→Integer(4)]))[1, 0]>>> list(g.private_neighbors(Integer(1), [Integer(3), Integer(4)]))[1, 0]>>> list(g.private_neighbors(Integer(1), [Integer(3), Integer(4),␣
˓→Integer(0)]))[]radius(by_weight=False, algorithm='DHV', weight_function=None, check_weight=True)
Return the radius of the 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 – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1

634

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• algorithm – string (default: DHV ).
–DHV – Radius computation is done using the algorithm proposed in [Dragan2018]. Works
for graph with non-negative edge weights. For more information see method sage.graphs.
distances_all_pairs.radius_DHV() and sage.graphs.base.boost_graph.
radius_DHV().

– see method eccentricity() for the list of remaining algorithms• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:
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>>> from sage.all import *>>> G = graphs.BarbellGraph(Integer(9), Integer(3))>>> G.radius()
3>>> G.diameter()6
sage: G = graphs.OctahedralGraph()
sage: G.radius()
2
sage: G.diameter()2>>> from sage.all import *>>> G = graphs.OctahedralGraph()>>> G.radius()
2>>> G.diameter()2

random_orientation(G)Return a random orientation of a graph 𝐺.
An orientation of an undirected graph is a directed graph such that every edge is assigned a direction. Hence
there are 2𝑚 oriented digraphs for a simple graph with 𝑚 edges.
INPUT:• G – a Graph.
EXAMPLES:

1.2. Undirected graphs635

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> from sage.graphs.orientations import random_orientation>>> G = graphs.PetersenGraph()>>> D = random_orientation(G)>>> D.order() == G.order(), D.size() == G.size()(True, True)

See also:• orientations()• strong_orientation()• strong_orientations_iterator()• nauty_directg()
random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_function=None,check_weight=True)
Return a random spanning tree of the graph.
This uses the Aldous-Broder algorithm ([Bro1989], [Ald1990]) to generate a random spanning tree with theuniform 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.
When by_weight is True or a weight function is given, the selection of the neighbor is done proportionaly
to the edge weights.
INPUT:• G – an undirected graph• output_as_graph – boolean (default: False); whether to return a list of edges or a graph• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise alledges have weight 1• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If Noneand by_weight is True, we use the edge label l , if l is not None, else 1 as a weight. The
weight_function can be used to transform the label into a weight (note that, if the weight returned
is not convertible to a float, an error is raised)• check_weight – boolean (default: True); whether to check that the weight_function outputs
a number for each edge.
See also:
spanning_trees_count() and spanning_trees()
EXAMPLES:

636

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = graphs.TietzeGraph()
sage: G.random_spanning_tree(output_as_graph=True)
Graph on 12 vertices
sage: rg = G.random_spanning_tree(); rg # random[(0, 9),(9, 11),(0, 8),(8, 7),(7, 6),(7, 2),(2, 1),(1, 5),(9, 10),(5, 4),(2, 3)]
sage: Graph(rg).is_tree()True>>> from sage.all import *>>> G = graphs.TietzeGraph()>>> G.random_spanning_tree(output_as_graph=True)
Graph on 12 vertices>>> rg = G.random_spanning_tree(); rg # random[(0, 9),(9, 11),(0, 8),(8, 7),(7, 6),(7, 2),(2, 1),(1, 5),(9, 10),(5, 4),(2, 3)]>>> 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)˓→# needs sage.plot␣>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(6), Integer(6))>>> pos = G.get_pos()>>> T = G.random_spanning_tree(True)>>> T.set_pos(pos)>>> T.show(vertex_labels=False)
˓→# needs sage.plot

We can also use edge weights to change the probability of returning a spanning tree:

1.2. Undirected graphs637

Graph Theory, Release 10.4

sage: def foo(G, k):....:
S = set()....:for _ in range(k):....:E = G.random_spanning_tree(by_weight=True)....:
S.add(Graph(E).graph6_string())....:
return S
sage: K3 = graphs.CompleteGraph(3)sage: for u, v in K3.edges(sort=True, labels=False):....:
K3.set_edge_label(u, v, randint(1, 2))
sage: foo(K3, 100) == { BW , Bg , Bo } # random
True
sage: K4 = graphs.CompleteGraph(4)sage: for u, v in K4.edges(sort=True, labels=False):....:
K4.set_edge_label(u, v, randint(1, 2))
sage: print(len(foo(K4, 100))) # random
16>>> from sage.all import *>>> def foo(G, k):...
S = set()...
for _ in range(k):...
E = G.random_spanning_tree(by_weight=True)...
S.add(Graph(E).graph6_string())...
return S>>> K3 = graphs.CompleteGraph(Integer(3))>>> for u, v in K3.edges(sort=True, labels=False):...
K3.set_edge_label(u, v, randint(Integer(1), Integer(2)))>>> foo(K3, Integer(100)) == { BW , Bg , Bo } # random
True>>> K4 = graphs.CompleteGraph(Integer(4))>>> for u, v in K4.edges(sort=True, labels=False):...
K4.set_edge_label(u, v, randint(Integer(1), Integer(2)))>>> print(len(foo(K4, Integer(100)))) # random
16

Check that the spanning tree returned when using weights is a tree:
sage: # needs networkx
sage: G = graphs.RandomBarabasiAlbert(50, 2)
sage: for u, v in G.edge_iterator(labels=False):....:
G.set_edge_label(u, v, randint(1, 10))sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True)
sage: T.is_tree()True>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomBarabasiAlbert(Integer(50), Integer(2))>>> for u, v in G.edge_iterator(labels=False):...
G.set_edge_label(u, v, randint(Integer(1), Integer(10)))>>> T = G.random_spanning_tree(by_weight=True, output_as_graph=True)>>> T.is_tree()Truerank_decomposition(G, verbose=False)
Compute an optimal rank-decomposition of the given graph.

638

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

This function is available as a method of the Graph class. See rank_decomposition.
INPUT:• verbose – boolean (default: False); whether to display progress information while computing thedecomposition
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)>>> from sage.all import *>>> from sage.graphs.graph_decompositions.rankwidth import rank_decomposition>>> g = graphs.PetersenGraph()>>> 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>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(40), RealNumber( .5 ))>>> 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)>>> from sage.all import *>>> g = Graph()>>> rank_decomposition(g)(0, Graph on 0 vertices)seidel_adjacency_matrix(vertices, base_ring=None, **kwds)
Return the Seidel adjacency matrix of self.
Returns 𝐽 − 𝐼 − 2𝐴, for 𝐴 the (ordinary) adjacency matrix of self, 𝐼 the identity matrix, and 𝐽 theall-1 matrix. It is closely related to twograph().
1.2. Undirected graphs639

Graph Theory, Release 10.4

By default, the matrix returned is over the integers.
INPUT:• vertices – list of vertices (default: None); the ordering of the vertices defining how they should
appear in the matrix. By default, the ordering given by vertices() is used.
• base_ring – a ring (default: None); the base ring of the matrix space to use• **kwds – other keywords to pass to matrix()
EXAMPLES:
sage: G = graphs.CycleGraph(5)sage: G = G.disjoint_union(graphs.CompleteGraph(1))
sage: G.seidel_adjacency_matrix().minpoly()
˓→needs sage.libs.pari sage.modulesx^2 - 5>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(5))>>> G = G.disjoint_union(graphs.CompleteGraph(Integer(1)))>>> G.seidel_adjacency_matrix().minpoly()
˓→needs sage.libs.pari sage.modulesx^2 - 5#␣#␣

Selecting the base ring:sage: G.seidel_adjacency_matrix()[0, 0].parent()
˓→needs sage.modules
Integer Ringsage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent()
˓→needs sage.modules
Real Double Field#␣#␣>>> from sage.all import *>>> G.seidel_adjacency_matrix()[Integer(0), Integer(0)].parent()␣˓→# needs sage.modules
Integer Ring>>> G.seidel_adjacency_matrix(base_ring=RDF)[Integer(0), Integer(0)].parent()␣
˓→# needs sage.modules
Real Double Field

seidel_switching(s, inplace=True)
Return the Seidel switching of self w.r.t. subset of vertices s.
Returns the graph obtained by Seidel switching of self with respect to the subset of vertices s. This is
the graph given by Seidel adjacency matrix 𝐷𝑆𝐷, for 𝑆 the Seidel adjacency matrix of self, and 𝐷 the
diagonal matrix with -1s at positions corresponding to s, and 1s elsewhere.
INPUT:• s – a list of vertices of self.
• inplace – boolean (default: True); whether to do the modification inplace, or to return a copy of thegraph after switching.
EXAMPLES:

640

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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()
˓→needs sage.libs.pari sage.modulesx^2 - 5sage: G.is_connected()
True

#␣

>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(5))>>> G = G.disjoint_union(graphs.CompleteGraph(Integer(1)))>>> G.seidel_switching([(Integer(0),Integer(1)),(Integer(1),Integer(0)),˓→(Integer(0),Integer(0))])>>> G.seidel_adjacency_matrix().minpoly()
˓→needs sage.libs.pari sage.modulesx^2 - 5>>> G.is_connected()
True

#␣

spanning_trees(g, labels=False)
Return an iterator over all spanning trees of the graph 𝑔.
A disconnected graph has no spanning tree.
Uses the Read-Tarjan backtracking algorithm [RT1975a].
INPUT:• labels – boolean (default: False); whether to return edges labels in the spanning trees or not
EXAMPLES:
sage: G = Graph([(1,2),(1,2),(1,3),(1,3),(2,3),(1,4)], multiedges=True)
sage: len(list(G.spanning_trees()))
8
sage: G.spanning_trees_count()␣˓→# needs sage.modules
8
sage: G = Graph([(1,2),(2,3),(3,1),(3,4),(4,5),(4,5),(4,6)], multiedges=True)
sage: len(list(G.spanning_trees()))
6
sage: G.spanning_trees_count()␣˓→# needs sage.modules
6>>> from sage.all import *>>> G = Graph([(Integer(1),Integer(2)),(Integer(1),Integer(2)),(Integer(1),˓→Integer(3)),(Integer(1),Integer(3)),(Integer(2),Integer(3)),(Integer(1),˓→Integer(4))], multiedges=True)>>> len(list(G.spanning_trees()))
8>>> G.spanning_trees_count()
˓→# needs sage.modules
8>>> G = Graph([(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(1)),(Integer(3),Integer(4)),(Integer(4),Integer(5)),(Integer(4),˓→Integer(5)),(Integer(4),Integer(6))], multiedges=True)(continues on next page)1.2. Undirected graphs641

Graph Theory, Release 10.4

(continued from previous page)>>> len(list(G.spanning_trees()))
6>>> G.spanning_trees_count()
˓→# needs sage.modules
6

See also:• spanning_trees_count() – counts the number of spanning trees• random_spanning_tree() – returns a random spanning treesparse6_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 copyof your graph will be encoded if necessary.
EXAMPLES:
sage: G = graphs.BullGraph()
sage: G.sparse6_string():Da@en>>> from sage.all import *>>> G = graphs.BullGraph()>>> G.sparse6_string():Da@ensage: G = Graph(loops=True, multiedges=True, data_structure="sparse")
sage: Graph( :? , data_structure="sparse") == G
True>>> from sage.all import *>>> G = Graph(loops=True, multiedges=True, data_structure="sparse")>>> Graph( :? , data_structure="sparse") == G
True

spqr_tree(G, algorithm='Hopcroft_Tarjan', solver=None, verbose=0, integrality_tolerance=0.001)
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 withit, 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 thathas only one edge.
• "R" – the associated graph is a 3-connected graph that is not a cycle or dipole. "R" stands for rigid.
642

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

This method decomposes a biconnected graph into cycles, cocycles, and 3-connected blocks summed overcocycles, 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 graphswith one edge per real edge between the included vertices and one additional (virtual) edge per connectedcomponent resulting from deletion of the vertices in the cut. See the Wikipedia article SPQR_tree.
INPUT:• G – the input graph• algorithm – string (default: "Hopcroft_Tarjan"); the algorithm to use among:– "Hopcroft_Tarjan" (default) – use the algorithm proposed by Hopcroft and Tarjan in[Hopcroft1973] and later corrected by Gutwenger and Mutzel in [Gut2001]. See TriconnectivitySPQR.
– "cleave" – using method cleave()• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
OUTPUT: SPQR-tree a tree whose vertices are labeled with the block’s type and the subgraph ofthree-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 if u[0] == R )True
sage: from sage.graphs.connectivity import spqr_tree_to_graphsage: 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 if u[0] == S )True
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))True
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edge_iterator())
sage: Tree = spqr_tree(G)(continues on next page)1.2. Undirected graphs643

Graph Theory, Release 10.4

(continued from previous page)

sage: Tree.order()13sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] ==Truesage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True

S )

sage: G = graphs.CycleGraph(6)sage: Tree = spqr_tree(G)sage: Tree.order()1sage: G.is_isomorphic(spqr_tree_to_graph(Tree))True
sage: G.add_edge(0, 3)
sage: Tree = spqr_tree(G)sage: Tree.order()3sage: 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 )˓→# needs sage.numerical.mip
sage: G.is_isomorphic(spqr_tree_to_graph(T2))˓→# needs sage.numerical.mip
True
sage: G = Graph([(0, 1)], multiedges=True)
sage: T = spqr_tree(G, algorithm= cleave )˓→# needs sage.numerical.mip
sage: T.vertices(sort=True)˓→# needs sage.numerical.mip[( Q , Multi-graph on 2 vertices)]sage: G.is_isomorphic(spqr_tree_to_graph(T))˓→# needs sage.numerical.mip
True
sage: T = spqr_tree(G, algorithm= Hopcroft_Tarjan )sage: T.vertices(sort=True)[( Q , Multi-graph on 2 vertices)]sage: G.add_edge(0, 1)
sage: spqr_tree(G, algorithm= cleave ).vertices(sort=True)˓→# needs sage.numerical.mip[( P , Multi-graph on 2 vertices)]sage: from collections import Countersage: 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")˓→# needs sage.numerical.mip
sage: Counter(u[0] for u in T)˓→# needs sage.numerical.mip
Counter({ R : 1})

␣
␣

␣
␣

␣

␣

␣
␣

(continues on next page)

644

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: for u,v in list(G.edges(labels=False, sort=False)):....:G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")sage: sorted(Counter(u[0] for u in T).items())[( P , 15), ( R , 1), ( S , 15)]
sage: T = G.spqr_tree(algorithm="cleave")˓→# needs sage.numerical.mip
sage: sorted(Counter(u[0] for u in T).items())˓→# needs sage.numerical.mip[( P , 15), ( R , 1), ( S , 15)]
sage: for u,v in list(G.edges(labels=False, sort=False)):....:G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")sage: sorted(Counter(u[0] for u in T).items())[( P , 60), ( R , 1), ( S , 75)]
sage: T = G.spqr_tree(algorithm="cleave")# long time˓→# needs sage.numerical.mip
sage: sorted(Counter(u[0] for u in T).items()) # long time˓→# needs sage.numerical.mip[( P , 60), ( R , 1), ( S , 75)]

␣
␣

␣
␣

>>> from sage.all import *>>> from sage.graphs.connectivity import spqr_tree>>> G = Graph(Integer(2))>>> for i in range(Integer(3)):...
G.add_clique([Integer(0), Integer(1), G.add_vertex(), G.add_vertex()])>>> Tree = spqr_tree(G)>>> Tree.order()4>>> K4 = graphs.CompleteGraph(Integer(4))>>> all(u[Integer(1)].is_isomorphic(K4) for u in Tree if u[Integer(0)] == R )True>>> from sage.graphs.connectivity import spqr_tree_to_graph>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G = Graph(Integer(2))>>> for i in range(Integer(3)):...
G.add_path([Integer(0), G.add_vertex(), G.add_vertex(), Integer(1)])>>> Tree = spqr_tree(G)>>> Tree.order()4>>> C4 = graphs.CycleGraph(Integer(4))>>> all(u[Integer(1)].is_isomorphic(C4) for u in Tree if u[Integer(0)] == S )True>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edge_iterator())>>> Tree = spqr_tree(G)>>> Tree.order()13>>> all(u[Integer(1)].is_isomorphic(C4) for u in Tree if u[Integer(0)] ==True>>> G.is_isomorphic(spqr_tree_to_graph(Tree))S )(continues on next page)1.2. Undirected graphs645Graph Theory, Release 10.4

(continued from previous page)

True>>> G = graphs.CycleGraph(Integer(6))>>> Tree = spqr_tree(G)>>> Tree.order()1>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G.add_edge(Integer(0), Integer(3))>>> Tree = spqr_tree(G)>>> Tree.order()3>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G = Graph( LlCG{O@?GBoMw? )>>> T = spqr_tree(G, algorithm="Hopcroft_Tarjan")>>> G.is_isomorphic(spqr_tree_to_graph(T))
True>>> T2 = spqr_tree(G, algorithm= cleave )˓→# needs sage.numerical.mip>>> G.is_isomorphic(spqr_tree_to_graph(T2))
˓→# needs sage.numerical.mip
True>>> G = Graph([(Integer(0), Integer(1))], multiedges=True)>>> T = spqr_tree(G, algorithm= cleave )˓→# needs sage.numerical.mip>>> T.vertices(sort=True)
˓→# needs sage.numerical.mip[( Q , Multi-graph on 2 vertices)]>>> G.is_isomorphic(spqr_tree_to_graph(T))˓→# needs sage.numerical.mip
True>>> T = spqr_tree(G, algorithm= Hopcroft_Tarjan )>>> T.vertices(sort=True)[( Q , Multi-graph on 2 vertices)]>>> G.add_edge(Integer(0), Integer(1))>>> spqr_tree(G, algorithm= cleave ).vertices(sort=True)
˓→# needs sage.numerical.mip[( P , Multi-graph on 2 vertices)]>>> from collections import Counter>>> G = graphs.PetersenGraph()>>> T = G.spqr_tree(algorithm="Hopcroft_Tarjan")>>> Counter(u[Integer(0)] for u in T)
Counter({ R : 1})>>> T = G.spqr_tree(algorithm="cleave")
˓→# needs sage.numerical.mip>>> Counter(u[Integer(0)] for u in T)˓→# needs sage.numerical.mip
Counter({ R : 1})>>> for u,v in list(G.edges(labels=False, sort=False)):...
G.add_path([u, G.add_vertex(), G.add_vertex(), v])>>> T = G.spqr_tree(algorithm="Hopcroft_Tarjan")>>> sorted(Counter(u[Integer(0)] for u in T).items())[( P , 15), ( R , 1), ( S , 15)]␣(continues on next page)

646

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> T = G.spqr_tree(algorithm="cleave")
˓→# needs sage.numerical.mip>>> sorted(Counter(u[Integer(0)] for u in T).items())˓→# needs sage.numerical.mip[( P , 15), ( R , 1), ( S , 15)]>>> for u,v in list(G.edges(labels=False, sort=False)):...
G.add_path([u, G.add_vertex(), G.add_vertex(), v])>>> T = G.spqr_tree(algorithm="Hopcroft_Tarjan")>>> sorted(Counter(u[Integer(0)] for u in T).items())[( P , 60), ( R , 1), ( S , 75)]>>> T = G.spqr_tree(algorithm="cleave")# long time
˓→# needs sage.numerical.mip>>> sorted(Counter(u[Integer(0)] for u in T).items()) # long time˓→# needs sage.numerical.mip[( P , 60), ( R , 1), ( S , 75)]␣␣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 time complexity is 𝑂(𝑛 + 𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph .
See also:• orientations()• strong_orientations_iterator()• nauty_directg()• random_orientation()
EXAMPLES:
For a 2-regular graph, a strong orientation gives to each vertex an out-degree equal to 1:
sage: g = graphs.CycleGraph(5)sage: g.strong_orientation().out_degree()[1, 1, 1, 1, 1]>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))(continues on next page)1.2. Undirected graphs

647

Graph Theory, Release 10.4

(continued from previous page)>>> 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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> o = g.strong_orientation()>>> 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>>> from sage.all import *>>> all(len(graphs.CubeGraph(i).strong_orientation().strongly_connected_
˓→components()) == Integer(1) for i in range(Integer(2),Integer(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>>> from sage.all import *>>> g = Graph([(Integer(1),Integer(2)),(Integer(1),Integer(2))],␣
˓→multiedges=True)>>> g.strong_orientation()
Multi-digraph on 2 vertices

strong_orientations_iterator(G)Return 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). According to Robbins’ theorem (see the Wikipedia article Robbins_theorem), the graphs that have strong orientations are exactly the2-edge-connected graphs (i.e., the bridgeless graphs).
ALGORITHM:
It is an adaptation of the algorithm published in [CGMRV16]. It runs in 𝑂(𝑚𝑛) amortized time, where 𝑚 isthe number of edges and 𝑛 is the number of vertices. The amortized time can be improved to 𝑂(𝑚) with amore involved method. In this function, first the graph is preprocessed and a spanning tree is generated. Thenevery 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 cor-

648

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

responding to the generation algorithm described in [CGMRV16]. In order to avoid trivial symmetries, theorientation of an arbitrary edge is fixed before the start of the enumeration process.
INPUT:• G – an undirected graph.
OUTPUT:• an iterator which will produce all strong orientations of this graph.
Note: Works only for simple graphs (no multiple edges). To avoid symmetries an orientation of an arbitraryedge is fixed.
See also:• orientations()• strong_orientation()• nauty_directg()• random_orientation()
EXAMPLES:
A cycle has one possible (non-symmetric) strong orientation:
sage: g = graphs.CycleGraph(4)sage: it = g.strong_orientations_iterator()sage: len(list(it))
1>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(4))>>> it = g.strong_orientations_iterator()>>> len(list(it))
1

A tree cannot be strongly oriented:
sage: g = graphs.RandomTree(10)sage: len(list(g.strong_orientations_iterator()))
0>>> from sage.all import *>>> g = graphs.RandomTree(Integer(10))>>> 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

1.2. Undirected graphs649

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> g.add_vertex(Integer(7))>>> len(list(g.strong_orientations_iterator()))
0

to_directed(data_structure=None, sparse=None)
Return a directed version of the graph.
A single edge becomes two edges, one in each direction.
INPUT:• data_structure – one of "sparse", "static_sparse", or "dense". See the documentation of Graph or DiGraph.
• sparse – boolean (default: None); sparse=True is an alias for data_structure="sparse",
and sparse=False is an alias for data_structure="dense".
EXAMPLES:
sage: graphs.PetersenGraph().to_directed()Petersen graph: Digraph on 10 vertices>>> from sage.all import *>>> graphs.PetersenGraph().to_directed()Petersen graph: Digraph on 10 vertices

to_undirected()
Since the graph is already undirected, simply returns a copy of itself.
EXAMPLES:
sage: graphs.PetersenGraph().to_undirected()Petersen graph: Graph on 10 vertices>>> from sage.all import *>>> graphs.PetersenGraph().to_undirected()Petersen graph: Graph on 10 vertices

topological_minor(H, vertices, paths=False, solver=False, verbose=None, integrality_tolerance=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 topologicalminor), 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.

650

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
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 everyedge 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))˓→needs sage.numerical.mip
Subgraph of (Petersen graph): Graph on ...
>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.topological_minor(graphs.CompleteGraph(Integer(4)))˓→# needs sage.numerical.mip
Subgraph of (Petersen graph): Graph on ...

#␣␣And a topological 𝐾3,3 -minor:
sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3))
˓→needs sage.numerical.mip
Subgraph of (Petersen graph): Graph on ...

#␣>>> from sage.all import *>>> g.topological_minor(graphs.CompleteBipartiteGraph(Integer(3),Integer(3)))␣
˓→# needs sage.numerical.mip
Subgraph of (Petersen graph): Graph on ...

And of course, a tree has no topological 𝐶3 -minor:
sage: g = graphs.RandomGNP(15,.3)
sage: g = g.subgraph(edges=g.min_spanning_tree())
sage: g.topological_minor(graphs.CycleGraph(3))˓→needs sage.numerical.mip
False

1.2. Undirected graphs

#␣

651

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(15),RealNumber( .3 ))>>> g = g.subgraph(edges=g.min_spanning_tree())>>> g.topological_minor(graphs.CycleGraph(Integer(3)))˓→# needs sage.numerical.mip
False

␣

treelength(G, k=None, certificate=False)
Compute the treelength of 𝐺 (and provide a decomposition).
The length of a tree decomposition, as proposed in [DG2006], is the maximum diameter in 𝐺 of its
bags, where the diameter of a bag 𝑋𝑖 is the largest distance in 𝐺 between the vertices in 𝑋𝑖 (i.e.,
max𝑢,𝑣∈𝑋𝑖 dist𝐺 (𝑢, 𝑣)). The treelength 𝑡𝑙(𝐺) of a graph 𝐺 is the minimum length among all possible tree
decompositions of 𝐺. See the documentation of the tree_decomposition module for more details.
INPUT:• G – a sage Graph• k – integer (default: None); indicates the length to be considered. When 𝑘 is an integer, the method
checks that the graph has treelength ≤ 𝑘. If 𝑘 is None (default), the method computes the optimal
treelength.
• certificate – boolean (default: False); whether to also return the tree-decomposition itself
OUTPUT:
G.treelength() returns the treelength of 𝐺. When 𝑘 is specified, it returns False when notree-decomposition of length ≤ 𝑘 exists or True otherwise. When certificate=True, thetree-decomposition is also returned.
ALGORITHM:
This method virtually explores the graph of all pairs (vertex_cut, connected_component), wherevertex_cut is a vertex cut of the graph of length ≤ 𝑘, and connected_component is a connectedcomponent of the graph induced by G - vertex_cut.
We deduce that the pair (vertex_cut, connected_component) is feasible with treelength 𝑘 if
connected_component is empty, or if a vertex v from vertex_cut can be replaced with a vertex
from connected_component, such that the pair (vertex_cut + v, connected_component- v) is feasible.
In practice, this method decomposes the graph by its clique minimal separators into atoms, computes thetreelength of each of atom and returns the maximum value over all the atoms. Indeed, we have that 𝑡𝑙(𝐺) =max𝑋∈𝐴 𝑡𝑙(𝐺[𝑋]) where 𝐴 is the set of atoms of the decomposition by clique separators of 𝐺. Whencertificate == True, the tree-decompositions of the atoms are connected to each others by addingedges with respect to the clique separators.
See also:• treewidth() computes the treewidth of a graph.
• path_decomposition() computes the pathwidth of a graph.
• module vertex_separation.
• atoms_and_clique_separators()
EXAMPLES:
The PetersenGraph has treelength 2:

652

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = graphs.PetersenGraph()
sage: G.treelength()2>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.treelength()2

Disconnected graphs have infinite treelength:
sage: G = Graph(2)sage: G.treelength()+Infinity
sage: G.treelength(k=+Infinity)
True
sage: G.treelength(k=2)
False
sage: G.treelength(certificate=True)
Traceback (most recent call last):...
ValueError: the tree decomposition of a disconnected graph is not defined>>> from sage.all import *>>> G = Graph(Integer(2))>>> G.treelength()+Infinity>>> G.treelength(k=+Infinity)
True>>> G.treelength(k=Integer(2))
False>>> G.treelength(certificate=True)
Traceback (most recent call last):...
ValueError: the tree decomposition of a disconnected graph is not defined

Chordal graphs have treelength 1:
sage: G = graphs.RandomChordalGraph(30)sage: while not G.is_connected():....:G = graphs.RandomChordalGraph(30)sage: G.treelength()
1>>> from sage.all import *>>> G = graphs.RandomChordalGraph(Integer(30))>>> while not G.is_connected():...
G = graphs.RandomChordalGraph(Integer(30))>>> G.treelength()1

Cycles have treelength ⌈𝑛/3⌉:
sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)][1, 2, 2, 2, 3, 3, 3, 4]

1.2. Undirected graphs653

Graph Theory, Release 10.4>>> from sage.all import *>>> [graphs.CycleGraph(n).treelength() for n in range(Integer(3),␣
˓→Integer(11))][1, 2, 2, 2, 3, 3, 3, 4]

treewidth(g, k=None, kmin=None, certificate=False, algorithm=None, nice=False)
Compute the treewidth of 𝑔 (and provide a decomposition).
INPUT:• g – a Sage Graph• k – integer (default: None); indicates 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
treewidth.
• kmin – integer (default: None); when specified, search for a tree-decomposition of width at least kmin.
This parameter is useful when the graph can be decomposed into atoms. This parameter is ignored when
k is not None or when algorithm == tdlib .
• certificate – boolean (default: False); whether to return the tree-decomposition itself.
• algorithm – whether to use "sage" or "tdlib" (requires the installation of the sagemath_tdlib:
Tree decompositions with tdlib package). The default behaviour is to use ‘tdlib’ if it is available, andSage’s own algorithm when it is not.
• nice – boolean (default: False); whether or not to return the nice tree decomposition, provided
certificate is True.
OUTPUT:g.treewidth() returns treewidth of the graph g.
When k is specified, it returns False if there is no tree decomposition of width ≤ 𝑘, and True otherwise.
When certificate=True, the tree decomposition is returned.
When nice=True, the nice tree decomposition is returned.
ALGORITHM:
This function virtually explores the graph of all pairs (vertex_cut, cc), where vertex_cut is avertex cut of the graph of cardinality ≤ 𝑘 + 1, and connected_component is a connected componentof the graph induced by G-vertex_cut.
We deduce that the pair (vertex_cut, cc) is feasible with treewidth 𝑘 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 reallya 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:

654

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: petersen = graphs.PetersenGraph()
sage: petersen.treewidth(algorithm= sage )4sage: petersen.treewidth(algorithm= sage , certificate=True)
Tree decomposition: Graph on 6 vertices>>> from sage.all import *>>> petersen = graphs.PetersenGraph()>>> petersen.treewidth(algorithm= sage )4>>> petersen.treewidth(algorithm= sage , certificate=True)
Tree decomposition: Graph on 6 vertices

The PetersenGraph has treewidth 4 (with tdlib):
sage: petersen = graphs.PetersenGraph()
sage: petersen.treewidth(algorithm= tdlib )˓→tdlib4
sage: petersen.treewidth(algorithm= tdlib , certificate=True)
˓→tdlib
Tree decomposition: Graph on 6 vertices>>> from sage.all import *>>> petersen = graphs.PetersenGraph()>>> petersen.treewidth(algorithm= tdlib )˓→tdlib4>>> petersen.treewidth(algorithm= tdlib , certificate=True)
˓→tdlib
Tree decomposition: Graph on 6 vertices# optional -␣# optional -␣# optional -␣# optional -␣

Nice tree decomposition of the PetersenGraph has 28 nodes:
sage: petersen = graphs.PetersenGraph()
sage: petersen.treewidth(algorithm= sage , certificate=True, nice=True)
Nice tree decomposition of Tree decomposition: Graph on 28 vertices
sage: petersen.treewidth(algorithm= tdlib , certificate=True, nice=True)
˓→optional - tdlib
Nice tree decomposition of Tree decomposition: Graph on 28 vertices>>> from sage.all import *>>> petersen = graphs.PetersenGraph()>>> petersen.treewidth(algorithm= sage , certificate=True, nice=True)
Nice tree decomposition of Tree decomposition: Graph on 28 vertices>>> petersen.treewidth(algorithm= tdlib , certificate=True, nice=True)
˓→optional - tdlib
Nice tree decomposition of Tree decomposition: Graph on 28 vertices#␣#␣The treewidth of a 2-dimensional grid is its smallest side:
sage: graphs.Grid2dGraph(2,5).treewidth()2
sage: graphs.Grid2dGraph(3,5).treewidth()31.2. Undirected graphs655

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.Grid2dGraph(Integer(2),Integer(5)).treewidth()2>>> graphs.Grid2dGraph(Integer(3),Integer(5)).treewidth()3

When parameter kmin is specified, the method searches for a tree-decomposition of width at least kmin:
sage: g = graphs.PetersenGraph()
sage: g.treewidth()4
sage: g.treewidth(kmin=2, algorithm= sage )4sage: g.treewidth(kmin=g.order(), certificate=True, algorithm= sage )Tree decomposition: Graph on 1 vertex>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.treewidth()4>>> g.treewidth(kmin=Integer(2), algorithm= sage )4>>> g.treewidth(kmin=g.order(), certificate=True, algorithm= sage )Tree decomposition: Graph on 1 vertex

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 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))˓→# needs sage.symbolicTrue␣>>> from sage.all import *>>> all(T.tutte_polynomial() == x**Integer(9) for T in graphs.
˓→trees(Integer(10)))# needs sage.symbolic
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

656

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.tutte_polynomial()x^9 + 6*x^8 + 21*x^7 + 56*x^6 + 12*x^5*y + y^6 + 114*x^5 + 70*x^4*y+ 30*x^3*y^2 + 15*x^2*y^3 + 10*x*y^4 + 9*y^5 + 170*x^4 + 170*x^3*y+ 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2+ 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y

The Tutte polynomial of a connected graph 𝐺 evaluated at (1,1) is the number of spanning trees of 𝐺:
sage: G = graphs.RandomGNP(10,0.6)
sage: while not G.is_connected():....:G = graphs.RandomGNP(10,0.6)
sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count()˓→# needs sage.modules
True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(10),RealNumber( 0.6 ))>>> while not G.is_connected():...
G = graphs.RandomGNP(Integer(10),RealNumber( 0.6 ))>>> G.tutte_polynomial()(Integer(1),Integer(1)) == G.spanning_trees_count()˓→# needs sage.modules
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()˓→# needs sage.symbolic(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage: G.chromatic_polynomial().factor()˓→# needs sage.libs.flint(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)>>> from sage.all import *>>> G = graphs.OctahedralGraph()>>> T = G.tutte_polynomial()>>> R = PolynomialRing(ZZ, x )>>> R((-Integer(1))**Integer(5)*x*T(Integer(1)-x,Integer(0))).factor()˓→# needs sage.symbolic(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)>>> G.chromatic_polynomial().factor()˓→# needs sage.libs.flint(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)

␣

␣

␣

two_factor_petersen(solver, verbose=None, integrality_tolerance=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
1.2. Undirected graphs

657

Graph Theory, Release 10.4

means that the edges of any graph of degree Δ can be partitionned in 𝑟 = 2⌈ Δ
2 ⌉ sets 𝐶1 , . . . , 𝐶𝑟 such thatfor all 𝑖, the set 𝐶𝑖 is a graph of maximal degree 2 (a disjoint union of paths and cycles).
INPUT:• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:The Complete Graph on 7 vertices is a 6-regular graph, so it can be edge-partitionned into 2-regular graphs:
sage: g = graphs.CompleteGraph(7)sage: classes = g.two_factor_petersen()˓→needs sage.numerical.mip
sage: for c in classes:
˓→needs sage.numerical.mip....:
gg = Graph()....:
gg.add_edges(c)....:print(max(gg.degree())<=2)
True
True
True
sage: Set(set(classes[0])˓→needs sage.numerical.mip....:| set(classes[1])....:| set(classes[2])).cardinality() == g.size()
True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(7))>>> classes = g.two_factor_petersen()˓→needs sage.numerical.mip>>> for c in classes:
˓→needs sage.numerical.mip...
gg = Graph()...
gg.add_edges(c)...
print(max(gg.degree())<=Integer(2))
True
True
True
>>> Set(set(classes[Integer(0)])˓→# needs sage.numerical.mip...
| set(classes[Integer(1)])...
| set(classes[Integer(2)])).cardinality() == g.size()
True
sage: g = graphs.CirculantGraph(24, [7, 11])sage: cl = g.two_factor_petersen()˓→needs sage.numerical.mip
sage: g.plot(edge_colors={ black :cl[0], red :cl[1]})˓→needs sage.numerical.mip sage.plot
Graphics object consisting of 73 graphics primitives

658

#␣
#␣

#␣

#␣
#␣

␣

#␣
#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CirculantGraph(Integer(24), [Integer(7), Integer(11)])>>> cl = g.two_factor_petersen()˓→needs sage.numerical.mip>>> g.plot(edge_colors={ black :cl[Integer(0)], red :cl[Integer(1)]})˓→# needs sage.numerical.mip sage.plot
Graphics object consisting of 73 graphics primitives#␣␣

twograph()
Return the two-graph of self
Returns the two-graph with the triples 𝑇 = {𝑡 ∈edges of self, respectively.

⃒(︀𝑉 )︀ ⃒(︀ 𝑡 )︀⃒⃒3 :2 ∩ 𝐸 odd} where 𝑉 and 𝐸 are vertices and

EXAMPLES:
sage: p = graphs.PetersenGraph()
sage: p.twograph()˓→needs sage.modules
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()˓→needs sage.modules
True
sage: T8.is_isomorphic(C)
False

#␣

#␣

>>> from sage.all import *>>> p = graphs.PetersenGraph()>>> p.twograph()#␣˓→needs sage.modules
Incidence structure with 10 points and 60 blocks>>> p = graphs.chang_graphs()>>> T8 = graphs.CompleteGraph(Integer(8)).line_graph()>>> C = T8.seidel_switching([(Integer(0),Integer(1),None), (Integer(2),˓→Integer(3),None), (Integer(4),Integer(5),None), (Integer(6),Integer(7),˓→None)],...
inplace=False)>>> T8.twograph() == C.twograph()#␣˓→needs sage.modules
True>>> 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, value_only='Cliquer', reduction_rules=False, solver=True, verbose=None,
integrality_tolerance=0)
Return a minimum vertex cover of self represented by a set of vertices.

1.2. Undirected graphs659

Graph Theory, Release 10.4

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.
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 thosevalues.
– "Cliquer" will compute a minimum vertex cover using the Cliquer package.
– "MILP" will compute a minimum vertex cover through a mixed integer linear program.
– "mcqd" will use the MCQD solver (http://www.sicmm.org/ konc/maxclique/). Note that the
MCQD package must be installed.
• value_only – boolean (default: False); if set to True, only the size of a minimum vertex cover isreturned. 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
On the Pappus graph:
sage: g = graphs.PappusGraph()
sage: g.vertex_cover(value_only=True)
9>>> from sage.all import *>>> g = graphs.PappusGraph()>>> g.vertex_cover(value_only=True)
9

vertex_isoperimetric_number(g)Return the vertex-isoperimetric number of the graph.
The vertex-isoperimetric number of a graph 𝐺 = (𝑉, 𝐸) is also sometimes called the magnifying constant.
It is defined as the minimum of |𝑁 (𝑆)|/|𝑆| where |𝑁 (𝑆)| is the vertex boundary of 𝑆 and the minimum istaken over the subsets 𝑆 of vertices of size at most half of the vertices.

660

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

0
6
1

5
7

8

12

11

13

17

14

16
15

2

10
4

9
3

1.2. Undirected graphs661

Graph Theory, Release 10.4

See also:
Alternative but similar quantities can be obtained via the methods cheeger_constant() andedge_isoperimetric_number().
EXAMPLES:
The vertex-isoperimetric number of a complete graph on 𝑛 vertices is ⌈𝑛/2⌉/⌊𝑛/2⌋:
sage: [graphs.CompleteGraph(k).vertex_isoperimetric_number() for k in range(2,˓→15)][1, 2, 1, 3/2, 1, 4/3, 1, 5/4, 1, 6/5, 1, 7/6, 1]>>> from sage.all import *>>> [graphs.CompleteGraph(k).vertex_isoperimetric_number() for k in␣˓→range(Integer(2),Integer(15))][1, 2, 1, 3/2, 1, 4/3, 1, 5/4, 1, 6/5, 1, 7/6, 1]

The vertex-isoperimetric number of a cycle on 𝑛 vertices is 2/⌊𝑛/2⌋:
sage: [graphs.CycleGraph(k).vertex_isoperimetric_number() for k in range(2,˓→15)][1, 2, 1, 1, 2/3, 2/3, 1/2, 1/2, 2/5, 2/5, 1/3, 1/3, 2/7]>>> from sage.all import *>>> [graphs.CycleGraph(k).vertex_isoperimetric_number() for k in␣˓→range(Integer(2),Integer(15))][1, 2, 1, 1, 2/3, 2/3, 1/2, 1/2, 2/5, 2/5, 1/3, 1/3, 2/7]

And the vertex-isoperimetric number of a disconnected graph is 0:
sage: Graph([[1,2,3],[(1,2)]]).vertex_isoperimetric_number()0>>> from sage.all import *>>> Graph([[Integer(1),Integer(2),Integer(3)],[(Integer(1),Integer(2))]]).
˓→vertex_isoperimetric_number()0

The vertex-isoperimetric number is independent of edge multiplicity:
sage: G = graphs.CycleGraph(6)sage: G.vertex_isoperimetric_number()
2/3
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: G.vertex_isoperimetric_number()
2/3>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(6))>>> G.vertex_isoperimetric_number()
2/3>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edges(sort=False))>>> G.vertex_isoperimetric_number()
2/3

662

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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 ))>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> 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.3 Directed graphs
This module implements functions and operations involving directed graphs. Here is what they can do
Graph basic operations:1.3. Directed graphs663

Graph Theory, Release 10.4

layout_acyclic_dummy()layout_acyclic()
reverse()reverse_edge()
reverse_edges()
out_degree_sequence()
out_degree_iterator()
out_degree()in_degree_sequence()
in_degree_iterator()
in_degree()neighbors_out()neighbor_out_iterator()neighbors_in()neighbor_in_iterator()outgoing_edges()outgoing_edge_iterator()incoming_edges()incoming_edge_iterator()sources()
sinks()
to_undirected()
to_directed()
is_directed()
dig6_string()

Compute a (dummy) ranked layout so that all edges point upward.
Compute a ranked layout so that all edges point upward.
Return a copy of digraph with edges reversed in direction.
Reverse an edge.
Reverse a list of edges.
Return the outdegree sequence.
Same as degree_iterator, but for out degree.
Same as degree, but for out degree.
Return the indegree sequence of this digraph.
Same as degree_iterator, but for in degree.
Same as degree, but for in-degree.
Return the list of the out-neighbors of a given vertex.
Return an iterator over the out-neighbors of a given vertex.
Return the list of the in-neighbors of a given vertex.
Return an iterator over the in-neighbors of vertex.
Return a list of edges departing from vertices.
Return an iterator over all departing edges from vertices
Return a list of edges arriving at vertices.
Return an iterator over all arriving edges from vertices
Return the list of all sources (vertices without incoming edges) of this digraph.
Return the list of all sinks (vertices without outgoing edges) of this digraph.
Return an undirected version of the graph.
Since the graph is already directed, simply returns a copy of itself.
Since digraph is directed, returns True.
Return the dig6 representation of the digraph as an ASCII string.

Distances:
eccentricity()
radius()diameter()center()periphery()

Return the eccentricity of vertex (or vertices) v.
Return the radius of the DiGraph.
Return the diameter of the DiGraph.
Return the set of vertices in the center of the DiGraph.
Return the set of vertices in the periphery of the DiGraph.

Paths and cycles:
all_cycles_iterator()
all_simple_cycles()Return an iterator over all the cycles of self starting with one of the given vertices.
Return a list of all simple cycles of self.

Representation theory:
path_semigroup()auslander_reiten_quiver()664

Return the (partial) semigroup formed by the paths of the digraph.
Return the Auslander-Reiten quiver of self.

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Connectivity:
is_strongly_connected()strongly_connected_components_digraph()strongly_connected_components_subgraphs()
strongly_connected_component_containing_vertex()strongly_connected_components()
strong_articulation_points()

Check whether the current DiGraph is strongly connected.
Return the digraph of the strongly connected components

Return the strongly connected components as a list of subgraphs.
Return the strongly connected component containing a given vertex

Return the list of strongly connected components.
Return the strong articulation points of this digraph.

Acyclicity:
is_directed_acyclic()
is_transitive()
is_aperiodic()
is_tournament()
period()level_sets()
topological_sort_generator()
topological_sort()

Check whether the digraph is acyclic or not.
Check whether the digraph is transitive or not.
Check whether the digraph is aperiodic or not.
Check whether the digraph is a tournament.
Return the period of the digraph.
Return the level set decomposition of the digraph.
Return a list of all topological sorts of the digraph if it is acyclic
Return a topological sort of the digraph if it is acyclic

Hard stuff:
feedback_edge_set()Compute the minimum feedback edge (arc) set of a digraphMiscellaneous:
flow_polytope()
degree_polynomial()
out_branchings()
in_branchings()

1.3. Directed graphs

Compute the flow polytope of a digraph
Return the generating polynomial of degrees of vertices in self.
Return an iterator over the out branchings rooted at given vertex in self.
Return an iterator over the in branchings rooted at given vertex in self.

665

Graph Theory, Release 10.4

1.3.1 Methods
class sage.graphs.digraph.DiGraph(data=None, pos=None, loops=None, format=None,weighted=None, data_structure='sparse', vertex_labels=True,
name=None, multiedges=None,convert_empty_dict_labels_to_None=None, sparse=True,
immutable=False, hash_labels=None)
Bases: 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) orby 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):
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,
tices/edges

list_of_edges]) – return a digraph with given ver-

To bypass auto-detection,
prefer theformat= vertices_and_edges ).

moreexplicit

DiGraph([V,E],

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 alist 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 documentationof adjacency_matrix()).
To
bypassauto-detection,
preferthemoreexplicit
format= adjacency_matrix ).
Totakeweights
intoformat= weighted_adjacency_matrix instead.

DiGraph(M,account,use

8. DiGraph(a_nonsquare_matrix) – return a digraph with given incidence matrix (see documentation of incidence_matrix()).
To
bypassauto-detection,format= incidence_matrix ).
666

preferthemoreexplicit

DiGraph(M,

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

9. DiGraph([V, f]) – return a digraph with a vertex set V and an edge 𝑢, 𝑣 whenever 𝑓 (𝑢, 𝑣) 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, NetworkX digraph, or igraph digraph.
• pos – dict (default: None); 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 – string (default: None); gives the graph a name (e.g., name=”complete”)• loops – boolean (default: None); whether to allow loops (ignored if data is an instance of the DiGraph
class)• multiedges – boolean (default: None); whether to allow multiple edges (ignored if data is an instance of
the DiGraph class)• weighted – boolean (default: None); whether digraph thinks of itself as weighted or not. See self.
weighted()• format – string (default: None); if set to None, DiGraph tries to guess input’s format. To avoid
this possibly time-consuming step, one of the following values can be specified (see description above):"int", "dig6", "rule", "list_of_edges", "dict_of_lists", "dict_of_dicts","adjacency_matrix", "weighted_adjacency_matrix", "incidence_matrix", "NX","igraph".
• sparse – boolean (default: True); sparse=True is an alias for data_structure="sparse", andsparse=False is an alias for data_structure="dense"• data_structure – string (default: "sparse"); one of the following (for more information, see
overview):– "dense" – selects the dense_graph backend– "sparse" – selects the sparse_graph backend– "static_sparse" – selects the static_sparse_backend (this backend is faster than thesparse backend and smaller in memory, and it is immutable, so that the resulting graphs can be usedas dictionary keys).
• immutable – boolean (default: False); whether to create a immutable digraph. Note that immutable=True is actually a shortcut for data_structure= static_sparse .
• hash_labels – boolean (default: None); whether to include edge labels during hashing. This parameter
defaults to True if the digraph is weighted. This parameter is ignored if the digraph is mutable. Beware thattrying to hash unhashable labels will raise an error.
• vertex_labels – boolean (default: True); whether to allow any object as a vertex (slower), or only the
integers 0, ..., 𝑛 − 1, where 𝑛 is the number of vertices.
• convert_empty_dict_labels_to_None – boolean (default: None); this arguments sets the default
edge labels used by NetworkX (empty dictionaries) to be replaced by None, the default Sage edge label. It
is set to True iff a NetworkX graph is on the input.

1.3. Directed graphs

667

Graph Theory, Release 10.4

EXAMPLES:
1. A dictionary of dictionaries:
sage: g = DiGraph({0: {1:Digraph on 5 vertices

x , 2:

z , 3:a }, 2: {5:out }}); g>>> from sage.all import *>>> g = DiGraph({Integer(0): {Integer(1): x , Integer(2):˓→ }, Integer(2): {Integer(5):out }}); g
Digraph on 5 vertices

z , Integer(3):aThe 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>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(2): [Integer(4)]}); g
Digraph on 5 vertices>>> g = DiGraph({Integer(0): (Integer(1), Integer(2), Integer(3)),␣
˓→Integer(2): (Integer(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 𝑖 to 𝑗 if and only if
𝑖 divides 𝑗:sage: g = DiGraph([[1..12], lambda i,j: i != j and i.divides(j)])
sage: g.vertices(sort=True)[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: g.adjacency_matrix()
˓→needs sage.modules[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]
[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]

#␣>>> from sage.all import *>>> g = DiGraph([(ellipsis_range(Integer(1),Ellipsis,Integer(12))), lambda i,
˓→j: i != j and i.divides(j)])>>> g.vertices(sort=True)(continues on next page)

668

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]>>> g.adjacency_matrix()
˓→needs sage.modules[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]
[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],␣˓→# needs sage.modules....:[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)␣˓→# needs sage.modules
Digraph on 5 vertices
sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M˓→# needs sage.modules
[
0
1
-1]
[ -1
0 -1/2][
1 1/2
0]
sage: G = DiGraph(M, sparse=True, weighted=True); G˓→# needs sage.modules
Digraph on 3 vertices
sage: G.weighted()˓→# needs sage.modules
True

␣

␣

␣

>>> from sage.all import *>>> M = Matrix([[Integer(0), Integer(1), Integer(1), Integer(1),␣
˓→Integer(0)], [Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0)],# needs sage.modules...
[Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(1)], [Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0)], [Integer(0), Integer(0), Integer(0), Integer(0),␣
˓→Integer(0)]]); M[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 1]
[0 0 0 0 0](continues on next page)

1.3. Directed graphs669

Graph Theory, Release 10.4

(continued from previous page)[0 0 0 0 0]>>> DiGraph(M)˓→# needs sage.modules
Digraph on 5 vertices>>> M = Matrix([[Integer(0),Integer(1),-Integer(1)], [-Integer(1),˓→Integer(0),-Integer(1)/Integer(2)], [Integer(1),Integer(1)/Integer(2),˓→Integer(0)]]); M# needs sage.modules
[
0
1
-1]
[ -1
0 -1/2][
1 1/2
0]>>> G = DiGraph(M, sparse=True, weighted=True); G
˓→# needs sage.modules
Digraph on 3 vertices>>> G.weighted()
˓→# needs sage.modules
True• an incidence matrix:
sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0,˓→# needs sage.modules....:
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)˓→# needs sage.modules
Digraph on 6 vertices␣␣>>> from sage.all import *>>> M = Matrix(Integer(6), [-Integer(1),Integer(0),Integer(0),Integer(0),˓→Integer(1), Integer(1),-Integer(1),Integer(0),Integer(0),Integer(0),␣
˓→Integer(0),Integer(1),-Integer(1),Integer(0),Integer(0),␣˓→# needs sage.modules...
Integer(0),Integer(0),Integer(1),-Integer(1),˓→Integer(0), Integer(0),Integer(0),Integer(0),Integer(1),-Integer(1),␣
˓→Integer(0),Integer(0),Integer(0),Integer(0),Integer(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]>>> DiGraph(M)˓→# needs sage.modules
Digraph on 6 vertices

5. A dig6 string: Sage automatically recognizes whether a string is in dig6 format, which is a directed versionof graph6:
sage: D = DiGraph( IRAaDCIIOWEOKcPWAo )sage: D(continues on next page)

670

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

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 shortsage: D = DiGraph("IRAaDCI OWEOKcPWAo")
Traceback (most recent call last):...
RuntimeError: the string seems corrupt: valid characters are?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ abcdefghijklmnopqrstuvwxyz{|}~>>> from sage.all import *>>> D = DiGraph( IRAaDCIIOWEOKcPWAo )>>> D
Digraph on 10 vertices>>> D = DiGraph( IRAaDCIIOEOKcPWAo )Traceback (most recent call last):...
RuntimeError: the string (IRAaDCIIOEOKcPWAo) seems corrupt: for n = 10, the␣˓→string is too short>>> D = DiGraph("IRAaDCI OWEOKcPWAo")
Traceback (most recent call last):...
RuntimeError: the string seems corrupt: valid characters are?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ abcdefghijklmnopqrstuvwxyz{|}~

6. A NetworkX MultiDiGraph:
sage: import networkx
˓→needs networkx
sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]})˓→needs networkx
sage: DiGraph(g)˓→needs networkx
Multi-digraph on 5 vertices

#␣
#␣
#␣

>>> from sage.all import *>>> import networkx#␣˓→needs networkx>>> g = networkx.MultiDiGraph({Integer(0): [Integer(1), Integer(2),␣
˓→Integer(3)], Integer(2): [Integer(4)]})# needs networkx>>> DiGraph(g)#␣˓→needs networkx
Multi-digraph on 5 vertices

7. A NetworkX digraph:
sage: import networkx
˓→needs networkx
sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]})˓→needs networkx#␣#␣(continues on next page)

1.3. Directed graphs671

Graph Theory, Release 10.4

(continued from previous page)

sage: DiGraph(g)˓→needs networkx
Digraph on 5 vertices#␣>>> from sage.all import *>>> import networkx#␣˓→needs networkx>>> g = networkx.DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(2): [Integer(4)]})# needs networkx>>> DiGraph(g)#␣˓→needs networkx
Digraph on 5 vertices

8. An igraph directed Graph (see also igraph_graph()):
sage: import igraph˓→igraph
sage: g = igraph.Graph([(0,1),(0,2)], directed=True)
˓→igraph
sage: DiGraph(g)˓→igraph
Digraph on 3 vertices# optional - python_# optional - python_# optional - python_>>> from sage.all import *>>> import igraph# optional - python_igraph>>> g = igraph.Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2))],␣
˓→directed=True)# optional - python_igraph>>> DiGraph(g)# optional - python_igraphDigraph on 3 vertices

If vertex_labels is True, the names of the vertices are given by the vertex attribute name , ifavailable:
sage: # optional - python_igraphsage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={ name :[ a
˓→ , b , c ]})sage: DiGraph(g).vertices(sort=True)[ a , b , c ]sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={ label :[ a
˓→ , b , c ]})sage: DiGraph(g).vertices(sort=True)[0, 1, 2]>>> from sage.all import *>>> # optional - python_igraph>>> g = igraph.Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2))],␣
˓→directed=True, vertex_attrs={ name :[ a , b , c ]})>>> DiGraph(g).vertices(sort=True)[ a , b , c ]>>> g = igraph.Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2))],␣
˓→directed=True, vertex_attrs={ label :[ a , b , c ]})>>> DiGraph(g).vertices(sort=True)[0, 1, 2]

If the igraph Graph has edge attributes, they are used as edge labels:

672

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: g = igraph.Graph([(0, 1), (0, 2)], directed=True,#␣˓→optional - python_igraph....:edge_attrs={ name :[ a , b ], weight :[1, 3]})sage: DiGraph(g).edges(sort=True)#␣˓→optional - python_igraph[(0, 1, { name : a , weight : 1}), (0, 2, { name : b , weight : 3})]>>> from sage.all import *>>> g = igraph.Graph([(Integer(0), Integer(1)), (Integer(0), Integer(2))],␣
˓→directed=True,# optional - python_igraph...
edge_attrs={ name :[ a , b ], weight :[Integer(1),␣
˓→Integer(3)]})>>> DiGraph(g).edges(sort=True)#␣˓→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)
Return an iterator over all the cycles of self starting with one of the given vertices.
The cycles are enumerated in increasing length order.
INPUT:• starting_vertices – iterable (default: None); vertices from which the cycles must start. If None,then all vertices of the graph can be starting points. This argument is necessary if rooted is set to True.
• simple – boolean (default: False); if set to True, then only simple cycles are considered. A cycle
is simple if the only vertex occurring twice in it is the starting and ending one.
• rooted – boolean (default: False); if set to False, then cycles differing only by their starting vertex
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 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
See also:• all_simple_cycles()
AUTHOR:
Alexandre Blondin Masse
EXAMPLES:
sage: g = DiGraph({ a : [ a , b ], b : [ 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 ]c : [ d ],d : [ c ]},␣(continues on next page)

1.3. Directed graphs673

Graph Theory, Release 10.4

(continued from previous page)

[ a ,
[ a ,
[ c ,
[ a ,

a ,
a ,
d ,
a ,

a ,
a ,
c ,
a ,

a ]
a ,
d ,
a ,

a ]
c ]
a ,

a ]

>>> from sage.all import *>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ],˓→loops=True)>>> it = g.all_cycles_iterator()>>> for _ in range(Integer(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 ]d : [ c ]},␣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)[]>>> from sage.all import *>>> g = DiGraph()>>> it = g.all_cycles_iterator()>>> list(it)[]>>> g = DiGraph({Integer(0):[Integer(1)]})>>> it = g.all_cycles_iterator()>>> 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 ][ c , d , c , d , c ][ c , d , c , d , c , d , c ]>>> from sage.all import *>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)>>> it = g.all_cycles_iterator(starting_vertices=[ b , c ])>>> for _ in range(Integer(3)): print(next(it))[ c , d , c ](continues on next page)

674

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

[ c ,
[ c ,

d ,
d ,

c ,
c ,

d ,
d ,

c ]
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 ]]>>> from sage.all import *>>> it = g.all_cycles_iterator(max_length=Integer(3))>>> 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 ]]>>> from sage.all import *>>> it = g.all_cycles_iterator(max_length=Integer(3), rooted=False)>>> list(it)[[ a , a ], [ a , a , a ], [ c , d , c ],[ a , a , a , a ]]>>> it = g.all_cycles_iterator(max_length=Integer(3), rooted=True)>>> 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 occurring twice in it is thestarting 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]]>>> from sage.all import *>>> it = g.all_cycles_iterator(simple=True)>>> list(it)[[ a , a ], [ c , d , c ]]>>> g = digraphs.Circuit(Integer(4))>>> list(g.all_cycles_iterator(simple=True))[[0, 1, 2, 3, 0]]

all_simple_cycles(starting_vertices=None, rooted=False, max_length=None, trivial=False)
1.3. Directed graphs675Graph Theory, Release 10.4

Return a list of all simple cycles of self.
INPUT:• starting_vertices – iterable (default: None); vertices from which the cycles must start. If None,then all vertices of the graph can be starting points. This argument is necessary if rooted is set to True.
• rooted – boolean (default: False); if set to False, then cycles differing only by their starting vertex
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 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 cycles of a finite graph is always finite, computing all its cycles may
take a very long time.
EXAMPLES:
sage: g = DiGraph({ a : [ a ,˓→loops=True)
sage: g.all_simple_cycles()[[ a , a ], [ c , d , c ]]b ],>>> from sage.all import *>>> g = DiGraph({ a : [ a , b ],˓→loops=True)>>> g.all_simple_cycles()[[ a , a ], [ c , d , c ]]b : [ c ],b : [ c ],c : [ d ],c : [ d ],d : [ 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, 4, 3], [3, 8, 3], [4, 9, 4], [5, 7, 5], [5, 8, 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, 4, 3], [3, 8, 3], [4, 9, 4], [5, 7, 5], [5, 8, 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, 3, 2, 1, 0], [0, 4, 3, 8, 5, 0], [0, 4, 9, 6, 1, 0],[0, 4, 9, 7, 5, 0], [0, 5, 7, 2, 1, 0], [0, 5, 7, 9, 4, 0],[0, 5, 8, 3, 4, 0], [0, 5, 8, 6, 1, 0], [1, 2, 3, 8, 6, 1],[1, 2, 7, 9, 6, 1], [1, 6, 8, 3, 2, 1], [1, 6, 9, 7, 2, 1],[2, 3, 4, 9, 7, 2], [2, 3, 8, 5, 7, 2], [2, 7, 5, 8, 3, 2],[2, 7, 9, 4, 3, 2], [3, 4, 9, 6, 8, 3], [3, 8, 6, 9, 4, 3],[5, 7, 9, 6, 8, 5], [5, 8, 6, 9, 7, 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, 3, 2, 7, 5, 0],(continues on next page)

676

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[0, 4, 3, 8, 6, 1, 0], [0, 4, 9, 6, 8, 5, 0],[0, 4, 9, 7, 2, 1, 0], [0, 5, 7, 2, 3, 4, 0],[0, 5, 7, 9, 6, 1, 0], [0, 5, 8, 3, 2, 1, 0],[0, 5, 8, 6, 9, 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, 4, 9, 7, 5, 8, 3],[3, 8, 5, 7, 9, 4, 3]]>>> from sage.all import *>>> g = graphs.PetersenGraph().to_directed()>>> g.all_simple_cycles(max_length=Integer(4))[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],[2, 7, 2], [3, 4, 3], [3, 8, 3], [4, 9, 4], [5, 7, 5], [5, 8, 5],[6, 8, 6], [6, 9, 6], [7, 9, 7]]>>> g.all_simple_cycles(max_length=Integer(6))[[0, 1, 0], [0, 4, 0], [0, 5, 0], [1, 2, 1], [1, 6, 1], [2, 3, 2],[2, 7, 2], [3, 4, 3], [3, 8, 3], [4, 9, 4], [5, 7, 5], [5, 8, 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, 3, 2, 1, 0], [0, 4, 3, 8, 5, 0], [0, 4, 9, 6, 1, 0],[0, 4, 9, 7, 5, 0], [0, 5, 7, 2, 1, 0], [0, 5, 7, 9, 4, 0],[0, 5, 8, 3, 4, 0], [0, 5, 8, 6, 1, 0], [1, 2, 3, 8, 6, 1],[1, 2, 7, 9, 6, 1], [1, 6, 8, 3, 2, 1], [1, 6, 9, 7, 2, 1],[2, 3, 4, 9, 7, 2], [2, 3, 8, 5, 7, 2], [2, 7, 5, 8, 3, 2],[2, 7, 9, 4, 3, 2], [3, 4, 9, 6, 8, 3], [3, 8, 6, 9, 4, 3],[5, 7, 9, 6, 8, 5], [5, 8, 6, 9, 7, 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, 3, 2, 7, 5, 0],[0, 4, 3, 8, 6, 1, 0], [0, 4, 9, 6, 8, 5, 0],[0, 4, 9, 7, 2, 1, 0], [0, 5, 7, 2, 3, 4, 0],[0, 5, 7, 9, 6, 1, 0], [0, 5, 8, 3, 2, 1, 0],[0, 5, 8, 6, 9, 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, 4, 9, 7, 5, 8, 3],[3, 8, 5, 7, 9, 4, 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]]>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4)).to_directed()>>> 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]]1.3. Directed graphs

677

Graph Theory, Release 10.4

If the graph contains a large number of cycles, one can bound the length of the cycles, or simply restrict thepossible starting vertices of the cycles:
sage: g = graphs.CompleteGraph(20).to_directed()sage: g.all_simple_cycles(max_length=2)[[0, 16, 0], [0, 1, 0], [0, 17, 0], [0, 2, 0], [0, 18, 0],[0, 3, 0], [0, 19, 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], [1, 16, 1], [1, 17, 1],[1, 2, 1], [1, 18, 1], [1, 3, 1], [1, 19, 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], [2, 16, 2],[2, 17, 2], [2, 18, 2], [2, 3, 2], [2, 19, 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],[3, 16, 3], [3, 17, 3], [3, 18, 3], [3, 19, 3], [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],[4, 16, 4], [4, 17, 4], [4, 18, 4], [4, 19, 4], [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], [5, 16, 5],[5, 17, 5], [5, 18, 5], [5, 19, 5], [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], [6, 16, 6], [6, 17, 6],[6, 18, 6], [6, 19, 6], [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], [7, 16, 7], [7, 17, 7], [7, 18, 7], [7, 19, 7],[7, 8, 7], [7, 9, 7], [7, 10, 7], [7, 11, 7], [7, 12, 7],[7, 13, 7], [7, 14, 7], [7, 15, 7], [8, 16, 8], [8, 17, 8],[8, 18, 8], [8, 19, 8], [8, 9, 8], [8, 10, 8], [8, 11, 8],[8, 12, 8], [8, 13, 8], [8, 14, 8], [8, 15, 8], [9, 16, 9],[9, 17, 9], [9, 18, 9], [9, 19, 9], [9, 10, 9], [9, 11, 9],[9, 12, 9], [9, 13, 9], [9, 14, 9], [9, 15, 9], [10, 16, 10],
[10, 17, 10], [10, 18, 10], [10, 19, 10], [10, 11, 10],
[10, 12, 10], [10, 13, 10], [10, 14, 10], [10, 15, 10],
[11, 16, 11], [11, 17, 11], [11, 18, 11], [11, 19, 11],
[11, 12, 11], [11, 13, 11], [11, 14, 11], [11, 15, 11],
[12, 16, 12], [12, 17, 12], [12, 18, 12], [12, 19, 12],
[12, 13, 12], [12, 14, 12], [12, 15, 12], [13, 16, 13],
[13, 17, 13], [13, 18, 13], [13, 19, 13], [13, 14, 13],
[13, 15, 13], [14, 16, 14], [14, 17, 14], [14, 18, 14],
[14, 19, 14], [14, 15, 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, 16, 0], [0, 1, 0], [0, 17, 0], [0, 2, 0], [0, 18, 0],[0, 3, 0], [0, 19, 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]]>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(20)).to_directed()>>> g.all_simple_cycles(max_length=Integer(2))[[0, 16, 0], [0, 1, 0], [0, 17, 0], [0, 2, 0], [0, 18, 0],[0, 3, 0], [0, 19, 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],(continues on next page)

678

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[0, 13, 0], [0, 14, 0], [0, 15, 0], [1, 16, 1], [1, 17, 1],[1, 2, 1], [1, 18, 1], [1, 3, 1], [1, 19, 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], [2, 16, 2],[2, 17, 2], [2, 18, 2], [2, 3, 2], [2, 19, 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],[3, 16, 3], [3, 17, 3], [3, 18, 3], [3, 19, 3], [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],[4, 16, 4], [4, 17, 4], [4, 18, 4], [4, 19, 4], [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], [5, 16, 5],[5, 17, 5], [5, 18, 5], [5, 19, 5], [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], [6, 16, 6], [6, 17, 6],[6, 18, 6], [6, 19, 6], [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], [7, 16, 7], [7, 17, 7], [7, 18, 7], [7, 19, 7],[7, 8, 7], [7, 9, 7], [7, 10, 7], [7, 11, 7], [7, 12, 7],[7, 13, 7], [7, 14, 7], [7, 15, 7], [8, 16, 8], [8, 17, 8],[8, 18, 8], [8, 19, 8], [8, 9, 8], [8, 10, 8], [8, 11, 8],[8, 12, 8], [8, 13, 8], [8, 14, 8], [8, 15, 8], [9, 16, 9],[9, 17, 9], [9, 18, 9], [9, 19, 9], [9, 10, 9], [9, 11, 9],[9, 12, 9], [9, 13, 9], [9, 14, 9], [9, 15, 9], [10, 16, 10],
[10, 17, 10], [10, 18, 10], [10, 19, 10], [10, 11, 10],
[10, 12, 10], [10, 13, 10], [10, 14, 10], [10, 15, 10],
[11, 16, 11], [11, 17, 11], [11, 18, 11], [11, 19, 11],
[11, 12, 11], [11, 13, 11], [11, 14, 11], [11, 15, 11],
[12, 16, 12], [12, 17, 12], [12, 18, 12], [12, 19, 12],
[12, 13, 12], [12, 14, 12], [12, 15, 12], [13, 16, 13],
[13, 17, 13], [13, 18, 13], [13, 19, 13], [13, 14, 13],
[13, 15, 13], [14, 16, 14], [14, 17, 14], [14, 18, 14],
[14, 19, 14], [14, 15, 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]]>>> g = graphs.CompleteGraph(Integer(20)).to_directed()>>> g.all_simple_cycles(max_length=Integer(2), starting_vertices=[Integer(0)])[[0, 16, 0], [0, 1, 0], [0, 17, 0], [0, 2, 0], [0, 18, 0],[0, 3, 0], [0, 19, 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]]

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]]>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4)).to_directed()(continues on next page)

1.3. Directed graphs679

Graph Theory, Release 10.4

(continued from previous page)>>> g.all_simple_cycles(max_length=Integer(2), rooted=False)[[0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 2, 1], [1, 3, 1], [2, 3, 2]]>>> g.all_simple_cycles(max_length=Integer(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]]auslander_reiten_quiver()Return the Auslander-Reiten quiver of self.
See also:
AuslanderReitenQuiver
EXAMPLES:
sage: D = DiGraph([[1,2, a ], [1,2, b ]], multiedges=True)
sage: D.auslander_reiten_quiver()
Auslander-Reiten quiver of Multi-digraph on 2 vertices>>> from sage.all import *>>> D = DiGraph([[Integer(1),Integer(2), a ], [Integer(1),Integer(2), b ]],␣˓→multiedges=True)>>> D.auslander_reiten_quiver()
Auslander-Reiten quiver of Multi-digraph on 2 vertices

center(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the set of vertices in the center of the DiGraph.
The center is the set of vertices whose eccentricity is equal to the radius of the DiGraph, i.e., achieving theminimum eccentricity.
For more information and examples on how to use input variables, see shortest_paths() and eccentricity()
INPUT:• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); see method eccentricity() for the list of available algorithms• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:
Every vertex is a center in a Circuit-DiGraph:
sage: G = digraphs.Circuit(9)sage: G.center()[0, 1, 2, 3, 4, 5, 6, 7, 8]

680

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = digraphs.Circuit(Integer(9))>>> G.center()[0, 1, 2, 3, 4, 5, 6, 7, 8]Center can be the whole graph:
sage: G.subgraph(G.center()) == G
True>>> from sage.all import *>>> G.subgraph(G.center()) == G
True

Some other graphs:
sage: G = digraphs.Path(5)sage: G.center()[0]sage: G = DiGraph([(0,1,2), (1,2,3), (2,0,2)])
sage: G.center(by_weight=True)[2]>>> from sage.all import *>>> G = digraphs.Path(Integer(5))>>> G.center()[0]>>> G = DiGraph([(Integer(0),Integer(1),Integer(2)), (Integer(1),Integer(2),˓→Integer(3)), (Integer(2),Integer(0),Integer(2))])>>> G.center(by_weight=True)[2]

degree_polynomial()
Return the generating polynomial of degrees of vertices in self.
This is the sum∑︁𝑥in(𝑣) 𝑦 out(𝑣) ,𝑣∈𝐺where in(v) and out(v) are the number of incoming and outgoing edges at vertex 𝑣 in the digraph 𝐺.
Because this polynomial is multiplicative for Cartesian product of digraphs, it is useful to help see if the
digraph can be isomorphic to a Cartesian product.
See also:
num_verts() for the value at (𝑥, 𝑦) = (1, 1)
EXAMPLES:
sage: G = posets.PentagonPoset().hasse_diagram()
˓→needs sage.modules
sage: G.degree_polynomial()
˓→needs sage.modulesx^2 + 3*x*y + y^2#␣#␣

sage: G = posets.BooleanLattice(4).hasse_diagram()(continues on next page)

1.3. Directed graphs

681

Graph Theory, Release 10.4

(continued from previous page)

sage: G.degree_polynomial().factor()˓→needs sage.libs.pari(x + y)^4#␣>>> from sage.all import *>>> G = posets.PentagonPoset().hasse_diagram()
˓→needs sage.modules>>> G.degree_polynomial()
˓→needs sage.modulesx^2 + 3*x*y + y^2>>> G = posets.BooleanLattice(Integer(4)).hasse_diagram()>>> G.degree_polynomial().factor()˓→needs sage.libs.pari(x + y)^4

#␣
#␣

#␣

diameter(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the diameter of the DiGraph.
The diameter is defined to be the maximum distance between two vertices. It is infinite if the DiGraph is notstrongly connected.
For more information and examples on how to use input variables, see shortest_paths() and eccentricity()
INPUT:• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); one of the following algorithms:

682–

BFS : the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False. It computes all the eccentricities and return the maximum value.

–

Floyd-Warshall-Cython : a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False. It computes all the eccentricities and return the maximum
value.

–

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).
It computes all the eccentricities and return the maximum value.

–

Dijkstra_NetworkX : the Dijkstra algorithm, implemented in NetworkX. It works withweighted graphs, but no negative weight is allowed. It computes all the eccentricities and returnthe maximum value.

–

DiFUB ,
2Dsweep :these algorithms are implemented in sage.graphs.
distances_all_pairs.diameter() and sage.graphs.base.boost_graph.
diameter(). 2Dsweep returns lower bound on the diameter, while DiFUB returns theexact computed diameter. They also work with negative weight, if there is no negative cycle. See
the functions documentation for more information.

–

standard:
the standard algorithm is implemented in sage.graphs.
distances_all_pairs.diameter(). It works only if by_weight==False. See
the function documentation for more information. It computes all the eccentricities and return the
maximum value.

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4–

Dijkstra_Boost : the Dijkstra algorithm, implemented in Boost (works only with positive
weights). It computes all the eccentricities and return the maximum value.

–

Johnson_Boost : the Johnson algorithm, implemented in Boost (works also with negative
weights, if there is no negative cycle). It computes all the eccentricities and return the maximum
value.

– None (default): Sage chooses the best algorithm: DiFUB .
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(5,4)
sage: G.diameter()4
sage: G = digraphs.GeneralizedDeBruijn(9, 3)
sage: G.diameter()2>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(5),Integer(4))>>> G.diameter()
4>>> G = digraphs.GeneralizedDeBruijn(Integer(9), Integer(3))>>> G.diameter()2

dig6_string()
Return the dig6 representation of the digraph as an ASCII string.
This is only valid for single (no multiple edges) digraphs on at most 218 − 1 = 262143 vertices.
Note: As the dig6 format only handles graphs with vertex set {0, . . . , 𝑛 − 1}, a relabelled copy
will be encoded, if necessary.
See also:• 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 _>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(0)]})(continues on next page)

1.3. Directed graphs683

Graph Theory, Release 10.4

(continued from previous page)>>> D.dig6_string()
CW _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_path_all_pairs(),
shortest_path_lengths() and shortest_paths()
INPUT:• v – either a single vertex or a list of vertices. If it is not specified, then it is taken to be all vertices.
• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); one of the following algorithms:–

BFS – the computation is done through a BFS centered on each vertex successively. Works only
if by_weight==False.

–

Floyd-Warshall-Cython – a Cython implementation of the Floyd-Warshall algorithm.
Works only if by_weight==False and v is None or v should contain all vertices of self.

–

Floyd-Warshall-Python – a Python implementation of the Floyd-Warshall algorithm.
Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
However, v must be None or v should contain all vertices of self.

–

Dijkstra_NetworkX – the Dijkstra algorithm, implemented in NetworkX. It works withweighted graphs, but no negative weight is allowed.

–

Dijkstra_Boost – the Dijkstra algorithm, implemented in Boost (works only with positive
weights).

–

Johnson_Boost – the Johnson algorithm, implemented in Boost (works also with negative
weights, if there is no negative cycle). Works only if v is None or v should contain all verticesof self.

–

From_Dictionary – uses the (already computed) distances, that are provided by input variable dist_dict.

– None (default): Sage chooses the best algorithm: From_Dictionary if dist_dict is
not None, BFS for unweighted graphs, Dijkstra_Boost if all weights are positive,
Johnson_Boost otherwise.
• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
• dist_dict – a dictionary (default: None); a dict of dicts of distances (used only if
algorithm== From_Dictionary )• with_labels – boolean (default: False); whether to return a list or a dictionary keyed by vertices.
EXAMPLES:

684

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = graphs.KrackhardtKiteGraph().to_directed()sage: G.eccentricity()[4, 4, 4, 4, 4, 3, 3, 2, 3, 4]
sage: G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: G.eccentricity(7)2sage: G.eccentricity([7,8,9])[2, 3, 4]
sage: G.eccentricity([7,8,9], with_labels=True) == {8: 3, 9: 4, 7: 2}
Truesage: G = DiGraph(3)sage: G.eccentricity(with_labels=True){0: +Infinity, 1: +Infinity, 2: +Infinity}
sage: G = DiGraph({0:[]})
sage: G.eccentricity(with_labels=True){0: 0}
sage: G = DiGraph([(0,1,2), (1,2,3), (2,0,2)])
sage: G.eccentricity(algorithm= BFS )[2, 2, 2]
sage: G.eccentricity(algorithm= Floyd-Warshall-Cython )[2, 2, 2]
sage: G.eccentricity(by_weight=True, algorithm= Dijkstra_NetworkX )#␣˓→needs networkx[5, 5, 4]
sage: G.eccentricity(by_weight=True, algorithm= Dijkstra_Boost )[5, 5, 4]
sage: G.eccentricity(by_weight=True, algorithm= Johnson_Boost )[5, 5, 4]
sage: G.eccentricity(by_weight=True, algorithm= Floyd-Warshall-Python )[5, 5, 4]
sage: G.eccentricity(dist_dict=G.shortest_path_all_pairs(by_weight=True)[0])[5, 5, 4]>>> from sage.all import *>>> G = graphs.KrackhardtKiteGraph().to_directed()>>> G.eccentricity()[4, 4, 4, 4, 4, 3, 3, 2, 3, 4]>>> G.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> G.eccentricity(Integer(7))
2>>> G.eccentricity([Integer(7),Integer(8),Integer(9)])[2, 3, 4]>>> G.eccentricity([Integer(7),Integer(8),Integer(9)], with_labels=True) ==˓→{Integer(8): Integer(3), Integer(9): Integer(4), Integer(7): Integer(2)}True>>> G = DiGraph(Integer(3))>>> G.eccentricity(with_labels=True){0: +Infinity, 1: +Infinity, 2: +Infinity}>>> G = DiGraph({Integer(0):[]})>>> G.eccentricity(with_labels=True){0: 0}>>> G = DiGraph([(Integer(0),Integer(1),Integer(2)), (Integer(1),Integer(2),˓→Integer(3)), (Integer(2),Integer(0),Integer(2))])>>> G.eccentricity(algorithm= BFS )[2, 2, 2](continues on next page)

1.3. Directed graphs

685

Graph Theory, Release 10.4

(continued from previous page)>>> G.eccentricity(algorithm= Floyd-Warshall-Cython )[2, 2, 2]>>> G.eccentricity(by_weight=True, algorithm= Dijkstra_NetworkX )˓→needs networkx[5, 5, 4]>>> G.eccentricity(by_weight=True, algorithm= Dijkstra_Boost )[5, 5, 4]>>> G.eccentricity(by_weight=True, algorithm= Johnson_Boost )[5, 5, 4]>>> G.eccentricity(by_weight=True, algorithm= Floyd-Warshall-Python )[5, 5, 4]>>> G.eccentricity(dist_dict=G.shortest_path_all_pairs(by_˓→weight=True)[Integer(0)])[5, 5, 4]#␣

feedback_edge_set(constraint_generation, value_only=True, solver=False, verbose=None,
integrality_tolerance=0)
Compute 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 𝐺 − 𝑆 isacyclic. 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 (default: True); whether to use constraint generation whensolving the Mixed Integer Linear Program.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
ALGORITHM:
This 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 𝑢 < 𝑣.

686

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Thus, this linear program is built in order to assign to each vertex 𝑣 a number 𝑑𝑣 ∈ [0, . . . , 𝑛 − 1] such that
if there exists an edge (𝑢, 𝑣) ∈ 𝐺 such that 𝑑𝑣 < 𝑑𝑢 , then the edge (𝑢, 𝑣) is removed.
The number of edges removed is then minimized, which is the objective.
(Constraint Generation)
If the parameter constraint_generation is enabled, a more efficient formulation is used :∑︁
Minimize :𝑏(𝑢,𝑣)(𝑢,𝑣)∈𝐺

Such that :∀𝐶 circuits ⊆ 𝐺,∑︁𝑏(𝑢,𝑣) ≥ 1

𝑢𝑣∈𝐶As the number of circuits contained in a graph is exponential, this LP is solved through constraint generation.
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), thenobviously 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)
˓→needs sage.numerical.mip
5#␣>>> from sage.all import *>>> cycle = graphs.CycleGraph(Integer(5))>>> dcycle = DiGraph(cycle)>>> cycle.size()5>>> dcycle.feedback_edge_set(value_only=True)
˓→needs sage.numerical.mip5#␣

And in this situation, for any edge 𝑢𝑣 of the first graph, 𝑢𝑣 of 𝑣𝑢 is in the returned feedback arc set:sage: g = graphs.RandomGNP(5,.3)
sage: while not g.num_edges():....:g = graphs.RandomGNP(5,.3)
sage: dg = DiGraph(g)sage: feedback = dg.feedback_edge_set()
˓→# needs sage.numerical.mip
sage: u,v,l = next(g.edge_iterator())
sage: (u,v) in feedback or (v,u) in feedback
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(5),RealNumber( .3 ))>>> while not g.num_edges():...
g = graphs.RandomGNP(Integer(5),RealNumber( .3 ))(continues on next page)

1.3. Directed graphs

687

Graph Theory, Release 10.4

(continued from previous page)>>> dg = DiGraph(g)>>> feedback = dg.feedback_edge_set()˓→needs sage.numerical.mip>>> u,v,l = next(g.edge_iterator())>>> (u,v) in feedback or (v,u) in feedback
˓→needs sage.numerical.mip
True

#␣

#␣

flow_polytope(edges=None, ends=None, backend=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 agiven 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 assignmentof 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 setof 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 isthe one returned by self.edges(sort=True). 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 [PS2002].
INPUT:• edges – list (default: None); a list of edges of self. If not specified, the list of all edges of self isused with the default ordering of self.edges(sort=True). This determines which coordinate ofa point in the polytope will correspond to which edge of self. It is also possible to specify a list whichcontains 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 outputtedby self.edges(); so, if self.edges() outputs an edge in the form (1, 3, None), then (1,3) will not do!
• ends – (default: (self.sources(), self.sinks())) a pair (𝑆, 𝑇 ) of an iterable 𝑆 and an
iterable 𝑇 .
• backend – string or None (default); the backend to use; see sage.geometry.polyhedron.
constructor.Polyhedron()Note: Flow polytopes can also be built through the polytopes.<tab> object:
sage: polytopes.flow_polytope(digraphs.Path(5))#␣˓→needs sage.geometry.polyhedron
A 0-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex>>> from sage.all import *>>> polytopes.flow_polytope(digraphs.Path(Integer(5)))␣(continues on next page)

688

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)# needs sage.geometry.polyhedron
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
˓→needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^4 defined as the convex hullof 2 vertices
sage: fl.vertices()
˓→needs sage.geometry.polyhedron(A vertex at (0, 1, 0, 1), A vertex at (1, 0, 1, 0))#␣#␣>>> from sage.all import *>>> G = DiGraph({Integer(1): [Integer(2), Integer(3)], Integer(2):␣
˓→[Integer(4)], Integer(3): [Integer(4)]})>>> fl = G.flow_polytope(); fl
˓→needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^4 defined as the convex hullof 2 vertices>>> fl.vertices()
˓→needs sage.geometry.polyhedron(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: ordered_edges = G.edges(sort=True, key=lambda x: x[0] - x[1])sage: fl = G.flow_polytope(edges=ordered_edges); fl#␣˓→needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices
sage: fl.vertices()#␣˓→needs sage.geometry.polyhedron(A vertex at (0, 1, 1, 0), A vertex at (1, 0, 0, 1))>>> from sage.all import *>>> ordered_edges = G.edges(sort=True, key=lambda x: x[Integer(0)] -␣˓→x[Integer(1)])>>> fl = G.flow_polytope(edges=ordered_edges); fl#␣˓→needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices>>> fl.vertices()#␣˓→needs sage.geometry.polyhedron(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
˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in QQ^6 defined as the convex hullof 4 vertices
sage: fl.vertices()#␣#␣(continues on next page)

1.3. Directed graphs689

Graph Theory, Release 10.4

(continued from previous page)needs sage.geometry.polyhedron(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))˓→>>> from sage.all import *>>> H = digraphs.TransitiveTournament(Integer(4))>>> fl = H.flow_polytope(); fl
˓→needs sage.geometry.polyhedron
A 3-dimensional polyhedron in QQ^6 defined as the convex hullof 4 vertices>>> fl.vertices()
˓→needs sage.geometry.polyhedron(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),˓→needs sage.geometry.polyhedron....:(2, 3, None), (0, 3, None)]); fl
A 1-dimensional polyhedron in QQ^4 defined as the convex hullof 2 vertices
sage: fl.vertices()
˓→needs sage.geometry.polyhedron(A vertex at (0, 0, 0, 1), A vertex at (1, 1, 1, 0))#␣#␣>>> from sage.all import *>>> fl = H.flow_polytope(edges=[(Integer(0), Integer(1), None), (Integer(1),␣
˓→Integer(2), None),# needs sage.geometry.polyhedron...
(Integer(2), Integer(3), None), (Integer(0),␣
˓→Integer(3), None)]); fl
A 1-dimensional polyhedron in QQ^4 defined as the convex hullof 2 vertices>>> fl.vertices()#␣˓→needs sage.geometry.polyhedron(A vertex at (0, 0, 0, 1), A vertex at (1, 1, 1, 0))Using a different choice of sources and sinks:
sage: # needs sage.geometry.polyhedronsage: fl = H.flow_polytope(ends=([1], [3])); fl
A 1-dimensional polyhedron in QQ^6 defined as the convex hullof 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^6sage: fl = H.flow_polytope(ends=([3], [0])); fl
The empty polyhedron in QQ^6sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl
A 3-dimensional polyhedron in QQ^6 defined as the convex hullof 5 vertices(continues on next page)

690

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

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 hullof 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))>>> from sage.all import *>>> # needs sage.geometry.polyhedron>>> fl = H.flow_polytope(ends=([Integer(1)], [Integer(3)])); fl
A 1-dimensional polyhedron in QQ^6 defined as the convex hullof 2 vertices>>> fl.vertices()(A vertex at (0, 0, 0, 1, 0, 1), A vertex at (0, 0, 0, 0, 1, 0))>>> fl = H.flow_polytope(ends=([Integer(0), Integer(1)], [Integer(3)])); fl
The empty polyhedron in QQ^6>>> fl = H.flow_polytope(ends=([Integer(3)], [Integer(0)])); fl
The empty polyhedron in QQ^6>>> fl = H.flow_polytope(ends=([Integer(0), Integer(1)], [Integer(2),␣
˓→Integer(3)])); fl
A 3-dimensional polyhedron in QQ^6 defined as the convex hullof 5 vertices>>> 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))>>> fl = H.flow_polytope(edges=[(Integer(0), Integer(1), None), (Integer(1),␣
˓→Integer(2), None),...
(Integer(2), Integer(3), None), (Integer(0),␣
˓→Integer(2), None),...
(Integer(1), Integer(3), None)],...
ends=([Integer(0), Integer(1)], [Integer(2),␣
˓→Integer(3)])); fl
A 2-dimensional polyhedron in QQ^5 defined as the convex hullof 4 vertices>>> 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:

1.3. Directed graphs691

Graph Theory, Release 10.4

sage: Y = DiGraph({1: [2], 2: [3, 4]})sage: Y.flow_polytope()
˓→needs sage.geometry.polyhedron
The empty polyhedron in QQ^3#␣>>> from sage.all import *>>> Y = DiGraph({Integer(1): [Integer(2)], Integer(2): [Integer(3),␣
˓→Integer(4)]})>>> Y.flow_polytope()
˓→needs sage.geometry.polyhedron
The empty polyhedron in QQ^3#␣

A digraph with one vertex and no edge:
sage: Z = DiGraph({1: []})
sage: Z.flow_polytope()
˓→needs sage.geometry.polyhedron
A 0-dimensional polyhedron in QQ^0 defined as the convex hullof 1 vertex>>> from sage.all import *>>> Z = DiGraph({Integer(1): []})>>> Z.flow_polytope()
˓→needs sage.geometry.polyhedron
A 0-dimensional polyhedron in QQ^0 defined as the convex hullof 1 vertex#␣#␣A digraph with multiple edges (Issue #28837):
sage: G = DiGraph([(0, 1), (0,1)], multiedges=True); G
Multi-digraph on 2 vertices
sage: P = G.flow_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices
sage: P.vertices()#␣˓→needs sage.geometry.polyhedron(A vertex at (1, 0), A vertex at (0, 1))
sage: P.lines()#␣˓→needs sage.geometry.polyhedron()>>> from sage.all import *>>> G = DiGraph([(Integer(0), Integer(1)), (Integer(0),Integer(1))],␣
˓→multiedges=True); G
Multi-digraph on 2 vertices>>> P = G.flow_polytope(); P#␣˓→needs sage.geometry.polyhedron
A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices>>> P.vertices()#␣˓→needs sage.geometry.polyhedron(A vertex at (1, 0), A vertex at (0, 1))>>> P.lines()#␣˓→needs sage.geometry.polyhedron()

in_branchings(source, spanning=True)
Return an iterator over the in branchings rooted at given vertex in self.
692

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

An in-branching is a directed tree rooted at source whose arcs are directed to source from leaves. An
in-branching is spanning if it contains all vertices of the digraph.
If no spanning in branching rooted at source exist, raises ValueError or return non spanning in branchingrooted at source, depending on the value of spanning.
INPUT:• source – vertex used as the source for all in branchings.
• spanning – boolean (default: True); if False return maximum in branching to source. Otherwise, return spanning in branching if exists.
OUTPUT:
An iterator over the in branchings rooted in the given source.
See also:• out_branchings() – iterator over out-branchings rooted at given vertex.
• spanning_trees() – returns all spanning trees.
• spanning_trees_count() – counts the number of spanning trees.
ALGORITHM:
Recursively computes all in branchings.
At each step:
0. clean the graph (see below)
1. pick an edge e incoming to source
2. find all in branchings that do not contain e by first removing it
3. find all in branchings that do contain e by first merging the end vertices of e
Cleaning the graph implies to remove loops and replace multiedges by a single one with an appropriate label
since these lead to similar steps of computation.
EXAMPLES:
A bidirectional 4-cycle:
sage: G = DiGraph({1:[2,3], 2:[1,4], 3:[1,4], 4:[2,3]}, format= dict_of_lists
˓→ )sage: list(G.in_branchings(1))[Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices]>>> from sage.all import *>>> G = DiGraph({Integer(1):[Integer(2),Integer(3)], Integer(2):[Integer(1),˓→Integer(4)], Integer(3):[Integer(1),Integer(4)], Integer(4):[Integer(2),˓→Integer(3)]}, format= dict_of_lists )>>> list(G.in_branchings(Integer(1)))[Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices]

1.3. Directed graphs693

Graph Theory, Release 10.4

With the Petersen graph turned into a symmetric directed graph:
sage: G = graphs.PetersenGraph().to_directed()sage: len(list(G.in_branchings(0)))
2000>>> from sage.all import *>>> G = graphs.PetersenGraph().to_directed()>>> len(list(G.in_branchings(Integer(0))))2000

With a non connected DiGraph and spanning = True:
sage: G = graphs.PetersenGraph().to_directed() + graphs.PetersenGraph().to_˓→directed()sage: G.in_branchings(0)Traceback (most recent call last):...
ValueError: no spanning in branching to vertex (0) exist>>> from sage.all import *>>> G = graphs.PetersenGraph().to_directed() + graphs.PetersenGraph().to_˓→directed()>>> G.in_branchings(Integer(0))
Traceback (most recent call last):...
ValueError: no spanning in branching to vertex (0) exist

With a non connected DiGraph and spanning = False:
sage: g=DiGraph([(1,0), (1,0), (2,1), (3,4)],multiedges=True)
sage: list(g.in_branchings(0,spanning=False))[Digraph on 3 vertices, Digraph on 3 vertices]>>> from sage.all import *>>> g=DiGraph([(Integer(1),Integer(0)), (Integer(1),Integer(0)), (Integer(2),˓→Integer(1)), (Integer(3),Integer(4))],multiedges=True)>>> list(g.in_branchings(Integer(0),spanning=False))[Digraph on 3 vertices, Digraph on 3 vertices]

With multiedges:
sage: G = DiGraph({0:[1,1,1], 1:[2,2]}, format= dict_of_lists ,␣˓→multiedges=True)
sage: len(list(G.in_branchings(2)))
6>>> from sage.all import *>>> G = DiGraph({Integer(0):[Integer(1),Integer(1),Integer(1)],␣
˓→Integer(1):[Integer(2),Integer(2)]}, format= dict_of_lists ,␣˓→multiedges=True)>>> len(list(G.in_branchings(Integer(2))))
6

With a DiGraph already being a spanning in branching:694

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = DiGraph({0:[], 1:[0], 2:[0], 3:[1], 4:[1], 5:[2]}, format= dict_of_
˓→lists )sage: next(G.in_branchings(0)) == G
True>>> from sage.all import *>>> G = DiGraph({Integer(0):[], Integer(1):[Integer(0)],␣
˓→Integer(2):[Integer(0)], Integer(3):[Integer(1)], Integer(4):[Integer(1)],␣
˓→Integer(5):[Integer(2)]}, format= dict_of_lists )>>> next(G.in_branchings(Integer(0))) == G
True

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>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> D.in_degree(vertices=[Integer(0), Integer(1), Integer(2)], labels=True){0: 2, 1: 2, 2: 2}>>> D.in_degree()[2, 2, 2, 2, 1, 1]>>> G = graphs.PetersenGraph().to_directed()>>> G.in_degree(Integer(0))
3in_degree_iterator(vertices=None, labels=False)
Same as degree_iterator, but for in degree.
EXAMPLES:
sage: D = graphs.Grid2dGraph(2,4).to_directed()sage: sorted(D.in_degree_iterator())[2, 2, 2, 2, 3, 3, 3, 3]
sage: sorted(D.in_degree_iterator(labels=True))[((0, 0), 2),((0, 1), 3),((0, 2), 3),((0, 3), 2),((1, 0), 2),((1, 1), 3),((1, 2), 3),((1, 3), 2)]

1.3. Directed graphs695

Graph Theory, Release 10.4>>> from sage.all import *>>> D = graphs.Grid2dGraph(Integer(2),Integer(4)).to_directed()>>> sorted(D.in_degree_iterator())[2, 2, 2, 2, 3, 3, 3, 3]>>> sorted(D.in_degree_iterator(labels=True))[((0, 0), 2),((0, 1), 3),((0, 2), 3),((0, 3), 2),((1, 0), 2),((1, 1), 3),((1, 2), 3),((1, 3), 2)]

in_degree_sequence()
Return the in-degree sequence.
EXAMPLES:
The in-degree sequences of two digraphs:
sage: g = DiGraph({1: [2, 5, 6], 2: [3, 6], 3: [4, 6], 4: [6], 5: [4, 6]})sage: g.in_degree_sequence()[5, 2, 1, 1, 1, 0]>>> from sage.all import *>>> g = DiGraph({Integer(1): [Integer(2), Integer(5), Integer(6)],␣
˓→Integer(2): [Integer(3), Integer(6)], Integer(3): [Integer(4), Integer(6)],␣
˓→Integer(4): [Integer(6)], Integer(5): [Integer(4), Integer(6)]})>>> 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)))
sage: g.in_degree_sequence()[2, 2, 2, 2, 1, 0, 0, 0]>>> from sage.all import *>>> V = [Integer(2), Integer(3), Integer(5), Integer(7), Integer(8),␣
˓→Integer(9), Integer(10), Integer(11)]>>> E = [[], [Integer(8), Integer(10)], [Integer(11)], [Integer(8),␣
˓→Integer(11)], [Integer(9)], [], [], [Integer(2), Integer(9), Integer(10)]]>>> g = DiGraph(dict(zip(V, E)))>>> 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 (default: True); whether to return edges as pairs of vertices, or as triples containing
the labels
EXAMPLES:
696

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> for a in D.incoming_edge_iterator([Integer(0)]):...
print(a)(1, 0, None)(4, 0, None)

incoming_edges(vertices, labels=True)
Return a list of edges arriving at vertices.
INPUT:• vertices – a vertex or a list of vertices• labels – boolean (default: True); whether to return edges as pairs of vertices, or as triples containing
the labels.
EXAMPLES:
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)]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> D.incoming_edges([Integer(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>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(0)]})>>> g.is_aperiodic()
False

The following graph has a cycle of length 2 and a cycle of length 3, so it is aperiodic:

1.3. Directed graphs697

Graph Theory, Release 10.4

sage: g = DiGraph({0: [1, 4], 1: [2], 2: [0], 4: [0]})sage: g.is_aperiodic()True>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1), Integer(4)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(0)], Integer(4): [Integer(0)]})>>> g.is_aperiodic()
True

See also:
period()is_directed()
Since digraph is directed, return True.
EXAMPLES:
sage: DiGraph().is_directed()True>>> from sage.all import *>>> DiGraph().is_directed()
True

is_directed_acyclic(certificate=False)
Check 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 thesame partial ordering.
INPUT:• certificate – boolean (default: False); whether to return a certificate
OUTPUT:• When certificate=False, returns a boolean value.
• When certificate=True:– If the graph is acyclic, returns a pair (True, ordering) where ordering is a list of thevertices such that 𝑢 appears before 𝑣 in ordering if 𝑢𝑣 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()#␣˓→needs sage.plot
sage: D.is_directed_acyclic()
True

698

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> D = DiGraph({Integer(0):[Integer(1), Integer(2), Integer(3)],␣
˓→Integer(4):[Integer(2), Integer(5)], Integer(1):[Integer(8)],␣
˓→Integer(2):[Integer(7)], Integer(3):[Integer(7)], Integer(5):[Integer(6),˓→Integer(7)], Integer(7):[Integer(8)], Integer(6):[Integer(9)],␣
˓→Integer(8):[Integer(10)], Integer(9):[Integer(10)]})>>> D.plot(layout= circular ).show()#␣˓→needs sage.plot>>> 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>>> from sage.all import *>>> D.add_edge(Integer(9), Integer(7))>>> 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])>>> from sage.all import *>>> 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>>> from sage.all import *>>> D.add_edge(Integer(7), Integer(4))>>> D.is_directed_acyclic()
False

Indeed, it creates a circuit 7, 4, 5:
sage: D.is_directed_acyclic(certificate=True)(False, [7, 4, 5])>>> from sage.all import *>>> 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)(continues on next page)

1.3. Directed graphs699

Graph Theory, Release 10.4

(continued from previous page)....: h = DiGraph()....: h.add_edges(((u, v) if u < v else (v, u)) for u, v in g.edge_
˓→iterator(labels=False))....: return h...
sage: all(random_acyclic(100, .2).is_directed_acyclic()# long time....:
for i in range(50))
True>>> from sage.all import *>>> 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.edge_
˓→iterator(labels=False))... return h...
>>> all(random_acyclic(Integer(100), RealNumber( .2 )).is_directed_acyclic() ␣˓→# long time...
for i in range(Integer(50)))
True

is_strongly_connected(G)Check 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)Truesage: g.is_strongly_connected()True>>> from sage.all import *>>> from sage.graphs.connectivity import is_strongly_connected>>> g = digraphs.Circuit(Integer(5))>>> is_strongly_connected(g)True>>> 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>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(2)]})>>> is_strongly_connected(g)
False

700

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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>>> from sage.all import *>>> g = digraphs.RandomTournament(Integer(6))>>> g.is_tournament()
True>>> u,v = next(g.edge_iterator(labels=False))>>> g.add_edge(v, u)>>> g.is_tournament()
False>>> g.add_edges([(u, v), (v, u)])>>> g.is_tournament()
False

See also:• Wikipedia article Tournament_(graph_theory)• RandomTournament()• TransitiveTournament()
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 thegraph.
– 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()(continues on next page)

1.3. Directed graphs

701

Graph Theory, Release 10.4

(continued from previous page)

False
sage: D = digraphs.DeBruijn(5, 2)␣˓→# needs sage.combinat
sage: D.is_transitive()␣˓→# needs sage.combinat
False
sage: cert = D.is_transitive(certificate=True)␣˓→# needs sage.combinat
sage: D.has_edge(*cert)␣˓→# needs sage.combinat
False
sage: bool(D.shortest_path(*cert))␣˓→# needs sage.combinat
Truesage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() ␣˓→# needs networkx
True>>> from sage.all import *>>> digraphs.Circuit(Integer(4)).is_transitive()
False>>> digraphs.Circuit(Integer(4)).is_transitive(certificate=True)(0, 2)>>> digraphs.RandomDirectedGNP(Integer(30),RealNumber( .2 )).is_transitive()
False>>> D = digraphs.DeBruijn(Integer(5), Integer(2))␣˓→# needs sage.combinat>>> D.is_transitive()
˓→# needs sage.combinat
False>>> cert = D.is_transitive(certificate=True)
˓→# needs sage.combinat>>> D.has_edge(*cert)
˓→# needs sage.combinat
False>>> bool(D.shortest_path(*cert))
˓→# needs sage.combinat
True>>> digraphs.RandomDirectedGNP(Integer(20),RealNumber( .2 )).transitive_
˓→closure().is_transitive()# needs networkx
Truelayout_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 (seelevel_sets()).
This is achieved by calling graphviz and dot2tex if available (see layout_graphviz()), and usinga spring layout with fixed vertical placement of the vertices otherwise (see layout_acyclic_dummy()and layout_ranked()).
Non acyclic graphs are partially supported by graphviz, which then chooses some edges to point down.
INPUT:• rankdir – string (default: up ); indicates which direction the edges should point toward among
up , down , left , or right
702

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• **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]})>>> from sage.all import *>>> H = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(3)], Integer(3): [], Integer(5):␣
˓→[Integer(1), Integer(6)], Integer(6): [Integer(2), Integer(3)]})

The actual layout computed depends on whether dot2tex and graphviz are installed, so we don’t test its relativevalues:sage: H.layout_acyclic(){0: [..., ...], 1: [..., ...], 2: [..., ...], 3: [..., ...], 5: [..., ...],␣
˓→6: [..., ...]}
sage: H = DiGraph({0: [1]})sage: pos = H.layout_acyclic(rankdir= up )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>>> from sage.all import *>>> H.layout_acyclic(){0: [..., ...], 1: [..., ...], 2: [..., ...], 3: [..., ...], 5: [..., ...],␣
˓→6: [..., ...]}>>> H = DiGraph({Integer(0): [Integer(1)]})>>> pos = H.layout_acyclic(rankdir= up )>>> pos[Integer(1)][Integer(1)] > pos[Integer(0)][Integer(1)] + RealNumber( .5
˓→ )
True
>>> pos = H.layout_acyclic(rankdir= down )>>> pos[Integer(1)][Integer(1)] < pos[Integer(0)][Integer(1)] - RealNumber( .5
˓→ )
True
>>> pos = H.layout_acyclic(rankdir= right )>>> pos[Integer(1)][Integer(0)] > pos[Integer(0)][Integer(0)] + RealNumber( .5
˓→ )
True
>>> pos = H.layout_acyclic(rankdir= left )>>> pos[Integer(1)][Integer(0)] < pos[Integer(0)][Integer(0)] - RealNumber( .5
˓→ )
True

layout_acyclic_dummy(heights=None, rankdir='up', **options)
Return a ranked layout so that all edges point upward.

1.3. Directed graphs703

Graph Theory, Release 10.4

To this end, the heights of the vertices are set according to the level set decomposition of the graph (seelevel_sets()). This is achieved by a spring layout with fixed vertical placement of the vertices otherwise(see layout_acyclic_dummy() and layout_ranked()).
INPUT:• rankdir – string (default: up ); indicates which direction the edges should point toward among
up , down , left , or right• **options – passed down to layout_ranked()
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.0..., 0], 1: [1.0..., 1], 2: [1.5..., 2], 3: [1.5..., 3], 5: [2.0...,␣
˓→0], 6: [2.0..., 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>>> from sage.all import *>>> H = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(3)], Integer(3): [], Integer(5):␣
˓→[Integer(1), Integer(6)], Integer(6): [Integer(2), Integer(3)]})>>> H.layout_acyclic_dummy(){0: [1.0..., 0], 1: [1.0..., 1], 2: [1.5..., 2], 3: [1.5..., 3], 5: [2.0...,␣
˓→0], 6: [2.0..., 1]}>>> H = DiGraph({Integer(0): [Integer(1)]})>>> H.layout_acyclic_dummy(rankdir= up ){0: [0.5..., 0], 1: [0.5..., 1]}>>> H.layout_acyclic_dummy(rankdir= down ){0: [0.5..., 1], 1: [0.5..., 0]}>>> H.layout_acyclic_dummy(rankdir= left ){0: [1, 0.5...], 1: [0, 0.5...]}>>> H.layout_acyclic_dummy(rankdir= right ){0: [0, 0.5...], 1: [1, 0.5...]}>>> H = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(3)], Integer(3): [Integer(1)],␣
˓→Integer(5): [Integer(1), Integer(6)], Integer(6): [Integer(2), Integer(3)]})>>> H.layout_acyclic_dummy()
Traceback (most recent call last):...
ValueError: self should be an acyclic graphlevel_sets()

704

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

Return the level set decomposition of the digraph.
OUTPUT:• a list of non empty lists of vertices of this graph
The level set decomposition of the digraph is a list 𝑙 such that the level 𝑙[𝑖] contains all the vertices having all
their predecessors in the levels 𝑙[𝑗] for 𝑗 < 𝑖, and at least one in level 𝑙[𝑖 − 1] (unless 𝑖 = 0).
The level decomposition contains exactly the vertices not occurring in any cycle of the graph. In particular,
the graph is acyclic if and only if the decomposition forms a set partition of its vertices, and we recover theusual 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]]>>> from sage.all import *>>> H = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(3)], Integer(3): [], Integer(5):␣
˓→[Integer(1), Integer(6)], Integer(6): [Integer(2), Integer(3)]})>>> H.level_sets()[[0, 5], [1, 6], [2], [3]]>>> H = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(3)], Integer(3): [Integer(1)],␣
˓→Integer(5): [Integer(1), Integer(6)], Integer(6): [Integer(2), Integer(3)]})>>> 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]>>> from sage.all import *>>> from sage.combinat.posets.hasse_diagram import HasseDiagram>>> H = HasseDiagram({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(3)], Integer(3): []})>>> [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]>>> from sage.all import *>>> from sage.combinat.posets.hasse_diagram import HasseDiagram(continues on next page)

1.3. Directed graphs705

Graph Theory, Release 10.4

(continued from previous page)>>> H = HasseDiagram({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(4)], Integer(3): [Integer(4)]})>>> [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)
Return an iterator over the in-neighbors of vertex.
A 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>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> for a in D.neighbor_in_iterator(Integer(0)):...
print(a)14neighbor_out_iterator(vertex)
Return an iterator over the out-neighbors of a given vertex.
A vertex 𝑢 is an out-neighbor of a vertex 𝑣 if 𝑣𝑢 in an edge.
EXAMPLES:
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>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> for a in D.neighbor_out_iterator(Integer(0)):...
print(a)123neighbors_in(vertex)
Return the list of the in-neighbors of a given vertex.
706

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

A 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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> D.neighbors_in(Integer(0))[1, 4]

neighbors_out(vertex)
Return the list of the out-neighbors of a given vertex.
A vertex 𝑢 is an out-neighbor of a vertex 𝑣 if 𝑣𝑢 in an edge.
EXAMPLES:
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]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> D.neighbors_out(Integer(0))[1, 2, 3]

out_branchings(source, spanning=True)
Return an iterator over the out branchings rooted at given vertex in self.
An out-branching is a directed tree rooted at source whose arcs are directed from source to leaves. An
out-branching is spanning if it contains all vertices of the digraph.
If no spanning out branching rooted at source exist, raises ValueError or return non spanning out branchingrooted at source, depending on the value of spanning.
INPUT:• source – vertex used as the source for all out branchings.
• spanning – boolean (default: True); if False return maximum out branching from source. Otherwise, return spanning out branching if exists.
OUTPUT:
An iterator over the out branchings rooted in the given source.
See also:• in_branchings() – iterator over in-branchings rooted at given vertex.
• spanning_trees() – returns all spanning trees.
• spanning_trees_count() – counts the number of spanning trees.

1.3. Directed graphs

707

Graph Theory, Release 10.4

ALGORITHM:
Recursively computes all out branchings.
At each step:
0. clean the graph (see below)
1. pick an edge e out of source
2. find all out branchings that do not contain e by first removing it
3. find all out branchings that do contain e by first merging the end vertices of e
Cleaning the graph implies to remove loops and replace multiedges by a single one with an appropriate label
since these lead to similar steps of computation.
EXAMPLES:
A bidirectional 4-cycle:
sage: G = DiGraph({1:[2,3], 2:[1,4], 3:[1,4], 4:[2,3]}, format= dict_of_lists
˓→ )sage: list(G.out_branchings(1))[Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices]>>> from sage.all import *>>> G = DiGraph({Integer(1):[Integer(2),Integer(3)], Integer(2):[Integer(1),˓→Integer(4)], Integer(3):[Integer(1),Integer(4)], Integer(4):[Integer(2),˓→Integer(3)]}, format= dict_of_lists )>>> list(G.out_branchings(Integer(1)))[Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices,
Digraph on 4 vertices]

With the Petersen graph turned into a symmetric directed graph:
sage: G = graphs.PetersenGraph().to_directed()sage: len(list(G.out_branchings(0)))
2000>>> from sage.all import *>>> G = graphs.PetersenGraph().to_directed()>>> len(list(G.out_branchings(Integer(0))))2000

With a non connected DiGraph and spanning = True:
sage: G = graphs.PetersenGraph().to_directed() + graphs.PetersenGraph().to_˓→directed()sage: G.out_branchings(0, spanning=True)
Traceback (most recent call last):...
ValueError: no spanning out branching from vertex (0) exist

708

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.PetersenGraph().to_directed() + graphs.PetersenGraph().to_˓→directed()>>> G.out_branchings(Integer(0), spanning=True)
Traceback (most recent call last):...
ValueError: no spanning out branching from vertex (0) exist

With a non connected DiGraph and spanning = False:
sage: g=DiGraph([(0,1), (0,1), (1,2), (3,4)],multiedges=True)
sage: list(g.out_branchings(0, spanning=False))[Digraph on 3 vertices, Digraph on 3 vertices]>>> from sage.all import *>>> g=DiGraph([(Integer(0),Integer(1)), (Integer(0),Integer(1)), (Integer(1),˓→Integer(2)), (Integer(3),Integer(4))],multiedges=True)>>> list(g.out_branchings(Integer(0), spanning=False))[Digraph on 3 vertices, Digraph on 3 vertices]

With multiedges:
sage: G = DiGraph({0:[1,1,1], 1:[2,2]}, format= dict_of_lists ,␣˓→multiedges=True)
sage: len(list(G.out_branchings(0)))
6>>> from sage.all import *>>> G = DiGraph({Integer(0):[Integer(1),Integer(1),Integer(1)],␣
˓→Integer(1):[Integer(2),Integer(2)]}, format= dict_of_lists ,␣˓→multiedges=True)>>> len(list(G.out_branchings(Integer(0))))6With a DiGraph already being a spanning out branching:sage: G = DiGraph({0:[1,2], 1:[3,4], 2:[5], 3:[], 4:[], 5:[]}, format= dict_
˓→of_lists )sage: next(G.out_branchings(0)) == G
True>>> from sage.all import *>>> G = DiGraph({Integer(0):[Integer(1),Integer(2)], Integer(1):[Integer(3),˓→Integer(4)], Integer(2):[Integer(5)], Integer(3):[], Integer(4):[],␣
˓→Integer(5):[]}, format= dict_of_lists )>>> next(G.out_branchings(Integer(0))) == G
True

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

1.3. Directed graphs709

Graph Theory, Release 10.4

(continued from previous page)

sage: D.out_degree()[3, 2, 1, 1, 2, 1]
sage: D.out_degree(2)1>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> D.out_degree(vertices=[Integer(0), Integer(1) ,Integer(2)], labels=True){0: 3, 1: 2, 2: 1}>>> D.out_degree()[3, 2, 1, 1, 2, 1]>>> D.out_degree(Integer(2))
1out_degree_iterator(vertices=None, labels=False)
Same as degree_iterator, but for out degree.
EXAMPLES:
sage: D = graphs.Grid2dGraph(2,4).to_directed()sage: sorted(D.out_degree_iterator())[2, 2, 2, 2, 3, 3, 3, 3]
sage: sorted(D.out_degree_iterator(labels=True))[((0, 0), 2),((0, 1), 3),((0, 2), 3),((0, 3), 2),((1, 0), 2),((1, 1), 3),((1, 2), 3),((1, 3), 2)]>>> from sage.all import *>>> D = graphs.Grid2dGraph(Integer(2),Integer(4)).to_directed()>>> sorted(D.out_degree_iterator())[2, 2, 2, 2, 3, 3, 3, 3]>>> sorted(D.out_degree_iterator(labels=True))[((0, 0), 2),((0, 1), 3),((0, 2), 3),((0, 3), 2),((1, 0), 2),((1, 1), 3),((1, 2), 3),((1, 3), 2)]

out_degree_sequence()
Return the outdegree sequence of this digraph.
EXAMPLES:
The outdegree sequences of two digraphs:

710

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> g = DiGraph({Integer(1): [Integer(2), Integer(5), Integer(6)],␣
˓→Integer(2): [Integer(3), Integer(6)], Integer(3): [Integer(4), Integer(6)],␣
˓→Integer(4): [Integer(6)], Integer(5): [Integer(4), Integer(6)]})>>> 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]>>> from sage.all import *>>> V = [Integer(2), Integer(3), Integer(5), Integer(7), Integer(8),␣
˓→Integer(9), Integer(10), Integer(11)]>>> E = [[], [Integer(8), Integer(10)], [Integer(11)], [Integer(8),␣
˓→Integer(11)], [Integer(9)], [], [], [Integer(2), Integer(9), Integer(10)]]>>> g = DiGraph(dict(zip(V, E)))>>> 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 (default: True); 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)>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> for a in D.outgoing_edge_iterator([Integer(0)]):...
print(a)(0, 1, None)(0, 2, None)(0, 3, None)

outgoing_edges(vertices, labels=True)
Return a list of edges departing from vertices.
1.3. Directed graphs711

Graph Theory, Release 10.4

INPUT:• vertices – a vertex or a list of vertices• labels – boolean (default: True); whether to return edges as pairs of vertices, or as triples containing
the labels.
EXAMPLES:
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)]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]})>>> D.outgoing_edges([Integer(0)])[(0, 1, None), (0, 2, None), (0, 3, None)]

path_semigroup()
The partial semigroup formed by the paths of this quiver.
EXAMPLES:
sage: Q = DiGraph({1: {2: [ a , c ]}, 2: {3: [ b ]}})
sage: F = Q.path_semigroup(); F#␣˓→needs sage.libs.flint
Partial semigroup formed by the directed paths of Multi-digraph on 3 vertices
sage: list(F)#␣˓→needs sage.libs.flint[e_1, e_2, e_3, a, c, b, a*b, c*b]>>> from sage.all import *>>> Q = DiGraph({Integer(1): {Integer(2): [ a , c ]}, Integer(2):˓→{Integer(3): [ b ]}})>>> F = Q.path_semigroup(); F#␣˓→needs sage.libs.flint
Partial semigroup formed by the directed paths of Multi-digraph on 3 vertices>>> list(F)#␣˓→needs sage.libs.flint[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()
2712

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(0)]})>>> 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>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1), Integer(4)], Integer(1):␣
˓→[Integer(2)], Integer(2): [Integer(0)], Integer(4): [Integer(0)]})>>> 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]>>> from sage.all import *>>> g = DiGraph({-Integer(1): [-Integer(2)], -Integer(2): [-Integer(3)], ˓→Integer(3): [-Integer(1)],...
Integer(1): [Integer(2)], Integer(2): [Integer(1)]})>>> g.period()1>>> 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()
periphery(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the set of vertices in the periphery of the DiGraph.
The periphery is the set of vertices whose eccentricity is equal to the diameter of the DiGraph, i.e., achieving
the maximum eccentricity.
For more information and examples on how to use input variables, see shortest_paths() and eccentricity()
INPUT:• by_weight – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1

1.3. Directed graphs713

Graph Theory, Release 10.4

• algorithm – string (default: None); see method eccentricity() for the list of available algorithms• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:
sage: G = graphs.DiamondGraph().to_directed()sage: G.periphery()[0, 3]
sage: P = digraphs.Path(5)sage: P.periphery()[1, 2, 3, 4]
sage: G = digraphs.Complete(5)sage: G.subgraph(G.periphery()) == G
True>>> from sage.all import *>>> G = graphs.DiamondGraph().to_directed()>>> G.periphery()[0, 3]>>> P = digraphs.Path(Integer(5))>>> P.periphery()[1, 2, 3, 4]>>> G = digraphs.Complete(Integer(5))>>> G.subgraph(G.periphery()) == G
Trueradius(by_weight=False, algorithm=None, weight_function=None, check_weight=True)
Return the radius of the DiGraph.
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 – boolean (default: False); if True, edge weights are taken into account; if False, alledges have weight 1• algorithm – string (default: None); see method eccentricity() for the list of available algorithms• weight_function – function (default: None); a function that takes as input an edge (u, v,l) and outputs its weight. If not None, by_weight is automatically set to True. If None andby_weight is True, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs a number for each edge
EXAMPLES:
The more symmetric a DiGraph is, the smaller (diameter - radius) is:

714

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = graphs.BarbellGraph(9, 3).to_directed()sage: G.radius()
3
sage: G.diameter()6>>> from sage.all import *>>> G = graphs.BarbellGraph(Integer(9), Integer(3)).to_directed()>>> G.radius()
3>>> G.diameter()6
sage: G = digraphs.Circuit(9)sage: G.radius()
8
sage: G.diameter()8>>> from sage.all import *>>> G = digraphs.Circuit(Integer(9))>>> G.radius()
8>>> G.diameter()8

reverse(immutable=None)
Return a copy of digraph with edges reversed in direction.
INPUT:• immutable – boolean (default: None); whether to return an immutable digraph or not. By default(None), the returned digraph has the same setting than self. That is, if self is immutable, thereturned digraph also is.
EXAMPLES:
sage: adj = {0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1]}sage: D = DiGraph(adj)sage: R = D.reverse(); R
Reverse of (): Digraph on 6 vertices
sage: H = R.reverse()
sage: adj == H.to_dictionary()True>>> from sage.all import *>>> adj = {Integer(0): [Integer(1),Integer(2),Integer(3)], Integer(1):␣
˓→[Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(4)],
˓→ Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]}>>> D = DiGraph(adj)>>> R = D.reverse(); R
Reverse of (): Digraph on 6 vertices>>> H = R.reverse()>>> adj == H.to_dictionary()True

1.3. Directed graphs715

Graph Theory, Release 10.4

reverse_edge(u, v=None, label=None, inplace=True, multiedges=None)
Reverse the edge from 𝑢 to 𝑣.
INPUT:• inplace – boolean (default: True); if False, a new digraph is created and returned as output,
otherwise self is modified.
• multiedges – boolean (default: None); how to decide what should be done in case of doubt (forinstance 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) willappear twice in the graph.
– If set to False, only one edge (1, 2) will remain in the graph after (2, 1) is reversed. Besides, thelabel 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 decision(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(sort=True)[(1, 0, 2)]>>> from sage.all import *>>> D = DiGraph([(Integer(0), Integer(1) ,Integer(2))])>>> D.reverse_edge(Integer(0), Integer(1))>>> D.edges(sort=True)[(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(sort=True)[(1, 0, 2)]
sage: D.edges(sort=True)[(0, 1, 2)]716

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> D = DiGraph([(Integer(0), Integer(1), Integer(2))])>>> re = D.reverse_edge(Integer(0), Integer(1), inplace=False)>>> re.edges(sort=True)[(1, 0, 2)]>>> D.edges(sort=True)[(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(sort=True)[(2, 1, A ), (2, 1, A ), (2, 3, None)]sage: D.allows_multiple_edges()True>>> from sage.all import *>>> D = DiGraph([(Integer(1), Integer(2), A ), (Integer(2), Integer(1),˓→ (Integer(2), Integer(3), None)])>>> D.reverse_edge(Integer(1), Integer(2), multiedges=True)>>> D.edges(sort=True)[(2, 1, A ), (2, 1, A ), (2, 3, None)]>>> D.allows_multiple_edges()
True

A ),

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(sort=True)[(1, 2, A ), (2, 1, A ), (3, 2, None)]sage: D.allows_multiple_edges()
False>>> from sage.all import *>>> D = DiGraph( [(Integer(1), Integer(2), A ), (Integer(2), Integer(1),˓→ ), (Integer(2), Integer(3), None)] )>>> D.reverse_edge(Integer(2), Integer(3), multiedges=True)>>> D.edges(sort=True)[(1, 2, A ), (2, 1, A ), (3, 2, None)]>>> D.allows_multiple_edges()
False

A

If user specifies multiedges = False, self will not be forced to allow parallel edges and a paralleledge will get deleted:sage: D = DiGraph( [(1, 2, A ), (2, 1, A ), (2, 3, None)] )sage: D.edges(sort=True)[(1, 2, A ), (2, 1, A ), (2, 3, None)]sage: D.reverse_edge(1, 2, multiedges=False)
sage: D.edges(sort=True)[(2, 1, A ), (2, 3, None)]>>> from sage.all import *>>> D = DiGraph( [(Integer(1), Integer(2),A ), (Integer(2), Integer(1),A(continues on next page)

1.3. Directed graphs

717

Graph Theory, Release 10.4

(continued from previous page)), (Integer(2), Integer(3), None)] )>>> D.edges(sort=True)[(1, 2, A ), (2, 1, A ), (2, 3, None)]>>> D.reverse_edge(Integer(1), Integer(2), multiedges=False)>>> D.edges(sort=True)[(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(sort=True)[(1, 2, B ), (2, 1, A ), (2, 3, None)]sage: D.reverse_edge(2, 1, multiedges=False)
sage: D.edges(sort=True)[(1, 2, A ), (2, 3, None)]>>> from sage.all import *>>> D = DiGraph( [(Integer(1), Integer(2), B ), (Integer(2), Integer(1),˓→ ), (Integer(2), Integer(3), None)] )>>> D.edges(sort=True)[(1, 2, B ), (2, 1, A ), (2, 3, None)]>>> D.reverse_edge(Integer(2), Integer(1), multiedges=False)>>> D.edges(sort=True)[(1, 2, A ), (2, 3, None)]A

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(sort=True)[(1, 0, 2), (1, 2, 1)]
sage: re = D.reverse_edge([1, 2], inplace=False)
sage: re.edges(sort=True)[(1, 0, 2), (2, 1, 1)]>>> from sage.all import *>>> D = DiGraph([[Integer(0), Integer(1), Integer(2)], [Integer(1),␣
˓→Integer(2), Integer(1)]], weighted=True)>>> D.reverse_edge(Integer(0), Integer(1))>>> D.edges(sort=True)[(1, 0, 2), (1, 2, 1)]>>> re = D.reverse_edge([Integer(1), Integer(2)], inplace=False)>>> re.edges(sort=True)[(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,
˓→weighted=True, multiedges=True)
sage: re = D.reverse_edge([0, 1, 01 ], inplace=False)
sage: re.edges(sort=True)[(0, 1, 01 ), (0, 1, cat ), (1, 0, 01 ), (1, 2, 12 )]

71812 )],␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> D = DiGraph([(Integer(0), Integer(1), 01 ), (Integer(0), Integer(1),˓→ ), (Integer(0), Integer(1),cat ), (Integer(1), Integer(2), 12 )],␣˓→weighted=True, multiedges=True)>>> re = D.reverse_edge([Integer(0), Integer(1), 01 ], inplace=False)>>> re.edges(sort=True)[(0, 1, 01 ), (0, 1, cat ), (1, 0, 01 ), (1, 2, 12 )]01

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 returnedby edge_label()):
sage: D = DiGraph([(0, 1, A ), (0, 1, B ), (0, 1, mouse ), (0, 1,
˓→multiedges=true)
sage: D.edge_label(0, 1)[ cat , mouse , B , A ]sage: D.reverse_edge(0, 1)
sage: D.edges(sort=True)[(0, 1, A ), (0, 1, B ), (0, 1, mouse ), (1, 0, cat )]cat )],␣

>>> from sage.all import *>>> D = DiGraph([(Integer(0), Integer(1), A ), (Integer(0), Integer(1),˓→ (Integer(0), Integer(1),mouse ), (Integer(0), Integer(1), cat )],␣˓→multiedges=true)>>> D.edge_label(Integer(0), Integer(1))[ cat , mouse , B , A ]>>> D.reverse_edge(Integer(0), Integer(1))>>> D.edges(sort=True)[(0, 1, A ), (0, 1, B ), (0, 1, mouse ), (1, 0, cat )]B ),Finally, an exception is raised when Sage does not know how to choose between allowing multiple edges andlosing some data:
sage: D = DiGraph([(0, 1, A ), (1, 0, B )])sage: D.reverse_edge(0, 1)
Traceback (most recent call last):...
ValueError: reversing the given edge is about to create two paralleledges but input digraph doesn t allow them - User needs to specify
multiedges is True or False.
>>> from sage.all import *>>> D = DiGraph([(Integer(0), Integer(1), A ), (Integer(1), Integer(0),˓→ )])>>> D.reverse_edge(Integer(0), Integer(1))
Traceback (most recent call last):...
ValueError: reversing the given edge is about to create two paralleledges but input digraph doesn t allow them - User needs to specify
multiedges is True or False.

B

The following syntax is supported, but note that you must use the label keyword:
sage: D = DiGraph()
sage: D.add_edge((1, 2), label= label )sage: D.edges(sort=True)(continues on next page)

1.3. Directed graphs719

Graph Theory, Release 10.4

(continued from previous page)[(1, 2, label )]sage: D.reverse_edge((1, 2), label= label )sage: D.edges(sort=True)[(2, 1, label )]sage: D.add_edge((1, 2), label )sage: D.edges(sort=False)[((1, 2), label , None), (2, 1, label )]sage: D.reverse_edge((1, 2), label )sage: D.edges(sort=False)[( label , (1, 2), None), (2, 1, label )]>>> from sage.all import *>>> D = DiGraph()>>> D.add_edge((Integer(1), Integer(2)), label= label )>>> D.edges(sort=True)[(1, 2, label )]>>> D.reverse_edge((Integer(1), Integer(2)), label= label )>>> D.edges(sort=True)[(2, 1, label )]>>> D.add_edge((Integer(1), Integer(2)), label )>>> D.edges(sort=False)[((1, 2), label , None), (2, 1, label )]>>> D.reverse_edge((Integer(1), Integer(2)), label )>>> D.edges(sort=False)[( label , (1, 2), None), (2, 1, label )]reverse_edges(edges, inplace=True, multiedges=None)
Reverse a list of edges.
INPUT:• edges – a list of edges in the DiGraph.
• inplace – boolean (default: True); if False, a new digraph is created and returned as output,
otherwise self is modified.
• multiedges – boolean (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(sort=True)[(0, 1, None), (1, 0, None), (2, 3, None), (3, 0, None),(3, 2, None), (4, 1, None), (5, 4, None)]>>> from sage.all import *>>> D = DiGraph({ Integer(0): [Integer(1), Integer(1), Integer(3)],␣
˓→Integer(2): [Integer(3), Integer(3)], Integer(4): [Integer(1), Integer(5)]},˓→ multiedges=true)(continues on next page)

720

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)>>> D.reverse_edges([[Integer(0), Integer(1)], [Integer(0), Integer(3)]])>>> D.reverse_edges([(Integer(2), Integer(3)), (Integer(4), Integer(5))])>>> D.edges(sort=True)[(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,
sage: re = D.reverse_edges([(0, 1), (1, 2)],....:inplace=False,....:
multiedges=True)
sage: re.edges(sort=True)[(1, 0, A ), (1, 0, B ), (2, 1, C )]sage: D.edges(sort=True)[(0, 1, A ), (1, 0, B ), (1, 2, C )]sage: D.allows_multiple_edges()
False
sage: re.allows_multiple_edges()
True

C )])

>>> from sage.all import *>>> D = DiGraph([(Integer(0), Integer(1), A ), (Integer(1), Integer(0), B ),˓→ (Integer(1), Integer(2),C )])>>> re = D.reverse_edges([(Integer(0), Integer(1)), (Integer(1), Integer(2))],...
inplace=False,...
multiedges=True)>>> re.edges(sort=True)[(1, 0, A ), (1, 0, B ), (2, 1, C )]>>> D.edges(sort=True)[(0, 1, A ), (1, 0, B ), (1, 2, C )]>>> D.allows_multiple_edges()
False>>> 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(sort=True)[(2, 1, A ), (2, 1, A ), (3, 2, None)]sage: D.allows_multiple_edges()True>>> from sage.all import *>>> D = DiGraph([(Integer(1), Integer(2), A ), (Integer(2), Integer(1), A ),˓→ (Integer(2), Integer(3), None)])>>> D.reverse_edges([(Integer(1), Integer(2)), (Integer(2), Integer(3))],␣
˓→multiedges=True)>>> D.edges(sort=True)[(2, 1, A ), (2, 1, A ), (3, 2, None)]>>> D.allows_multiple_edges()
True

Even if multiedges is True, self will not be forced to allow parallel edges when it is not necessary:

1.3. Directed graphs721

Graph Theory, Release 10.4

sage: D = DiGraph([(1, 2, A ), (2, 1, A ), (2, 3, None)])sage: D.reverse_edges([(2, 3)], multiedges=True)
sage: D.edges(sort=True)[(1, 2, A ), (2, 1, A ), (3, 2, None)]sage: D.allows_multiple_edges()
False>>> from sage.all import *>>> D = DiGraph([(Integer(1), Integer(2), A ), (Integer(2), Integer(1),˓→ (Integer(2), Integer(3), None)])>>> D.reverse_edges([(Integer(2), Integer(3))], multiedges=True)>>> D.edges(sort=True)[(1, 2, A ), (2, 1, A ), (3, 2, None)]>>> D.allows_multiple_edges()
False

A ),

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(sort=True)[(1, 2, None), (2, 1, None)]sage: D.reverse_edges([(1, 2)], multiedges=False)
sage: D.edges(sort=True)[(2, 1, None)]>>> from sage.all import *>>> D = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(1))])>>> D.edges(sort=True)[(1, 2, None), (2, 1, None)]>>> D.reverse_edges([(Integer(1), Integer(2))], multiedges=False)>>> D.edges(sort=True)[(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(sort=True)[(1, 0, 01 ), (2, 1, 1), (3, 2, 23 )]>>> from sage.all import *>>> D = DiGraph([(Integer(0), Integer(1), 01 ), (Integer(1), Integer(2),␣
˓→Integer(1)), (Integer(2), Integer(3),23 )], weighted=True)>>> D.reverse_edges([(Integer(0), Integer(1), 01 ), (Integer(1), Integer(2)),˓→ (Integer(2), Integer(3))])>>> D.edges(sort=True)[(1, 0, 01 ), (2, 1, 1), (3, 2, 23 )]sinks()
Return a list of sinks of the digraph.
OUTPUT:• list of the vertices of the digraph that have no edges beginning at them
EXAMPLES:

722

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: G = DiGraph({1: {3: [ a ]}, 2: {3: [ b ]}})
sage: G.sinks()[3]sage: T = DiGraph({1: {}})
sage: T.sinks()[1]>>> from sage.all import *>>> G = DiGraph({Integer(1): {Integer(3): [ a ]}, Integer(2): {Integer(3): [ b˓→ ]}})>>> G.sinks()[3]>>> T = DiGraph({Integer(1): {}})>>> T.sinks()[1]sources()
Return a list of sources of the digraph.
OUTPUT:• list of the vertices of the digraph that have no edges going into them
EXAMPLES:
sage: G = DiGraph({1: {3: [ a ]}, 2: {3: [ b ]}})
sage: G.sources()[1, 2]
sage: T = DiGraph({1: {}})
sage: T.sources()[1]>>> from sage.all import *>>> G = DiGraph({Integer(1): {Integer(3): [ a ]}, Integer(2): {Integer(3): [ b˓→ ]}})>>> G.sources()[1, 2]>>> T = DiGraph({Integer(1): {}})>>> 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 components.
This method implements the algorithm described in [ILS2012]. The time complexity is dominated by thetime 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)(continues on next page)

1.3. Directed graphs723

Graph Theory, Release 10.4

(continued from previous page)[3]
sage: D.strong_articulation_points()[3]>>> from sage.all import *>>> from sage.graphs.connectivity import strong_articulation_points>>> D = digraphs.Complete(Integer(4))>>> D.add_clique([Integer(3), Integer(4), Integer(5), Integer(6)])>>> strong_articulation_points(D)[3]>>> 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)[]>>> from sage.all import *>>> D = digraphs.Complete(Integer(4)) * Integer(2)>>> D.add_edges([(Integer(0), Integer(4)), (Integer(7), Integer(3))])>>> sorted(strong_articulation_points(D))[0, 3, 4, 7]>>> D.add_edge(Integer(1), Integer(5))>>> sorted(strong_articulation_points(D))[3, 7]>>> D.add_edge(Integer(6), Integer(2))>>> strong_articulation_points(D)[]See also:• strongly_connected_components()• dominator_tree()strongly_connected_component_containing_vertex(G, v)
Return the strongly connected component containing a given vertex
INPUT:• G – the input DiGraph• v – a vertex
EXAMPLES:In the symmetric digraph of a graph, the strongly connected components are the connected components:

724

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> from sage.graphs.connectivity import strongly_connected_component_
˓→containing_vertex>>> g = graphs.PetersenGraph()>>> d = DiGraph(g)>>> strongly_connected_component_containing_vertex(d, Integer(0))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> d.strongly_connected_component_containing_vertex(Integer(0))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])sage: strongly_connected_component_containing_vertex(g, 0)[0, 1]>>> from sage.all import *>>> g = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(0)),␣
˓→(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(3),␣
˓→Integer(2))])>>> strongly_connected_component_containing_vertex(g, Integer(0))[0, 1]

strongly_connected_components(G)Return the lists of vertices in each strongly connected components (SCCs).
This method implements the Tarjan algorithm to compute the strongly connected components of the 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 (andsubsequent 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 correspondto 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, andthe index of 𝑣 equals the lowlink of 𝑣, that whole subtree is a new SCC.
For more information, see the Wikipedia article Tarjan%27s_strongly_connected_components_algorithm.
EXAMPLES:
sage: 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(sort=True)(continues on next page)

1.3. Directed graphs725

Graph Theory, Release 10.4

(continued from previous page)[[0, 1, 2, 3], [4, 5, 6]]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )sage: D.strongly_connected_components()[[3], [2], [1], [0], [6], [5], [4]]sage: D.add_edge([2,0])
sage: D.strongly_connected_components()[[3], [0, 1, 2], [6], [5], [4]]sage: D = DiGraph([( a , b ), ( b , c ), ( c , d ), ( d , b ), ( c , e )])sage: [sorted(scc) for scc in D.strongly_connected_components()][[ e ], [ b , c , d ], [ a ]]>>> from sage.all import *>>> from sage.graphs.base.static_sparse_graph import tarjan_strongly_
˓→connected_components>>> tarjan_strongly_connected_components(digraphs.Path(Integer(3)))[[2], [1], [0]]>>> D = DiGraph( { Integer(0) : [Integer(1), Integer(3)], Integer(1) :␣˓→[Integer(2)], Integer(2) : [Integer(3)], Integer(4) : [Integer(5),␣
˓→Integer(6)], Integer(5) : [Integer(6)] } )>>> D.connected_components(sort=True)[[0, 1, 2, 3], [4, 5, 6]]>>> D = DiGraph( { Integer(0) : [Integer(1), Integer(3)], Integer(1) :␣˓→[Integer(2)], Integer(2) : [Integer(3)], Integer(4) : [Integer(5),␣
˓→Integer(6)], Integer(5) : [Integer(6)] } )>>> D.strongly_connected_components()[[3], [2], [1], [0], [6], [5], [4]]>>> D.add_edge([Integer(2),Integer(0)])>>> D.strongly_connected_components()[[3], [0, 1, 2], [6], [5], [4]]>>> D = DiGraph([( a , b ), ( b , c ), ( c , d ), ( d , b ), ( c , e )])>>> [sorted(scc) for scc in D.strongly_connected_components()][[ e ], [ b , c , d ], [ a ]]strongly_connected_components_digraph(G, keep_labels=False)
Return the digraph of the strongly connected components
The digraph of the strongly connected components of a graph 𝐺 has a vertex per strongly connected component included in 𝐺. There is an edge from a component 𝐶1 to a component 𝐶2 if there is an edge in 𝐺 froma vertex 𝑢1 ∈ 𝐶1 to a vertex 𝑢2 ∈ 𝐶2 .
INPUT:• G – the input DiGraph• keep_labels – boolean (default: False); when keep_labels=True, the resulting digraph has
an edge from a component 𝐶𝑖 to a component 𝐶𝑗 for each edge in 𝐺 from a vertex 𝑢𝑖 ∈ 𝐶𝑖 to a vertex 𝑢𝑗 ∈ 𝐶𝑗 . Hence the resulting digraph may have loops and multiple edges. However, edges in the
result with same source, target, and label are not duplicated (see examples below). When keep_labels=False, the return digraph is simple, so without loops nor multiple edges, and edges are unlabelled.
EXAMPLES:
Such a digraph is always acyclic:
sage: from sage.graphs.connectivity import strongly_connected_components_
˓→digraph(continues on next page)

726

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: g = digraphs.RandomDirectedGNP(15, .1)
sage: scc_digraph = strongly_connected_components_digraph(g)sage: scc_digraph.is_directed_acyclic()Truesage: scc_digraph = g.strongly_connected_components_digraph()
sage: scc_digraph.is_directed_acyclic()True>>> from sage.all import *>>> from sage.graphs.connectivity import strongly_connected_components_digraph>>> g = digraphs.RandomDirectedGNP(Integer(15), RealNumber( .1 ))>>> scc_digraph = strongly_connected_components_digraph(g)>>> scc_digraph.is_directed_acyclic()True>>> scc_digraph = g.strongly_connected_components_digraph()>>> 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()Truesage: V_scc = list(scc_digraph)
sage: all(Set(scc) in V_scc for scc in g.strongly_connected_components())
True>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(2))>>> scc_digraph = strongly_connected_components_digraph(g)>>> g.is_directed_acyclic()
True>>> V_scc = list(scc_digraph)>>> all(Set(scc) in V_scc for scc in g.strongly_connected_components())
True

The following digraph has three strongly connected components, and the digraph of those is a TransitiveTournament():
sage: g = DiGraph({0: {1: "01", 2: "02", 3: "03"}, 1: {2: "12"}, 2:{1: "21",␣
˓→3: "23"}})sage: scc_digraph = strongly_connected_components_digraph(g)sage: scc_digraph.is_isomorphic(digraphs.TransitiveTournament(3))
True>>> from sage.all import *>>> g = DiGraph({Integer(0): {Integer(1): "01", Integer(2): "02", Integer(3):˓→"03"}, Integer(1): {Integer(2): "12"}, Integer(2):{Integer(1): "21",␣
˓→Integer(3): "23"}})>>> scc_digraph = strongly_connected_components_digraph(g)>>> scc_digraph.is_isomorphic(digraphs.TransitiveTournament(Integer(3)))
True

By default, the labels are discarded, and the result has no loops nor multiple edges. If keep_labels isTrue, then the labels are kept, and the result is a multi digraph, possibly with multiple edges and loops.
1.3. Directed graphs

727

Graph Theory, Release 10.4

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: g.order(), g.size()(4, 7)
sage: scc_digraph = strongly_connected_components_digraph(g, keep_labels=True)
sage: (scc_digraph.order(), scc_digraph.size())(3, 6)
sage: set(g.edge_labels()) == set(scc_digraph.edge_labels())
True>>> from sage.all import *>>> g = DiGraph({Integer(0): {Integer(1): "0-12", Integer(2): "0-12",␣
˓→Integer(3): "0-3"}, Integer(1): {Integer(2): "1-2", Integer(3): "1-3"},␣
˓→Integer(2): {Integer(1): "2-1", Integer(3): "2-3"}})>>> g.order(), g.size()(4, 7)>>> scc_digraph = strongly_connected_components_digraph(g, keep_labels=True)>>> (scc_digraph.order(), scc_digraph.size())(3, 6)>>> set(g.edge_labels()) == set(scc_digraph.edge_labels())
Truestrongly_connected_components_subgraphs(G)Return the strongly connected components as a list of subgraphs.
EXAMPLES:In the symmetric digraph of a graph, the strongly connected components are the connected components:
sage: 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]>>> from sage.all import *>>> from sage.graphs.connectivity import strongly_connected_components_
˓→subgraphs>>> g = graphs.PetersenGraph()>>> d = DiGraph(g)>>> strongly_connected_components_subgraphs(d)[Subgraph of (Petersen graph): Digraph on 10 vertices]>>> d.strongly_connected_components_subgraphs()[Subgraph of (Petersen graph): Digraph on 10 vertices]sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])sage: strongly_connected_components_subgraphs(g)[Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 2 vertices]>>> from sage.all import *>>> g = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(0)),␣
(continues on next page)

728

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(3),␣
˓→Integer(2))])>>> strongly_connected_components_subgraphs(g)[Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 2 vertices]˓→

to_directed()
Since the graph is already directed, simply returns a copy of itself.
EXAMPLES:
sage: DiGraph({0: [1, 2, 3], 4: [5, 1]}).to_directed()
Digraph on 6 vertices>>> from sage.all import *>>> DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(4):␣
˓→[Integer(5), Integer(1)]}).to_directed()
Digraph on 6 vertices

to_undirected(data_structure=None, sparse=None)
Return an undirected version of the graph.
Every directed edge becomes an edge.
INPUT:• data_structure – string (default: None); one of "sparse", "static_sparse", or"dense". See the documentation of Graph or DiGraph.
• sparse – boolean (default: None); sparse=True is an alias for data_structure="sparse",
and sparse=False is an alias for data_structure="dense".
EXAMPLES:
sage: D = DiGraph({0: [1, 2], 1: [0]})sage: G = D.to_undirected()sage: D.edges(sort=True, labels=False)[(0, 1), (0, 2), (1, 0)]
sage: G.edges(sort=True, labels=False)[(0, 1), (0, 2)]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(0)]})>>> G = D.to_undirected()>>> D.edges(sort=True, labels=False)[(0, 1), (0, 2), (1, 0)]>>> G.edges(sort=True, labels=False)[(0, 1), (0, 2)]

topological_sort(implementation='default')
Return a topological sort of the digraph if it is acyclic.
If the digraph contains a directed cycle, a TypeError is raised. As topological sorts are not necessarily
unique, different implementations may yield different results.
A topological sort is an ordering of the vertices of the digraph such that each vertex comes before all of its
successors. That is, if 𝑢 comes before 𝑣 in the sort, then there may be a directed path from 𝑢 to 𝑣, but there
will be no directed path from 𝑣 to 𝑢.
1.3. Directed graphs729

Graph Theory, Release 10.4

INPUT:• implementation – string (default: "default"); either use the default Cython implementation, or
the default NetworkX library (implementation = "NetworkX")
See also:• is_directed_acyclic() – Tests whether a directed graph is acyclic (can also join a certificate –a topological sort or a circuit in the graph).
EXAMPLES:
sage: D = 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()˓→needs sage.plot
sage: D.topological_sort()[4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]#␣>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2), Integer(3)],␣
˓→Integer(4): [Integer(2), Integer(5)], Integer(1): [Integer(8)], Integer(2):␣
˓→[Integer(7)], Integer(3): [Integer(7)],...
Integer(5): [Integer(6), Integer(7)], Integer(7): [Integer(8)],␣
˓→Integer(6): [Integer(9)], Integer(8): [Integer(10)], Integer(9):␣
˓→[Integer(10)]})>>> D.plot(layout= circular ).show()#␣˓→needs sage.plot>>> 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]>>> from sage.all import *>>> D.add_edge(Integer(9), Integer(7))>>> D.topological_sort()[4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]

Using the NetworkX implementation
sage: s = list(D.topological_sort(implementation="NetworkX")); s˓→needs networkx[0, 4, 1, 3, 2, 5, 6, 9, 7, 8, 10]
sage: all(s.index(u) < s.index(v)˓→needs networkx....:
for u, v in D.edges(sort=False, labels=False))
True>>> from sage.all import *>>> s = list(D.topological_sort(implementation="NetworkX")); s˓→needs networkx[0, 4, 1, 3, 2, 5, 6, 9, 7, 8, 10]>>> all(s.index(u) < s.index(v)˓→needs networkx# random#␣#␣# random#␣#␣(continues on next page)730

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

...
True

for u, v in D.edges(sort=False, labels=False))

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>>> from sage.all import *>>> D.add_edge(Integer(7), Integer(4))>>> D.topological_sort()
Traceback (most recent call last):...
TypeError: digraph is not acyclic; there is no topological sort

topological_sort_generator()
Return an iterator over all topological sorts of the digraph if it is acyclic.
If the digraph contains a directed cycle, a TypeError is raised.
A topological sort is an ordering of the vertices of the digraph such that each vertex comes before all of its
successors. That is, if u comes before v in the sort, then there may be a directed path from u to v, but there
will be no directed path from v to u. See also topological_sort().
AUTHORS:• Mike Hansen - original implementation• Robert L. Miller: wrapping, documentation
REFERENCE:• [1] Pruesse, Gara and Ruskey, Frank. Generating Linear Extensions Fast. SIAM J. Comput., Vol. 23(1994), no. 2, pp. 373-386.
EXAMPLES:
sage: D = DiGraph({0: [1, 2], 1: [3], 2: [3, 4]})sage: D.plot(layout= circular ).show()˓→needs sage.plot
sage: list(D.topological_sort_generator())˓→needs sage.modules sage.rings.finite_rings[[0, 1, 2, 3, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3],[0, 2, 4, 1, 3], [0, 1, 2, 4, 3]]>>> from sage.all import *>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1):␣
˓→[Integer(3)], Integer(2): [Integer(3), Integer(4)]})>>> D.plot(layout= circular ).show()˓→needs sage.plot>>> list(D.topological_sort_generator())˓→needs sage.modules sage.rings.finite_rings[[0, 1, 2, 3, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3],[0, 2, 4, 1, 3], [0, 1, 2, 4, 3]]

1.3. Directed graphs

#␣
#␣

#␣
#␣

731

Graph Theory, Release 10.4

sage: for sort in D.topological_sort_generator():˓→needs sage.modules sage.rings.finite_rings....:
for u, v in D.edge_iterator(labels=False):....:
if sort.index(u) > sort.index(v):....:print("this should never happen")>>> from sage.all import *>>> for sort in D.topological_sort_generator():˓→needs sage.modules sage.rings.finite_rings...
for u, v in D.edge_iterator(labels=False):...
if sort.index(u) > sort.index(v):...
print("this should never happen")#␣#␣

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• Enjeck M. Cleopatra (2022): fixes incorrect partite sets and adds graph creation from graph6 stringclass sage.graphs.bipartite_graph.BipartiteGraph(data=None, partition=None, check=True,
hash_labels=None, *args, **kwds)
Bases: 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.
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 theleft, and the rows correspond to vertices on the right.
4. A file in alist format.
The alist file format is described at http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
5. A graph6 string (see documentation of graph6_string()).
6. From a NetworkX bipartite graph.
• partition – (default: None); a tuple defining vertices of the left and right partition of the graph. Partitions
will be determined automatically if partition is None.
• check – boolean (default: True); if True, an invalid input partition raises an exception. In the other caseoffending edges simply won’t be included.
• loops – ignored; bipartite graphs cannot have loops
732

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• multiedges – boolean (default: None); whether to allow multiple edges• weighted – boolean (default: None); whether graph thinks of itself as weighted or not. See self.
weighted()• hash_labels – boolean (default: None); whether to include edge labels during hashing. This parameter
defaults to True if the graph is weighted. This parameter is ignored if the graph is mutable. Beware thattrying to hash unhashable labels will raise an error.
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()0sage: B == BipartiteGraph(None)
True>>> from sage.all import *>>> B = BipartiteGraph()>>> type(B)<class sage.graphs.bipartite_graph.BipartiteGraph >>>> B.order()0>>> 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):...
ValueError: input graph is not bipartite
sage: G = Graph({0: [5, 6], 1: [4, 5], 2: [4, 6], 3: [4, 5, 6]})sage: B = BipartiteGraph(G)sage: B == G
True
sage: B.left{0, 1, 2, 3}
sage: B.right{4, 5, 6}
sage: B = BipartiteGraph({0: [5, 6], 1: [4, 5], 2: [4, 6], 3: [4, 5, 6]})sage: B == G
True
sage: B.left{0, 1, 2, 3}
sage: B.right{4, 5, 6}>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(4)))(continues on next page)

1.4. Bipartite graphs733

Graph Theory, Release 10.4

(continued from previous page)>>> B = BipartiteGraph(graphs.CycleGraph(Integer(5)))
Traceback (most recent call last):...
ValueError: input graph is not bipartite>>> G = Graph({Integer(0): [Integer(5), Integer(6)], Integer(1): [Integer(4),␣
˓→Integer(5)], Integer(2): [Integer(4), Integer(6)], Integer(3): [Integer(4),␣
˓→Integer(5), Integer(6)]})>>> B = BipartiteGraph(G)>>> B == G
True>>> B.left{0, 1, 2, 3}>>> B.right{4, 5, 6}>>> B = BipartiteGraph({Integer(0): [Integer(5), Integer(6)], Integer(1):␣
˓→[Integer(4), Integer(5)], Integer(2): [Integer(4), Integer(6)], Integer(3):␣
˓→[Integer(4), Integer(5), Integer(6)]})>>> B == G
True>>> B.left{0, 1, 2, 3}>>> B.right{4, 5, 6}

3. If a Graph or DiGraph is used as data, you can specify a partition using partition argument. Notethat 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 lumpcreating 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()˓→# needs sage.plot␣>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> partition = [list(range(Integer(5))), list(range(Integer(5),␣
˓→Integer(10)))]>>> B = BipartiteGraph(P, partition)
Traceback (most recent call last):...
TypeError: input graph is not bipartite with respect to the given partition>>> B = BipartiteGraph(P, partition, check=False)>>> B.left{0, 1, 2, 3, 4}>>> B.show()˓→# needs sage.plot

734

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

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>>> from sage.all import *>>> G = Graph({Integer(0): [Integer(5), Integer(6)], Integer(1): [Integer(4),␣
˓→Integer(5)], Integer(2): [Integer(4), Integer(6)], Integer(3): [Integer(4),␣
˓→Integer(5), Integer(6)]})>>> B = BipartiteGraph(G)>>> B2 = BipartiteGraph(B)>>> B == B2
True>>> B3 = BipartiteGraph(G, [list(range(Integer(4))), list(range(Integer(4),␣
˓→Integer(7)))])>>> B3
Bipartite graph on 7 vertices>>> B3 == B2
True
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>>> from sage.all import *>>> G = Graph({Integer(0): [], Integer(1): [], Integer(2): []})>>> part = (list(range(Integer(2))), [Integer(2)])>>> B = BipartiteGraph(G, part)>>> B2 = BipartiteGraph(B)>>> 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}>>> from sage.all import *>>> d = DiGraph(Integer(6))>>> d.add_edge(Integer(0), Integer(1))>>> part=[[Integer(1), Integer(2), Integer(3)], [Integer(0), Integer(4),␣
˓→Integer(5)]]>>> b = BipartiteGraph(d, part)(continues on next page)

1.4. Bipartite graphs735

Graph Theory, Release 10.4

(continued from previous page)>>> b.left{1, 2, 3}>>> b.right{0, 4, 5}

4. From a reduced adjacency matrix:
sage: # needs sage.modules
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(sort=True)[(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)]>>> from sage.all import *>>> # needs sage.modules>>> M = Matrix([(Integer(1),Integer(1),Integer(1),Integer(0),Integer(0),˓→Integer(0),Integer(0)), (Integer(1),Integer(0),Integer(0),Integer(1),˓→Integer(1),Integer(0),Integer(0)),...
(Integer(0),Integer(1),Integer(0),Integer(1),Integer(0),˓→Integer(1),Integer(0)), (Integer(1),Integer(1),Integer(0),Integer(1),˓→Integer(0),Integer(0),Integer(1))])>>> 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]>>> H = BipartiteGraph(M); H
Bipartite graph on 11 vertices>>> H.edges(sort=True)[(0, 7, None),(0, 8, None),(0, 10, None),(1, 7, None),(1, 9, None),(1, 10, None),(2, 7, None),(3, 8, None),(continues on next page)

736

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)(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)])˓→# needs sage.modules
sage: B = BipartiteGraph(M, multiedges=True, sparse=True)˓→# needs sage.modules
sage: B.edges(sort=True)˓→# needs sage.modules[(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),(3, 6, None),(3, 7, None),(4, 6, None),(4, 7, None)]␣␣␣>>> from sage.all import *>>> M = Matrix([(Integer(1), Integer(1), Integer(2), Integer(0), Integer(0)),␣
˓→(Integer(0), Integer(2), Integer(1), Integer(1), Integer(1)), (Integer(0),␣
˓→Integer(1), Integer(2), Integer(1), Integer(1))])# needs sage.
˓→modules>>> B = BipartiteGraph(M, multiedges=True, sparse=True)
˓→# needs sage.modules>>> B.edges(sort=True)
˓→# needs sage.modules[(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),(3, 6, None),(3, 7, None),(4, 6, None),(4, 7, None)]sage: # needs sage.modules sage.rings.finite_rings
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)

1.4. Bipartite graphs(continues on next page)

737

Graph Theory, Release 10.4

(continued from previous page)

sage: B.edges(sort=True)[(0, 4, a), (1, 3, 1), (1, 4, 1), (2, 3, a + 1), (2, 4, 1)]
sage: B.weighted()True>>> from sage.all import *>>> # needs sage.modules sage.rings.finite_rings>>> F = GF(Integer(4), names=( a ,)); (a,) = F._first_ngens(1)>>> MS = MatrixSpace(F, Integer(2), Integer(3))>>> M = MS.matrix([[Integer(0), Integer(1), a + Integer(1)], [a, Integer(1),␣
˓→Integer(1)]])>>> B = BipartiteGraph(M, weighted=True, sparse=True)>>> B.edges(sort=True)[(0, 4, a), (1, 3, 1), (1, 4, 1), (2, 3, a + 1), (2, 4, 1)]>>> B.weighted()True

5. From an alist file:
sage: import tempfile
sage: with tempfile.NamedTemporaryFile(mode="w+t") as f:....:_ = f.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")....:f.flush()....:B = BipartiteGraph(f.name)sage: B.is_isomorphic(H)˓→ # needs sage.modules
True␣>>> from sage.all import *>>> import tempfile>>> with tempfile.NamedTemporaryFile(mode="w+t") as f:...
_ = f.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")...
f.flush()...
B = BipartiteGraph(f.name)>>> B.is_isomorphic(H)˓→# needs sage.modules
True

6. From a graph6 string:sage: B = BipartiteGraph( Bo )sage: B
Bipartite graph on 3 vertices
sage: B.left{0}
sage: B.right{1, 2}

738

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4>>> from sage.all import *>>> B = BipartiteGraph( Bo )>>> B
Bipartite graph on 3 vertices>>> B.left{0}>>> B.right{1, 2}
sage: B = BipartiteGraph( F?^T_\n , format= graph6 )sage: B.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6]
sage: B.edges(sort=True)[(0, 5, None), (0, 6, None), (1, 4, None), (1, 5, None), (2, 4, None),(2, 6, None), (3, 4, None), (3, 5, None), (3, 6, None)]sage: B.left{0, 1, 2, 3}
sage: B.right{4, 5, 6}>>> from sage.all import *>>> B = BipartiteGraph( F?^T_\n , format= graph6 )>>> B.vertices(sort=True)[0, 1, 2, 3, 4, 5, 6]>>> B.edges(sort=True)[(0, 5, None), (0, 6, None), (1, 4, None), (1, 5, None), (2, 4, None),(2, 6, None), (3, 4, None), (3, 5, None), (3, 6, None)]>>> B.left{0, 1, 2, 3}>>> B.right{4, 5, 6}::
sage: B = BipartiteGraph(‘Bo’, partition=[[0], [1, 2]]) sage: B.left {0} sage: B.right {1, 2}
sage: B = BipartiteGraph( F?^T_\n , partition=[[0, 1, 2], [3, 4, 5, 6]])
Traceback (most recent call last):...
TypeError: input graph is not bipartite with respect to the given partition
sage: B = BipartiteGraph( F?^T_\n , partition=[[0, 1, 2], [3, 4, 5, 6]],␣
˓→check=False)
sage: B.left{0, 1, 2}
sage: B.show()˓→ # needs sage.plot␣>>> from sage.all import *>>> B = BipartiteGraph( F?^T_\n , partition=[[Integer(0), Integer(1),␣
˓→Integer(2)], [Integer(3), Integer(4), Integer(5), Integer(6)]])
Traceback (most recent call last):...
TypeError: input graph is not bipartite with respect to the given partition>>> B = BipartiteGraph( F?^T_\n , partition=[[Integer(0), Integer(1),␣
(continues on next page)

1.4. Bipartite graphs739

Graph Theory, Release 10.4

(continued from previous page)

Integer(2)], [Integer(3), Integer(4), Integer(5), Integer(6)]], check=False)>>> B.left{0, 1, 2}>>> B.show()˓→# needs sage.plot
˓→

7. From a NetworkX bipartite graph:
sage: # needs networkx
sage: import networkx
sage: G = graphs.OctahedralGraph()
sage: N = networkx.make_clique_bipartite(G.networkx_graph())
sage: B = BipartiteGraph(N)>>> from sage.all import *>>> # needs networkx>>> import networkx>>> G = graphs.OctahedralGraph()>>> N = networkx.make_clique_bipartite(G.networkx_graph())>>> B = BipartiteGraph(N)add_edge(u, v=None, label=None)
Add an edge from 𝑢 to 𝑣.
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 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 leftpartition, the second to the right partition. If both vertices are in the same partition but different connectedcomponents, one of the components will be “flipped”, i.e. each vertex will be put into whichever partition it’s
not currently in. This will allow for the graph to remain bipartite, without changing the edges or vertices.
add_edges(edges, loops=True)
Add edges from an iterable container.
INPUT:• edges – an iterable of edges, given either as (u, v) or (u, v, label).
• loops – ignored
740

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

See add_edges() for more detail.
This method simply checks that the edge endpoints are in different partitions. If a new vertex is to be created,
it will be added to the proper partition. If both vertices are created, the first one will be added to the leftpartition, the second to the right partition. If both vertices are in the same partition but different connectedcomponents, one of the components will be “flipped”, i.e. each vertex will be put into whichever partition it’s
not currently in. This will allow for the graph to remain bipartite, without changing the edges or vertices.
EXAMPLES:
sage: bg = BipartiteGraph()
sage: bg.add_vertices([0, 1, 2], left=[True, False, True])sage: bg.add_edges([(0, 1), (2, 1)])
sage: bg.add_edges([[0, 2]])
Traceback (most recent call last):...
ValueError: the specified set of edges cannot be added
while still preserving the bipartition property
sage: G = BipartiteGraph()
sage: G.add_edges([(0, 1), (3, 2), (1, 2)])sage: G.bipartition()({0, 2}, {1, 3})>>> from sage.all import *>>> bg = BipartiteGraph()>>> bg.add_vertices([Integer(0), Integer(1), Integer(2)], left=[True, False,␣
˓→True])>>> bg.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(1))])>>> bg.add_edges([[Integer(0), Integer(2)]])
Traceback (most recent call last):...
ValueError: the specified set of edges cannot be added
while still preserving the bipartition property>>> G = BipartiteGraph()>>> G.add_edges([(Integer(0), Integer(1)), (Integer(3), Integer(2)),␣
˓→(Integer(1), Integer(2))])>>> G.bipartition()({0, 2}, {1, 3})Loops will raise an error:
sage: bg.add_edges([[0, 3], [3, 3]])
Traceback (most recent call last):...
ValueError: the specified set of edges cannot be added
while still preserving the bipartition property>>> from sage.all import *>>> bg.add_edges([[Integer(0), Integer(3)], [Integer(3), Integer(3)]])
Traceback (most recent call last):...
ValueError: the specified set of edges cannot be added
while still preserving the bipartition property

Adding edges is fine as long as there exists a valid bipartition. Otherwise an error is raised without modifyiong
the graph:1.4. Bipartite graphs741

Graph Theory, Release 10.4

sage: G = BipartiteGraph()
sage: G.add_edges([(0, 1), (2, 3)])sage: G.bipartition()({0, 2}, {1, 3})
sage: G.add_edges([(0,2), (0,3)])Traceback (most recent call last):...
ValueError: the specified set of edges cannot be added
while still preserving the bipartition property
sage: G.bipartition()({0, 2}, {1, 3})
sage: G.edges(labels=False, sort=True)[(0, 1), (2, 3)]>>> from sage.all import *>>> G = BipartiteGraph()>>> G.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3))])>>> G.bipartition()({0, 2}, {1, 3})>>> G.add_edges([(Integer(0),Integer(2)), (Integer(0),Integer(3))])
Traceback (most recent call last):...
ValueError: the specified set of edges cannot be added
while still preserving the bipartition property>>> G.bipartition()({0, 2}, {1, 3})>>> G.edges(labels=False, sort=True)[(0, 1), (2, 3)]

add_vertex(name=None, left=False, right=False)
Create 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 immutableobject and cannot be None.
• left – boolean (default: False); if True, puts the new vertex in the left partition.
• right – boolean (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 is None, the new vertex name is returned. None otherwise.
EXAMPLES:
sage: G = BipartiteGraph()
sage: G.add_vertex(left=True)0sage: G.add_vertex(right=True)1
sage: G.vertices(sort=True)[0, 1](continues on next page)742

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: G.left{0}
sage: G.right{1}>>> from sage.all import *>>> G = BipartiteGraph()>>> G.add_vertex(left=True)0>>> G.add_vertex(right=True)
1>>> G.vertices(sort=True)[0, 1]>>> G.left{0}>>> 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}>>> from sage.all import *>>> bg = BipartiteGraph()>>> bg.add_vertices([Integer(0), Integer(1), Integer(2)], left=True)>>> bg.add_vertices([Integer(3), Integer(4), Integer(5)], left=[True, False,␣
˓→True])>>> bg.add_vertices([Integer(6), Integer(7), Integer(8)], right=[True, False,␣
˓→True])>>> bg.add_vertices([Integer(9), Integer(10), Integer(11)], right=True)>>> bg.left{0, 1, 2, 3, 5, 7}(continues on next page)

1.4. Bipartite graphs743

Graph Theory, Release 10.4

(continued from previous page)>>> bg.right{4, 6, 8, 9, 10, 11}

allow_loops(new, check=True)
Change whether loops are permitted in the (di)graphNote: 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>>> from sage.all import *>>> B = BipartiteGraph()>>> B.allow_loops(True)
Traceback (most recent call last):...
ValueError: loops are not allowed in bipartite graphs

bipartition()
Return the underlying bipartition of the bipartite graph.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B.bipartition()({0, 2}, {1, 3})>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(4)))>>> B.bipartition()({0, 2}, {1, 3})canonical_label(partition=None, certificate=False, edge_labels=False, algorithm=None,
return_graph=True)
Return the canonical graph.
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.

744

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

• certificate – boolean (default: False). When set to True, a dictionary mapping from the verticesof the (di)graph to its canonical label will also be returned.
• edge_labels – boolean (default: False). When set to True, allows only permutations respectingedge 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 thecanonical graph instead of the canonical graph; only available when bliss is explicitly set as algorithm.
EXAMPLES:
sage: B = BipartiteGraph( [(0, 4), (0, 5), (0, 6), (0, 8), (1, 5),....:(1, 7), (1, 8), (2, 6), (2, 7), (2, 8),....:(3, 4), (3, 7), (3, 8), (4, 9), (5, 9),....:(6, 9), (7, 9)] )sage: C = B.canonical_label(partition=(B.left,B.right), algorithm= sage )sage: C
Bipartite graph on 10 vertices
sage: C.left{0, 1, 2, 3, 4}
sage: C.right{5, 6, 7, 8, 9}>>> from sage.all import *>>> B = BipartiteGraph( [(Integer(0), Integer(4)), (Integer(0), Integer(5)),␣
˓→(Integer(0), Integer(6)), (Integer(0), Integer(8)), (Integer(1),␣
˓→Integer(5)),...
(Integer(1), Integer(7)), (Integer(1), Integer(8)),␣
˓→(Integer(2), Integer(6)), (Integer(2), Integer(7)), (Integer(2),␣
˓→Integer(8)),...
(Integer(3), Integer(4)), (Integer(3), Integer(7)),␣
˓→(Integer(3), Integer(8)), (Integer(4), Integer(9)), (Integer(5),␣
˓→Integer(9)),...
(Integer(6), Integer(9)), (Integer(7), Integer(9))] )>>> C = B.canonical_label(partition=(B.left,B.right), algorithm= sage )>>> CBipartite graph on 10 vertices>>> C.left{0, 1, 2, 3, 4}>>> C.right{5, 6, 7, 8, 9}
sage: B = BipartiteGraph( [(0, 4), (0, 5), (0, 6), (0, 8), (1, 5),....:(1, 7), (1, 8), (2, 6), (2, 7), (2, 8),....:(3, 4), (3, 7), (3, 8), (4, 9), (5, 9),....:(6, 9), (7, 9)] )sage: C, cert = B.canonical_label(partition=(B.left, B.right),(continues on next page)

1.4. Bipartite graphs745Graph Theory, Release 10.4

(continued from previous page)....:certificate=True, algorithm= sage )sage: C
Bipartite graph on 10 vertices
sage: C.left{0, 1, 2, 3, 4}
sage: C.right{5, 6, 7, 8, 9}
sage: cert == {0: 3, 1: 0, 2: 1, 3: 2, 4: 5, 5: 7, 6: 6, 7: 8, 8: 9, 9: 4}
True>>> from sage.all import *>>> B = BipartiteGraph( [(Integer(0), Integer(4)), (Integer(0), Integer(5)),␣
˓→(Integer(0), Integer(6)), (Integer(0), Integer(8)), (Integer(1),␣
˓→Integer(5)),...
(Integer(1), Integer(7)), (Integer(1), Integer(8)),␣
˓→(Integer(2), Integer(6)), (Integer(2), Integer(7)), (Integer(2),␣
˓→Integer(8)),...
(Integer(3), Integer(4)), (Integer(3), Integer(7)),␣
˓→(Integer(3), Integer(8)), (Integer(4), Integer(9)), (Integer(5),␣
˓→Integer(9)),...
(Integer(6), Integer(9)), (Integer(7), Integer(9))] )>>> C, cert = B.canonical_label(partition=(B.left, B.right),...
certificate=True, algorithm= sage )>>> CBipartite graph on 10 vertices>>> C.left{0, 1, 2, 3, 4}>>> C.right{5, 6, 7, 8, 9}>>> cert == {Integer(0): Integer(3), Integer(1): Integer(0), Integer(2):␣
˓→Integer(1), Integer(3): Integer(2), Integer(4): Integer(5), Integer(5):␣
˓→Integer(7), Integer(6): Integer(6), Integer(7): Integer(8), Integer(8):␣
˓→Integer(9), Integer(9): Integer(4)}Truesage: G = Graph({0: [5, 6], 1: [4, 5], 2: [4, 6], 3: [4, 5, 6]})sage: B = BipartiteGraph(G)sage: C = B.canonical_label(partition=(B.left, B.right),....:
edge_labels=True, algorithm= sage )sage: C.left{0, 1, 2, 3}
sage: C.right{4, 5, 6}>>> from sage.all import *>>> G = Graph({Integer(0): [Integer(5), Integer(6)], Integer(1): [Integer(4),␣
˓→Integer(5)], Integer(2): [Integer(4), Integer(6)], Integer(3): [Integer(4),␣
˓→Integer(5), Integer(6)]})>>> B = BipartiteGraph(G)>>> C = B.canonical_label(partition=(B.left, B.right),...
edge_labels=True, algorithm= sage )>>> C.left{0, 1, 2, 3}>>> C.right{4, 5, 6}746

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

See also:
canonical_label()
complement()
Return a complement of this graph.
Given a simple BipartiteGraph 𝐺 = (𝐿, 𝑅, 𝐸) with vertex set 𝐿 ∪ 𝑅 and edge set 𝐸, this method
returns a Graph 𝐻 = (𝑉, 𝐹 ), where 𝑉 = 𝐿 ∪ 𝑅 and 𝐹 is the set of edges of a complete graph of order |𝑉 |minus the edges in 𝐸.
Warning: This method returns the complement of a bipartite graph 𝐺 = (𝑉 = 𝐿 ∪ 𝑅, 𝐸) with respect
the complete graph of order |𝑉 |. If looking for the complement with respect the complete bipartite graph
𝐾 = (𝐿, 𝑅, 𝐿 × 𝑅), use method complement_bipartite().
See also:
complement_bipartite()
EXAMPLES:
sage: B = BipartiteGraph({1: [2, 4], 3: [4, 5]})sage: G = B.complement(); GGraph on 5 vertices
sage: G.edges(sort=True, labels=False)[(1, 3), (1, 5), (2, 3), (2, 4), (2, 5), (4, 5)]
sage: B.size() + G.size() == graphs.CompleteGraph(B.order()).size()
True>>> from sage.all import *>>> B = BipartiteGraph({Integer(1): [Integer(2), Integer(4)], Integer(3):␣
˓→[Integer(4), Integer(5)]})>>> G = B.complement(); GGraph on 5 vertices>>> G.edges(sort=True, labels=False)[(1, 3), (1, 5), (2, 3), (2, 4), (2, 5), (4, 5)]>>> B.size() + G.size() == graphs.CompleteGraph(B.order()).size()
Truecomplement_bipartite()
Return the bipartite complement of this bipartite graph.
Given a simple BipartiteGraph 𝐺 = (𝐿, 𝑅, 𝐸) with vertex set 𝐿 ∪ 𝑅 and edge set 𝐸, this method
returns a BipartiteGraph 𝐻 = (𝐿 ∪ 𝑅, 𝐹 ), where 𝐹 is the set of edges of a complete bipartite graphbetween vertex sets 𝐿 and 𝑅 minus the edges in 𝐸.
See also:
complement()
EXAMPLES:
sage: B = BipartiteGraph({0: [1, 2, 3]}) sage: C = B.complement_bipartite() sage: C Bipartite
graph on 4 vertices sage: C.is_bipartite() True sage: B.left == C.left and B.right == C.right True
sage: C.size() == len(B.left)*len(B.right) - B.size() True sage: G = B.complement() sage: G.is_bipartite() False

1.4. Bipartite graphs

747

Graph Theory, Release 10.4

delete_vertex(vertex, in_order=False)
Delete vertex, removing all incident edges.
Deleting a non-existent vertex will raise an exception.
INPUT:• vertex – a vertex to delete.
• in_order – boolean (default False); if True, deletes the 𝑖-th vertex in the sorted list of vertices,
i.e. G.vertices(sort=True)[i].
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B
Bipartite cycle graph: graph on 4 vertices
sage: B.delete_vertex(0)sage: B
Bipartite cycle graph: graph on 3 vertices
sage: B.left{2}
sage: B.edges(sort=True)[(1, 2, None), (2, 3, None)]sage: B.delete_vertex(3)sage: B.right{1}
sage: B.edges(sort=True)[(1, 2, None)]sage: B.delete_vertex(0)Traceback (most recent call last):...
ValueError: vertex (0) not in the graph>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(4)))>>> B
Bipartite cycle graph: graph on 4 vertices>>> B.delete_vertex(Integer(0))>>> B
Bipartite cycle graph: graph on 3 vertices>>> B.left{2}>>> B.edges(sort=True)[(1, 2, None), (2, 3, None)]>>> B.delete_vertex(Integer(3))>>> B.right{1}>>> B.edges(sort=True)[(1, 2, None)]>>> B.delete_vertex(Integer(0))
Traceback (most recent call last):...
ValueError: vertex (0) not in the graphsage: g = Graph({ a : [ b ],sage: bg = BipartiteGraph(g)sage: bg.vertices(sort=True)[ a , b , c ]c : [ b ]})# finds bipartition(continues on next page)

748

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: bg.delete_vertex( a )sage: bg.edges(sort=True)[( b , c , None)]sage: bg.vertices(sort=True)[ b , c ]sage: bg2 = BipartiteGraph(g)sage: bg2.delete_vertex(0, in_order=True)
sage: bg2 == bg
True>>> from sage.all import *>>> g = Graph({ a : [ b ], c : [ b ]})>>> bg = BipartiteGraph(g) # finds bipartition>>> bg.vertices(sort=True)[ a , b , c ]>>> bg.delete_vertex( a )>>> bg.edges(sort=True)[( b , c , None)]>>> bg.vertices(sort=True)[ b , c ]>>> bg2 = BipartiteGraph(g)>>> bg2.delete_vertex(Integer(0), in_order=True)>>> bg2 == bg
Truedelete_vertices(vertices)
Remove vertices from the bipartite graph taken from an iterable sequence of vertices.
Deleting a non-existent vertex will raise an exception.
INPUT:• vertices – a sequence of vertices to remove
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(4))
sage: B
Bipartite cycle graph: graph on 4 vertices
sage: B.delete_vertices([0, 3])
sage: B
Bipartite cycle graph: graph on 2 vertices
sage: B.left{2}
sage: B.right{1}
sage: B.edges(sort=True)[(1, 2, None)]sage: B.delete_vertices([0])
Traceback (most recent call last):...
ValueError: vertex (0) not in the graph>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(4)))>>> B
Bipartite cycle graph: graph on 4 vertices(continues on next page)

1.4. Bipartite graphs749

Graph Theory, Release 10.4

(continued from previous page)>>> B.delete_vertices([Integer(0), Integer(3)])>>> B
Bipartite cycle graph: graph on 2 vertices>>> B.left{2}>>> B.right{1}>>> B.edges(sort=True)[(1, 2, None)]>>> B.delete_vertices([Integer(0)])
Traceback (most recent call last):...
ValueError: vertex (0) not in the graphis_bipartite(certificate=False)
Check whether the graph is bipartite.
This method always returns True as first value, plus a certificate when certificate == True.
INPUT:• certificate – boolean (default: False); whether to return a certificate. If set to True, the certificate returned is a proper 2-coloring of the vertices.
See also:
is_bipartite()
EXAMPLES:
sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5))
˓→needs numpy
sage: g.is_bipartite()
˓→needs numpy
True
sage: g.is_bipartite(certificate=True) # random
˓→needs numpy(True, {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 1, (1, 1): 1, (1, 2): 1})

#␣
#␣

#␣

>>> from sage.all import *>>> g = BipartiteGraph(graphs.RandomBipartite(Integer(3), Integer(3),␣
˓→RealNumber( .5 )))# needs numpy>>> g.is_bipartite()#␣˓→needs numpy
True>>> g.is_bipartite(certificate=True) # random#␣˓→needs numpy(True, {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 1, (1, 1): 1, (1, 2): 1})

load_afile(fname)Load into the current object the bipartite graph specified in the given file name.
This file should follow David MacKay’s alist format, see http://www.inference.phy.cam.ac.uk/mackay/codes/
data.html for examples and definition of the format.
EXAMPLES:

750

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

sage: import tempfile
sage: with tempfile.NamedTemporaryFile(mode="w+t") as f:....:_ = f.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")....:f.flush()....:B = BipartiteGraph()....:B2 = BipartiteGraph(f.name)....:B.load_afile(f.name)
Bipartite graph on 11 vertices
sage: B.edges(sort=True)[(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: B2 == B
True>>> from sage.all import *>>> import tempfile>>> with tempfile.NamedTemporaryFile(mode="w+t") as f:...
_ = f.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")...
f.flush()...
B = BipartiteGraph()...
B2 = BipartiteGraph(f.name)...
B.load_afile(f.name)
Bipartite graph on 11 vertices>>> B.edges(sort=True)[(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)]>>> B2 == B
(continues on next page)

1.4. Bipartite graphs751

Graph Theory, Release 10.4

(continued from previous page)Truematching(value_only, algorithm=False, use_edge_labels=None, solver=False, verbose=None,
integrality_tolerance=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 thematching is returned• algorithm – string (default: "Hopcroft-Karp" if use_edge_labels==False, otherwise"Edmonds"); algorithm to use among:– "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 anedge has no label, 1 is assumed); only if algorithm is "Edmonds", "LP"– when set to False, each edge has weight 1• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
See also:• Wikipedia article Matching_(graph_theory)• matching()
EXAMPLES:
Maximum matching in a cycle graph:
sage: G = BipartiteGraph(graphs.CycleGraph(10))
sage: G.matching()
˓→needs networkx[(0, 1, None), (2, 3, None), (4, 5, None), (6, 7, None), (8, 9, None)]>>> from sage.all import *>>> G = BipartiteGraph(graphs.CycleGraph(Integer(10)))>>> G.matching()
˓→needs networkx[(0, 1, None), (2, 3, None), (4, 5, None), (6, 7, None), (8, 9, None)]

752

#␣

#␣

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

The size of a maximum matching in a complete bipartite graph using Eppstein:sage: G = BipartiteGraph(graphs.CompleteBipartiteGraph(4,5))
sage: G.matching(algorithm="Eppstein", value_only=True)
˓→needs networkx
4#␣>>> from sage.all import *>>> G = BipartiteGraph(graphs.CompleteBipartiteGraph(Integer(4),Integer(5)))>>> G.matching(algorithm="Eppstein", value_only=True)#␣˓→needs networkx
4

matching_polynomial(algorithm='Godsil', name=None)
Compute the matching polynomial.
The matching polynomial is defined as in [God1993], where 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings(matchings with 𝑘 edges) in 𝐺 :∑︁𝜇(𝑥) =(−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘𝑘≥0INPUT:• algorithm – string (default: "Godsil"); either “Godsil” or “rook”; “rook” is usually faster for larger
graphs• name – string (default: None); name of the variable in the polynomial, set to 𝑥 when name is None
EXAMPLES:
sage: BipartiteGraph(graphs.CubeGraph(3)).matching_polynomial()
˓→needs sage.libs.flintx^8 - 12*x^6 + 42*x^4 - 44*x^2 + 9>>> from sage.all import *>>> BipartiteGraph(graphs.CubeGraph(Integer(3))).matching_polynomial()˓→# needs sage.libs.flintx^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)
˓→needs sage.symbolic....:== g.matching_polynomial(algorithm= rook ))True>>> from sage.all import *>>> x = polygen(QQ)>>> g = BipartiteGraph(graphs.CompleteBipartiteGraph(Integer(16),␣
˓→Integer(16)))>>> bool(factorial(Integer(16)) * laguerre(Integer(16), x**Integer(2))˓→# needs sage.symbolic...
== g.matching_polynomial(algorithm= rook ))
True

#␣

␣

#␣

␣

Compute the matching polynomial of a line with 60 vertices:

1.4. Bipartite graphs753

Graph Theory, Release 10.4

sage: from sage.functions.orthogonal_polys import chebyshev_U˓→needs sage.symbolic
sage: g = next(graphs.trees(60))
sage: (chebyshev_U(60, x/2)
˓→needs sage.symbolic....:== BipartiteGraph(g).matching_polynomial(algorithm= rook ))True>>> from sage.all import *>>> from sage.functions.orthogonal_polys import chebyshev_U˓→needs sage.symbolic>>> g = next(graphs.trees(Integer(60)))>>> (chebyshev_U(Integer(60), x/Integer(2))˓→# needs sage.symbolic...
== BipartiteGraph(g).matching_polynomial(algorithm= rook ))
True

#␣

#␣

#␣

␣

The matching polynomial of a tree is equal to its characteristic polynomial:
sage: g = graphs.RandomTree(20)sage: p = g.characteristic_polynomial()
˓→needs sage.modules
sage: p == BipartiteGraph(g).matching_polynomial(algorithm= rook )˓→needs sage.modules
True>>> from sage.all import *>>> g = graphs.RandomTree(Integer(20))>>> p = g.characteristic_polynomial()
˓→needs sage.modules>>> p == BipartiteGraph(g).matching_polynomial(algorithm= rook )˓→needs sage.modules
True

#␣
#␣

#␣
#␣

perfect_matchings(labels=False)
Return an iterator over all perfect matchings of the bipartite graph.
ALGORITHM:
Choose a vertex 𝑣 in the right set of vertices, then recurse through all edges incident to 𝑣, removing one edge
at a time whenever an edge is added to a matching.
INPUT:• labels – boolean (default: False); when True, the edges in each perfect matching are triples (containing the label as the third element), otherwise the edges are pairs.
See also:
perfect_matchings() matching()
EXAMPLES:
sage: B = BipartiteGraph({0: [5, 7], 1: [4, 6, 7], 2: [4, 5, 8],....:
3: [4, 5, 6], 6: [9], 8: [9]})sage: len(list(B.perfect_matchings()))
6
sage: G = Graph(B.edges(sort=False))(continues on next page)754

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: len(list(G.perfect_matchings()))
6>>> from sage.all import *>>> B = BipartiteGraph({Integer(0): [Integer(5), Integer(7)], Integer(1):␣
˓→[Integer(4), Integer(6), Integer(7)], Integer(2): [Integer(4), Integer(5),␣
˓→Integer(8)],...
Integer(3): [Integer(4), Integer(5), Integer(6)],␣
˓→Integer(6): [Integer(9)], Integer(8): [Integer(9)]})>>> len(list(B.perfect_matchings()))
6>>> G = Graph(B.edges(sort=False))>>> len(list(G.perfect_matchings()))
6

The algorithm ensures that for any edge of a perfect matching, the first vertex is on the left set of vertices andthe second vertex in the right set:sage: B = BipartiteGraph({0: [5, 7], 1: [4, 6, 7], 2: [4, 5, 8],....:
3: [4, 5, 6], 6: [9], 8: [9]})sage: m = next(B.perfect_matchings(labels=False))
sage: B.left{0, 1, 2, 3, 9}
sage: B.right{4, 5, 6, 7, 8}
sage: sorted(m)[(0, 7), (1, 4), (2, 5), (3, 6), (9, 8)]
sage: all((u in B.left and v in B.right) for u, v in m)
True>>> from sage.all import *>>> B = BipartiteGraph({Integer(0): [Integer(5), Integer(7)], Integer(1):␣
˓→[Integer(4), Integer(6), Integer(7)], Integer(2): [Integer(4), Integer(5),␣
˓→Integer(8)],...
Integer(3): [Integer(4), Integer(5), Integer(6)],␣
˓→Integer(6): [Integer(9)], Integer(8): [Integer(9)]})>>> m = next(B.perfect_matchings(labels=False))>>> B.left{0, 1, 2, 3, 9}>>> B.right{4, 5, 6, 7, 8}>>> sorted(m)[(0, 7), (1, 4), (2, 5), (3, 6), (9, 8)]>>> all((u in B.left and v in B.right) for u, v in m)
True

Multiple edges are taken into account:sage: B = BipartiteGraph({0: [5, 7], 1: [4, 6, 7], 2: [4, 5, 8],....:
3: [4, 5, 6], 6: [9], 8: [9]})sage: B.allow_multiple_edges(True)
sage: B.add_edge(0, 7)
sage: len(list(B.perfect_matchings()))
10

1.4. Bipartite graphs755Graph Theory, Release 10.4>>> from sage.all import *>>> B = BipartiteGraph({Integer(0): [Integer(5), Integer(7)], Integer(1):␣
˓→[Integer(4), Integer(6), Integer(7)], Integer(2): [Integer(4), Integer(5),␣
˓→Integer(8)],...
Integer(3): [Integer(4), Integer(5), Integer(6)],␣
˓→Integer(6): [Integer(9)], Integer(8): [Integer(9)]})>>> B.allow_multiple_edges(True)>>> B.add_edge(Integer(0), Integer(7))>>> len(list(B.perfect_matchings()))
10

Empty graph:
sage: list(BipartiteGraph().perfect_matchings())[[]]>>> from sage.all import *>>> list(BipartiteGraph().perfect_matchings())[[]]

Bipartite graph without perfect matching:sage: B = BipartiteGraph(graphs.CompleteBipartiteGraph(3, 4))
sage: list(B.perfect_matchings())[]>>> from sage.all import *>>> B = BipartiteGraph(graphs.CompleteBipartiteGraph(Integer(3), Integer(4)))>>> list(B.perfect_matchings())[]

Check that the number of perfect matchings of a complete bipartite graph is consistent with the matching
polynomial:
sage: B = BipartiteGraph(graphs.CompleteBipartiteGraph(4, 4))
sage: len(list(B.perfect_matchings()))
24
sage: B.matching_polynomial(algorithm= rook )(0)˓→needs sage.modules24#␣>>> from sage.all import *>>> B = BipartiteGraph(graphs.CompleteBipartiteGraph(Integer(4), Integer(4)))>>> len(list(B.perfect_matchings()))
24>>> B.matching_polynomial(algorithm= rook )(Integer(0))␣˓→# needs sage.modules
24

plot(*args, **kwds)
Override Graph’s plot function, to illustrate the bipartite nature.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(20))
sage: B.plot()#␣(continues on next page)

756

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)needs sage.plot
Graphics object consisting of 41 graphics primitives˓→>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(20)))>>> B.plot()
˓→needs sage.plot
Graphics object consisting of 41 graphics primitives#␣

project_left()
Project self onto left vertices. Edges are 2-paths in the original.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(20))
sage: G = B.project_left()
sage: G.order(), G.size()(10, 10)>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(20)))>>> G = B.project_left()>>> G.order(), G.size()(10, 10)project_right()
Project self onto right vertices. Edges are 2-paths in the original.
EXAMPLES:
sage: B = BipartiteGraph(graphs.CycleGraph(20))
sage: G = B.project_right()
sage: G.order(), G.size()(10, 10)>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(20)))>>> G = B.project_right()>>> G.order(), G.size()(10, 10)

reduced_adjacency_matrix(sparse, base_ring=True, **kwds)
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]].
By default, the matrix returned is over the integers.
INPUT:• sparse – boolean (default: True); whether to return a sparse matrix• base_ring – a ring (default: None); the base ring of the matrix space to use. By default, the basering is ZZ if the graph is not weighted and otherwise the same ring as the (first) weights.
• **kwds – other keywords to pass to matrix()
1.4. Bipartite graphs757

Graph Theory, Release 10.4

EXAMPLES:
Bipartite graphs that are not weighted will return a matrix over ZZ, unless a base ring is specified:sage: # needs sage.modules
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(); 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 Ringsage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2[1.0 1.0 1.0 0.0 0.0 0.0 0.0]
[1.0 0.0 0.0 1.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0 1.0 0.0]
[1.0 1.0 0.0 1.0 0.0 0.0 1.0]
sage: N2[0, 0].parent()
Real Double Field>>> from sage.all import *>>> # needs sage.modules>>> M = Matrix([(Integer(1),Integer(1),Integer(1),Integer(0),Integer(0),˓→Integer(0),Integer(0)), (Integer(1),Integer(0),Integer(0),Integer(1),˓→Integer(1),Integer(0),Integer(0)),...
(Integer(0),Integer(1),Integer(0),Integer(1),Integer(0),˓→Integer(1),Integer(0)), (Integer(1),Integer(1),Integer(0),Integer(1),˓→Integer(0),Integer(0),Integer(1))])>>> B = BipartiteGraph(M)>>> N = B.reduced_adjacency_matrix(); 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]>>> N == M
True>>> N[Integer(0),Integer(0)].parent()
Integer Ring>>> N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2[1.0 1.0 1.0 0.0 0.0 0.0 0.0]
[1.0 0.0 0.0 1.0 1.0 0.0 0.0]
[0.0 1.0 0.0 1.0 0.0 1.0 0.0]
[1.0 1.0 0.0 1.0 0.0 0.0 1.0]>>> N2[Integer(0), Integer(0)].parent()
Real Double Field

Multi-edge graphs also return a matrix over ZZ, unless a base ring is specified:sage: # needs sage.modules
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
(continues on next page)

758

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)True
sage: N[0,0].parent()
Integer Ringsage: N2 = B.reduced_adjacency_matrix(base_ring=RDF)
sage: N2[0, 0].parent()
Real Double Field>>> from sage.all import *>>> # needs sage.modules>>> M = Matrix([(Integer(1),Integer(1),Integer(2),Integer(0),Integer(0)),␣
˓→(Integer(0),Integer(2),Integer(1),Integer(1),Integer(1)), (Integer(0),˓→Integer(1),Integer(2),Integer(1),Integer(1))])>>> B = BipartiteGraph(M, multiedges=True, sparse=True)>>> N = B.reduced_adjacency_matrix()>>> N == M
True>>> N[Integer(0),Integer(0)].parent()
Integer Ring>>> N2 = B.reduced_adjacency_matrix(base_ring=RDF)>>> N2[Integer(0), Integer(0)].parent()
Real Double Field

Weighted graphs will return a matrix over the ring given by their (first) weights, unless a base ring is specified:sage: # needs sage.modules sage.rings.finite_rings
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: N = B.reduced_adjacency_matrix(sparse=False)
sage: N == M
True
sage: N[0,0].parent()
Finite Field in a of size 2^2
sage: N2 = B.reduced_adjacency_matrix(base_ring=F)
sage: N2[0, 0].parent()
Finite Field in a of size 2^2>>> from sage.all import *>>> # needs sage.modules sage.rings.finite_rings>>> F = GF(Integer(4), names=( a ,)); (a,) = F._first_ngens(1)>>> MS = MatrixSpace(F, Integer(2), Integer(3))>>> M = MS.matrix([[Integer(0), Integer(1), a+Integer(1)], [a, Integer(1),␣
˓→Integer(1)]])>>> B = BipartiteGraph(M, weighted=True, sparse=True)>>> N = B.reduced_adjacency_matrix(sparse=False)>>> N == M
True>>> N[Integer(0),Integer(0)].parent()
Finite Field in a of size 2^2>>> N2 = B.reduced_adjacency_matrix(base_ring=F)>>> N2[Integer(0), Integer(0)].parent()
Finite Field in a of size 2^2

save_afile(fname)
Save the graph to file in alist format.
1.4. Bipartite graphs759

Graph Theory, Release 10.4

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: # needs sage.modules
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: import tempfile
sage: with tempfile.NamedTemporaryFile() as f:....:b.save_afile(f.name)....:b2 = BipartiteGraph(f.name)sage: b.is_isomorphic(b2)True>>> from sage.all import *>>> # needs sage.modules>>> M = Matrix([(Integer(1),Integer(1),Integer(1),Integer(0),Integer(0),˓→Integer(0),Integer(0)), (Integer(1),Integer(0),Integer(0),Integer(1),˓→Integer(1),Integer(0),Integer(0)),...
(Integer(0),Integer(1),Integer(0),Integer(1),Integer(0),˓→Integer(1),Integer(0)), (Integer(1),Integer(1),Integer(0),Integer(1),˓→Integer(0),Integer(0),Integer(1))])>>> 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]>>> b = BipartiteGraph(M)>>> import tempfile>>> with tempfile.NamedTemporaryFile() as f:...
b.save_afile(f.name)...
b2 = BipartiteGraph(f.name)>>> b.is_isomorphic(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>>> from sage.all import *>>> BipartiteGraph(graphs.CycleGraph(Integer(6))).to_undirected()
Cycle graph: Graph on 6 vertices

vertex_cover(algorithm, value_only='Konig', reduction_rules=False, solver=True, verbose=None,
integrality_tolerance=0)
Return a minimum vertex cover of self represented by a set of vertices.

760

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

A minimum vertex cover of a graph is a set 𝑆 of vertices such that each edge is incident to at least one elementof 𝑆, 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"); algorithm to use among:– "Konig" will compute a minimum vertex cover using Konig’s algorithm (Wikipedia article
Kőnig%27s_theorem_(graph_theory))– "Cliquer" will compute a minimum vertex cover using the Cliquer package– "MILP" will compute a minimum vertex cover through a mixed integer linear program– "mcqd" will use the MCQD solver (http://www.sicmm.org/ konc/maxclique/), and the MCQD
package must be installed• value_only – boolean (default: False); if set to True, only the size of a minimum vertex cover isreturned. 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be
used. If set to None, the default one is used. For more information on MILP solvers and which default
solver is used, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring;see MixedIntegerLinearProgram.get_values().
EXAMPLES:
On the Cycle Graph:
sage: B = BipartiteGraph(graphs.CycleGraph(6))
sage: len(B.vertex_cover())
˓→needs networkx
3
sage: B.vertex_cover(value_only=True)
˓→needs networkx
3>>> from sage.all import *>>> B = BipartiteGraph(graphs.CycleGraph(Integer(6)))>>> len(B.vertex_cover())
˓→needs networkx
3>>> B.vertex_cover(value_only=True)

#␣

#␣

#␣

#␣
(continues on next page)

1.4. Bipartite graphs761

Graph Theory, Release 10.4

(continued from previous page)needs networkx

˓→3

The two algorithms should return the same result:
sage: # needs networkx numpy
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>>> from sage.all import *>>> # needs networkx numpy>>> g = BipartiteGraph(graphs.RandomBipartite(Integer(10), Integer(10),␣
˓→RealNumber( .5 )))>>> vc1 = g.vertex_cover(algorithm="Konig")>>> vc2 = g.vertex_cover(algorithm="Cliquer")>>> len(vc1) == len(vc2)True

1.5 View classes
This module implements views for (di)graphs. A view is a read-only iterable container enabling operations like for e
in E and e in E. It is updated as the graph is updated. Hence, the graph should not be updated while iterating througha view. Views can be iterated multiple times.
Todo:• View of neighborhood to get open/close neighborhood of a vertex/set of vertices

1.5.1 Classes
class sage.graphs.views.EdgesView
Bases: object
EdgesView class.
This class implements a read-only iterable container of edges enabling operations like for e in E and e in E.
An EdgesView can be iterated multiple times, and checking membership is done in constant time. It avoids theconstruction of edge lists and so consumes little memory. It is updated as the graph is updated. Hence, the graphshould not be updated while iterating through an EdgesView.
INPUT:• G – a (di)graph• vertices – list (default: None); an iterable container of vertices or None. When set, consider only edges
incident to specified vertices.
• vertices2 – list (default: None); an iterable container of vertices or None. When set, consider only edges
incident to specified vertices. More precisely:

762

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

– When both vertices and vertices2 are set, consider only edges (u, v, l) with u in vertices and v in vertices2.
– When vertices is None and vertices2 is set, consider only edges (u, v, l) with v invertices2.
• labels – boolean (default: True); if False, each edge is simply a pair (u, v) of vertices• ignore_direction – boolean (default: False); only applies to directed graphs. If True, searches
across edges in either direction.
• sort – boolean (default: False); whether to sort edges according the ordering specified with parameter
key. If False (default), edges are not sorted. This is the fastest and less memory consuming method for
iterating over edges.
• key – a function (default: None); a function that takes an edge (a pair or a triple, according to the labels
keyword) as its one argument and returns a value that can be used for comparisons in the sorting algorithm.
This parameter is ignored when sort = False.
• sort_vertices – boolean (default: True); whether to sort the ends of the edges; not sorting the ends isfaster; only applicable to undirected graphs when sort is False
Warning: Since any object may be a vertex, there is no guarantee that any two vertices will be comparable,
and thus no guarantee how two edges may compare. With default objects for vertices (all integers), or when
all the vertices are of the same simple type, then there should not be a problem with how the vertices will besorted. 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: from sage.graphs.views import EdgesView
sage: G = Graph([(0, 1, C ), (0, 2, A ), (1, 2, B )])sage: E = EdgesView(G, sort=True); E[(0, 1, C ), (0, 2, A ), (1, 2, B )]sage: (1, 2) in E
False
sage: (1, 2, B ) in E
True
sage: E = EdgesView(G, labels=False, sort=True); E[(0, 1), (0, 2), (1, 2)]
sage: (1, 2) in E
True
sage: (1, 2, B ) in E
False
sage: [e for e in E][(0, 1), (0, 2), (1, 2)]>>> from sage.all import *>>> from sage.graphs.views import EdgesView>>> G = Graph([(Integer(0), Integer(1), C ), (Integer(0), Integer(2),˓→(Integer(1), Integer(2),B )])>>> E = EdgesView(G, sort=True); E[(0, 1, C ), (0, 2, A ), (1, 2, B )]>>> (Integer(1), Integer(2)) in E
False>>> (Integer(1), Integer(2), B ) in E
True

A ),␣

(continues on next page)

1.5. View classes

763

Graph Theory, Release 10.4

(continued from previous page)>>> E = EdgesView(G, labels=False, sort=True); E[(0, 1), (0, 2), (1, 2)]>>> (Integer(1), Integer(2)) in E
True>>> (Integer(1), Integer(2), B ) in E
False>>> [e for e in E][(0, 1), (0, 2), (1, 2)]

An EdgesView can be iterated multiple times:
sage: G = graphs.CycleGraph(3)sage: print(E)[(0, 1), (0, 2), (1, 2)]
sage: print(E)[(0, 1), (0, 2), (1, 2)]
sage: for e in E:....:
for ee in E:....:
print((e, ee))((0, 1), (0, 1))((0, 1), (0, 2))((0, 1), (1, 2))((0, 2), (0, 1))((0, 2), (0, 2))((0, 2), (1, 2))((1, 2), (0, 1))((1, 2), (0, 2))((1, 2), (1, 2))>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> print(E)[(0, 1), (0, 2), (1, 2)]>>> print(E)[(0, 1), (0, 2), (1, 2)]>>> for e in E:...
for ee in E:...
print((e, ee))((0, 1), (0, 1))((0, 1), (0, 2))((0, 1), (1, 2))((0, 2), (0, 1))((0, 2), (0, 2))((0, 2), (1, 2))((1, 2), (0, 1))((1, 2), (0, 2))((1, 2), (1, 2))

We can check if a view is empty:
sage: E = EdgesView(graphs.CycleGraph(3), sort=False)
sage: if E:....:
print( not empty )not empty
sage: E = EdgesView(Graph(), sort=False)
sage: if not E:(continues on next page)

764

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

....:
empty

print( empty )>>> from sage.all import *>>> E = EdgesView(graphs.CycleGraph(Integer(3)), sort=False)>>> if E:...
print( not empty )not empty>>> E = EdgesView(Graph(), sort=False)>>> if not E:...
print( empty )empty

When sort is True, edges are sorted by default in the default fashion:
sage: G = Graph([(0, 1, C ), (0, 2, A ), (1, 2,
sage: E = EdgesView(G, sort=True); E[(0, 1, C ), (0, 2, A ), (1, 2, B )]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1),˓→(Integer(1), Integer(2),B )])>>> E = EdgesView(G, sort=True); E[(0, 1, C ), (0, 2, A ), (1, 2, B )]B )])C ), (Integer(0), Integer(2),A ),␣This can be overridden by specifying a key function. This first example just ignores the labels in the third componentof the triple:
sage: G = Graph([(0, 1, C ), (0, 2, A ), (1, 2, B )])sage: E = EdgesView(G, sort=True, key=lambda x: (x[1], -x[0])); E[(0, 1, C ), (1, 2, B ), (0, 2, A )]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1), C ), (Integer(0), Integer(2), A ),␣
˓→(Integer(1), Integer(2),B )])>>> E = EdgesView(G, sort=True, key=lambda x: (x[Integer(1)], -x[Integer(0)])); E[(0, 1, C ), (1, 2, B ), (0, 2, A )]We can also sort according to the labels:
sage: G = Graph([(0, 1, C ), (0, 2, A ), (1, 2, B )])sage: E = EdgesView(G, sort=True, key=lambda x: x[2]); E[(0, 2, A ), (1, 2, B ), (0, 1, C )]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1), C ), (Integer(0), Integer(2),˓→(Integer(1), Integer(2),B )])>>> E = EdgesView(G, sort=True, key=lambda x: x[Integer(2)]); E[(0, 2, A ), (1, 2, B ), (0, 1, C )]A ),␣Not sorting the ends of the vertices:sage: G = Graph()
sage: G.add_edges([[1,2], [2,3], [0,3]])(continues on next page)

1.5. View classes

765

Graph Theory, Release 10.4

(continued from previous page)

sage: E = EdgesView(G, sort=False, sort_vertices=False); E[(3, 0, None), (2, 1, None), (3, 2, None)]>>> from sage.all import *>>> G = Graph()>>> G.add_edges([[Integer(1),Integer(2)], [Integer(2),Integer(3)], [Integer(0),˓→Integer(3)]])>>> E = EdgesView(G, sort=False, sort_vertices=False); E[(3, 0, None), (2, 1, None), (3, 2, None)]

With a directed graph:
sage: G = digraphs.DeBruijn(2, 2)
˓→needs sage.combinat
sage: E = EdgesView(G, labels=False, sort=True); E
˓→needs sage.combinat[( 00 , 00 ), ( 00 , 01 ), ( 01 , 10 ), ( 01 , 11 ),( 10 , 00 ), ( 10 , 01 ), ( 11 , 10 ), ( 11 , 11 )]sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E˓→needs sage.combinat[( 00 , 00 ), ( 10 , 00 ), ( 00 , 01 ), ( 10 , 01 ),( 01 , 10 ), ( 11 , 10 ), ( 01 , 11 ), ( 11 , 11 )]>>> from sage.all import *>>> G = digraphs.DeBruijn(Integer(2), Integer(2))˓→# needs sage.combinat>>> E = EdgesView(G, labels=False, sort=True); E
˓→needs sage.combinat[( 00 , 00 ), ( 00 , 01 ), ( 01 , 10 ), ( 01 , 11 ),( 10 , 00 ), ( 10 , 01 ), ( 11 , 10 ), ( 11 , 11 )]>>> E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[Integer(1)],␣
˓→e[Integer(0)])); E# needs sage.combinat[( 00 , 00 ), ( 10 , 00 ), ( 00 , 01 ), ( 10 , 01 ),( 01 , 10 ), ( 11 , 10 ), ( 01 , 11 ), ( 11 , 11 )]

#␣
#␣

#␣

␣
#␣

We can consider only edges incident to a specified set of vertices:sage: G = graphs.CycleGraph(5)sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True); E[(0, 1), (0, 4), (1, 2)]
sage: E = EdgesView(G, vertices=[0], labels=False, sort=True); E[(0, 1), (0, 4)]
sage: E = EdgesView(G, vertices=None, labels=False, sort=True); E[(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
sage: G = digraphs.Circuit(5)sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True); E[(0, 1), (1, 2)]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(5))>>> E = EdgesView(G, vertices=[Integer(0), Integer(1)], labels=False, sort=True);␣
˓→E[(0, 1), (0, 4), (1, 2)]>>> E = EdgesView(G, vertices=[Integer(0)], labels=False, sort=True); E(continues on next page)

766

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[(0, 1), (0, 4)]>>> E = EdgesView(G, vertices=None, labels=False, sort=True); E[(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]>>> G = digraphs.Circuit(Integer(5))>>> E = EdgesView(G, vertices=[Integer(0), Integer(1)], labels=False, sort=True);␣
˓→E[(0, 1), (1, 2)]

We can ignore the direction of the edges of a directed graph, in which case we search across edges in either direction:
sage: G = digraphs.Circuit(5)sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True, ignore_
˓→direction=False); E[(0, 1), (1, 2)]
sage: (1, 0) in E
False
sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True, ignore_
˓→direction=True); E[(0, 1), (0, 1), (1, 2), (4, 0)]
sage: (1, 0) in E
True
sage: G.has_edge(1, 0)
False>>> from sage.all import *>>> G = digraphs.Circuit(Integer(5))>>> E = EdgesView(G, vertices=[Integer(0), Integer(1)], labels=False, sort=True,␣
˓→ignore_direction=False); E[(0, 1), (1, 2)]>>> (Integer(1), Integer(0)) in E
False>>> E = EdgesView(G, vertices=[Integer(0), Integer(1)], labels=False, sort=True,␣
˓→ignore_direction=True); E[(0, 1), (0, 1), (1, 2), (4, 0)]>>> (Integer(1), Integer(0)) in E
True>>> G.has_edge(Integer(1), Integer(0))
False

We can consider only the edges between two specifed sets of vertices:sage: G = Graph([(0, 1), (1, 2)])sage: E = EdgesView(G, vertices=[0], vertices2=[1], labels=False)
sage: (0, 1) in E and (1, 2) not in E
True
sage: E = EdgesView(G, vertices=[0], labels=False)
sage: (0, 1) in E and (1, 2) not in E
True
sage: E = EdgesView(G, vertices2=[1], labels=False)
sage: (0, 1) in E and (1, 2) in E
True
sage: D = DiGraph([(0, 1), (1, 2)])sage: E = EdgesView(D, vertices=[0], vertices2=[1], labels=False)
sage: (0, 1) in E and (1, 2) not in E
True(continues on next page)

1.5. View classes

767

Graph Theory, Release 10.4

(continued from previous page)

sage: EdgesView(D, vertices=[1], vertices2=[0], labels=False)[]
sage: E = EdgesView(D, vertices=[1], vertices2=[0], labels=False, ignore_
˓→direction=True)
sage: (0, 1) in E and (1, 2) not in E
True
sage: E = EdgesView(D, vertices=[0], labels=False)
sage: (0, 1) in E and (1, 2) not in E
True
sage: E = EdgesView(D, vertices2=[1], labels=False)
sage: (0, 1) in E and (1, 2) not in E
True
sage: E = EdgesView(D, vertices2=[1], labels=False, ignore_direction=True)
sage: (0, 1) in E and (1, 2) in E
True>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1)), (Integer(1), Integer(2))])>>> E = EdgesView(G, vertices=[Integer(0)], vertices2=[Integer(1)], labels=False)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) not in E
True>>> E = EdgesView(G, vertices=[Integer(0)], labels=False)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) not in E
True>>> E = EdgesView(G, vertices2=[Integer(1)], labels=False)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) in E
True>>> D = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(2))])>>> E = EdgesView(D, vertices=[Integer(0)], vertices2=[Integer(1)], labels=False)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) not in E
True>>> EdgesView(D, vertices=[Integer(1)], vertices2=[Integer(0)], labels=False)[]>>> E = EdgesView(D, vertices=[Integer(1)], vertices2=[Integer(0)], labels=False,␣
˓→ignore_direction=True)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) not in E
True>>> E = EdgesView(D, vertices=[Integer(0)], labels=False)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) not in E
True>>> E = EdgesView(D, vertices2=[Integer(1)], labels=False)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) not in E
True>>> E = EdgesView(D, vertices2=[Integer(1)], labels=False, ignore_direction=True)>>> (Integer(0), Integer(1)) in E and (Integer(1), Integer(2)) in E
True

A view is updated as the graph is updated:sage: G = Graph()
sage: E = EdgesView(G, vertices=[0, 3], labels=False, sort=True); E[]
sage: G.add_edges([(0, 1), (1, 2)])sage: E[(0, 1)]
sage: G.add_edge(2, 3)(continues on next page)

768

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)

sage: E[(0, 1), (2, 3)]>>> from sage.all import *>>> G = Graph()>>> E = EdgesView(G, vertices=[Integer(0), Integer(3)], labels=False, sort=True);␣
˓→E[]>>> G.add_edges([(Integer(0), Integer(1)), (Integer(1), Integer(2))])>>> E[(0, 1)]>>> G.add_edge(Integer(2), Integer(3))>>> E[(0, 1), (2, 3)]Hence, the graph should not be updated while iterating through a view:
sage: G = Graph([( a , b ), ( b , c )])sage: E = EdgesView(G, labels=False, sort=False); E[( a , b ), ( b , c )]sage: for u, v in E:....:
G.add_edge(u + u, v + v)
Traceback (most recent call last):...
RuntimeError: dictionary changed size during iteration>>> from sage.all import *>>> G = Graph([( a , b ), ( b , c )])>>> E = EdgesView(G, labels=False, sort=False); E[( a , b ), ( b , c )]>>> for u, v in E:...
G.add_edge(u + u, v + v)
Traceback (most recent call last):...
RuntimeError: dictionary changed size during iteration

Two EdgesView are considered equal if they report either both directed, or both undirected edges, they havethe same settings for ignore_direction, they have the same settings for labels, and they report the sameedges in the same order:
sage: G = graphs.HouseGraph()
sage: EG = EdgesView(G, sort=False)
sage: H = Graph(EG)sage: EH = EdgesView(H, sort=False)
sage: EG == EH
True
sage: G.add_edge(0, 10)
sage: EG = EdgesView(G, sort=False)
sage: EG == EH
False
sage: H.add_edge(0, 10)
sage: EH = EdgesView(H, sort=False)
sage: EG == EH
True
sage: H = G.strong_orientation()sage: EH = EdgesView(H, sort=False)(continues on next page)

1.5. View classes

769

Graph Theory, Release 10.4

(continued from previous page)

sage: EG == EH
False>>> from sage.all import *>>> G = graphs.HouseGraph()>>> EG = EdgesView(G, sort=False)>>> H = Graph(EG)>>> EH = EdgesView(H, sort=False)>>> EG == EH
True>>> G.add_edge(Integer(0), Integer(10))>>> EG = EdgesView(G, sort=False)>>> EG == EH
False>>> H.add_edge(Integer(0), Integer(10))>>> EH = EdgesView(H, sort=False)>>> EG == EH
True>>> H = G.strong_orientation()>>> EH = EdgesView(H, sort=False)>>> EG == EH
False

The sum of two EdgesView is a list containing the edges in both EdgesView:
sage: E1 = EdgesView(Graph([(0, 1)]), labels=False, sort=False)
sage: E2 = EdgesView(Graph([(2, 3)]), labels=False, sort=False)
sage: E1 + E2[(0, 1), (2, 3)]
sage: E2 + E1[(2, 3), (0, 1)]>>> from sage.all import *>>> E1 = EdgesView(Graph([(Integer(0), Integer(1))]), labels=False, sort=False)>>> E2 = EdgesView(Graph([(Integer(2), Integer(3))]), labels=False, sort=False)>>> E1 + E2[(0, 1), (2, 3)]>>> E2 + E1[(2, 3), (0, 1)]

Recall that a EdgesView is read-only and that this method returns a list:
sage: E1 += E2
sage: type(E1) is list
True>>> from sage.all import *>>> E1 += E2>>> type(E1) is list
True

It is also possible to get the sum a EdgesView with itself 𝑛 times:
sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False, sort=True)
sage: E * 3(continues on next page)

770

Chapter 1. Graph objects and methods

Graph Theory, Release 10.4

(continued from previous page)[(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)]
sage: 3 * E[(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)]>>> from sage.all import *>>> E = EdgesView(Graph([(Integer(0), Integer(1)), (Integer(2), Integer(3))]),␣
˓→labels=False, sort=True)>>> E * Integer(3)[(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)]>>> Integer(3) * E[(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)]

Recall that a EdgesView is read-only and that this method returns a list:
sage: E *= 2
sage: type(E) is list
True>>> from sage.all import *>>> E *= Integer(2)>>> type(E) is list
True

We can ask for the 𝑖-th edge, or a slice of the edges as a list:
sage: E = EdgesView(graphs.HouseGraph(), labels=False, sort=True)
sage: E[0](0, 1)
sage: E[2](1, 3)
sage: E[-1](3, 4)
sage: E[1:-1][(0, 2), (1, 3), (2, 3), (2, 4)]
sage: E[::-1][(3, 4), (2, 4), (2, 3), (1, 3), (0, 2), (0, 1)]>>> from sage.all import *>>> E = EdgesView(graphs.HouseGraph(), labels=False, sort=True)>>> E[Integer(0)](0, 1)>>> E[Integer(2)](1, 3)>>> E[-Integer(1)](3, 4)>>> E[Integer(1):-Integer(1)][(0, 2), (1, 3), (2, 3), (2, 4)]>>> E[::-Integer(1)][(3, 4), (2, 4), (2, 3), (1, 3), (0, 2), (0, 1)]

1.5. View classes

771

Graph Theory, Release 10.4

772

Chapter 1. Graph objects and methods

CHAPTERTWOCONSTRUCTORS 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 cando:sage: g = graphs.CompleteGraph(15)>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(15))

To get a path with 4 vertices, and the house graph:
sage: p = graphs.PathGraph(4)sage: h = graphs.HouseGraph()>>> from sage.all import *>>> p = graphs.PathGraph(Integer(4))>>> 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 thenhitting Tab.
Basic structures
BullGraph
ButterflyGraph
CircularLadderGraph
ClawGraph
CycleGraph
CompleteBipartiteGraph
CompleteGraph
CompleteMultipartiteGraph
CorrelationGraph

DiamondGraph
GemGraph
DartGraph
ForkGraph
DipoleGraph
EmptyGraph
Grid2dGraph
GridGraph

HouseXGraph
LadderGraph
LollipopGraph
MoebiusLadderGraph
PathGraph
StarGraph
TadpoleGraph
ToroidalGrid2dGraph

HouseGraph

Toroidal6RegularGrid2dGraph

Small Graphs
A small graph is just a single graph and has no parameter influencing the number of edges or vertices.

773

Graph Theory, Release 10.4

Balaban10Cage

GolombGraph

Balaban11Cage
BidiakisCube
BiggsSmithGraph
BlanusaFirstSnarkGraph
BlanusaSecondSnarkGraph
BrinkmannGraph
BrouwerHaemersGraph
BuckyBall
CameronGraph
Cell600
Cell120
ChvatalGraph
ClebschGraph

GossetGraphgraph_3O73
GrayGraph
GritsenkoGraph
GrotzschGraph
HallJankoGraph
HarborthGraph
HarriesGraph
HarriesWongGraph
HeawoodGraph
HerschelGraph
HigmanSimsGraph
HoffmanGraphcocliques_HoffmannSingleton

HoffmanSingletonGraph

ConwaySmith_for_3S7
CoxeterGraph
DesarguesGraph
DejterGraph

HoltGraph
HortonGraph
IoninKharaghani765Graph
IvanovIvanovFaradjevGraph
J2Graphdistance_3_doubly_truncated_Golay_code_graph
DoubleStarSnark
DoublyTruncatedWittGraph
DurerGraph

JankoKharaghaniGraph
JankoKharaghaniTonchevGraph
KittellGraph

DyckGraph

KrackhardtKiteGraph

EllinghamHorton54Graph
EllinghamHorton78Graph
ErreraGraph
F26AGraph
FlowerSnark
FolkmanGraph
FosterGraph
FosterGraph3S6

Klein3RegularGraph
Klein7RegularGraph
LargeWittGraph
LeonardGraph
LjubljanaGraphvanLintSchrijverGraph
LivingstoneGraph
locally_GQ42_distance_transitive_graph
LocalMcLaughlinGraph
M22GraphMarkstroemGraph

FranklinGraph
FruchtGraph
GoldnerHararyGraph

MathonStronglyRegularGraph
McGeeGraph
McLaughlinGraph
MeredithGraph
MoebiusKantorGraph
MoserSpindle
NauruGraph
PappusGraph
PoussinGraph
PerkelGraphPetersenGraph
RobertsonGraph
SchlaefliGraphshortened_00_11_binary_Golay_code_graphshortened_000_111_extended_binary_Golay_code_graphShrikhandeGraph
SimsGewirtzGraph
SousselierGraph
SylvesterGraph
SzekeresSnarkGraph
ThomsenGraph
TietzeGraph
TruncatedIcosidodecahedralGraph
TruncatedTetrahedralGraph
TruncatedWittGraph
Tutte12Cage
TutteCoxeterGraph
TutteGraph
U42Graph216
U42Graph540
WagnerGraph
WatkinsSnarkGraph
WellsGraph
WienerArayaGraph
SuzukiGraph

Platonic solids (ordered ascending by number of vertices)
TetrahedralGraph
OctahedralGraph

HexahedralGraph
IcosahedralGraph

DodecahedralGraph

Families of graphs
774

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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 ora list of graphs or …)
AlternatingFormsGraph
AztecDiamondGraph

CaiFurerImmermanGraphchang_graphs
CirculantGraph
cographs
cospectral_graphs
CubeGraph
CubeConnectedCycle

FuzzyBallGraph
GeneralisedDodecagonGraph
GeneralisedHexagonGraph
GeneralisedOctagonGraph
GeneralizedPetersenGraph
GeneralizedSierpinskiGraph
GoethalsSeidelGraph
GrassmannGraph
HalfCubeHammingGraph
HanoiTowerGraph
HararyGraph
HermitianFormsGraphdistance_regular_graph

HyperStarGraph

DorogovtsevGoltsevMendesGraph
DoubleGrassmannGraph
DoubleOddGraph
EgawaGraph

JohnsonGraph

BalancedTree
BarbellGraph
BilinearFormsGraph
BubbleSortGraph

FibonacciTree
FoldedCubeGraph
FriendshipGraphfullerenes
FurerGadget
fusenes

KneserGraph
LCFGraphline_graph_forbidden_subgraphs
MathonPseudocyclicMergingGraph
MathonPseudocyclicStronglyRegularGraph
MuzychukS6Graph
MycielskiGraph
MycielskiStep
nauty_geng

nauty_genbg
NKStarGraph
NStarGraph
OddGraph
PaleyGraph
PasechnikGraphpetersen_family
planar_graphs
plantri_gen
quadrangulations
RingedTree
SierpinskiGasketGraph
SquaredSkewHadamardMatrixGraph
SwitchedSquaredSkewHadamardMatrixGraphstrongly_regular_graphtrees
nauty_gentreeg
triangulations
TuranGraph
UstimenkoGraph
WheelGraph
WindmillGraph

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.
AffineOrthogonalPolarGraph
AhrensSzekeresGeneralizedQuadrangleGraph
NonisotropicOrthogonalPolarGraph
NonisotropicUnitaryPolarGraph
OrthogonalDualPolarGraph
OrthogonalPolarGraph2.1. Common graphs

SymplecticDualPolarGraph

HaemersGraph

SymplecticPolarGraph

CossidentePenttilaGraph

TaylorTwographDescendantSRG
TaylorTwographSRG

UnitaryDualPolarGraph
UnitaryPolarGraph

T2starGeneralizedQuadrangleGraph
Nowhere0WordsTwoWeightCodeGraph
775

Graph Theory, Release 10.4

Chessboard Graphs
BishopGraph
KingGraph

KnightGraph
QueenGraph

RookGraph

Intersection graphs
These graphs are generated by geometric representations. The objects of the representation correspond to the graphvertices and the intersections of objects yield the graph edges.
IntersectionGraph
IntervalGraph

OrthogonalArrayBlockGraph
PermutationGraph

ToleranceGraph

RandomHolmeKim
RandomChordalGraph
RandomIntervalGraph
RandomKTree
RandomPartialKTree
RandomLobster

RandomShell
RandomToleranceGraph
RandomTree
RandomTreePowerlaw
RandomTriangulation
RandomUnitDiskGraph

Random graphs
RandomBarabasiAlbert
RandomBicubicPlanar
RandomBipartite
RandomRegularBipartite
RandomBlockGraph
RandomBoundedToleranceGraph
RandomGNM
RandomGNP

RandomNewmanWattsStrogatz
RandomRegular

Graphs with a given degree sequence
DegreeSequence
DegreeSequenceBipartite

DegreeSequenceConfigurationModel
DegreeSequenceExpected

DegreeSequenceTree

Miscellaneous
WorldMap
EuropeMap

AfricaMap
USAMapAUTHORS:• 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
776

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• 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• Janmenjaya Panda (2024-05-26): added MoebiusLadderGraph2.1.1 Functions and methods
class sage.graphs.graph_generators.GraphGenerators
Bases: object
A class consisting of constructors for several common graphs, as well as orderly generation of isomorphism classrepresentatives. See the module s help for a list of supported constructors.
A list of all graphs and graph structures (other than isomorphism class representatives) in this database is available
via tab completion. Type “graphs.” and then hit the Tab key to see which graphs are available.
The docstrings include educational information about each named graph with the hopes that this class can be used
as a reference.
For all the constructors in this class (except the octahedral, dodecahedral, random and empty graphs), the position
dictionary is filled to override the spring-layout algorithm.
ORDERLY GENERATION:
graphs(vertices, property=lambda x: True, augment= edges , size=None)

This syntax accesses the generator of isomorphism class representatives. Iterates over distinct, exhaustive representatives.
Also: see the use of the nauty package for generating graphs at the nauty_geng() method.
INPUT:
2.1. Common graphs777Graph Theory, Release 10.4

• 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, butnote that in general the graphs produced are not the same as those produced by using the property function tofilter a list of graphs produced by using the lambda x: True default. The generation process assumes theproperty 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 agraph 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 fromG 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 theproperty, 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 theproperty, 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, thegenerated graphs will have these integers for degrees. In this case, property and size are both ignored.
• loops – (default: False) whether to allow loops in the graph or not.
• sparse – (default: True); whether to use a sparse or dense data structure. See the documentation ofGraph.
• copy (boolean) – If set to True (default) this method makes copies of the graphs before returning them. If
set to False the method returns the graph it is working on. The second alternative is faster, but modifying
any of the graph instances returned by the method may break the function’s behaviour, as it is using thesegraphs 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>>> from sage.all import *>>> for G in graphs(Integer(3), augment= vertices ):...
print(G)Graph on 0 vertices
Graph on 1 vertex
Graph on 2 vertices(continues on next page)

778

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

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>>> from sage.all import *>>> for G in graphs(Integer(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>>> from sage.all import *>>> L = graphs(Integer(5), size=Integer(4))>>> len(list(L))
6Generate 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
˓→needs sage.plot>>> from sage.all import *>>> L = list(graphs(Integer(5), lambda G: G.size() <= Integer(4)))>>> len(L)14>>> graphs_list.show_graphs(L)# long time
˓→needs sage.plot#␣#␣

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)31
sage: graphs_list.show_graphs(L)# long time
˓→needs sage.plot

2.1. Common graphs

#␣

779

Graph Theory, Release 10.4>>> from sage.all import *>>> L = list(graphs(Integer(5), lambda G: G.size() <= Integer(4), augment=
˓→ vertices ))>>> len(L)31>>> graphs_list.show_graphs(L)# long time
˓→needs sage.plot#␣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>>> from sage.all import *>>> property = lambda G: ( max([G.degree(v) for v in G] + [Integer(0)]) <=␣
˓→Integer(2) )>>> L = list(graphs(Integer(6), property, augment= vertices ))>>> 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]>>> from sage.all import *>>> L = list( graphs(Integer(7), lambda G: G.is_bipartite(), augment= vertices ) )>>> [len([g for g in L if g.order() == i]) for i in (ellipsis_range(Integer(1),˓→Ellipsis,Integer(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>>> from sage.all import *>>> L = list( graphs(Integer(7), lambda G: G.is_bipartite()) )>>> 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 time303>>> from sage.all import *>>> L = list( graphs(Integer(8), lambda G: G.is_bipartite()) ) # long time>>> len(L)# long time
303

Remember that the property argument does not behave as a filter, except for appropriately inheritable properties:
780

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: property = lambda G: G.is_vertex_transitive()sage: len(list(graphs(4, property)))˓→needs sage.groups
1
sage: sum(1 for g in graphs(4) if property(g))˓→needs sage.groups
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>>> from sage.all import *>>> property = lambda G: G.is_vertex_transitive()>>> len(list(graphs(Integer(4), property)))˓→# needs sage.groups1>>> sum(Integer(1) for g in graphs(Integer(4)) if property(g))˓→# needs sage.groups4␣␣>>> property = lambda G: G.is_bipartite()>>> len(list(graphs(Integer(4), property)))7>>> sum(Integer(1) for g in graphs(Integer(4)) if property(g))
7Generate 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
>>> from sage.all import *>>> for i in range(Integer(7)):...
print(len(list(graphs(i))))
1
1
2
4
11
34
156

Generate all simple graphs, allowing loops: (see OEIS sequence A000666)
sage: L = list(graphs(5,augment= vertices ,loops=True))sage: for i in [0..5]: # long time....:
print((i, len([g for g in L if g.order() == i])))# long time(continues on next page)2.1. Common graphs781

Graph Theory, Release 10.4

(continued from previous page)(0, 1)(1, 2)(2, 6)(3, 20)(4, 90)(5, 544)>>> from sage.all import *>>> L = list(graphs(Integer(5),augment= vertices ,loops=True))
˓→long time>>> for i in (ellipsis_range(Integer(0),Ellipsis,Integer(5))):...
print((i, len([g for g in L if g.order() == i])))(0, 1)(1, 2)(2, 6)(3, 20)(4, 90)(5, 544)#␣# long time

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)>>> from sage.all import *>>> for i in [Integer(4),Integer(6),Integer(8)]: # long time (4s on sage.math,␣
˓→2012)...
print((i, len([g for g in graphs(i, degree_sequence=[Integer(3)]*i) if g.
˓→is_connected()])))(4, 1)(6, 2)(8, 5)>>> for i in [Integer(4),Integer(6),Integer(8)]: # long time (7s on sage.math,␣
˓→2012)...
print((i, len([g for g in graphs(i, augment= vertices , degree_
˓→sequence=[Integer(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)>>> from sage.all import *(continues on next page)782

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> print((Integer(10), len([g for g in graphs(Integer(10),degree_
˓→sequence=[Integer(3)]*Integer(10)) if g.is_connected()]))) # not tested(10, 19)

Make sure that the graphs are really independent and the generator survives repeated vertex removal (Issue #8458):
sage: for G in graphs(3):....:G.delete_vertex(0)....:print(G.order())
22
2
2>>> from sage.all import *>>> for G in graphs(Integer(3)):...
G.delete_vertex(Integer(0))...
print(G.order())
22
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='+')
Return the affine polar graph 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞).
Affine Polar graphs are built from a 𝑑-dimensional vector space over 𝐹𝑞 , and a quadratic form which is
hyperbolic, elliptic or parabolic according to the value of sign.
Note that 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) are strongly regular graphs, while 𝑉 𝑂(𝑑, 𝑞) is not.
For more information on Affine Polar graphs, see Affine Polar Graphs page of Andries Brouwer’s website.
INPUT:• d – integer; d must be even if sign is not None, and odd otherwise• q – integer; a power of a prime number, as 𝐹𝑞 must exist• sign – string (default: "+"); must be equal to "+", "-", or None to compute (respectively)
𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞)Note: The graph 𝑉 𝑂𝜖 (𝑑, 𝑞) is the graph induced by the non-neighbors of a vertex in an Orthogonal
Polar Graph 𝑂𝜖 (𝑑 + 2, 𝑞).
EXAMPLES:
The Brouwer-Haemers graph is isomorphic to 𝑉 𝑂− (4, 3):
sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-")
˓→# needs sage.libs.gap
sage: g.is_isomorphic(graphs.BrouwerHaemersGraph())␣␣(continues on next page)2.1. Common graphs783

Graph Theory, Release 10.4

(continued from previous page)˓→# needs sage.libs.gap

True>>> from sage.all import *>>> g = graphs.AffineOrthogonalPolarGraph(Integer(4),Integer(3),"-")
˓→# needs sage.libs.gap>>> g.is_isomorphic(graphs.BrouwerHaemersGraph())˓→# needs sage.libs.gap
True␣

Some examples from Brouwer’s table or strongly regular graphs:
sage: # needs sage.libs.gap
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)>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.AffineOrthogonalPolarGraph(Integer(6),Integer(2),"-"); g
Affine Polar Graph VO^-(6,2): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 27, 10, 12)>>> g = graphs.AffineOrthogonalPolarGraph(Integer(6),Integer(2),"+"); g
Affine Polar Graph VO^+(6,2): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 35, 18, 20)

When sign is None:sage: # needs sage.libs.gap
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>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.AffineOrthogonalPolarGraph(Integer(5),Integer(2),None); g
Affine Polar Graph VO^-(5,2): Graph on 32 vertices>>> g.is_strongly_regular(parameters=True)
False>>> g.is_regular()True>>> g.is_vertex_transitive()
True

784

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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 – boolean (default: False); whether to only return states in the continental Africa or
all African states• year – integer (default: 2018); 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
sage: Madagaskar in cont_Africa
False>>> from sage.all import *>>> Africa = graphs.AfricaMap(); Africa
Africa Map: Graph on 54 vertices>>> sorted(Africa.neighbors( Libya ))[ Algeria , Chad , Egypt , Niger , Sudan ,Tunisia ]>>> cont_Africa = graphs.AfricaMap(continental=True)>>> cont_Africa.order()48>>> 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 (Wikipedia article Generalized_quadrangle)of order (𝑞 − 1, 𝑞 + 1), see 3.1.5 in [PT2009]. Its points are elements of 𝐹𝑞3 , and lines are sets of size 𝑞 of
the form• {(𝜎, 𝑎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }• {(𝑎, 𝜎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }• {(𝑐𝜎 2 − 𝑏𝜎 + 𝑎, −2𝑐𝜎 + 𝑏, 𝜎) | 𝜎 ∈ 𝐹𝑞 },where 𝑎, 𝑏, 𝑐 are arbitrary elements of 𝐹𝑞 .
INPUT:• q – a power of an odd prime number• dual – boolean (default: False); whether to return the collinearity graph of 𝐴𝑆(𝑞) or of the dual𝐴𝑆(𝑞) (when True)
EXAMPLES:

2.1. Common graphs785

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(Integer(5)); g
AS(5); GQ(4, 6): Graph on 125 vertices>>> g.is_strongly_regular(parameters=True)(125, 28, 3, 7)>>> g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(Integer(5),␣
˓→dual=True); g
AS(5)*; GQ(6, 4): Graph on 175 vertices>>> g.is_strongly_regular(parameters=True)(175, 30, 5, 5)

static AlternatingFormsGraph(n, q)
Return the alternating forms graph with the given parameters.
This builds a graph whose vertices are all 𝑛`𝑥`𝑛 skew-symmetric matrices over 𝐺𝐹 (𝑞) with zero diagonal.
Two vertices are adjacent if and only if the difference of the two matrices has rank 2.
𝑛This grap is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 𝑞 2 , 𝑞 2 − 1, 𝑞 2⌈ 2 ⌉−1 ).
INPUT:• n – integer• q – a prime power
EXAMPLES:
sage: G = graphs.AlternatingFormsGraph(5, 2) # long time
sage: G.is_distance_regular(True) # long time([155, 112, None], [None, 1, 20])>>> from sage.all import *>>> G = graphs.AlternatingFormsGraph(Integer(5), Integer(2))>>> G.is_distance_regular(True) # long time([155, 112, None], [None, 1, 20])# long time

REFERENCES:
See [BCN1989] pp. 282-284 for a rather detailed discussion, otherwise see [VDKT2016] p. 22.
static AztecDiamondGraph(n)Return the Aztec Diamond graph of order n.
See the Wikipedia article Aztec_diamond for more information.
EXAMPLES:
sage: graphs.AztecDiamondGraph(2)Aztec Diamond graph of order 2(continues on next page)

786

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

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>>> from sage.all import *>>> graphs.AztecDiamondGraph(Integer(2))
Aztec Diamond graph of order 2>>> [graphs.AztecDiamondGraph(i).num_verts() for i in range(Integer(8))][0, 4, 12, 24, 40, 60, 84, 112]>>> [graphs.AztecDiamondGraph(i).num_edges() for i in range(Integer(8))][0, 4, 16, 36, 64, 100, 144, 196]>>> G = graphs.AztecDiamondGraph(Integer(3))>>> sum(Integer(1) for p in G.perfect_matchings())
64

static Balaban10Cage(embedding=1)
Return the Balaban 10-cage.
The Balaban 10-cage is a 3-regular graph with 70 vertices and 105 edges. See the Wikipedia article Balaban_10-cage.
The default embedding gives a deeper understanding of the graph’s automorphism group. It is divided into 4layers (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 cyclesof length 10.
This graph is not vertex-transitive, and its vertices are partitioned into 3 orbits: L2, L3, and the union of L1
of L4 whose elements are equivalent.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to be either 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.Balaban10Cage()sage: g.girth()10
sage: g.chromatic_number()2(continues on next page)2.1. Common graphs

787

Graph Theory, Release 10.4

(continued from previous page)

sage: g.diameter()6
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: g.show(figsize=[10,10])˓→# needs sage.plot

␣# long time>>> from sage.all import *>>> # needs networkx>>> g = graphs.Balaban10Cage()>>> g.girth()
10>>> g.chromatic_number()2>>> g.diameter()6>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> g.show(figsize=[Integer(10),Integer(10)])˓→# needs sage.plot

␣# long time␣

static Balaban11Cage(embedding=1)
Return the Balaban 11-cage.
For more information, see the Wikipedia article Balaban_11-cage.
INPUT:• embedding – integer (default: 1); three embeddings are available, and can be selected by setting
embedding to be 1, 2, or 3
– The first embedding is the one appearing on page 9 of the Fifth Annual Graph Drawing Contest
report [EMMN1998]. It separates vertices based on their eccentricity (see eccentricity()).
– The second embedding has been produced just for Sage and is meant to emphasize the automorphismgroup’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:
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()␣(continues on next page)

788

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)˓→# needs sage.groups

64>>> from sage.all import *>>> g = graphs.Balaban11Cage()>>> g.order()112>>> g.size()168>>> g.girth()11>>> g.diameter()8>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
64

Our many embeddings:
sage: g1 = graphs.Balaban11Cage(embedding=1)
sage: g2 = graphs.Balaban11Cage(embedding=2)
˓→# needs networkx
sage: g3 = graphs.Balaban11Cage(embedding=3)
˓→# needs networkx
sage: g1.show(figsize=[10,10])# long time˓→# needs sage.plot
sage: g2.show(figsize=[10,10])# long time˓→# needs networkx sage.plot
sage: g3.show(figsize=[10,10])# long time˓→# needs networkx sage.plot>>> from sage.all import *>>> g1 = graphs.Balaban11Cage(embedding=Integer(1))>>> g2 = graphs.Balaban11Cage(embedding=Integer(2))˓→# needs networkx>>> g3 = graphs.Balaban11Cage(embedding=Integer(3))˓→# needs networkx>>> g1.show(figsize=[Integer(10),Integer(10)])˓→# needs sage.plot>>> g2.show(figsize=[Integer(10),Integer(10)])˓→# needs networkx sage.plot>>> g3.show(figsize=[Integer(10),Integer(10)])˓→# needs networkx sage.plot

␣
␣
␣
␣
␣

␣
␣
# long time␣# long time␣# long time␣Proof that the embeddings are the same graph:
sage: g1.is_isomorphic(g2)˓→# needs networkx
True# g2 and g3 are obviously isomorphic

␣>>> from sage.all import *>>> g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic
˓→# needs networkx
Truestatic BalancedTree(r, h)
2.1. Common graphs789

Graph Theory, Release 10.4

Return the perfectly balanced tree of height ℎ ≥ 1, whose root has degree 𝑟 ≥ 2.
ℎ+1

The number of vertices of this graph is 1 + 𝑟 + 𝑟2 + · · · + 𝑟ℎ , that is, 𝑟 𝑟−1−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.
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()3sage: G.size()2
sage: r = 2; h = 1
sage: v = 1 + r
sage: v; v - 1
3
2>>> from sage.all import *>>> G = graphs.BalancedTree(Integer(2), Integer(1)); G
Balanced tree: Graph on 3 vertices>>> G.order()3>>> G.size()2>>> r = Integer(2); h = Integer(1)>>> v = Integer(1) + r>>> v; v - Integer(1)32Plot a balanced tree of height 5, whose root node has degree 𝑟 = 3:
sage: G = graphs.BalancedTree(3, 5)
sage: G.plot()# long time˓→# needs sage.plot
Graphics object consisting of 728 graphics primitives␣>>> from sage.all import *>>> G = graphs.BalancedTree(Integer(3), Integer(5))>>> G.plot()# long time
˓→# needs sage.plot
Graphics object consisting of 728 graphics primitives

A tree is bipartite. If its vertex set is finite, then it is planar.

790

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs networkx
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>>> from sage.all import *>>> # needs networkx>>> r = randint(Integer(2), Integer(5)); h = randint(Integer(1), Integer(7))>>> T = graphs.BalancedTree(r, h)>>> T.is_bipartite()
True>>> T.is_planar()True>>> v = (r**(h + Integer(1)) - Integer(1)) / (r - Integer(1))>>> T.order() == v
True>>> T.size() == v - Integer(1)Truestatic BarbellGraph(n1, n2)
Returns a barbell graph with 2 * 𝑛1 + 𝑛2 nodes.
The argument 𝑛1 must be greater than or equal to 2.
A barbell graph is a basic structure that consists of a path graph of order 𝑛2 connecting two complete graphsof order 𝑛1 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 * 𝑛1 + 𝑛2 . A ValueError is returned if 𝑛1 < 2 or 𝑛2 < 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 𝑛1 -th node will be drawn at a 45 degree
angle from the horizontal right center of the first complete graph, and the 𝑛1 + 𝑛2 + 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()˓→# needs sage.plot

2.1. Common graphs# long time

␣791

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.BarbellGraph(Integer(9), Integer(4)); g
Barbell graph: Graph on 22 vertices>>> g.show()# long time
˓→# needs sage.plot

An 𝑛1 ≥ 2, 𝑛2 ≥ 0 barbell graph has order 2 * 𝑛1 + 𝑛2 . It has the complete graph on 𝑛1 vertices as a
subgraph. It also has the path graph on 𝑛2 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)sage: P_n2 = graphs.PathGraph(n2)sage: # needs sage.modules
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>>> from sage.all import *>>> n1 = randint(Integer(2), Integer(2)*Integer(10)**Integer(2))>>> n2 = randint(Integer(0), Integer(2)*Integer(10)**Integer(2))>>> g = graphs.BarbellGraph(n1, n2)>>> v = Integer(2)*n1 + n2>>> g.order() == v
True>>> K_n1 = graphs.CompleteGraph(n1)>>> P_n2 = graphs.PathGraph(n2)>>> # needs sage.modules>>> s_K = g.subgraph_search(K_n1, induced=True)>>> s_P = g.subgraph_search(P_n2, induced=True)>>> K_n1.is_isomorphic(s_K)
True>>> P_n2.is_isomorphic(s_P)
Truestatic 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 adegree of 3:
sage: g = graphs.BidiakisCube(); gBidiakis cube: Graph on 12 vertices
sage: g.show()# long time␣(continues on next page)

792

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)# needs sage.plot
sage: g.order()12sage: g.size()18
sage: g.is_regular(3)True˓→>>> from sage.all import *>>> g = graphs.BidiakisCube(); gBidiakis cube: Graph on 12 vertices>>> g.show()˓→# needs sage.plot>>> g.order()12>>> g.size()18>>> g.is_regular(Integer(3))
True# long time

It is a Hamiltonian graph with diameter 3 and girth 4:
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: g.diameter()3
sage: g.girth()4␣>>> from sage.all import *>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> g.diameter()3>>> g.girth()4

It is a planar graph with characteristic polynomial (𝑥 − 3)(𝑥 − 2)(𝑥4 )(𝑥 + 1)(𝑥 + 2)(𝑥2 + 𝑥 − 4)2 andchromatic number 3:
sage: g.is_planar()True
sage: char_poly = g.characteristic_polynomial()␣˓→# needs sage.modules
sage: x = char_poly.parent()( x )␣˓→# needs sage.modules
sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x -␣˓→4)^2# needs sage.modules
True
sage: g.chromatic_number()␣˓→# needs sage.modules
3

2.1. Common graphs793

Graph Theory, Release 10.4>>> from sage.all import *>>> g.is_planar()True>>> char_poly = g.characteristic_polynomial()
˓→# needs sage.modules>>> x = char_poly.parent()( x )˓→# needs sage.modules>>> char_poly == (x - Integer(3)) * (x - Integer(2)) * (x**Integer(4)) * (x +␣˓→Integer(1)) * (x + Integer(2)) * (x**Integer(2) + x -␣˓→Integer(4))**Integer(2)# needs sage.modules
True>>> g.chromatic_number()˓→# needs sage.modules
3

static BiggsSmithGraph(embedding=1)
Return the Biggs-Smith graph.
For more information, see the Wikipedia article Biggs-Smith_graph.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to be 1 or 2
EXAMPLES:
Basic properties:
sage: # needs networkx
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˓→# needs sage.plot>>> from sage.all import *>>> # needs networkx>>> g = graphs.BiggsSmithGraph()>>> g.order()102>>> g.size()153>>> g.girth()9>>> g.diameter()7>>> g.automorphism_group().cardinality()# long time2448>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot

794

␣

␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

The other embedding:sage: graphs.BiggsSmithGraph(embedding=2).show()˓→# needs networkx>>> from sage.all import *>>> graphs.BiggsSmithGraph(embedding=Integer(2)).show()˓→# needs networkx# long time␣# long time␣

static BilinearFormsGraph(d, e, q)
Return a bilinear forms graph with the given parameters.
This builds a graph whose vertices are all 𝑑`𝑥`𝑒 matrices over 𝐺𝐹 (𝑞). Two vertices are adjacent if thedifference of the two matrices has rank 1.
The graph is distance-regular with classical parameters (min(𝑑, 𝑒), 𝑞, 𝑞 − 1, 𝑞 max(𝑑,𝑒) − 1).
INPUT:• d, e – integers; dimension of the matrices• q – integer; a prime power
EXAMPLES:
sage: # needs sage.modules
sage: G = graphs.BilinearFormsGraph(3, 3, 2)
sage: G.is_distance_regular(True)([49, 36, 16, None], [None, 1, 6, 28])
sage: G = graphs.BilinearFormsGraph(3,3,3)# not tested (20 s)˓→# needs sage.rings.finite_rings
sage: G.order()# not tested (due to above)˓→# needs sage.rings.finite_rings
19683
sage: G = graphs.BilinearFormsGraph(3, 4, 2)# long time˓→# needs sage.rings.finite_rings
sage: G.is_distance_regular(True)# long time˓→# needs sage.rings.finite_rings([105, 84, 48, None], [None, 1, 6, 28])>>> from sage.all import *>>> # needs sage.modules>>> G = graphs.BilinearFormsGraph(Integer(3), Integer(3), Integer(2))>>> G.is_distance_regular(True)([49, 36, 16, None], [None, 1, 6, 28])>>> G = graphs.BilinearFormsGraph(Integer(3),Integer(3),Integer(3))˓→not tested (20 s)# needs sage.rings.finite_rings>>> G.order()# not tested (due to above)˓→# needs sage.rings.finite_rings
19683>>> G = graphs.BilinearFormsGraph(Integer(3), Integer(4), Integer(2))˓→long time
# needs sage.rings.finite_rings>>> G.is_distance_regular(True)# long time
˓→# needs sage.rings.finite_rings([105, 84, 48, None], [None, 1, 6, 28])

␣
␣

␣
␣

#␣

#␣

REFERENCES:
See [BCN1989] pp. 280-282 for a rather detailed discussion, otherwise see [VDKT2016] p. 21.

2.1. Common graphs795

Graph Theory, Release 10.4

static BishopGraph(dim_list, radius=None, relabel=False)
Return the 𝑑-dimensional Bishop Graph with prescribed dimensions.
The 2-dimensional Bishop Graph of parameters 𝑛 and 𝑚 is a graph with 𝑛𝑚 vertices in which each vertex
represents a square in an 𝑛 × 𝑚 chessboard, and each edge corresponds to a legal move by a bishop.
The 𝑑-dimensional Bishop Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid withprescribed dimensions, and each edge corresponds to a legal move by a bishop in any pairs of dimensions.
The Bishop Graph is not connected.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of thechessboard• radius – integer (default: None); by setting the radius to a positive integer, one may decrease thepower of the bishop to at most radius steps.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (n,m)-Bishop Graph is not connected:
sage: G = graphs.BishopGraph( [3, 4] )sage: G.is_connected()
False>>> from sage.all import *>>> G = graphs.BishopGraph( [Integer(3), Integer(4)] )>>> 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(sort=False) )....:if not B.is_isomorphic(H):....:print("that s not good!")>>> from sage.all import *>>> for d in range(Integer(3),Integer(12)):# long time...
H = Graph()...
for r in range(Integer(1),d+Integer(1)):...
B = graphs.BishopGraph([d,d],radius=r)...
H.add_edges( graphs.KnightGraph([d,d],one=r,two=r).
˓→edges(sort=False) )...
if not B.is_isomorphic(H):...
print("that s not good!")static BlanusaFirstSnarkGraph()
Return the first Blanusa Snark Graph.
The Blanusa graphs are two snarks on 18 vertices and 27 edges. For more information on them, see the
Wikipedia article Blanusa_snarks.

796

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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()˓→# needs sage.groups8␣>>> from sage.all import *>>> g = graphs.BlanusaFirstSnarkGraph()>>> g.order()18>>> g.size()27>>> g.diameter()4>>> g.girth()5>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
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()˓→# needs sage.groups
4

2.1. Common graphs␣797

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.BlanusaSecondSnarkGraph()>>> g.order()18>>> g.size()27>>> g.diameter()4>>> g.girth()5>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
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()˓→# needs sage.plot
sage: G.order()21
sage: G.size()42
sage: G.is_regular(4)True# long time␣>>> from sage.all import *>>> G = graphs.BrinkmannGraph(); G
Brinkmann graph: Graph on 21 vertices>>> G.show()# long time
˓→# needs sage.plot>>> G.order()21>>> G.size()42>>> G.is_regular(Integer(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

798

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> G.is_eulerian()
True>>> G.radius()
3>>> G.diameter()3>>> G.girth()
5

The Brinkmann graph is also Hamiltonian with chromatic number 4:
sage: G.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: G.chromatic_number()4␣>>> from sage.all import *>>> G.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> G.chromatic_number()4

Its automorphism group is isomorphic to 𝐷7 :sage: ag = G.automorphism_group()˓→# needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(7))˓→# needs sage.groups
True>>> from sage.all import *>>> ag = G.automorphism_group()
˓→# needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(7)))˓→# needs sage.groups
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(); g˓→# needs sage.modules
Brouwer-Haemers: Graph on 81 vertices␣>>> from sage.all import *>>> g = graphs.BrouwerHaemersGraph(); g˓→# needs sage.modules
Brouwer-Haemers: Graph on 81 vertices

2.1. Common graphs799

Graph Theory, Release 10.4

It is indeed strongly regular with parameters (81, 20, 1, 6):
sage: g.is_strongly_regular(parameters=True)# long time˓→# needs sage.modules sage.rings.finite_rings(81, 20, 1, 6)

␣>>> from sage.all import *>>> g.is_strongly_regular(parameters=True)# long time
˓→# needs sage.modules sage.rings.finite_rings(81, 20, 1, 6)

Its has as eigenvalues 20, 2 and −7:sage: set(g.spectrum()) == {20,2,-7}˓→# needs sage.modules sage.rings.finite_rings
True>>> from sage.all import *>>> set(g.spectrum()) == {Integer(20),Integer(2),-Integer(7)}˓→# needs sage.modules sage.rings.finite_rings
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 1 ≤ 𝑖 ≤ 𝑛−1.
In total, 𝐵(𝑛) has order 𝑛!. Swapping two labels as described previously corresponds to multiplying on theright 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˓→# needs sage.plot
Graphics object consisting of 61 graphics primitives␣>>> from sage.all import *>>> g = graphs.BubbleSortGraph(Integer(4)); g
Bubble sort: Graph on 24 vertices>>> g.plot()# long time
˓→# needs sage.plot
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

800

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.BubbleSortGraph(Integer(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>>> from sage.all import *>>> n = randint(Integer(1), Integer(8))>>> g = graphs.BubbleSortGraph(n)>>> g.order() == factorial(n)True

See also:• permutahedron()
AUTHORS:• Michael Yurko (2009-09-01)
static BuckyBall()Return the Bucky Ball graph.
This graph is a 3-regular 60-vertex planar graph. Its vertices and edges correspond precisely to the carbon
atoms and bonds in buckminsterfullerene. When embedded on a sphere, its 12 pentagon and 20 hexagon
faces are arranged exactly as the sections of a soccer ball.
EXAMPLES:
The Bucky Ball is planar:
sage: g = graphs.BuckyBall()sage: g.is_planar()True>>> from sage.all import *>>> g = graphs.BuckyBall()>>> g.is_planar()
True

The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky Ball polyhedron, but this ismuch slower:
sage: # needs sage.geometry.polyhedron sage.groups sage.rings.number_fieldsage: g = polytopes.buckyball().vertex_graph()
sage: g.remove_loops()
sage: h = graphs.BuckyBall()sage: g.is_isomorphic(h)True

2.1. Common graphs801

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.geometry.polyhedron sage.groups sage.rings.number_field>>> g = polytopes.buckyball().vertex_graph()>>> g.remove_loops()>>> h = graphs.BuckyBall()>>> g.is_isomorphic(h)True

The graph is returned along with an attractive embedding:sage: g = graphs.BuckyBall() # long time
sage: g.plot(vertex_labels=False, vertex_size=10).show()˓→needs sage.plot>>> from sage.all import *>>> g = graphs.BuckyBall() # long time>>> g.plot(vertex_labels=False, vertex_size=Integer(10)).show()
˓→time, needs sage.plot# long time,␣

# long␣static BullGraph()
Return a bull graph with 5 nodes.
A bull graph is named for its shape. It’s a triangle with horns. See the Wikipedia article Bull_graph for more
information.
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention,
the bull graph is drawn as a triangle with the first node (0) on the bottom. The second and third nodes (1 and
2) complete the triangle. Node 3 is the horn connected to 1 and node 4 is the horn connected to node 2.
EXAMPLES:
Construct and show a bull graph:
sage: g = graphs.BullGraph(); g
Bull graph: Graph on 5 vertices
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.BullGraph(); g
Bull graph: Graph on 5 vertices>>> g.show()˓→# needs sage.plot# long time␣# 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 isplanar with chromatic number 3 and chromatic index also 3:
sage: g.order(); g.size()55
sage: g.radius(); g.diameter(); g.girth()2
3
3
sage: g.chromatic_number()
3

802

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g.order(); g.size()55>>> g.radius(); g.diameter(); g.girth()2
3
3>>> g.chromatic_number()
3

The bull graph has chromatic polynomial 𝑥(𝑥 − 2)(𝑥 − 1)3 and Tutte polynomial 𝑥4 + 𝑥3 + 𝑥2 𝑦. Itscharacteristic 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: # needs sage.libs.flint
sage: chrompoly = g.chromatic_polynomial()
sage: x = chrompoly.parent()( x )sage: x * (x - 2) * (x - 1)^3 == chrompoly
True
sage: # needs sage.libs.flint sage.modules
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]
[0 1 0 0 0]
[0 0 1 0 0]
sage: Id = identity_matrix(ZZ, M.nrows())
sage: D = x*Id - M
sage: D.determinant() == charpoly˓→# needs sage.symbolicTruesage: x * (x^2 - x - 3) * (x^2 + x - 1) == charpolyTrue␣>>> from sage.all import *>>> # needs sage.libs.flint>>> chrompoly = g.chromatic_polynomial()>>> x = chrompoly.parent()( x )>>> x * (x - Integer(2)) * (x - Integer(1))**Integer(3) == chrompoly
True>>> # needs sage.libs.flint sage.modules>>> charpoly = g.characteristic_polynomial()>>> M = g.adjacency_matrix(); M[0 1 1 0 0]
[1 0 1 1 0]
[1 1 0 0 1]
[0 1 0 0 0]
[0 0 1 0 0]>>> Id = identity_matrix(ZZ, M.nrows())>>> D = x*Id - M>>> D.determinant() == charpoly
˓→# needs sage.symbolic(continues on next page)2.1. Common graphs803

Graph Theory, Release 10.4

(continued from previous page)True>>> x * (x**Integer(2) - x - Integer(3)) * (x**Integer(2) + x - Integer(1))␣
˓→== charpoly
Truestatic ButterflyGraph()
Return the butterfly graph.
Let 𝐶3 be the cycle graph on 3 vertices. The butterfly or bowtie graph is obtained by joining two copies of
𝐶3 at a common vertex, resulting in a graph that is isomorphic to the friendship graph 𝐹2 . See the Wikipedia
article Butterfly_graph for more information.
See also:• 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()˓→# needs sage.plot
sage: G.is_planar()True
sage: G.order()5sage: G.size()
6>>> from sage.all import *>>> G = graphs.ButterflyGraph(); G
Butterfly graph: Graph on 5 vertices>>> G.show()˓→# needs sage.plot>>> G.is_planar()
True>>> G.order()5>>> G.size()
6# long time␣# long time

It has diameter 2, girth 3, and radius 1:
sage: G.diameter()2
sage: G.girth()3
sage: G.radius()
1>>> from sage.all import *>>> G.diameter()2>>> G.girth()(continues on next page)

804

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)3>>> G.radius()
1

The butterfly graph is Eulerian, with chromatic number 3:
sage: G.is_eulerian()True
sage: G.chromatic_number()3>>> from sage.all import *>>> G.is_eulerian()
True>>> 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 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 theCai-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 thepartition induced by the coloring on H
EXAMPLES:
CaiFurerImmerman graph with no balanced vertex separator smaller than 2
sage: G = graphs.CycleGraph(4)sage: CFI, p = graphs.CaiFurerImmermanGraph(G)sage: sorted(CFI, key=str)[(0, ()), (0, (0, a )), (0, (0, b )), (0, (0, 1)), (0, (1, a )),(0, (1, b )), (1, ()), (1, (0, a )), (1, (0, b )), (1, (0, 1)),
(1, (1, a )), (1, (1, b )), (2, ()), (2, (0, a )), (2, (0, b )),(continues on next page)2.1. Common graphs

805

Graph Theory, Release 10.4

(continued from previous page)(2, (0, 1)), (2, (1, a )), (2, (1, b )), (3, ()), (3, (0,(3, (0, b )), (3, (0, 1)), (3, (1, a )), (3, (1, b ))]sage: sorted(CFI.edge_iterator(), key=str)[((0, ()), (0, (0, b )), None),((0, ()), (0, (1, b )), None),((0, (0, a )), (1, (0, a )), None),((0, (0, b )), (1, (0, b )), None),((0, (0, 1)), (0, (0, a )), None),((0, (0, 1)), (0, (1, a )), None),((0, (1, a )), (3, (0, a )), None),((0, (1, b )), (3, (0, b )), None),((1, ()), (1, (0, b )), None),((1, ()), (1, (1, b )), None),((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)]a )),>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> CFI, p = graphs.CaiFurerImmermanGraph(G)>>> sorted(CFI, key=str)[(0, ()), (0, (0, a )), (0, (0, b )), (0, (0, 1)), (0, (1, a )),(0, (1, b )), (1, ()), (1, (0, a )), (1, (0, b )), (1, (0, 1)),
(1, (1, a )), (1, (1, b )), (2, ()), (2, (0, a )), (2, (0, b )),(2, (0, 1)), (2, (1, a )), (2, (1, b )), (3, ()), (3, (0, a )),(3, (0, b )), (3, (0, 1)), (3, (1, a )), (3, (1, b ))]>>> sorted(CFI.edge_iterator(), key=str)[((0, ()), (0, (0, b )), None),((0, ()), (0, (1, b )), None),((0, (0, a )), (1, (0, a )), None),((0, (0, b )), (1, (0, b )), None),((0, (0, 1)), (0, (0, a )), None),((0, (0, 1)), (0, (1, a )), None),((0, (1, a )), (3, (0, a )), None),((0, (1, b )), (3, (0, b )), None),((1, ()), (1, (0, b )), None),((1, ()), (1, (1, b )), None),((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),(continues on next page)

806

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)((2, (1, a )), (3, (1, a )), None),((2, (1, b )), (3, (1, b )), None),((3, ()), (3, (0, b )), None),((3, ()), (3, (1, b )), None),((3, (0, 1)), (3, (0, a )), None),((3, (0, 1)), (3, (1, a )), None)]static CameronGraph()
Return the Cameron graph.
The Cameron graph is strongly regular with parameters 𝑣 = 231, 𝑘 = 30, 𝜆 = 9, 𝜇 = 3.
For more information on the Cameron graph, see https://www.win.tue.nl/ aeb/graphs/Cameron.html.
EXAMPLES:
sage: # needs sage.groups
sage: g = graphs.CameronGraph()
sage: g.order()231
sage: g.size()
3465
sage: g.is_strongly_regular(parameters=True)(231, 30, 9, 3)>>> from sage.all import *>>> # needs sage.groups>>> g = graphs.CameronGraph()>>> g.order()231>>> g.size()3465>>> g.is_strongly_regular(parameters=True)(231, 30, 9, 3)# long time

# long time

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: # long time, needs sage.rings.number_fieldsage: g = graphs.Cell120()sage: g.size()
1200
sage: g.is_regular(4)True
sage: g.is_vertex_transitive()
True>>> from sage.all import *>>> # long time, needs sage.rings.number_field>>> g = graphs.Cell120()>>> g.size()
1200(continues on next page)2.1. Common graphs

807

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_regular(Integer(4))
True>>> g.is_vertex_transitive()
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 – integer (default: 1); two different embeddings for a plot
EXAMPLES:
sage: # long time, needs sage.rings.number_fieldsage: g = graphs.Cell600()
sage: g.size()
720
sage: g.is_regular(12)Truesage: g.is_vertex_transitive()
True>>> from sage.all import *>>> # long time, needs sage.rings.number_field>>> g = graphs.Cell600()>>> g.size()
720>>> g.is_regular(Integer(12))
True>>> g.is_vertex_transitive()
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)
Return a Graph built on a 𝑑-dimensional chessboard with prescribed dimensions and interconnections.
This function allows to generate many kinds of graphs corresponding to legal movements on a 𝑑-dimensional
chessboard: Queen Graph, King Graph, Knight Graphs, Bishop Graph, and many generalizations. It also
allows to avoid redundant code.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of thechessboard• rook – boolean (default: True); indicates whether the chess piece is able to move as a rook, that is at
any distance along a dimension• rook_radius – integer (default: None); restriction on the rook-like movements to distance at mostrook_radius• bishop – boolean (default: True); indicates whether the chess piece is able to move like a bishop, thatis along diagonals

808

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• bishop_radius – integer (default: None); restriction on the bishop-like movements to distance at
most bishop_radius• knight – boolean (default: True); indicating whether the chess piece is able to move like a knight• knight_x – integer (default: 1); indicates the number on steps the chess piece moves in one dimension
when moving like a knight• knight_y – integer (default: 2); indicates the number on steps the chess piece moves in the second
dimension when moving like a knight• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
OUTPUT:• A Graph build on a 𝑑-dimensional chessboard with prescribed dimensions, and with edges according
given parameters.
• A string encoding the dimensions. This is mainly useful for providing names to graphs.
EXAMPLES:
A (2, 2)-King Graph is isomorphic to the complete graph on 4 vertices:sage: G, _ = graphs.ChessboardGraphGenerator( [2,2] )sage: G.is_isomorphic( graphs.CompleteGraph(4) )True>>> from sage.all import *>>> G, _ = graphs.ChessboardGraphGenerator( [Integer(2),Integer(2)] )>>> G.is_isomorphic( graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> G, _ = graphs.ChessboardGraphGenerator([Integer(3),Integer(4)], rook=True,
˓→ rook_radius=None, bishop=False, knight=False)>>> H = (graphs.CompleteGraph(Integer(3))).cartesian_product(graphs.
˓→CompleteGraph(Integer(4)))>>> G.is_isomorphic(H)True

static ChvatalGraph()
Return the Chvatal graph.
Chvatal graph is one of the few known graphs to satisfy Grunbaum’s conjecture that for every 𝑚, 𝑛, there
is an 𝑚-regular, 𝑚-chromatic graph of girth at least 𝑛. For more information, see the Wikipedia article
Chv%C3%A1tal_graph.
EXAMPLES:The Chvatal graph has 12 vertices and 24 edges. It is a 4-regular, 4-chromatic graph with radius 2, diameter2, and girth 4:

2.1. Common graphs809

Graph Theory, Release 10.4

sage: G = graphs.ChvatalGraph(); G
Chvatal graph: Graph on 12 vertices
sage: G.order(); G.size()
1224
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>>> from sage.all import *>>> G = graphs.ChvatalGraph(); G
Chvatal graph: Graph on 12 vertices>>> G.order(); G.size()1224>>> G.degree()[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]>>> G.chromatic_number()4>>> G.radius(); G.diameter(); G.girth()2
2
4

static CirculantGraph(n, adjacency)
Returns a circulant graph with 𝑛 nodes.
A circulant graph has the property that the vertex 𝑖 is connected with the vertices 𝑖 + 𝑗 and 𝑖 − 𝑗 for each 𝑗in adjacency.
INPUT:• n – number of vertices in the graph• adjacency – the list of 𝑗 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 ina counterclockwise manner.
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor.
See also:• 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: # needs networkx
sage: import networkx
sage: n = networkx.cycle_graph(23)sage: spring23 = Graph(n)(continues on next page)

810

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: posdict23 = graphs.CirculantGraph(23,2)
sage: spring23.show()# long time
sage: posdict23.show() # long time>>> from sage.all import *>>> # needs networkx>>> import networkx>>> n = networkx.cycle_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.CirculantGraph(Integer(23),Integer(2))>>> spring23.show()# long time>>> posdict23.show() # long time

We next view many cycle graphs as a Sage graphics array. First we use the CirculantGraph constructor,
which fills in the position dictionary:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.CirculantGraph(i+4, i+1)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CirculantGraph(i+Integer(4), i+Integer(1))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

Compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
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):(continues on next page)2.1. Common graphs811

Graph Theory, Release 10.4

(continued from previous page)....: n = []....: for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....: j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.cycle_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):... n = []... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)>>> G = graphics_array(j)>>> 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(sort=True, labels=false)[(0, 1),(0, 3),(0, 4),(0, 6),(1, 2),(1, 4),(1, 5),(2, 3),(2, 5),(2, 6),(3, 4),(3, 6),(4, 5),(5, 6)]>>> from sage.all import *>>> graphs.CirculantGraph(Integer(6),Integer(1)) == graphs.
˓→CycleGraph(Integer(6))
True>>> graphs.CirculantGraph(Integer(7),[Integer(1),Integer(3)]).edges(sort=True,
˓→ labels=false)[(0, 1),(0, 3),(0, 4),(0, 6),(1, 2),(1, 4),(continues on next page)812

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)(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 nodepair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the circular ladder graph is displayed as an inner and outer cycle pair, with the first 𝑛 nodes drawn
on the inner circle. The first (0) node is drawn at the top of the inner-circle, moving clockwise after that. The
outer circle is drawn with the (𝑛 + 1)-th node at the top, then counterclockwise as well. When 𝑛 == 2, werotate the outer circle by an angle of 𝜋/8 to ensure that all edges are visible (otherwise the 4 vertices of thegraph would be placed on a single line).
EXAMPLES:
Construct and show a circular ladder graph with 26 nodes:
sage: g = graphs.CircularLadderGraph(13)sage: g.show()# long time˓→# needs sage.plot␣>>> from sage.all import *>>> g = graphs.CircularLadderGraph(Integer(13))>>> g.show()# long time
˓→# needs sage.plot

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):˓→# needs sage.plot....:
n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)˓→# needs sage.plot
sage: G.show()# long time˓→# needs sage.plot␣␣␣>>> from sage.all import *>>> g = [](continues on next page)2.1. Common graphs813

Graph Theory, Release 10.4

(continued from previous page)>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CircularLadderGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):␣˓→# needs sage.plot...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)˓→# needs sage.plot>>> G.show()# long time
˓→# needs sage.plot

static ClawGraph()
Return a claw graph.
A claw graph is named for its shape. It is actually a complete bipartite graph with (n1, n2) = (1, 3).
PLOTTING: See CompleteBipartiteGraph().
EXAMPLES:Show a Claw graph:
sage: (graphs.ClawGraph()).show()˓→# needs sage.plot>>> from sage.all import *>>> (graphs.ClawGraph()).show()˓→# needs sage.plot# long time␣# long time

Inspect a Claw graph:
sage: G = graphs.ClawGraph()
sage: G
Claw graph: Graph on 4 vertices>>> from sage.all import *>>> G = graphs.ClawGraph()>>> 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()˓→# needs sage.groups
1920
sage: g.girth()␣(continues on next page)

814

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)4
sage: g.chromatic_number()4
sage: g.diameter()2
sage: g.show(figsize=[10, 10])˓→# needs sage.plot# long time>>> from sage.all import *>>> g = graphs.ClebschGraph()>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
1920>>> g.girth()4>>> g.chromatic_number()4>>> g.diameter()2>>> g.show(figsize=[Integer(10), Integer(10)])˓→# needs sage.plot

␣# long time␣

static CompleteBipartiteGraph(p, q, set_position=True)
Return a Complete Bipartite Graph on 𝑝 + 𝑞 vertices.
A Complete Bipartite Graph is a graph with its vertices partitioned into two groups, 𝑉1 = {0, ..., 𝑝 − 1} and𝑉2 = {𝑝, ..., 𝑝 + 𝑞 − 1}. Each 𝑢 ∈ 𝑉1 is connected to every 𝑣 ∈ 𝑉2 .
INPUT:• p, q – number of vertices in each side
• set_position – boolean (default True); if set to True, we assign positions to the vertices so thatthe set of cardinality 𝑝 is on the line 𝑦 = 1 and the set of cardinality 𝑞 is on the line 𝑦 = 0.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each complete bipartite graph will be displayed with the first 𝑝 nodes on the top row (at 𝑦 = 1)
from left to right. The remaining 𝑞 nodes appear at 𝑦 = 0, also from left to right. The shorter row (partition
with fewer nodes) is stretched to the same length as the longer row, unless the shorter row has 1 node; inwhich case it is centered. The 𝑥 values in the plot are in domain [0, max(𝑝, 𝑞)].
In the Complete Bipartite graph, there is a visual difference in using the spring-layout algorithm vs. theposition dictionary used in this constructor. The position dictionary flattens the graph and separates thepartitioned nodes, making it clear which nodes an edge is connected to. The Complete Bipartite graph plottedwith the spring-layout algorithm tends to center the nodes in 𝑝 (see spring_med in examples below), thus
overlapping its nodes and edges, making it typically hard to decipher.
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor. Feel free to race the constructors
below in the examples section. The much larger difference is the time added by the spring-layout algorithm
when plotting. (Also shown in the example below). The spring model is typically described as 𝑂(𝑛3 ), as
appears to be the case in the NetworkX source code.
EXAMPLES:
Two ways of constructing the complete bipartite graph, using different layout algorithms:
sage: # needs networkx
sage: import networkx(continues on next page)2.1. Common graphs815Graph Theory, Release 10.4

(continued from previous page)

sage: n = networkx.complete_bipartite_graph(389, 157)
# long time
sage: spring_big = Graph(n)# long time
sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157)
# long time>>> from sage.all import *>>> # needs networkx>>> import networkx>>> n = networkx.complete_bipartite_graph(Integer(389), Integer(157))#␣˓→long time>>> spring_big = Graph(n)# long time>>> posdict_big = graphs.CompleteBipartiteGraph(Integer(389), Integer(157))˓→# long time␣Compare the plotting:sage: n = networkx.complete_bipartite_graph(11, 17)˓→# needs networkx
sage: spring_med = Graph(n)˓→# needs networkx
sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)␣␣>>> from sage.all import *>>> n = networkx.complete_bipartite_graph(Integer(11), Integer(17))˓→# needs networkx>>> spring_med = Graph(n)˓→# needs networkx>>> posdict_med = graphs.CompleteBipartiteGraph(Integer(11), Integer(17))␣

Notice here how the spring-layout tends to center the nodes of 𝑛1:
sage: spring_med.show()˓→# needs networkx
sage: posdict_med.show()˓→# needs sage.plot>>> from sage.all import *>>> spring_med.show()˓→# needs networkx>>> posdict_med.show()˓→# needs sage.plot# long time␣# long time␣# long time
# 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):␣˓→# needs sage.plot....:
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)

816

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: G = graphics_array(j)˓→# needs sage.plot
sage: G.show()˓→# needs sage.plot

␣# long time␣>>> from sage.all import *>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CompleteBipartiteGraph(i+Integer(1),Integer(4))...
g.append(k)>>> for i in range(Integer(3)):␣˓→# needs sage.plot...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)˓→# needs sage.plot>>> G.show()# long time
˓→# needs sage.plot

We compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.complete_bipartite_graph(i+1,4)....:
k = Graph(spr)....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.complete_bipartite_graph(i+Integer(1),Integer(4))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

2.1. Common graphs

817

Graph Theory, Release 10.4

Issue #12155:
sage: graphs.CompleteBipartiteGraph(5,6).complement()
complement(Complete bipartite graph of order 5+6): Graph on 11 vertices>>> from sage.all import *>>> graphs.CompleteBipartiteGraph(Integer(5),Integer(6)).complement()
complement(Complete bipartite graph of order 5+6): Graph on 11 vertices

static CompleteGraph(n)Return a complete graph on 𝑛 nodes.
A Complete Graph is a graph in which all nodes are connected to all other nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each complete graph will be displayed with the first (0) node at the top, with the rest following ina 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: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.CompleteGraph(i+3)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CompleteGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

818

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

We compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
sage: import networkx
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.complete_graph(i+3)....:
k = Graph(spr)....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> import networkx>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.complete_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

Compare the constructors (results will vary):
sage: # needs networkx
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>>> from sage.all import *>>> # needs networkx>>> import networkx>>> t = cputime()>>> n = networkx.complete_graph(Integer(389)); spring389 = Graph(n)>>> cputime(t) # random
0.59203700000000126>>> t = cputime()(continues on next page)2.1. Common graphs819

Graph Theory, Release 10.4

(continued from previous page)>>> posdict389 = graphs.CompleteGraph(Integer(389))>>> cputime(t) # random
0.6680419999999998

We compare plotting:sage: # needs networkx
sage: import networkx
sage: n = networkx.complete_graph(23)sage: spring23 = Graph(n)sage: posdict23 = graphs.CompleteGraph(23)sage: spring23.show()# long time˓→# needs sage.plot
sage: posdict23.show()# long time˓→# needs sage.plot␣␣>>> from sage.all import *>>> # needs networkx>>> import networkx>>> n = networkx.complete_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.CompleteGraph(Integer(23))>>> spring23.show()# long time
˓→# needs sage.plot>>> posdict23.show()# long time
˓→# needs sage.plot

static CompleteMultipartiteGraph(L)Return a complete multipartite graph.
INPUT:• L – a list of integers; the respective sizes of the components
PLOTTING: Produce a layout of the vertices so that vertices in the same vertex set are adjacent and clearly
separated from vertices in other vertex sets.
This is done by calculating the vertices of an 𝑟-gon then calculating the slope between adjacent vertices. We
then ‘walk’ around the 𝑟-gon placing graph vertices in regular intervals between adjacent vertices of the 𝑟-gon.
Makes a nicely organized graph like in this picture: https://commons.wikimedia.org/wiki/File:Turan_13-4.
svg
EXAMPLES:
A complete tripartite graph with sets of sizes 5, 6, 8:
sage: g = graphs.CompleteMultipartiteGraph([5, 6, 8]); g
Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices>>> from sage.all import *>>> g = graphs.CompleteMultipartiteGraph([Integer(5), Integer(6),␣
˓→Integer(8)]); g
Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices

It clearly has a chromatic number of 3:

820

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: g.chromatic_number()3>>> from sage.all import *>>> g.chromatic_number()3

static ConwaySmith_for_3S7()
Return the Conway-Smith graph related to 3𝑆𝑦𝑚(7).
This is a distance-regular graph with intersection array [10, 6, 4, 1; 1, 2, 6, 10].
EXAMPLES:
sage: G = graphs.ConwaySmith_for_3S7()˓→# needs sage.modules sage.rings.finite_rings sage.rings.number_fieldsage: G.is_distance_regular(True)˓→# needs sage.modules sage.rings.finite_rings sage.rings.number_field([10, 6, 4, 1, None], [None, 1, 2, 6, 10])␣␣>>> from sage.all import *>>> G = graphs.ConwaySmith_for_3S7()
˓→# needs sage.modules sage.rings.finite_rings sage.rings.number_field>>> G.is_distance_regular(True)
˓→# needs sage.modules sage.rings.finite_rings sage.rings.number_field([10, 6, 4, 1, None], [None, 1, 2, 6, 10])REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 399.
static CorrelationGraph(seqs, alpha, include_anticorrelation)
Return a correlation graph with a node per sequence in seqs.
Edges are added between nodes where the corresponding sequences have a correlation coeffecient greaterthan alpha.
If include_anticorrelation is True, then edges are also added between nodes with correlation
coefficient less than -alpha.
INPUT:• seqs – list of sequences, taht is a list of lists• alpha – float; threshold on the correlation coefficient between two sequences for adding an edge
• include_anticorrelation – boolean; whether to add edges between nodes with correlation
coefficient less than -alpha or not
EXAMPLES:
sage: # needs numpy
sage: from sage.graphs.generators.basic import CorrelationGraphsage: data = [[1,2,3], [4,5,6], [7,8,9999]]
sage: CG1 = CorrelationGraph(data, 0.9, False)
sage: CG2 = CorrelationGraph(data, 0.9, True)
sage: CG3 = CorrelationGraph(data, 0.1, True)
sage: CG1.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)](continues on next page)2.1. Common graphs821

Graph Theory, Release 10.4

(continued from previous page)

sage: CG2.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]sage: CG3.edges(sort=False)[(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2,␣
˓→None)]>>> from sage.all import *>>> # needs numpy>>> from sage.graphs.generators.basic import CorrelationGraph>>> data = [[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),˓→Integer(6)], [Integer(7),Integer(8),Integer(9999)]]>>> CG1 = CorrelationGraph(data, RealNumber( 0.9 ), False)>>> CG2 = CorrelationGraph(data, RealNumber( 0.9 ), True)>>> CG3 = CorrelationGraph(data, RealNumber( 0.1 ), True)>>> CG1.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]>>> CG2.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]>>> CG3.edges(sort=False)[(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2,␣
˓→None)]static CossidentePenttilaGraph(q)Return the Cossidente-Penttila ((𝑞 3 +1)(𝑞 +1)/2, (𝑞 2 +1)(𝑞 −1)/2, (𝑞 −3)/2, (𝑞 −1)2 /2)-strongly regulargraph
For each odd prime power 𝑞, one can partition the points of the 𝑂6− (𝑞)-generalized quadrangle 𝐺𝑄(𝑞, 𝑞 2 )into two parts, so that on any of them the induced subgraph of the point graph of the GQ has parameters as
above [CP2005].
Directly following the construction in [CP2005] is not efficient, as one then needs to construct the dual
𝐺𝑄(𝑞 2 , 𝑞). Thus we describe here a more efficient approach that we came up with, following a suggestion by T.Penttila. Namely, this partition is invariant under the subgroup 𝐻 = Ω3 (𝑞 2 ) < 𝑂6− (𝑞). We build
the appropriate 𝐻, which leaves the form 𝐵(𝑋, 𝑌, 𝑍) = 𝑋𝑌 + 𝑍 2 invariant, and pick up two orbits of
𝐻 on the 𝐹𝑞 -points. One them is 𝐵-isotropic, and we take the representative (1 : 0 : 0). The other one
corresponds to the points of 𝑃 𝐺(2, 𝑞 2 ) that have all the lines on them either missing the conic specified by
𝐵, or intersecting the conic in two points. We take (1 : 1 : 𝑒) as the representative. It suffices to pick 𝑒so that 𝑒2 + 1 is not a square in 𝐹𝑞2 . Indeed, The conic can be viewed as the union of {(0 : 1 : 0)} and{(1 : −𝑡2 : 𝑡)|𝑡 ∈ 𝐹𝑞2 }. The coefficients of a generic line on (1 : 1 : 𝑒) are [1 : −1 − 𝑒𝑏 : 𝑏], for−1 ̸= 𝑒𝑏. Thus, to make sure the intersection with the conic is always even, we need that the discriminant of
1 + (1 + 𝑒𝑏)𝑡2 + 𝑡𝑏 = 0 never vanishes, and this is if and only if 𝑒2 + 1 is not a square. Further, we need toadjust 𝐵, 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)sage: G.is_strongly_regular(parameters=True)(56, 10, 0, 2)

822# optional - gap_package_grape# optional - gap_package_grape

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.CossidentePenttilaGraph(Integer(3))# optional - gap_
˓→package_grape>>> G.is_strongly_regular(parameters=True)# optional - gap_package_grape(56, 10, 0, 2)

For 𝑞 > 3 one gets new graphs.
sage: G = graphs.CossidentePenttilaGraph(5)sage: G.is_strongly_regular(parameters=True)(378, 52, 1, 8)# optional - gap_package_grape# optional - gap_package_grape>>> from sage.all import *>>> G = graphs.CossidentePenttilaGraph(Integer(5))# optional - gap_
˓→package_grape>>> G.is_strongly_regular(parameters=True)# optional - gap_package_grape(378, 52, 1, 8)

static CoxeterGraph()
Return the Coxeter graph.
See the Wikipedia article Coxeter_graph.
EXAMPLES:
sage: g = graphs.CoxeterGraph()
sage: g.automorphism_group().cardinality()˓→# needs sage.groups336
sage: g.girth()7
sage: g.chromatic_number()3
sage: g.diameter()4
sage: g.show(figsize=[10, 10])# long time˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.CoxeterGraph()>>> g.automorphism_group().cardinality()
˓→# needs sage.groups336>>> g.girth()7>>> g.chromatic_number()3>>> g.diameter()4>>> g.show(figsize=[Integer(10), Integer(10)])˓→# needs sage.plot

␣␣# long time␣

static CubeConnectedCycle(d)Return the cube-connected cycle of dimension 𝑑.
The cube-connected cycle of order 𝑑 is the 𝑑-dimensional hypercube with each of its vertices replaced bya cycle of length 𝑑. This graph has order 𝑑 × 2𝑑 . The construction is as follows: Construct vertex (𝑥, 𝑦)2.1. Common graphs823

Graph Theory, Release 10.4

for 0 ≤ 𝑥 < 2𝑑 , 0 ≤ 𝑦 < 𝑑. For each vertex, (𝑥, 𝑦), add an edge between it and (𝑥, (𝑦 − 1) mod 𝑑)),(𝑥, (𝑦 + 1) mod 𝑑), and (𝑥 ⊕ 2𝑦 , 𝑦), where ⊕ is the bitwise xor operator.
For 𝑑 = 1 and 2, the cube-connected cycle graph contains self-loops or multiple edges between a pair ofvertices, but for all other 𝑑, it is simple.
INPUT:• d – The dimension of the desired hypercube as well as the length of the cycle to be placed at each vertexof the 𝑑-dimensional hypercube. 𝑑 must be a positive integer.
EXAMPLES:
The order of the graph is 𝑑 × 2𝑑
sage: d = 3
sage: g = graphs.CubeConnectedCycle(d)sage: len(g) == d*2**dTrue>>> from sage.all import *>>> d = Integer(3)>>> g = graphs.CubeConnectedCycle(d)>>> len(g) == d*Integer(2)**d
True

The diameter of cube-connected cycles for 𝑑 > 3 is 2𝑑 + ⌊ 𝑑2 ⌋ − 2sage: d = 4
sage: g = graphs.CubeConnectedCycle(d)sage: g.diameter() == 2*d+d//2-2
True>>> from sage.all import *>>> d = Integer(4)>>> g = graphs.CubeConnectedCycle(d)>>> g.diameter() == Integer(2)*d+d//Integer(2)-Integer(2)True

All vertices have degree 3 when 𝑑 > 1
sage: g = graphs.CubeConnectedCycle(5)sage: all(g.degree(v) == 3 for v in g)
True>>> from sage.all import *>>> g = graphs.CubeConnectedCycle(Integer(5))>>> all(g.degree(v) == Integer(3) for v in g)Truestatic CubeGraph(n, embedding=1)
Return the 𝑛-cube graph, also called the hypercube in 𝑛 dimensions.
The hypercube in 𝑛 dimension is build upon the binary strings on 𝑛 bits, two of them being adjacent if theydiffer in exactly one bit. Hence, the distance between two vertices in the hypercube is the Hamming distance.
INPUT:• n – integer; the dimension of the cube graph

824

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• embedding – integer (default: 1); two embeddings of the 𝑛-cube are available:– 1: the 𝑛-cube is projected inside a regular 2𝑛-gonal polygon by a skew orthogonal projection. See
the Wikipedia article Hypercube for more details.
– 2: orthogonal projection of the 𝑛-cube. This orientation shows columns of independent vertices suchthat the neighbors of a vertex are located in the columns on the left and on the right. The number ofvertices in each column represents rows in Pascal’s triangle. See for instance the Wikipedia article
10-cube for more details.
– 3: oblique projection of the 𝑛-cube. Oblique projection involves aligning one face parallel tothe viewer and projecting at a specified angle, maintaining equal size for edges parallel to one
axis while applying fixed foreshortening to others. This method simplifies the representation ofa four-dimensional hypercube onto a two-dimensional plane, offering a geometrically consistent visualization.
– None or O: no embedding is provided
EXAMPLES:
The distance between 0100110 and 1011010 is 5, as expected:
sage: g = graphs.CubeGraph(7)sage: g.distance( 0100110 , 1011010 )5>>> from sage.all import *>>> g = graphs.CubeGraph(Integer(7))>>> g.distance( 0100110 , 1011010 )5

Plot several 𝑛-cubes in a Sage Graphics Array:sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(6):....: k = graphs.CubeGraph(i+1)....: g.append(k)...
sage: for i in range(2):....: n = []....: for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....: j.append(n)...
sage: G = graphics_array(j)sage: G.show(figsize=[6,4])# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(6)):... k = graphs.CubeGraph(i+Integer(1))... g.append(k)...
>>> for i in range(Integer(2)):... n = [](continues on next page)2.1. Common graphs825Graph Theory, Release 10.4

(continued from previous page)... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)...
>>> G = graphics_array(j)>>> G.show(figsize=[Integer(6),Integer(4)])# long time

Use the plot options to display larger 𝑛-cubes:
sage: g = graphs.CubeGraph(9, embedding=1)
sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20)
˓→long time, needs sage.plot
sage: g = graphs.CubeGraph(9, embedding=2)
sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20)
˓→long time, needs sage.plot
sage: g = graphs.CubeGraph(9, embedding=3)
sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20)
˓→long time, needs sage.plot

#␣

#␣

#␣

>>> from sage.all import *>>> g = graphs.CubeGraph(Integer(9), embedding=Integer(1))>>> g.show(figsize=[Integer(12),Integer(12)],vertex_labels=False, vertex_
˓→size=Integer(20))# long time, needs sage.plot>>> g = graphs.CubeGraph(Integer(9), embedding=Integer(2))>>> g.show(figsize=[Integer(12),Integer(12)],vertex_labels=False, vertex_
˓→size=Integer(20))# long time, needs sage.plot>>> g = graphs.CubeGraph(Integer(9), embedding=Integer(3))>>> g.show(figsize=[Integer(12),Integer(12)],vertex_labels=False, vertex_
˓→size=Integer(20))# long time, needs sage.plot

AUTHORS:• Robert Miller• David Coudert
static CycleGraph(n)Return a cycle graph with 𝑛 nodes.
A cycle graph is a basic structure which is also typically called an 𝑛-gon.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each cycle graph will be displayed with the first (0) node at the top, with the rest following in acounterclockwise manner.
The cycle graph is a good opportunity to compare efficiency of filling a position dictionary vs. using thespring-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: # needs networkx sage.plot
sage: import networkx
sage: n = networkx.cycle_graph(23)(continues on next page)

826

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: spring23 = Graph(n)sage: posdict23 = graphs.CycleGraph(23)sage: spring23.show()# long time
sage: posdict23.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> import networkx>>> n = networkx.cycle_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.CycleGraph(Integer(23))>>> spring23.show()# long time>>> posdict23.show()# long time

We next view many cycle graphs as a Sage graphics array. First we use the CycleGraph constructor, whichfills in the position dictionary:
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.CycleGraph(i+3)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CycleGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

Compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.cycle_graph(i+3)....:
k = Graph(spr)....:g.append(k)(continues on next page)2.1. Common graphs

827Graph Theory, Release 10.4

(continued from previous page)

sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.cycle_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static DartGraph()
Return a dart graph with 5 nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the dart graph is drawn as a dart, with the sharp part on the bottom.
EXAMPLES:
Construct and show a dart graph:
sage: g = graphs.DartGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.DartGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

static DegreeSequence(deg_sequence)
Return a graph with the given degree sequence.
This method raises a NetworkX error if the proposed degree sequence cannot be that of a graph.
Graph returned is the one returned by the Havel-Hakimi algorithm, which constructs a simple graph by connecting vertices of highest degree to other vertices of highest degree, resorting the remaining vertices bydegree and repeating the process. See Theorem 1.4 in [CL1996].
INPUT:• deg_sequence – list of integers with each entry corresponding to the degree of a different vertex
EXAMPLES:

828

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.DegreeSequence([3,3,3,3])˓→# needs networkx
sage: G.edges(sort=True, labels=False)˓→# needs networkx[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: G.show()# long time˓→# needs networkx sage.plot␣␣␣>>> from sage.all import *>>> G = graphs.DegreeSequence([Integer(3),Integer(3),Integer(3),Integer(3)]) ␣˓→# needs networkx>>> G.edges(sort=True, labels=False)
˓→# needs networkx[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]>>> G.show()# long time
˓→# needs networkx sage.plot
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])# needs networkx
sage: G.show()# long time˓→# needs networkx sage.plot␣>>> from sage.all import *>>> G = graphs.DegreeSequence([Integer(3),Integer(3),Integer(3),Integer(3),˓→Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),˓→Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),˓→Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),Integer(3)])#␣˓→needs networkx>>> G.show()# long time
˓→# needs networkx sage.plot
sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4])˓→# needs networkx
sage: G.show()# long time˓→# needs networkx sage.plot␣␣>>> from sage.all import *>>> G = graphs.DegreeSequence([Integer(4),Integer(4),Integer(4),Integer(4),˓→Integer(4),Integer(4),Integer(4),Integer(4)])
˓→# needs networkx>>> G.show()# long time
˓→# needs networkx sage.plot
sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1])
˓→# needs networkx
sage: G.show()# long time˓→# needs networkx sage.plot␣␣>>> from sage.all import *>>> G = graphs.DegreeSequence([Integer(1),Integer(2),Integer(3),Integer(4),˓→Integer(3),Integer(4),Integer(3),Integer(2),Integer(3),Integer(2),˓→Integer(1)])# needs networkx>>> G.show()# long time
˓→# needs networkx sage.plot

2.1. Common graphs829

Graph Theory, Release 10.4

static DegreeSequenceBipartite(s1, s2)
Return 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 onsets 𝐴 and 𝐵 such that the vertices in 𝐴 have 𝑠1 as their degree sequence, while 𝑠2 is the degree sequence ofthe vertices in 𝐵.
INPUT:• s_1 – list of integers corresponding to the degree sequence of the first set of vertices• s_2 – list of integers corresponding to the degree sequence of the second set of vertices
ALGORITHM:
This function works through the computation of the matrix given by the Gale-Ryser theorem, which is in thiscase 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])˓→# needs sage.combinat sage.modules
sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2))˓→# needs sage.combinat sage.modules
True

␣
␣

>>> from sage.all import *>>> g = graphs.DegreeSequenceBipartite([Integer(2),Integer(2),Integer(2),˓→Integer(2),Integer(2)],[Integer(5),Integer(5)])# needs␣
˓→sage.combinat sage.modules>>> g.is_isomorphic(graphs.CompleteBipartiteGraph(Integer(5),Integer(2)))␣˓→# needs sage.combinat sage.modules
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])␣˓→# needs sage.combinat sage.modules
Traceback (most recent call last):...
ValueError: there exists no bipartite graph corresponding to the given degree␣˓→sequences>>> from sage.all import *>>> g = graphs.DegreeSequenceBipartite([Integer(2),Integer(2),Integer(2),˓→Integer(2),Integer(1)],[Integer(5),Integer(5)])# needs␣
˓→sage.combinat sage.modules
Traceback (most recent call last):...
ValueError: there exists no bipartite graph corresponding to the given degree␣˓→sequences

static DegreeSequenceConfigurationModel(deg_sequence, seed=None)
Return a random pseudograph with the given degree sequence.

830

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

This method 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 twovertices.
INPUT:• deg_sequence – list of integers with each entry corresponding to the expected degree of a different
vertex• seed – (optional) a random.Random seed or a Python int for the random number generator
EXAMPLES:
sage: G = graphs.DegreeSequenceConfigurationModel([1,1])˓→# needs networkx
sage: G.adjacency_matrix()˓→# needs networkx sage.modules
[0 1]
[1 0]
>>> from sage.all import *>>> G = graphs.DegreeSequenceConfigurationModel([Integer(1),Integer(1)])˓→# needs networkx>>> G.adjacency_matrix()
˓→# needs networkx sage.modules
[0 1]
[1 0]

␣
␣

␣

The output is allowed to contain both loops and multiple edges:
sage: # needs networkx
sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence)sage: G.order(), G.size()(20, 30)
sage: G.has_loops() or G.has_multiple_edges() # random
True
sage: G.show()# long time˓→# needs sage.plot␣>>> from sage.all import *>>> # needs networkx>>> deg_sequence = [Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),˓→Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),˓→Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),Integer(3),˓→Integer(3),Integer(3),Integer(3)]>>> G = graphs.DegreeSequenceConfigurationModel(deg_sequence)>>> G.order(), G.size()(20, 30)>>> G.has_loops() or G.has_multiple_edges() # random
True>>> G.show()# long time
˓→# needs sage.plot

REFERENCE:[New2003]

2.1. Common graphs831

Graph Theory, Release 10.4

static DegreeSequenceExpected(deg_sequence, seed=None)
Return a random graph with expected given degree sequence.
This method raises a NetworkX error if the proposed degree sequence cannot be that of a graph.
One requirement is that the sum of the degrees must be even, since every edge must be incident with twovertices.
INPUT:• deg_sequence – list of integers with each entry corresponding to the expected degree of a different
vertex• seed – (optional) a random.Random seed or a Python int for the random number generator
EXAMPLES:
sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G˓→# needs networkx
Looped graph on 5 vertices
sage: G.show()# long time˓→# needs networkx sage.plot␣␣>>> from sage.all import *>>> G = graphs.DegreeSequenceExpected([Integer(1),Integer(2),Integer(3),˓→Integer(2),Integer(3)]); G# needs networkx
Looped graph on 5 vertices>>> G.show()# long time
˓→# needs networkx sage.plot

REFERENCE:[CL2002]
static DegreeSequenceTree(deg_sequence)
Return a tree with the given degree sequence.
This method raises a NetworkX error if the proposed degree sequence cannot be that of a tree.
Since every tree has one more vertex than edge, the degree sequence must satisfy len(deg_sequence)- sum(deg_sequence)/2 == 1.
INPUT:• deg_sequence – list of integers with each entry corresponding to the expected degree of a different
vertexEXAMPLES:
sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G˓→# needs networkx
Graph on 9 vertices
sage: G.show()# long time˓→# needs networkx sage.plot␣␣>>> from sage.all import *>>> G = graphs.DegreeSequenceTree([Integer(3),Integer(1),Integer(3),˓→Integer(3),Integer(1),Integer(1),Integer(1),Integer(2),Integer(1)]); G˓→# needs networkx
Graph on 9 vertices␣(continues on next page)

832

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G.show()˓→# needs networkx sage.plot# 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˓→# needs sage.rings.finite_rings
Dejter Graph: Graph on 112 vertices
sage: g.is_regular(k=6)˓→# needs sage.rings.finite_rings
True
sage: g.girth()˓→# needs sage.rings.finite_rings
4>>> from sage.all import *>>> g = graphs.DejterGraph(); g˓→# needs sage.rings.finite_rings
Dejter Graph: Graph on 112 vertices>>> g.is_regular(k=Integer(6))˓→# needs sage.rings.finite_rings
True>>> g.girth()
˓→# needs sage.rings.finite_rings
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)˓→# needs networkx
sage: D.is_isomorphic(L)˓→# needs networkx
True
sage: D.show()# long time˓→# needs sage.plot␣␣␣>>> from sage.all import *>>> D = graphs.DesarguesGraph()>>> L = graphs.LCFGraph(Integer(20),[Integer(5),-Integer(5),Integer(9),˓→Integer(9)],Integer(5))# needs networkx>>> D.is_isomorphic(L)˓→# needs networkx
True>>> D.show()# long time
˓→# needs sage.plot

2.1. Common graphs833

Graph Theory, Release 10.4

static DiamondGraph()
Return a diamond graph with 4 nodes.
A diamond graph is a square with one pair of diagonal nodes connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the diamond graph is drawn as a diamond, with the first node on top, second on the left, third on
the right, and fourth on the bottom; with the second and third node connected.
EXAMPLES:
Construct and show a diamond graph:
sage: g = graphs.DiamondGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.DiamondGraph()>>> g.show()˓→# needs sage.plot# long time␣# 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˓→# needs sage.plot␣>>> from sage.all import *>>> g = graphs.DipoleGraph(Integer(13)); g
Dipole graph: Multi-graph on 2 vertices>>> g.show()# long time
˓→# needs sage.plot

static DodecahedralGraph()
Return a Dodecahedral graph (with 20 nodes)
The dodecahedral graph is cubic symmetric, so the spring-layout algorithm will be very effective for display.
It is dual to the icosahedral graph.
PLOTTING: The Dodecahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument
will be added to select the desired layout.
EXAMPLES:
Construct and show a Dodecahedral graph:
sage: g = graphs.DodecahedralGraph()
sage: g.show()˓→# needs sage.plot

834# long time␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.DodecahedralGraph()>>> g.show()˓→# needs sage.plot# long time

Create several dodecahedral graphs in a Sage graphics array They will be drawn differently due to the use of
the spring-layout algorithm:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.DodecahedralGraph()....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.DodecahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static DorogovtsevGoltsevMendesGraph(n)Construct the n-th generation of the Dorogovtsev-Goltsev-Mendes graph.
EXAMPLES:
sage: G = graphs.DorogovtsevGoltsevMendesGraph(8)˓→# needs networkx
sage: G.size()˓→# needs networkx
6561>>> from sage.all import *>>> G = graphs.DorogovtsevGoltsevMendesGraph(Integer(8))˓→# needs networkx>>> G.size()
˓→# needs networkx
6561

␣
␣

␣

REFERENCE:
2.1. Common graphs835Graph Theory, Release 10.4

• [1] Dorogovtsev, S. N., Goltsev, A. V., and Mendes, J. F. F., Pseudofractal scale-free web, Phys. Rev.
E 066122 (2002).
static DoubleGeneralizedPetersenGraph(n, k)
Return a double generalized Petersen graph with 4𝑛 nodes.
The double generalized Petersen graphs is a family of graphs proposed in [ZF2012] as a variant of generalizedPetersen graphs. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋.
INPUT:• n – the number of nodes is 4 * 𝑛• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how vertices on second and third inner rims areconnected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the double generalized Petersen graphs are displayed as 4 cocentric cycles, with the first n nodes
drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise
after that. The second circle is drawn with the (n)th node at the top, then counterclockwise as well. The tird
cycle is drawn with the (2n)th node at the top, then counterclockwise. And the fourth cycle is drawn with the(3n)th node at the top, then again counterclockwise.
EXAMPLES:
When 𝑛 is even the resulting graph will be isomorphic to a double generalized Petersen graph with 𝑘 ′ =𝑛/2 − 𝑘:sage: g = graphs.DoubleGeneralizedPetersenGraph(10, 2)
sage: g2 = graphs.DoubleGeneralizedPetersenGraph(10, 3)
sage: g.is_isomorphic(g2)
True>>> from sage.all import *>>> g = graphs.DoubleGeneralizedPetersenGraph(Integer(10), Integer(2))>>> g2 = graphs.DoubleGeneralizedPetersenGraph(Integer(10), Integer(3))>>> g.is_isomorphic(g2)Truestatic DoubleGrassmannGraph(q, e)
Return the bipartite double of the distance-𝑒 graph of the Grassmann graph 𝐽𝑞 (𝑛, 𝑒).
This graph can also be descirbed as follows: Let 𝑉 be the vector space of dimension 𝑛 over 𝐺𝐹 (𝑞). The
vertex set is the set of 𝑒 + 1 or 𝑒 subspaces of 𝑉 . Two vertices are adjacent if one subspace is contained in
the other.
This graph is distance-transitive.
INPUT:• q – a prime power• e – integer
EXAMPLES:
sage: G = graphs.DoubleGrassmannGraph(2,1)˓→# needs sage.modules
sage: G.diameter()˓→# needs sage.modules
3␣␣(continues on next page)

836

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: G.is_distance_regular(True)˓→# needs sage.modules([3, 2, 2, None], [None, 1, 1, 3])>>> from sage.all import *>>> G = graphs.DoubleGrassmannGraph(Integer(2),Integer(1))˓→# needs sage.modules>>> G.diameter()
˓→# needs sage.modules
3>>> G.is_distance_regular(True)
˓→# needs sage.modules([3, 2, 2, None], [None, 1, 1, 3])

␣␣

REFERENCES:
See [BCN1989] pp. 272, 273 or [VDKT2016] p. 25.
static DoubleOddGraph(n)Return the double odd graph on 2𝑛 + 1 points.
The graph is obtained using the subsets of size 𝑛 and 𝑛 + 1 of 1, 2, ..., 2𝑛 + 1 as vertices. Two vertices are
adjacent if one is included in the other.
The graph is distance-transitive.
INPUT:• n – integer; must be greater than 0
EXAMPLES:
sage: G = graphs.DoubleOddGraph(5)sage: G.is_distance_regular(True)([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])
sage: G = graphs.DoubleOddGraph(3)sage: G.diameter()7
sage: G.is_distance_regular(True)([4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4])>>> from sage.all import *>>> G = graphs.DoubleOddGraph(Integer(5))>>> G.is_distance_regular(True)([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])>>> G = graphs.DoubleOddGraph(Integer(3))>>> G.diameter()
7>>> G.is_distance_regular(True)([4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4])

REFERENCES:
See [BCN1989] pp. 259-261 or [VDKT2016] p. 25.
static DoubleStarSnark()
Return the double star snark.
2.1. Common graphs

837

Graph Theory, Release 10.4

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()˓→# needs sage.numerical.mip
False
sage: g.automorphism_group().cardinality()˓→# needs sage.groups
80
sage: g.show()˓→# needs sage.plot

␣

␣

␣

>>> from sage.all import *>>> g = graphs.DoubleStarSnark()>>> g.order()30>>> g.size()45>>> g.chromatic_number()3>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
False>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
80>>> g.show()˓→# needs sage.plot

static DoublyTruncatedWittGraph()
Return the doubly truncated Witt graph.
This builds the truncated Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [7, 6, 4, 4; 1, 1, 1, 6].
EXAMPLES:
sage: G = graphs.DoublyTruncatedWittGraph()˓→# needs sage.libs.pari sage.modules
sage: G.is_distance_regular(True)˓→# needs sage.libs.pari sage.modules([7, 6, 4, 4, None], [None, 1, 1, 1, 6])␣␣>>> from sage.all import *>>> G = graphs.DoublyTruncatedWittGraph()˓→# needs sage.libs.pari sage.modules>>> G.is_distance_regular(True)
˓→# needs sage.libs.pari sage.modules([7, 6, 4, 4, None], [None, 1, 1, 1, 6])838

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 368.
static DurerGraph()
Return the Dürer graph.
For more information, see the Wikipedia article D%C3%BCrer_graph.
EXAMPLES:The Dürer graph is named after Albrecht Dürer. It is a planar graph with 12 vertices and 18 edges:
sage: G = graphs.DurerGraph(); G
Durer graph: Graph on 12 vertices
sage: G.is_planar()True
sage: G.order()12sage: G.size()18>>> from sage.all import *>>> G = graphs.DurerGraph(); G
Durer graph: Graph on 12 vertices>>> G.is_planar()
True>>> G.order()12>>> 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>>> from sage.all import *>>> G.chromatic_number()3>>> G.diameter()
4>>> G.girth()3

Its automorphism group is isomorphic to 𝐷6 :sage: ag = G.automorphism_group()˓→# needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(6))˓→# needs sage.groupsTrue

2.1. Common graphs

␣
␣

839

Graph Theory, Release 10.4>>> from sage.all import *>>> ag = G.automorphism_group()
˓→# needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(6)))˓→# needs sage.groups
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>>> from sage.all import *>>> G = graphs.DyckGraph(); G
Dyck graph: Graph on 32 vertices>>> G.order()32>>> G.size()48>>> G.is_regular()
True>>> G.is_regular(Integer(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()˓→# needs sage.numerical.mip
True
sage: G.is_bipartite()True␣>>> from sage.all import *>>> G.is_planar()
False>>> G.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> G.is_bipartite()
True

840

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

It has radius 5, diameter 5, and girth 6:
sage: G.radius()
5
sage: G.diameter()5
sage: G.girth()6>>> from sage.all import *>>> G.radius()
5>>> G.diameter()5>>> 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()˓→# needs sage.groups192␣>>> from sage.all import *>>> G.chromatic_number()2>>> G.automorphism_group().cardinality()
˓→# needs sage.groups
192

It is a non-integral graph as it has irrational eigenvalues:
sage: G.characteristic_polynomial().factor()˓→# needs sage.libs.pari sage.modules(x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6␣>>> from sage.all import *>>> G.characteristic_polynomial().factor()˓→# needs sage.libs.pari sage.modules(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 notrecognizable by 1-WL (Weisfeiler Lehamn algorithm of the first order) and 2-WL, that is their orbits are notcorrectly 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]
2.1. Common graphs841

Graph Theory, Release 10.4

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>>> from sage.all import *>>> g = graphs.EgawaGraph(Integer(1), Integer(2))>>> 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>>> from sage.all import *>>> g = graphs.EgawaGraph(Integer(0), Integer(4))>>> g.is_isomorphic(graphs.HammingGraph(Integer(4),Integer(4)))
True

static EllinghamHorton54Graph()
Return the Ellingham-Horton 54-graph.
For more information, see the Wikipedia article Ellingham-Horton_graph.
EXAMPLES:This graph is 3-regular:
sage: g = graphs.EllinghamHorton54Graph()
sage: g.is_regular(k=3)
True>>> from sage.all import *>>> g = graphs.EllinghamHorton54Graph()>>> g.is_regular(k=Integer(3))
True

It is 3-connected and bipartite:sage: g.vertex_connectivity()3
sage: g.is_bipartite()
True

842

# not tested - too long

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g.vertex_connectivity()3>>> g.is_bipartite()True# not tested - too long

It is not Hamiltonian:sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
False>>> from sage.all import *>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
False# not tested␣# not tested… and it has a nice drawing
sage: g.show(figsize=[10, 10])# not tested - too long>>> from sage.all import *>>> g.show(figsize=[Integer(10), Integer(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>>> from sage.all import *>>> g = graphs.EllinghamHorton78Graph()>>> g.is_regular(k=Integer(3))
True

It is 3-connected and bipartite:sage: g.vertex_connectivity()3
sage: g.is_bipartite()True>>> from sage.all import *>>> g.vertex_connectivity()3>>> g.is_bipartite()True# not tested (too long)# not tested (too long)

It is not Hamiltonian:

2.1. Common graphs843

Graph Theory, Release 10.4

sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
False# not tested>>> from sage.all import *>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
False

␣

# not tested… and it has a nice drawing
sage: g.show(figsize=[10,10])# not tested (too long)>>> from sage.all import *>>> g.show(figsize=[Integer(10),Integer(10)])# not tested (too long)

static EmptyGraph()
Return an empty graph (0 nodes and 0 edges).
This is useful for constructing graphs by adding edges and vertices individually or in a loop.
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary is specified.
EXAMPLES:
Add one vertex to an empty graph and then show:
sage: empty1 = graphs.EmptyGraph()
sage: empty1.add_vertex()0sage: empty1.show()˓→# needs sage.plot>>> from sage.all import *>>> empty1 = graphs.EmptyGraph()>>> empty1.add_vertex()0>>> empty1.show()˓→# needs sage.plot# long time␣# 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˓→# needs sage.plot

844

␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> empty2 = graphs.EmptyGraph()>>> for i in range(Integer(5)):...
empty2.add_vertex() # add 5 nodes, labeled 0-4
0
1
2
3
4
>>> for i in range(Integer(3)):...
empty2.add_edge(i,i+Integer(1)) # add edges {[0:1],[1:2],[2:3]}>>> for i in range(Integer(1), Integer(4)):...
empty2.add_edge(Integer(4),i) # add edges {[1:4],[2:4],[3:4]}>>> empty2.show()# long time
˓→# needs sage.plot

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()17sage: G.size()45>>> from sage.all import *>>> G = graphs.ErreraGraph(); G
Errera graph: Graph on 17 vertices>>> G.is_planar()
True>>> G.order()17>>> G.size()45

The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and chromatic number 4:
sage: G.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: G.radius()
3
sage: G.diameter()4
sage: G.girth()3
sage: G.chromatic_number()4

2.1. Common graphs␣845

Graph Theory, Release 10.4>>> from sage.all import *>>> G.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> G.radius()
3>>> G.diameter()
4>>> G.girth()3>>> 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 thenumber of vertices of degree 6, then 𝑓 + 𝑠 is equal to the order of the Errera graph:
sage: D = G.degree_sequence()
sage: D.count(5) + D.count(6) == G.order()True>>> from sage.all import *>>> D = G.degree_sequence()>>> D.count(Integer(5)) + D.count(Integer(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()˓→# needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(10))˓→# needs sage.groups
True

␣
␣

>>> from sage.all import *>>> ag = G.automorphism_group()
˓→# needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(10)))˓→# needs sage.groups
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 anedge between those countries that have common land border.
INPUT:• continental – boolean (default: False); whether to only return states in the continental Europe or
all European states• year – integer (default: 2018); reserved for future use
EXAMPLES:
sage: Europe = graphs.EuropeMap(); Europe
Europe Map: Graph on 44 vertices
sage: Europe.neighbors( Ireland )(continues on next page)

846

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)[ United Kingdom ]sage: cont_Europe = graphs.EuropeMap(continental=True)
sage: cont_Europe.order()40
sage: Iceland in cont_Europe
False>>> from sage.all import *>>> Europe = graphs.EuropeMap(); Europe
Europe Map: Graph on 44 vertices>>> Europe.neighbors( Ireland )[ United Kingdom ]>>> cont_Europe = graphs.EuropeMap(continental=True)>>> cont_Europe.order()40>>> 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: # needs networkx
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>>> from sage.all import *>>> # needs networkx>>> g = graphs.F26AGraph(); g
F26A Graph: Graph on 26 vertices>>> g.order(), g.size()(26, 39)>>> g.automorphism_group().cardinality()78>>> g.girth()6>>> g.is_bipartite()True>>> g.characteristic_polynomial().factor()(x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6

2.1. Common graphs847

Graph Theory, Release 10.4

static FibonacciTree(n)Return the graph of the Fibonacci Tree 𝐹𝑖 of order 𝑛.
The Fibonacci tree 𝐹𝑖 is recursively defined as the tree with a root vertex and two attached child trees 𝐹𝑖−1
and 𝐹𝑖−2 , where 𝐹1 is just one vertex and 𝐹0 is empty.
INPUT:• n – the recursion depth of the Fibonacci Tree
EXAMPLES:
sage: g = graphs.FibonacciTree(3)˓→# needs sage.libs.pari
sage: g.is_tree()˓→# needs sage.libs.pari
True

␣
␣

>>> from sage.all import *>>> g = graphs.FibonacciTree(Integer(3))˓→# needs sage.libs.pari>>> g.is_tree()˓→# needs sage.libs.pariTrue␣

sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ]˓→# needs sage.libs.pari
sage: l2 = list(fibonacci_sequence(2,8))˓→# needs sage.libs.pari
sage: l1 == l2˓→# needs sage.libs.pari
True>>> from sage.all import *>>> l1 = [ len(graphs.FibonacciTree(_)) + Integer(1) for _ in␣˓→range(Integer(6)) ]# needs sage.libs.pari>>> l2 = list(fibonacci_sequence(Integer(2),Integer(8)))˓→# needs sage.libs.pari>>> l1 == l2
˓→# needs sage.libs.pari
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 Petersengraph 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:

848

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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>>> from sage.all import *>>> F = graphs.FlowerSnark()>>> F
Flower Snark: Graph on 20 vertices>>> F.graph6_string()
ShCGHC@?GGg@?@?Gp?K??C?CA?G?_G?Cc

Now show it:
sage: F.show()˓→# needs sage.plot>>> from sage.all import *>>> F.show()˓→# needs sage.plot# long time␣# 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>>> from sage.all import *>>> fc = graphs.FoldedCubeGraph(Integer(5))>>> clebsch = graphs.ClebschGraph()>>> fc.is_isomorphic(clebsch)
Truestatic FolkmanGraph()
Return the Folkman graph.
See the Wikipedia article Folkman_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.FolkmanGraph()
sage: g.order()20(continues on next page)2.1. Common graphs849

Graph Theory, Release 10.4

(continued from previous page)

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()˓→# needs sage.numerical_mip
True
sage: g.is_vertex_transitive()
False
sage: g.is_bipartite()True␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.FolkmanGraph()>>> g.order()20>>> g.size()40>>> g.diameter()4>>> g.girth()4>>> g.charpoly().factor()(x - 4) * (x + 4) * x^10 * (x^2 - 6)^4>>> g.chromatic_number()2>>> g.is_eulerian()True>>> g.is_hamiltonian()
˓→# needs sage.numerical_mip
True>>> g.is_vertex_transitive()
False>>> g.is_bipartite()True

static ForkGraph()
Return a fork graph with 5 nodes.
A fork graph, sometimes also called chair graph, is 5 vertex tree.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the fork graph is drawn as a fork, with the sharp part on the bottom.
EXAMPLES:
Construct and show a fork graph:

850

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: g = graphs.ForkGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.ForkGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

static FosterGraph()
Return the Foster graph.
See the Wikipedia article Foster_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.FosterGraph()
sage: g.order()90sage: g.size()
135
sage: g.diameter()8
sage: g.girth()10
sage: g.automorphism_group().cardinality()
4320
sage: g.is_hamiltonian()˓→# needs sage.numerical_mip
True␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.FosterGraph()>>> g.order()90>>> g.size()135>>> g.diameter()8>>> g.girth()
10>>> g.automorphism_group().cardinality()
4320>>> g.is_hamiltonian()
˓→# needs sage.numerical_mip
Truestatic FosterGraph3S6()
Return the Foster graph for 3.𝑆𝑦𝑚(6).
This graph is distance-regular with intersection array [6, 4, 2, 1; 1, 1, 4, 6].
The graph is also distance transitive.
EXAMPLES:

2.1. Common graphs851

Graph Theory, Release 10.4

sage: G = graphs.FosterGraph3S6()
˓→# needs sage.libs.gap
sage: G.is_distance_regular(True)˓→# needs sage.libs.gap([6, 4, 2, 1, None], [None, 1, 1, 4, 6])␣␣>>> from sage.all import *>>> G = graphs.FosterGraph3S6()
˓→# needs sage.libs.gap>>> G.is_distance_regular(True)
˓→# needs sage.libs.gap([6, 4, 2, 1, None], [None, 1, 1, 4, 6])

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 397.
static FranklinGraph()
Return the Franklin graph.
For more information, see the Wikipedia article Franklin_graph.
EXAMPLES:
The Franklin graph is named after Philip Franklin. It is a 3-regular graph on 12 vertices and having 18 edges:
sage: G = graphs.FranklinGraph(); GFranklin graph: Graph on 12 vertices
sage: G.is_regular(3)True
sage: G.order()12sage: G.size()18>>> from sage.all import *>>> G = graphs.FranklinGraph(); GFranklin graph: Graph on 12 vertices>>> G.is_regular(Integer(3))
True>>> G.order()12>>> G.size()18

The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4:
sage: G.is_hamiltonian()˓→# needs sage.numerical_mip
True
sage: G.is_bipartite()True
sage: G.radius()
3
sage: G.diameter()3
sage: G.girth()
4

852

␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> G.is_hamiltonian()
˓→# needs sage.numerical_mip
True>>> G.is_bipartite()
True>>> G.radius()
3>>> G.diameter()3>>> 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>>> from sage.all import *>>> G.is_perfect()True>>> G.is_triangle_free()True>>> 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: # needs sage.plot
sage: A = []; B = []sage: for i in range(9):....:g = graphs.FriendshipGraph(i + 1)
(continues on next page)2.1. Common graphs853

Graph Theory, Release 10.4

(continued from previous page)....:
A.append(g)sage: for i in range(3):....:n = []....:
for j in range(3):....:n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False))....:
B.append(n)sage: G = graphics_array(B)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> A = []; B = []>>> for i in range(Integer(9)):...
g = graphs.FriendshipGraph(i + Integer(1))...
A.append(g)>>> for i in range(Integer(3)):...
n = []...
for j in range(Integer(3)):...
n.append(A[Integer(3)*i + j].plot(vertex_size=Integer(20), vertex_
˓→labels=False))...
B.append(n)>>> G = graphics_array(B)>>> G.show()# long time

For 𝑛 = 1, the friendship graph 𝐹1 is isomorphic to the cycle graph 𝐶3 , whose visual representation is atriangle.
sage: G = graphs.FriendshipGraph(1); G
Friendship graph: Graph on 3 vertices
sage: G.show()# long time˓→# needs sage.plot
sage: G.is_isomorphic(graphs.CycleGraph(3))
True␣>>> from sage.all import *>>> G = graphs.FriendshipGraph(Integer(1)); GFriendship graph: Graph on 3 vertices>>> G.show()# long time
˓→# needs sage.plot>>> G.is_isomorphic(graphs.CycleGraph(Integer(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>>> from sage.all import *>>> G = graphs.FriendshipGraph(Integer(2)); GFriendship graph: Graph on 5 vertices>>> G.is_isomorphic(graphs.ButterflyGraph())
True

If 𝑛 ≥ 2, then the friendship graph 𝐹𝑛 has 2𝑛 + 1 vertices and 3𝑛 edges. It has radius 1, diameter 2, girth 3,
854

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

and chromatic number 3. Furthermore, 𝐹𝑛 is planar and Eulerian.
sage: n = randint(2, 10^3)sage: G = graphs.FriendshipGraph(n)sage: G.order() == 2*n + 1
True
sage: G.size() == 3*nTrue
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>>> from sage.all import *>>> n = randint(Integer(2), Integer(10)**Integer(3))>>> G = graphs.FriendshipGraph(n)>>> G.order() == Integer(2)*n + Integer(1)True>>> G.size() == Integer(3)*nTrue>>> G.radius()
1>>> G.diameter()2>>> G.girth()3>>> G.chromatic_number()3>>> G.is_planar()
True>>> G.is_eulerian()Truestatic FruchtGraph()
Return a Frucht Graph.
A Frucht graph has 12 nodes and 18 edges. It is the smallest cubic identity graph. It is planar and Hamiltonian.
See the Wikipedia article Frucht_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the first seven nodes are on the outer circle, with the next four on an inner circle and the last in
the center.
EXAMPLES:
sage: FRUCHT = graphs.FruchtGraph()
sage: FRUCHT
Frucht graph: Graph on 12 vertices
sage: FRUCHT.graph6_string()
KhCKM?_EGK?L(continues on next page)2.1. Common graphs855

Graph Theory, Release 10.4

(continued from previous page)

sage: (graphs.FruchtGraph()).show()˓→# needs networkx>>> from sage.all import *>>> FRUCHT = graphs.FruchtGraph()>>> FRUCHT
Frucht graph: Graph on 12 vertices>>> FRUCHT.graph6_string()
KhCKM?_EGK?L>>> (graphs.FruchtGraph()).show()˓→# needs networkx# long time␣# 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 coloringcolors the middle section with one color, and then each pair (𝑎𝑖 , 𝑏𝑖 ) with another color. Since this method ismainly 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 thepartition induced by the coloring of G’s vertices
EXAMPLES:
Furer gadget of order 3, without any prefix.
sage: G, p = graphs.FurerGadget(3)sage: sorted(G, key=str)[(), (0, a ), (0, b ), (0, 1), (0, 2),(1, a ), (1, b ), (1, 2), (2, a ), (2, b )]sage: sorted(G.edge_iterator(), key=str)[((), (0, b ), None), ((), (1, b ), None),((), (2, b ), None), ((0, b ), (1, 2), None),((0, 1), (0, a ), None), ((0, 1), (1, a ), None),((0, 1), (2, b ), None), ((0, 2), (0, a ), None),((0, 2), (1, b ), None), ((0, 2), (2, a ), None),((1, 2), (1, a ), None), ((1, 2), (2, a ), None)]>>> from sage.all import *>>> G, p = graphs.FurerGadget(Integer(3))>>> sorted(G, key=str)[(), (0, a ), (0, b ), (0, 1), (0, 2),(1, a ), (1, b ), (1, 2), (2, a ), (2,b )](continues on next page)

856

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> sorted(G.edge_iterator(), key=str)[((), (0, b ), None), ((), (1, b ), None),((), (2, b ), None), ((0, b ), (1, 2), None),((0, 1), (0, a ), None), ((0, 1), (1, a ), None),((0, 1), (2, b ), None), ((0, 2), (0, a ), None),((0, 2), (1, b ), None), ((0, 2), (2, a ), None),((1, 2), (1, a ), None), ((1, 2), (2, a ), None)]

Furer gadget of order 3, with a prefix.
sage: G, p = graphs.FurerGadget(3, Prefix )sage: sorted(G, key=str)[( Prefix , ()), ( Prefix , (0, a )), ( Prefix , (0, b )),( Prefix , (0, 1)), ( Prefix , (0, 2)), ( Prefix , (1, a )),( Prefix , (1, b )), ( Prefix , (1, 2)), ( Prefix , (2, a )),( Prefix , (2, b ))]sage: sorted(G.edge_iterator(), key=str)[(( Prefix , ()), ( Prefix , (0, b )), None),(( Prefix , ()), ( Prefix , (1, b )), None),(( Prefix , ()), ( Prefix , (2, b )), None),(( Prefix , (0, b )), ( Prefix , (1, 2)), None),(( 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 , (1, 2)), ( Prefix , (1, a )), None),(( Prefix , (1, 2)), ( Prefix , (2, a )), None)]>>> from sage.all import *>>> G, p = graphs.FurerGadget(Integer(3), Prefix )>>> sorted(G, key=str)[( Prefix , ()), ( Prefix , (0, a )), ( Prefix , (0, b )),( Prefix , (0, 1)), ( Prefix , (0, 2)), ( Prefix , (1, a )),( Prefix , (1, b )), ( Prefix , (1, 2)), ( Prefix , (2, a )),( Prefix , (2, b ))]>>> sorted(G.edge_iterator(), key=str)[(( Prefix , ()), ( Prefix , (0, b )), None),(( Prefix , ()), ( Prefix , (1, b )), None),(( Prefix , ()), ( Prefix , (2, b )), None),(( Prefix , (0, b )), ( Prefix , (1, 2)), None),(( 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 , (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 𝐺.
2.1. Common graphs857

Graph Theory, Release 10.4

For given positive integers 𝑘 and 𝑚 and nonnegative integer 𝑞, the set of graphs FuzzyBallGraph(p,q) for all partitions 𝑝 of 𝑚 with 𝑘 parts are cospectral with respect to the normalized Laplacian.
EXAMPLES:
sage: F = graphs.FuzzyBallGraph([3,1],2)
sage: F.adjacency_matrix(vertices=list(F))˓→# needs sage.modules[0 0 1 1 1 0 0 0]
[0 0 0 0 0 1 0 0]
[1 0 0 1 1 1 1 1]
[1 0 1 0 1 1 1 1]
[1 0 1 1 0 1 1 1]
[0 1 1 1 1 0 1 1]
[0 0 1 1 1 1 0 1]
[0 0 1 1 1 1 1 0]

␣>>> from sage.all import *>>> F = graphs.FuzzyBallGraph([Integer(3),Integer(1)],Integer(2))>>> F.adjacency_matrix(vertices=list(F))˓→# needs sage.modules[0 0 1 1 1 0 0 0]
[0 0 0 0 0 1 0 0]
[1 0 0 1 1 1 1 1]
[1 0 1 0 1 1 1 1]
[1 0 1 1 0 1 1 1]
[0 1 1 1 1 0 1 1]
[0 0 1 1 1 1 0 1]
[0 0 1 1 1 1 1 0]

Pick positive integers 𝑚 and 𝑘 and a nonnegative integer 𝑞. All the FuzzyBallGraphs constructed from partitions of 𝑚 with 𝑘 parts should be cospectral with respect to the normalized Laplacian:sage: m = 4; q = 2; k = 2
sage: g_list = [graphs.FuzzyBallGraph(p,q)␣˓→# needs sage.combinat sage.modules....:
for p in Partitions(m, length=k)]
sage: set(g.laplacian_matrix(normalized=True,# long time (7s on sage.math,␣
˓→2011), needs sage.combinat sage.modules....:
vertices=list(g)).charpoly()....:
for g in g_list){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}>>> from sage.all import *>>> m = Integer(4); q = Integer(2); k = Integer(2)>>> g_list = [graphs.FuzzyBallGraph(p,q)˓→# needs sage.combinat sage.modules...
for p in Partitions(m, length=k)]>>> set(g.laplacian_matrix(normalized=True,# long time (7s on sage.math,␣
˓→2011), needs sage.combinat sage.modules...
vertices=list(g)).charpoly()...
for g in g_list){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 GemGraph()
Return a gem graph with 5 nodes.
858

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

A gem graph is a fan graph (4,1).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the gem graph is drawn as a gem, with the sharp part on the bottom.
EXAMPLES:
Construct and show a gem graph:
sage: g = graphs.GemGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.GemGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

static GeneralisedDodecagonGraph(s, t)
Return the point-graph of a generalised dodecagon of order (𝑠, 𝑡).
INPUT:• s, t – integers; order of the generalised dodecagon
EXAMPLES:
sage: # optional - gap_package_atlasrep internet
sage: G = graphs.GeneralisedDodecagonGraph(1, 5)
sage: G.is_distance_regular(True)([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6])
sage: H = graphs.GeneralisedDodecagonGraph(5, 1)
sage: H.order()23436
sage: H.is_distance_regular(True)# not tested (6 min)([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2])>>> from sage.all import *>>> # optional - gap_package_atlasrep internet>>> G = graphs.GeneralisedDodecagonGraph(Integer(1), Integer(5))>>> G.is_distance_regular(True)([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6])>>> H = graphs.GeneralisedDodecagonGraph(Integer(5), Integer(1))>>> H.order()23436>>> H.is_distance_regular(True)# not tested (6 min)([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2])Note: This function indirectly uses the GAP’s AtlasRep package. Thus you may need an internet connection
and the optional Sage’s package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
static GeneralisedHexagonGraph(s, t)
Return the point-graph of a generalised hexagon of order (𝑠, 𝑡).
INPUT:
2.1. Common graphs859

Graph Theory, Release 10.4

• s, t – integers; order of the generalised hexagon
EXAMPLES:
sage: # needs sage.libs.gap
sage: G = graphs.GeneralisedHexagonGraph(5, 5)
˓→package_atlasrep internet
sage: G.is_distance_regular(True)
˓→package_atlasrep internet([30, 25, 25, None], [None, 1, 1, 6])
sage: G = graphs.GeneralisedHexagonGraph(7, 1)
sage: G.is_distance_regular(True)([14, 7, 7, None], [None, 1, 1, 2])
sage: graphs.GeneralisedHexagonGraph(1, 1)
Cycle graph: Graph on 6 vertices# optional - gap_
# optional - gap_>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.GeneralisedHexagonGraph(Integer(5), Integer(5))#␣˓→optional - gap_package_atlasrep internet>>> G.is_distance_regular(True)# optional - gap_
˓→package_atlasrep internet([30, 25, 25, None], [None, 1, 1, 6])>>> G = graphs.GeneralisedHexagonGraph(Integer(7), Integer(1))>>> G.is_distance_regular(True)([14, 7, 7, None], [None, 1, 1, 2])>>> graphs.GeneralisedHexagonGraph(Integer(1), Integer(1))
Cycle graph: Graph on 6 vertices

Note: This function uses the GAP’s AtlasRep package to build GHs of order (𝑞, 𝑞), (𝑞, 𝑞 3 ) or (𝑞 3 , 𝑞). For
those graphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
static GeneralisedOctagonGraph(s, t)
Return the point-graph of a generalised octagon of order (𝑠, 𝑡).
INPUT:• s, t – integers; order of the generalised octagon
EXAMPLES:
sage: # needs sage.libs.gap
sage: G = graphs.GeneralisedOctagonGraph(1, 4)
sage: G.is_distance_regular(True)([5, 4, 4, 4, None], [None, 1, 1, 1, 5])
sage: G = graphs.GeneralisedOctagonGraph(2, 4)
˓→package_atlasrep internet
sage: G.is_distance_regular(True)
˓→package_atlasrep internet([10, 8, 8, 8, None], [None, 1, 1, 1, 5])
sage: G = graphs.GeneralisedOctagonGraph(5, 1)
sage: G.is_distance_regular(True)([10, 5, 5, 5, None], [None, 1, 1, 1, 2])860# optional - gap_
# optional - gap_

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.GeneralisedOctagonGraph(Integer(1), Integer(4))>>> G.is_distance_regular(True)([5, 4, 4, 4, None], [None, 1, 1, 1, 5])>>> G = graphs.GeneralisedOctagonGraph(Integer(2), Integer(4))#␣˓→optional - gap_package_atlasrep internet>>> G.is_distance_regular(True)# optional - gap_
˓→package_atlasrep internet([10, 8, 8, 8, None], [None, 1, 1, 1, 5])>>> G = graphs.GeneralisedOctagonGraph(Integer(5), Integer(1))>>> G.is_distance_regular(True)([10, 5, 5, 5, None], [None, 1, 1, 1, 2])Note: This function uses the GAP’s AtlasRep package to build the graphs of order (2, 4) or (4, 2). For thosegraphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
static GeneralizedPetersenGraph(n, k)
Returns a generalized Petersen graph with 2𝑛 nodes. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and
0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋
For 𝑘 = 1 the result is a graph isomorphic to the circular ladder graph with the same 𝑛. The regular Petersen
Graph has 𝑛 = 5 and 𝑘 = 2. Other named graphs that can be described using this notation include theDesargues graph and the Möbius-Kantor graph.
INPUT:• n – the number of nodes is 2 * 𝑛.
• k – integer 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. Decides how inner vertices are connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the generalized Petersen graphs are displayed as an inner and outer cycle pair, with the first n nodes
drawn on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise
after that. The inner circle is drawn with the (n)th node at the top, then counterclockwise as well.
EXAMPLES: For 𝑘 = 1 the resulting graph will be isomorphic to a circular ladder graph.
sage: g = graphs.GeneralizedPetersenGraph(13,1)
sage: g2 = graphs.CircularLadderGraph(13)sage: g.is_isomorphic(g2)
True>>> from sage.all import *>>> g = graphs.GeneralizedPetersenGraph(Integer(13),Integer(1))>>> g2 = graphs.CircularLadderGraph(Integer(13))>>> g.is_isomorphic(g2)
True

The Desargues graph:
sage: g = graphs.GeneralizedPetersenGraph(10,3)
sage: g.girth()(continues on next page)2.1. Common graphs861

Graph Theory, Release 10.4

(continued from previous page)6
sage: g.is_bipartite()True>>> from sage.all import *>>> g = graphs.GeneralizedPetersenGraph(Integer(10),Integer(3))>>> g.girth()6>>> g.is_bipartite()
True

AUTHORS:• Anders Jonsson (2009-10-15)
static GeneralizedSierpinskiGraph(G, k, stretch=None)
Return the generalized Sierpinski graph of 𝐺 of dimension 𝑘.
Generalized Sierpinski graphs have been introduced in [GKP2011] to generalize the notion of Sierpinski
graphs [KM1997].
Given a graph 𝐺 = (𝑉, 𝐸) of order 𝑛 and a parameter 𝑘, the generalized Sierpinski graph of 𝐺 of dimension
𝑘, denoted by 𝑆(𝐺, 𝑘), can be constructed recursively from 𝐺 as follows. 𝑆(𝐺, 1) is isomorphic to 𝐺. To
construct 𝑆(𝐺, 𝑘) for 𝑘 > 1, copy 𝑛 times 𝑆(𝐺, 𝑘 − 1), once per vertex 𝑢 ∈ 𝑉 , and add 𝑢 at the beginning of
the labels of each vertex in the copy of 𝑆(𝐺, 𝑘 −1) corresponding to vertex 𝑢. Then for any edge {𝑢, 𝑣} ∈ 𝐸,
add an edge between vertex (𝑢, 𝑣, . . . , 𝑣) and vertex (𝑣, 𝑢, . . . , 𝑢).
INPUT:• G – a sage Graph• k – integer; the dimension• stretch – integer (default: None); stretching factor used to determine the positions of the vertices ofthe output graph. By default (None), this value is set to twice the maximum Euclidean distance between
the vertices of 𝐺. This parameter is used only when the vertices of 𝐺 have positions.
See also:• SierpinskiGasketGraph()• HanoiTowerGraph()
EXAMPLES:
The generalized Sierpinski graph of dimension 1 of any graph 𝐺 is isomorphic to 𝐺:
sage: G = graphs.RandomGNP(10, .5)
sage: S = graphs.GeneralizedSierpinskiGraph(G, 1)
sage: S.is_isomorphic(G)True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(10), RealNumber( .5 ))>>> S = graphs.GeneralizedSierpinskiGraph(G, Integer(1))>>> S.is_isomorphic(G)
TrueWhen 𝐺 is a clique of order 3, the generalized Sierpinski graphs of 𝐺 are isomorphic to Hanoi Tower graphs:
862

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: k = randint(1, 5)
sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k)˓→# needs sage.modules
sage: H = graphs.HanoiTowerGraph(3, k)
sage: S.is_isomorphic(H)˓→# needs sage.modules
True

␣

␣

>>> from sage.all import *>>> k = randint(Integer(1), Integer(5))>>> S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(Integer(3)),␣
˓→k)# needs sage.modules>>> H = graphs.HanoiTowerGraph(Integer(3), k)>>> S.is_isomorphic(H)˓→# needs sage.modules
True

The generalized Sierpinski graph of dimension 𝑘 of any graph 𝐺 with 𝑛 vertices and 𝑚 edges has 𝑛𝑘 vertices∑︀𝑘−1
and 𝑚 𝑖=0 𝑛𝑖 edges:
sage: # needs sage.modules
sage: n = randint(2, 6)
sage: k = randint(1, 5)
sage: G = graphs.RandomGNP(n, .5)
sage: m = G.size()
sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == m*sum([n**i for i in range(k)])
Truesage: G = graphs.CompleteGraph(n)sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)])
True>>> from sage.all import *>>> # needs sage.modules>>> n = randint(Integer(2), Integer(6))>>> k = randint(Integer(1), Integer(5))>>> G = graphs.RandomGNP(n, RealNumber( .5 ))>>> m = G.size()>>> S = graphs.GeneralizedSierpinskiGraph(G, k)>>> S.order() == n**k
True>>> S.size() == m*sum([n**i for i in range(k)])
True>>> G = graphs.CompleteGraph(n)>>> S = graphs.GeneralizedSierpinskiGraph(G, k)>>> S.order() == n**k
True>>> S.size() == (n*(n - Integer(1))/Integer(2))*sum([n**i for i in range(k)])
True

The positions of the vertices of the output graph are determined from the positions of the vertices of 𝐺, ifany:
2.1. Common graphs863

Graph Theory, Release 10.4

sage: G = graphs.HouseGraph()
sage: G.get_pos() is not None
True
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)˓→# needs sage.symbolic
sage: H.get_pos() is not None˓→# needs sage.symbolicTruesage: G = Graph([(0, 1)])
sage: G.get_pos() is not None
False
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)˓→# needs sage.symbolic
sage: H.get_pos() is not None˓→# needs sage.symbolic
False>>> from sage.all import *>>> G = graphs.HouseGraph()>>> G.get_pos() is not None
True>>> H = graphs.GeneralizedSierpinskiGraph(G, Integer(2))˓→# needs sage.symbolic>>> H.get_pos() is not None˓→# needs sage.symbolic
True>>> G = Graph([(Integer(0), Integer(1))])>>> G.get_pos() is not None
False>>> H = graphs.GeneralizedSierpinskiGraph(G, Integer(2))˓→# needs sage.symbolic>>> H.get_pos() is not None˓→# needs sage.symbolic
False

␣
␣

␣
␣

␣

␣

static GoethalsSeidelGraph(k, r)
Returns the graph Goethals-Seidel(𝑘, 𝑟).
The graph Goethals-Seidel(𝑘, 𝑟) comes from a construction presented in Theorem 2.4 of [GS1970]. It relies
on a (v,k)-BIBD with 𝑟 blocks and a hadamard_matrix() of order 𝑟 + 1. The result is a sage.
graphs.strongly_regular_db.strongly_regular_graph() on 𝑣(𝑟 + 1) vertices with degree 𝑘 = (𝑛 + 𝑟 − 1)/2.
It appears under this name in Andries Brouwer’s database of strongly regular graphs.
INPUT:• k, r – integers
See also:• is_goethals_seidel()EXAMPLES:
sage: graphs.GoethalsSeidelGraph(3,3)˓→# needs sage.combinat sage.modules
Graph on 28 vertices␣(continues on next page)

864

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

2.1. Common graphs865

Graph Theory, Release 10.4

(continued from previous page)

sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True)˓→# needs sage.combinat sage.modules(28, 15, 6, 10)>>> from sage.all import *>>> graphs.GoethalsSeidelGraph(Integer(3),Integer(3))˓→# needs sage.combinat sage.modules
Graph on 28 vertices>>> graphs.GoethalsSeidelGraph(Integer(3),Integer(3)).is_strongly_
˓→regular(parameters=True)# needs sage.combinat sage.modules(28, 15, 6, 10)␣␣

static GoldnerHararyGraph()
Return the Goldner-Harary graph.
For more information, see the Wikipedia article Goldner%E2%80%93Harary_graph.
EXAMPLES:The Goldner-Harary graph is named after A. Goldner and Frank Harary. It is a planar graph having 11
vertices and 27 edges:
sage: G = graphs.GoldnerHararyGraph(); G
Goldner-Harary graph: Graph on 11 vertices
sage: G.is_planar()True
sage: G.order()11sage: G.size()27>>> from sage.all import *>>> G = graphs.GoldnerHararyGraph(); G
Goldner-Harary graph: Graph on 11 vertices>>> G.is_planar()
True>>> G.order()11>>> G.size()
27

The Goldner-Harary graph is chordal with radius 2, diameter 2, and girth 3:
sage: G.is_chordal()Truesage: G.radius()
2
sage: G.diameter()2
sage: G.girth()3>>> from sage.all import *>>> G.is_chordal()
True>>> G.radius()(continues on next page)

866

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)2>>> G.diameter()2>>> 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()˓→# needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(6))˓→# needs sage.groups
True

␣
␣

>>> from sage.all import *>>> G.chromatic_number()4>>> ag = G.automorphism_group()
˓→# needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(6)))˓→# needs sage.groups
True␣

static GolombGraph()
Return the Golomb graph.
See the Wikipedia article Golomb_graph for more information.
EXAMPLES:The Golomb graph is a planar and Hamiltonian graph with 10 vertices and 18 edges. It has chromatic number
4, diameter 3, radius 2 and girth 3. It can be drawn in the plane as a unit distance graph:
sage: G = graphs.GolombGraph(); G˓→# needs sage.symbolic
Golomb graph: Graph on 10 vertices
sage: pos = G.get_pos()˓→# needs sage.symbolic
sage: def dist2(u, v):....:
return (u[0]-v[0])**2 + (u[1]-v[1])**2
sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_
˓→iterator(labels=None))# needs sage.symbolic
True

␣

␣

>>> from sage.all import *>>> G = graphs.GolombGraph(); G
˓→# needs sage.symbolic
Golomb graph: Graph on 10 vertices>>> pos = G.get_pos()
˓→# needs sage.symbolic>>> def dist2(u, v):...
return (u[Integer(0)]-v[Integer(0)])**Integer(2) + (u[Integer(1)]˓→v[Integer(1)])**Integer(2)>>> all(dist2(pos[u], pos[v]) == Integer(1) for u, v in G.edge_(continues on next page)2.1. Common graphs867

Graph Theory, Release 10.4

(continued from previous page)

iterator(labels=None))True˓→# needs sage.symbolic

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(); gGosset Graph: Graph on 56 vertices
sage: g.order(), g.size()(56, 756)>>> from sage.all import *>>> g = graphs.GossetGraph(); gGosset Graph: Graph on 56 vertices>>> g.order(), g.size()(56, 756)

static GrassmannGraph(q, n, input_e)
Return the Grassmann graph with parameters (𝑞, 𝑛, 𝑒).
This builds the Grassmann graph 𝐽𝑞 (𝑛, 𝑒). That is, for a vector space 𝑉 = F(𝑞)𝑛 the output is the graph on
the subspaces of dimension 𝑒 where two subspaces are adjacent if their intersection has dimension 𝑒 − 1.
[︀]︀This graph is distance-regular with classical parameters (min(𝑒, 𝑛 − 𝑒), 𝑞, 𝑞, 𝑛−𝑒+1− 1)1𝑞INPUT:• q – a prime power• n, e – integers with 𝑛 > 𝑒 + 1
EXAMPLES:
sage: G = graphs.GrassmannGraph(2, 4, 2)˓→# needs sage.modules sage.rings.finite_rings
sage: G.is_distance_regular(True)˓→# needs sage.modules sage.rings.finite_rings([18, 8, None], [None, 1, 9])>>> from sage.all import *>>> G = graphs.GrassmannGraph(Integer(2), Integer(4), Integer(2))˓→# needs sage.modules sage.rings.finite_rings>>> G.is_distance_regular(True)
˓→# needs sage.modules sage.rings.finite_rings([18, 8, None], [None, 1, 9])␣␣␣

REFERENCES:
See [BCN1989] pp. 268-272 or [VDKT2016] p. 21.
static GrayGraph(embedding=1)
Return the Gray graph.
See the Wikipedia article Gray_graph.
868

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.GrayGraph()
sage: g.order()54
sage: g.size()81
sage: g.girth()8
sage: g.diameter()6
sage: g.show(figsize=[10, 10])# long time˓→# needs sage.plot
sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10])˓→needs sage.plot

␣# long time,␣

>>> from sage.all import *>>> # needs networkx>>> g = graphs.GrayGraph()>>> g.order()54>>> g.size()81>>> g.girth()8>>> g.diameter()6>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot>>> graphs.GrayGraph(embedding=Integer(2)).show(figsize=[Integer(10),␣
˓→Integer(10)])# long time, needs sage.plot

␣

static Grid2dGraph(p, q, set_positions=True)
Return a 2-dimensional grid graph with 𝑝 × 𝑞 nodes (𝑝 rows and 𝑞 columns).
A 2d grid graph resembles a 2 dimensional grid. All inner nodes are connected to their 4 neighbors. Outer(non-corner) nodes are connected to their 3 neighbors. Corner nodes are connected to their 2 neighbors.
INPUT:• p and q – two positive integers• set_positions – boolean (default: True); whether to set the position of the nodes
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, nodes are labelled in (row, column) pairs with (0, 0) in the top left corner. Edges will always be
horizontal and vertical - another advantage of filling the position dictionary.
EXAMPLES:
Construct and show a grid 2d graph Rows = 5, Columns = 7:
sage: g = graphs.Grid2dGraph(5,7)
sage: g.show()˓→# needs sage.plot

2.1. Common graphs# long time␣869

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5),Integer(7))>>> g.show()# long time
˓→# needs sage.plot

static GridGraph(dim_list)
Return an 𝑛-dimensional grid graph.
INPUT:• dim_list – a list of integers representing the number of nodes toextend 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()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> G = graphs.GridGraph([Integer(2),Integer(3),Integer(4)])>>> G.show()# long time
˓→# needs sage.plot
sage: C = graphs.CubeGraph(4)sage: G = graphs.GridGraph([2,2,2,2])
sage: C.show()˓→# needs sage.plot
sage: G.show()˓→# needs sage.plot# long time␣# long time␣>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(4))>>> G = graphs.GridGraph([Integer(2),Integer(2),Integer(2),Integer(2)])>>> C.show()# long time
˓→# needs sage.plot>>> G.show()# long time
˓→# needs sage.plot

static GritsenkoGraph()
Return SRG(65, 32, 15, 16) constructed by Gritsenko.
We took the adjacency matrix from O. Gritsenko’s [Gri2021] and extracted orbits of the automorphism groupon the edges.
EXAMPLES:
sage: H = graphs.GritsenkoGraph(); H˓→# needs sage.groups
Gritsenko strongly regular graph: Graph on 65 vertices
sage: H.is_strongly_regular(parameters=True)˓→# needs sage.groups(65, 32, 15, 16)

870

␣

␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> H = graphs.GritsenkoGraph(); H
˓→# needs sage.groups
Gritsenko strongly regular graph: Graph on 65 vertices>>> H.is_strongly_regular(parameters=True)
˓→# needs sage.groups(65, 32, 15, 16)

static GrotzschGraph()
Return the Grötzsch graph.
The Grötzsch graph is an example of a triangle-free graph with chromatic number equal to 4. For more
information, see the Wikipedia article Gr%C3%B6tzsch_graph.
EXAMPLES:The Grötzsch graph is named after Herbert Grötzsch. It is a Hamiltonian graph with 11 vertices and 20 edges:
sage: G = graphs.GrotzschGraph(); G
Grotzsch graph: Graph on 11 vertices
sage: G.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: G.order()11sage: G.size()20␣>>> from sage.all import *>>> G = graphs.GrotzschGraph(); G
Grotzsch graph: Graph on 11 vertices>>> G.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> G.order()11>>> 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>>> from sage.all import *>>> G.is_triangle_free()True>>> G.radius()
2>>> G.diameter()2(continues on next page)2.1. Common graphs871

Graph Theory, Release 10.4

(continued from previous page)>>> 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()˓→# needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(5))˓→# needs sage.groups
True

␣
␣

>>> from sage.all import *>>> G.chromatic_number()4>>> ag = G.automorphism_group()
˓→# needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(5)))˓→# needs sage.groups
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 [BL1984] one finds a construction of a strongly regular graph withparameters (𝑞 2 (𝑞 + 2), 𝑞 2 + 𝑞 − 1, 𝑞 − 2, 𝑞) from the graph of 𝑇2* (𝑞)* , constructed by T2starGeneralizedQuadrangleGraph(), by redefining adjacencies in the way specified by an arbitrary hyperoval_matching of the points (i.e. partitioning into size two parts) of hyperoval defining 𝑇2* (𝑞)* .
While [BL1984] gives the construction in geometric terms, it can be formulated, and is implemented, ingraph-theoretic ones, of re-adjusting the edges. Namely, 𝐺 = 𝑇2* (𝑞)* has a partition into 𝑞 + 2 independent
sets 𝐼𝑘 of size 𝑞 2 each. Each vertex in 𝐼𝑗 is adjacent to 𝑞 vertices from 𝐼𝑘 . Each 𝐼𝑘 is paired to some 𝐼𝑘′ ,according to hyperoval_matching. One adds edges (𝑠, 𝑡) for 𝑠, 𝑡 ∈ 𝐼𝑘 whenever 𝑠 and 𝑡 are adjacent
to some 𝑢 ∈ 𝐼𝑘′ , and removes all the edges between 𝐼𝑘 and 𝐼𝑘′ .
INPUT:• q – a power of two• hyperoval_matching – if None (default), pair each 𝑖-th point of hyperoval with (𝑖 + 1)-th.
Otherwise, specifies the pairing in the format ((𝑖1 , 𝑖′1 ), (𝑖2 , 𝑖′2 ), ...).
• hyperoval – a hyperoval defining 𝑇2* (𝑞)* . If None (default), the classical hyperoval obtained from a
conic is used. See the documentation of T2starGeneralizedQuadrangleGraph(), for more
information.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness ornot
EXAMPLES:
using the built-in constructions:872

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.combinat sage.rings.finite_rings
sage: g = graphs.HaemersGraph(4); g
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)(96, 19, 2, 4)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.HaemersGraph(Integer(4)); g
Haemers(4): Graph on 96 vertices>>> g.is_strongly_regular(parameters=True)(96, 19, 2, 4)

supplying your own hyperoval_matching:sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.HaemersGraph(Integer(4), hyperoval_matching=((Integer(0),˓→Integer(5)),(Integer(1),Integer(4)),(Integer(2),Integer(3)))); g
Haemers(4): Graph on 96 vertices>>> g.is_strongly_regular(parameters=True)(96, 19, 2, 4)

static HalfCube(n)Return the halved cube in 𝑛 dimensions.
The graph is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 1, 2, 2⌈ 𝑛2 ⌉ − 1).
INPUT:• n – integer; must be greater than 2
EXAMPLES:
sage: G = graphs.HalfCube(8)sage: G.is_distance_regular(True)([28, 15, 6, 1, None], [None, 1, 6, 15, 28])
sage: G = graphs.HalfCube(4)sage: G.is_distance_regular(True)([6, 1, None], [None, 1, 6])>>> from sage.all import *>>> G = graphs.HalfCube(Integer(8))>>> G.is_distance_regular(True)([28, 15, 6, 1, None], [None, 1, 6, 15, 28])>>> G = graphs.HalfCube(Integer(4))>>> G.is_distance_regular(True)([6, 1, None], [None, 1, 6])

REFERENCES:

2.1. Common graphs873

Graph Theory, Release 10.4

See [BCN1989] pp. 264, 265 or [VDKT2016] p. 21. This construction can be found on Wikipedia article
Halved_cube_graph#Equivalent_constructions
static HallJankoGraph(from_string=True)
Return the Hall-Janko graph.
For more information on the Hall-Janko graph, see the Wikipedia article Hall-Janko_graph.
The construction used to generate this graph in Sage is by a 100-point permutation representation of the Jankogroup 𝐽2 , as described in version 3 of the ATLAS of Finite Group representations, in particular on the page
ATLAS: J2 – Permutation representation on 100 points.
INPUT:• from_string – boolean (default: True); whether to build the graph from its sparse6 string or through
GAP. The two methods return the same graph though doing it through GAP takes more time.
EXAMPLES:
sage: g = graphs.HallJankoGraph()
sage: g.is_regular(36)True
sage: g.is_vertex_transitive()˓→# needs sage.groupsTrue␣>>> from sage.all import *>>> g = graphs.HallJankoGraph()>>> g.is_regular(Integer(36))
True>>> g.is_vertex_transitive()
˓→# needs sage.groups
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
>>> from sage.all import *>>> nu = set(g.neighbors(Integer(0)))>>> for v in range(Integer(1), Integer(100)):...
if v in nu:...
expected = Integer(14)
...
else:
...
expected = Integer(12)...
nv = set(g.neighbors(v))...
nv.discard(Integer(0))...
if len(nu & nv) != expected:(continues on next page)874

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

...
...

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())˓→# needs sage.libs.pari sage.modules(x - 36) * (x - 6)^36 * (x + 4)^63␣>>> from sage.all import *>>> g.diameter()2>>> g.girth()3>>> factor(g.characteristic_polynomial())
˓→# needs sage.libs.pari sage.modules(x - 36) * (x - 6)^36 * (x + 4)^63

static HammingGraph(n, q, X=None)
Return the Hamming graph with parameters 𝑛, 𝑞 over 𝑋.
Hamming graphs are graphs over the cartesian product of n copies of 𝑋, 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 𝑋.
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 theunderlying 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()˓→# needs sage.groupsTrue

2.1. Common graphs␣875

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.HammingGraph(Integer(3), Integer(7))>>> g.is_distance_regular()True>>> g.is_regular()True>>> g.is_vertex_transitive()
˓→# needs sage.groups
True

A Hamming graph with parameters (1, 𝑞) is isomorphic to the Complete graph with parameter 𝑞:
sage: g = graphs.HammingGraph(1, 23)
sage: g.is_isomorphic(graphs.CompleteGraph(23))
True>>> from sage.all import *>>> g = graphs.HammingGraph(Integer(1), Integer(23))>>> g.is_isomorphic(graphs.CompleteGraph(Integer(23)))
True

If a parameter 𝑞 is provided which is not equal to 𝑋’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>>> from sage.all import *>>> X = [ a , b , c , d , e ]>>> g = graphs.HammingGraph(Integer(2), Integer(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_graphstatic HanoiTowerGraph(pegs, disks, labels=True, positions=True)
Returns the graph whose vertices are the states of the Tower of Hanoi puzzle, with edges representing legal
moves between states.
INPUT:• pegs – the number of pegs in the puzzle, 2 or greater• disks – the number of disks in the puzzle, 1 or greater• labels – default: True, if True the graph contains more meaningful labels, see explanation below.
For large instances, turn off labels for much faster creation of the graph.
• positions – default: True, if True the graph contains layout information. This creates a planar
layout for the case of three pegs. For large instances, turn off layout information for much faster creationof the graph.
OUTPUT:

876

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

The Tower of Hanoi puzzle has a certain number of identical pegs and a certain number of disks, each of adifferent 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 wherethat 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 ison 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 (theempty) peg 1. So the solution to a 3-disk puzzle (with at least two pegs) can be expressed by the shortest
path between (0,0,0) and (1,1,1). For more on this representation of the graph, or its properties, see[AD2010].
For greatest speed we create graphs with integer vertices, where we encode the tuples as integers with a baseequal 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 offlabels 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 thatis output.
See also:• GeneralizedSierpinskiGraph()
PLOTTING:
The layout computed when positions = True will look especially good for the three-peg case, when
the graph is known to be planar. Except for two small cases on 4 pegs, the graph is otherwise not planar, andlikely 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 numberof 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>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(3), Integer(5), labels=False,␣
˓→positions=False)>>> H.distance(Integer(0), Integer(3)**Integer(5)-Integer(1))
31

A slightly larger instance.

2.1. Common graphs877

Graph Theory, Release 10.4

sage: H = graphs.HanoiTowerGraph(4, 6, labels=False, positions=False)
sage: H.num_verts()
4096
sage: H.distance(0, 4^6-1)
17>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(4), Integer(6), labels=False,␣
˓→positions=False)>>> H.num_verts()
4096>>> H.distance(Integer(0), Integer(4)**Integer(6)-Integer(1))
17

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)]>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(3), Integer(3), labels=True,␣
˓→positions=True)>>> H.shortest_path((Integer(0),Integer(0),Integer(0)), (Integer(1),˓→Integer(1),Integer(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))˓→# needs sage.groupsTrue
sage: H.chromatic_number()3
sage: len(H.independent_set()) == 3^(4-1)
True>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(3), Integer(4), labels=False,␣
˓→positions=False)>>> H.automorphism_group().is_isomorphic(SymmetricGroup(Integer(3)))˓→# needs sage.groups
True>>> H.chromatic_number()3>>> len(H.independent_set()) == Integer(3)**(Integer(4)-Integer(1))
True

878

␣

␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

AUTHOR:• Rob Beezer, (2009-12-26), with assistance from Su Doreestatic 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 ofedges 𝐺 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 [West2001] or
the MathWorld article on Harary graphs.
EXAMPLES:
Harary graphs 𝐻𝑘,𝑛 :sage: h = graphs.HararyGraph(5,9); hHarary graph 5, 9: Graph on 9 vertices
sage: h.order()9sage: h.size()23
sage: h.vertex_connectivity()˓→# needs sage.numerical.mip
5␣>>> from sage.all import *>>> h = graphs.HararyGraph(Integer(5),Integer(9)); hHarary graph 5, 9: Graph on 9 vertices>>> h.order()9>>> h.size()23>>> h.vertex_connectivity()
˓→# needs sage.numerical.mip
5

static HarborthGraph()
Return the Harborth Graph.
The Harborth graph has 104 edges and 52 vertices, and is the smallest known example of a 4-regular matchstick graph. For more information, see the Wikipedia article Harborth_graph.
EXAMPLES:
sage: g = graphs.HarborthGraph(); gHarborth Graph: Graph on 52 vertices
sage: g.is_regular(4)True>>> from sage.all import *>>> g = graphs.HarborthGraph(); gHarborth Graph: Graph on 52 vertices>>> g.is_regular(Integer(4))
True

2.1. Common graphs879

Graph Theory, Release 10.4

static HarriesGraph(embedding=1)
Return the Harries Graph.
The Harries graph is a Hamiltonian 3-regular graph on 70 vertices. See the Wikipedia article Harries_graph.
The default embedding here is to emphasize the graph’s 4 orbits. This graph actually has a funny construction.
The following procedure gives an idea of it, though not all the adjacencies are being properly defined.
1. Take two disjoint copies of a Petersen graph. Their vertices will form an orbit of the final graph.
2. Subdivide all the edges once, to create 15+15=30 new vertices, which together form another orbit.
3. Create 15 vertices, each of them linked to 2 corresponding vertices of the previous orbit, one in eachof the two subdivided Petersen graphs. At the end of this step all vertices from the previous orbit havedegree 3, and the only vertices of degree 2 in the graph are those that were just created.
4. Create 5 vertices connected only to the ones from the previous orbit so that the graph becomes 3-regular.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.HarriesGraph()
sage: g.order()70sage: g.size()105
sage: g.girth()10
sage: g.diameter()6
sage: g.show(figsize=[10, 10])# long time˓→# needs sage.plot
sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10])˓→needs sage.plot

␣# long time,␣

>>> from sage.all import *>>> # needs networkx>>> g = graphs.HarriesGraph()>>> g.order()70>>> g.size()105>>> g.girth()
10>>> g.diameter()6>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot>>> graphs.HarriesGraph(embedding=Integer(2)).show(figsize=[Integer(10),␣
˓→Integer(10)])# long time, needs sage.plot

␣

static HarriesWongGraph(embedding=1)
Return the Harries-Wong Graph.
See the Wikipedia article Harries-Wong_graph.

880

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

About the default embedding:
The default embedding is an attempt to emphasize the graph’s 8 (!!!) different orbits. In order to understandthis better, one can picture the graph as being built in the following way.
1. One first creates a 3-dimensional cube (8 vertices, 12 edges), whose vertices define the first orbit of the
final graph.
2. The edges of this graph are subdivided once, to create 12 new vertices which define a second orbit.
3. The edges of the graph are subdivided once more, to create 24 new vertices giving a third orbit.
4. 4 vertices are created and made adjacent to the vertices of the second orbit so that they have degree 3.
These 4 vertices also define a new orbit.
5. In order to make the vertices from the third orbit 3-regular (they all miss one edge), one creates a binary
tree on 1 + 3 + 6 + 12 vertices. The leaves of this new tree are made adjacent to the 12 vertices of thethird orbit, and the graph is now 3-regular. This binary tree contributes 4 new orbits to the Harries-Wonggraph.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.HarriesWongGraph()
sage: g.order()70sage: g.size()105
sage: g.girth()10
sage: g.diameter()6
sage: orbits = g.automorphism_group(orbits=True)[-1]˓→# needs sage.groups
sage: g.show(figsize=[15, 15], partition=orbits)˓→# needs sage.groups sage.plot# long time␣# long time␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.HarriesWongGraph()>>> g.order()70>>> g.size()105>>> g.girth()
10>>> g.diameter()6>>> orbits = g.automorphism_group(orbits=True)[-Integer(1)]# long time˓→# needs sage.groups>>> g.show(figsize=[Integer(15), Integer(15)], partition=orbits)#␣˓→long time
# needs sage.groups sage.plot

␣Alternative embedding:

2.1. Common graphs881

Graph Theory, Release 10.4

sage: graphs.HarriesWongGraph(embedding=2).show()˓→# needs networkx sage.plot>>> from sage.all import *>>> graphs.HarriesWongGraph(embedding=Integer(2)).show()˓→# needs networkx sage.plot# long time

# long time␣␣

static HeawoodGraph()
Return a Heawood graph.
The Heawood graph is a cage graph that has 14 nodes. It is a cubic symmetric graph. (See also the
Möbius-Kantor graph, MobiusKantorGraph()). It is nonplanar and Hamiltonian. It has diameter 3,
radius 3, girth 6, and chromatic number 2. It is 4-transitive but not 5-transitive. See the Wikipedia article
Heawood_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the nodes are positioned in a circular layout with the first node appearing at the top, and thencontinuing 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()˓→# needs sage.plot>>> from sage.all import *>>> H = graphs.HeawoodGraph()>>> H
Heawood graph: Graph on 14 vertices>>> H.graph6_string()
MhEGHC@AI?_PC@_G_>>> (graphs.HeawoodGraph()).show()˓→# needs sage.plot# long time␣# long time

static HermitianFormsGraph(n, r)
Return the Hermitian forms graph with the given parameters.
We build a graph whose vertices are all 𝑛 × 𝑛 Hermitian matrices over GF(r^2). Two vertices are adjacentif the difference of the two vertices has rank 1.
This graph is distance-regular with classical parameters (𝑛, −𝑟, −𝑟 − 1, −(−𝑟)𝑑 − 1).
INPUT:• n – integer• r – a prime power
EXAMPLES:
sage: # needs sage.modules sage.rings.finite_rings
sage: G = graphs.HermitianFormsGraph(2, 2)
sage: G.is_distance_regular(True)([5, 4, None], [None, 1, 2])(continues on next page)882

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: G = graphs.HermitianFormsGraph(3, 3)# not tested (2 min)sage: G.order()# not tested (bacuase of the above)
19683>>> from sage.all import *>>> # needs sage.modules sage.rings.finite_rings>>> G = graphs.HermitianFormsGraph(Integer(2), Integer(2))>>> G.is_distance_regular(True)([5, 4, None], [None, 1, 2])>>> G = graphs.HermitianFormsGraph(Integer(3), Integer(3))# not tested␣
˓→(2 min)>>> G.order()# not tested (bacuase of the above)
19683

REFERENCES:
See [BCN1989] p. 285 or [VDKT2016] p. 22.
static HerschelGraph()
Return the Herschel graph.
For more information, see the Wikipedia article Herschel_graph.
EXAMPLES:
The Herschel graph is named after Alexander Stewart Herschel. It is a planar, bipartite graph with 11 vertices
and 18 edges:
sage: G = graphs.HerschelGraph(); G
Herschel graph: Graph on 11 vertices
sage: G.is_planar()True
sage: G.is_bipartite()True
sage: G.order()11sage: G.size()18>>> from sage.all import *>>> G = graphs.HerschelGraph(); G
Herschel graph: Graph on 11 vertices>>> G.is_planar()
True>>> G.is_bipartite()
True>>> G.order()11>>> 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(continues on next page)2.1. Common graphs883

Graph Theory, Release 10.4

(continued from previous page)

sage: G.diameter()4
sage: G.girth()4>>> from sage.all import *>>> G.is_perfect()True>>> G.radius()
3>>> G.diameter()
4>>> 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()˓→# needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(6))˓→# needs sage.groups
True

␣
␣

>>> from sage.all import *>>> G.chromatic_number()2>>> ag = G.automorphism_group()
˓→# needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(6)))˓→# needs sage.groups
True␣

static HexahedralGraph()
Return a hexahedral graph (with 8 nodes).
A regular hexahedron is a 6-sided cube. The hexahedral graph corresponds to the connectivity of the verticesof the hexahedron. This graph is equivalent to a 3-cube.
PLOTTING: The Hexahedral graph should be viewed in 3 dimensions. We choose to use a planar embeddingof the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will
be added to select the desired layout.
EXAMPLES:
Construct and show a Hexahedral graph:
sage: g = graphs.HexahedralGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.HexahedralGraph()>>> g.show()˓→# needs sage.plot

884# long time␣# long time

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of
the spring-layout algorithm:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.HexahedralGraph()....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.HexahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static HigmanSimsGraph(relabel=True)
Return the Higman-Sims graph.
The Higman-Sims graph is a remarkable strongly regular graph of degree 22 on 100 vertices. For example, it can be split into two sets of 50 vertices each, so that each half induces a subgraph isomorphic
to the Hoffman-Singleton graph (HoffmanSingletonGraph()). This can be done in 352 ways (seeHigman-Sims graph by Andries E. Brouwer, accessed 24 October 2009.)
Its most famous property is that the automorphism group has an index 2 subgroup which is one of the 26
sporadic groups [HS1968].
The construction used here follows [Haf2004].
See also the Wikipedia article Higman–Sims_graph.
INPUT:• relabel – boolean (default: True); whether to relabel the vertices with consecutive integers. If
False the labels are strings that are three digits long. “xyz” means the vertex is in group 𝑥 (zerothrough three), pentagon or pentagram 𝑦 (zero through four), and is vertex 𝑧 (zero through four) of that
pentagon or pentagram. See [Haf2004] for more.
OUTPUT:
The Higman-Sims graph.
EXAMPLES:

2.1. Common graphs885Graph Theory, Release 10.4

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)Truesage: 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>>> from sage.all import *>>> H = graphs.HigmanSimsGraph()>>> A = H.subgraph(range(Integer(0),Integer(50)))>>> B = H.subgraph(range(Integer(50),Integer(100)))>>> K = graphs.HoffmanSingletonGraph()>>> K.is_isomorphic(A) and K.is_isomorphic(B)
True>>> C = H.subgraph(range(Integer(25),Integer(75)))>>> D = H.subgraph(list(range(Integer(0),Integer(25)))+list(range(Integer(75),
˓→Integer(100))))>>> 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 issimple. It is known as the Higman-Sims group:sage: H = graphs.HigmanSimsGraph()
sage: G = H.automorphism_group()˓→# needs sage.groups
sage: g = G.order(); g˓→# needs sage.groups
88704000
sage: K = G.normal_subgroups()[1]˓→# needs sage.groups
sage: K.is_simple()˓→# needs sage.groupsTrue
sage: g//K.order()˓→# needs sage.groups2>>> from sage.all import *>>> H = graphs.HigmanSimsGraph()>>> G = H.automorphism_group()
˓→# needs sage.groups>>> g = G.order(); g˓→# needs sage.groups
88704000>>> K = G.normal_subgroups()[Integer(1)]˓→# needs sage.groups>>> K.is_simple()˓→# needs sage.groups
True

␣
␣

␣
␣

␣

␣

(continues on next page)

886

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g//K.order()˓→# needs sage.groups
2

AUTHOR:• Rob Beezer (2009-10-24)
static HoffmanGraph()
Return the Hoffman Graph.
See the Wikipedia article Hoffman_graph.
EXAMPLES:
sage: g = graphs.HoffmanGraph()
sage: g.is_bipartite()True
sage: g.is_hamiltonian()# long time˓→# needs sage.numerical.mip
True
sage: g.radius()
3
sage: g.diameter()4
sage: g.automorphism_group().cardinality()˓→# needs sage.groups
48

␣

␣

>>> from sage.all import *>>> g = graphs.HoffmanGraph()>>> g.is_bipartite()True>>> g.is_hamiltonian()# long time
˓→# needs sage.numerical.mip
True>>> g.radius()
3>>> g.diameter()4>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
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 withgirth 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 distanceregular.
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.
2.1. Common graphs887

Graph Theory, Release 10.4

EXAMPLES:
sage: HS = graphs.HoffmanSingletonGraph()
sage: Set(HS.degree()){7}
sage: HS.girth()5
sage: HS.diameter()2
sage: HS.num_verts()
50>>> from sage.all import *>>> HS = graphs.HoffmanSingletonGraph()>>> Set(HS.degree()){7}>>> HS.girth()5>>> HS.diameter()2>>> HS.num_verts()
50

Note that you get a different layout each time you create the graph.
sage: HS.layout()[1] # random(-0.844..., 0.535...)sage: HS = graphs.HoffmanSingletonGraph()
sage: HS.layout()[1] # random(-0.904..., 0.425...)>>> from sage.all import *>>> HS.layout()[Integer(1)] # random(-0.844..., 0.535...)>>> HS = graphs.HoffmanSingletonGraph()>>> HS.layout()[Integer(1)] # random(-0.904..., 0.425...)static HoltGraph()
Return the Holt graph (also called the Doyle graph).
See the Wikipedia article Holt_graph.
EXAMPLES:
sage: g = graphs.HoltGraph();gHolt graph: Graph on 27 vertices
sage: g.is_regular()True
sage: g.is_vertex_transitive()˓→# needs sage.groupsTrue
sage: g.chromatic_number()3
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: g.radius()␣# long time␣(continues on next page)

888

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)3
sage: g.diameter()3
sage: g.girth()5
sage: g.automorphism_group().cardinality()˓→# needs sage.groups54␣>>> from sage.all import *>>> g = graphs.HoltGraph();gHolt graph: Graph on 27 vertices>>> g.is_regular()True>>> g.is_vertex_transitive()
˓→# needs sage.groupsTrue>>> g.chromatic_number()3>>> g.is_hamiltonian()# long time
˓→# needs sage.numerical.mip
True>>> g.radius()
3>>> g.diameter()3>>> g.girth()5>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
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: # needs networkx
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)␣(continues on next page)2.1. Common graphs889

Graph Theory, Release 10.4

(continued from previous page)# needs sage.numerical.mip
False
˓→

>>> from sage.all import *>>> # needs networkx>>> g = graphs.HortonGraph()>>> g.order()96>>> g.size()144>>> g.radius()
10>>> g.diameter()
10>>> g.girth()6>>> g.automorphism_group().cardinality()96>>> g.chromatic_number()2>>> g.is_hamiltonian()# not tested (veeeery long)
˓→# needs sage.numerical.mip
False

static HouseGraph()
Return a house graph with 5 nodes.
A house graph is named for its shape. It is a triangle (roof) over a square (walls).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the house graph is drawn with the first node in the lower-left corner of the house, the second in
the lower-right corner of the house. The third node is in the upper-left corner connecting the roof to the wall,and the fourth is in the upper-right corner connecting the roof to the wall. The fifth node is the top of theroof, connected only to the third and fourth.
EXAMPLES:
Construct and show a house graph:
sage: g = graphs.HouseGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.HouseGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

static HouseXGraph()
Return a house X graph with 5 nodes.
A house X graph is a house graph with two additional edges. The upper-right corner is connected to thelower-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 secondin the lower-right corner of the house. The third node is in the upper-left corner connecting the roof to the890

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.HouseXGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

static HyperStarGraph(n, k)
Return the hyper-star graph 𝐻𝑆(𝑛, 𝑘).
The vertices of the hyper-star graph are the set of binary strings of length 𝑛 which contain 𝑘 1s. Two vertices, 𝑢and 𝑣, are adjacent only if 𝑢 can be obtained from 𝑣 by swapping the first bit with a different symbol in anotherposition. For instance, vertex 011100 of 𝐻𝑆(6, 3) is adjacent to vertices 101100 , 110100 and
111000 . See [LKOL2002] for more details.
INPUT:• n – non-negative integer; length of the binary strings• k – non-negative integer; number of 1s per binary string
EXAMPLES:
sage: g = graphs.HyperStarGraph(6,3)
sage: sorted(g.neighbors( 011100 ))[ 101100 , 110100 , 111000 ]sage: g.plot()# long time˓→# needs sage.plot
Graphics object consisting of 51 graphics primitives␣>>> from sage.all import *>>> g = graphs.HyperStarGraph(Integer(6),Integer(3))>>> sorted(g.neighbors( 011100 ))[ 101100 , 110100 , 111000 ]>>> g.plot()# long time
˓→# needs sage.plot
Graphics object consisting of 51 graphics primitives

AUTHORS:• Michael Yurko (2009-09-01)
static IGraph(n, j, k)
Return an I-graph with 2𝑛 nodes.
The I-Graph family as been proposed in [BCMS1988] as a generalization of the generalized Petersen graphs.
The variables 𝑛, 𝑗, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑗, 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. When 𝑗 = 1 the resulting
graph is isomorphic to the generalized Petersen graph with the same 𝑛 and 𝑘.
INPUT:• n – the number of nodes is 2 * 𝑛
2.1. Common graphs891

Graph Theory, Release 10.4

• j – integer such that 0 < 𝑗 ≤ ⌊(𝑛 − 1)/2⌋ determining how outer vertices are connected• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the I-graphs are displayed as an inner and outer cycle pair, with the first n nodes drawn on theouter circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that.
The inner circle is drawn with the (n)th node at the top, then counterclockwise as well.
EXAMPLES:
When 𝑗 = 1 the resulting graph will be isomorphic to a generalized Petersen graph:
sage: g = graphs.IGraph(7,1,2)
sage: g2 = graphs.GeneralizedPetersenGraph(7,2)
sage: g.is_isomorphic(g2)
True>>> from sage.all import *>>> g = graphs.IGraph(Integer(7),Integer(1),Integer(2))>>> g2 = graphs.GeneralizedPetersenGraph(Integer(7),Integer(2))>>> g.is_isomorphic(g2)
True

The IGraph with parameters (𝑛, 𝑗, 𝑘) is isomorphic to the IGraph with parameters (𝑛, 𝑘, 𝑗):sage: g = graphs.IGraph(7, 2, 3)
sage: h = graphs.IGraph(7, 3, 2)
sage: g.is_isomorphic(h)True>>> from sage.all import *>>> g = graphs.IGraph(Integer(7), Integer(2), Integer(3))>>> h = graphs.IGraph(Integer(7), Integer(3), Integer(2))>>> g.is_isomorphic(h)Truestatic IcosahedralGraph()
Return an Icosahedral graph (with 12 nodes).
The regular icosahedron is a 20-sided triangular polyhedron. The icosahedral graph corresponds to the connectivity of the vertices of the icosahedron. It is dual to the dodecahedral graph. The icosahedron is symmetric, so the spring-layout algorithm will be very effective for display.
PLOTTING: The Icosahedral graph should be viewed in 3 dimensions. We choose to use a planar embeddingof the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will
be added to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.IcosahedralGraph()
sage: g.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> g = graphs.IcosahedralGraph()(continues on next page)892

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.show()˓→# needs sage.plot# 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: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.IcosahedralGraph()....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.IcosahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static IntersectionGraph(S)Return the intersection graph of the family 𝑆
The intersection graph of a family 𝑆 is a graph 𝐺 with 𝑉 (𝐺) = 𝑆 such that two elements 𝑠1 , 𝑠2 ∈ 𝑆 are
adjacent in 𝐺 if and only if 𝑠1 ∩ 𝑠2 ̸= ∅.
INPUT:• S – a list of sets/tuples/iterables
Note: The elements of 𝑆 must be finite, hashable, and the elements of any 𝑠 ∈ 𝑆 must be
hashable too.
EXAMPLES:
sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)])Intersection Graph: Graph on 3 vertices

2.1. Common graphs893

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.IntersectionGraph([(Integer(1),Integer(2),Integer(3)),(Integer(3),˓→Integer(4),Integer(5)),(Integer(5),Integer(6),Integer(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 graphand can be recovered using get_vertex() or get_vertices().
EXAMPLES:
The following line creates the sequence of intervals (𝑖, 𝑖 + 2) for i in [0, ..., 8]:
sage: intervals = [(i,i+2) for i in range(9)]>>> from sage.all import *>>> intervals = [(i,i+Integer(2)) for i in range(Integer(9))]

In the corresponding graphsage: 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)>>> from sage.all import *>>> g = graphs.IntervalGraph(intervals)>>> g.get_vertex(Integer(3))(3, 5)>>> neigh = g.neighbors(Integer(3))>>> 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.

894

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: g.is_interval()
True>>> from sage.all import *>>> 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)}>>> from sage.all import *>>> intervals = [ (Integer(1),Integer(2)), (Integer(1),Integer(2)),␣
˓→(Integer(1),Integer(2)), (Integer(2),Integer(3)), (Integer(3),Integer(4)) ]>>> g = graphs.IntervalGraph(intervals,True)>>> g.clique_maximum()[0, 1, 2, 3]>>> 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(sort=True) == h.edges(sort=True)
True>>> from sage.all import *>>> rev_intervals = [ (Integer(2),Integer(1)), (Integer(2),Integer(1)),␣
˓→(Integer(2),Integer(1)), (Integer(3),Integer(2)), (Integer(4),Integer(3)) ]>>> h = graphs.IntervalGraph(rev_intervals,False)>>> h.get_vertices(){0: (2, 1), 1: (2, 1), 2: (2, 1), 3: (3, 2), 4: (4, 3)}>>> g.edges(sort=True) == h.edges(sort=True)
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 theconstruction in the latter did not work, however. This function implements the following instructions, sharedby Yury Ionin and Hadi Kharaghani.
Let 𝐴 be the affine plane over the field 𝐺𝐹 (3) = {−1, 0, 1}. Let
𝜑1 (𝑥, 𝑦) = 𝑥
𝜑2 (𝑥, 𝑦) = 𝑦𝜑3 (𝑥, 𝑦) = 𝑥 + 𝑦
𝜑4 (𝑥, 𝑦) = 𝑥 − 𝑦2.1. Common graphs895

Graph Theory, Release 10.4

For 𝑖 = 1, 2, 3, 4 and 𝑗 ∈ 𝐺𝐹 (3), let 𝐿𝑖,𝑗 be the line in 𝐴 defined by 𝜑𝑖 (𝑥, 𝑦) = 𝑗. Let ℳ be the setof all 12 lines 𝐿𝑖,𝑗 , plus the empty set. Let 𝜋 be the permutation defined on ℳ by 𝜋(𝐿𝑖,𝑗 ) = 𝐿𝑖,𝑗+1
and 𝜋(∅) = ∅, so that 𝜋 has three orbits of cardinality 3 and one of cardinality 1.
Let 𝐴 = (𝑝1 , ..., 𝑝9 ) with 𝑝1 = (−1, 1), 𝑝2 = (−1, 0), 𝑝3 = (−1, 1), 𝑝4 = (0, −1), 𝑝5 = (0, 0),
𝑝6 = (0, 1), 𝑝7 = (1, −1), 𝑝8 = (1, 0), 𝑝9 = (1, 1). Note that 𝑝𝑖 + 𝑝10−𝑖 = (0, 0). For any
subset 𝑋 of 𝐴, let 𝑀 (𝑋) be the (0, 1)-matrix of order 9 whose (𝑖, 𝑗)-entry equals 1 if and only if
𝑝10−𝑖 − 𝑝𝑗 ∈ 𝑋. Note that 𝑀 is a symmetric matrix.
An 𝑀 𝐹 -tuple is an ordered quintuple (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) of subsets of 𝐴, of which one is theempty 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 ) ⎟⎜⎟⎟𝑁 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = ⎜⎜ 𝑀 (𝑋3 ) 𝑀 (𝑋4 ) 𝑀 (𝑋5 ) 𝑀 (𝑋1 ) 𝑀 (𝑋2 ) ⎟⎝ 𝑀 (𝑋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 symmetric 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 𝜔 𝑘 with0 ≤ 𝑘 ≤ 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 thematrix 𝑁 (𝜎 𝑘 (𝑋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, andtherefore 𝑆 is an adjacency matrix of a strongly regular graph with parameters (765, 192, 48, 48).
EXAMPLES:
sage: g = graphs.IoninKharaghani765Graph(); g˓→# needs sage.modules sage.rings.finite_rings
Ionin-Kharaghani: Graph on 765 vertices␣>>> from sage.all import *>>> g = graphs.IoninKharaghani765Graph(); g˓→# needs sage.modules sage.rings.finite_rings
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

896

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

static IvanovIvanovFaradjevGraph()
Return the IvanovIvanovFaradjev graph.
The graph is distance-transitive with automorphism group 3.𝑀22 .
EXAMPLES:
sage: G = graphs.IvanovIvanovFaradjevGraph()# optional - internet␣
˓→gap_package_atlasrep
sage: G.is_distance_regular(True)# optional - internet␣
˓→gap_package_atlasrep([7, 6, 4, 4, 4, 1, 1, 1, None], [None, 1, 1, 1, 2, 4, 4, 6, 7])>>> from sage.all import *>>> G = graphs.IvanovIvanovFaradjevGraph()# optional - internet␣
˓→gap_package_atlasrep>>> G.is_distance_regular(True)# optional - internet␣
˓→gap_package_atlasrep([7, 6, 4, 4, 4, 1, 1, 1, None], [None, 1, 1, 1, 2, 4, 4, 6, 7])

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 369.
static J2Graph()
Return the distance-transitive graph with automorphism group 𝐽2 .
EXAMPLES:
sage: G = graphs.J2Graph()˓→gap_package_atlasrep
sage: G.is_distance_regular(True)
˓→gap_package_atlasrep([10, 8, 8, 2, None], [None, 1, 1, 4, 5])>>> from sage.all import *>>> G = graphs.J2Graph()˓→gap_package_atlasrep>>> G.is_distance_regular(True)
˓→gap_package_atlasrep([10, 8, 8, 2, None], [None, 1, 1, 4, 5])# optional - internet␣
# optional - internet␣

# optional - internet␣
# optional - internet␣

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 408.
static JankoKharaghaniGraph(v)Return a (936, 375, 150, 150)-srg or a (1800, 1029, 588, 588)-srg.
This functions returns a strongly regular graph for the two sets of parameters shown to be realizable in[JK2002]. The paper also uses a construction from [GM1987].
INPUT:• v – integer; one of 936 or 1800
EXAMPLES:

2.1. Common graphs897

Graph Theory, Release 10.4

sage: g = graphs.JankoKharaghaniGraph(936)˓→# needs sage.libs.pari
sage: g.is_strongly_regular(parameters=True)˓→# needs sage.libs.pari(936, 375, 150, 150)

# long time␣# long time␣sage: g = graphs.JankoKharaghaniGraph(1800)
sage: g.is_strongly_regular(parameters=True)(1800, 1029, 588, 588)

# not tested (30s)# not tested (30s)>>> from sage.all import *>>> g = graphs.JankoKharaghaniGraph(Integer(936))# long time˓→# needs sage.libs.pari>>> g.is_strongly_regular(parameters=True)# long time
˓→# needs sage.libs.pari(936, 375, 150, 150)

␣>>> g = graphs.JankoKharaghaniGraph(Integer(1800))# not tested (30s)>>> 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 adjacencies
of vertices 1 and 163, respectively, and taking the edge orbits of the group 𝐺 provided.
EXAMPLES:
sage: Gamma = graphs.JankoKharaghaniTonchevGraph()˓→# needs sage.libs.gap
sage: Gamma.is_strongly_regular(parameters=True)˓→# needs sage.libs.gap(324, 153, 72, 72)>>> from sage.all import *>>> Gamma = graphs.JankoKharaghaniTonchevGraph()˓→# needs sage.libs.gap>>> Gamma.is_strongly_regular(parameters=True)
˓→# needs sage.libs.gap(324, 153, 72, 72)# long time␣# long time␣# long time
# long time

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 theJohnson graph 𝐽(𝑛, 𝑘) are the 𝑘-element subsets of an 𝑛-element set; two vertices are adjacent when theymeet 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()˓→# needs sage.numerical.mip
True

898

␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.JohnsonGraph(Integer(7), Integer(3))>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
True

Every Johnson graph is vertex transitive:
sage: g = graphs.JohnsonGraph(6, 4)
sage: g.is_vertex_transitive()˓→# needs sage.groupsTrue␣>>> from sage.all import *>>> g = graphs.JohnsonGraph(Integer(6), Integer(4))>>> g.is_vertex_transitive()
˓→# needs sage.groups
True

The complement of the Johnson graph 𝐽(𝑛, 2) is isomorphic to the Kneser Graph 𝐾(𝑛, 2). In particular thecomplement of 𝐽(5, 2) is isomorphic to the Petersen graph.:
sage: g = graphs.JohnsonGraph(5,2)
sage: g.complement().is_isomorphic(graphs.PetersenGraph())
True>>> from sage.all import *>>> g = graphs.JohnsonGraph(Integer(5),Integer(2))>>> g.complement().is_isomorphic(graphs.PetersenGraph())
True

static KingGraph(dim_list, radius=None, relabel=False)
Return 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 prescribed dimensions, and each edge corresponds to a legal move by a king in either one or two dimensions.
All 2-dimensional King Graphs are Hamiltonian, biconnected, and have chromatic number 4 as soon as bothdimensions are larger or equal to 2.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of thechessboard• radius – integer (default: None); by setting the radius to a positive integer, one may increase thepower 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 – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (2, 2)-King Graph is isomorphic to the complete graph on 4 vertices:

2.1. Common graphs899

Graph Theory, Release 10.4

sage: G = graphs.QueenGraph( [2, 2] )sage: G.is_isomorphic( graphs.CompleteGraph(4) )True>>> from sage.all import *>>> G = graphs.QueenGraph( [Integer(2), Integer(2)] )>>> G.is_isomorphic( graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> G = graphs.KingGraph( [Integer(5), Integer(4)], radius=Integer(5) )>>> H = graphs.QueenGraph( [Integer(4), Integer(5)] )>>> 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>>> from sage.all import *>>> G = graphs.KingGraph( [Integer(2), Integer(5), Integer(4)],␣
˓→radius=Integer(5) )>>> H = graphs.QueenGraph( [Integer(4), Integer(5), Integer(2)] )>>> G.is_isomorphic( H )Truestatic 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

900

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.KittellGraph()>>> g.order()23>>> g.size()63>>> g.radius()
3>>> g.diameter()4>>> g.girth()3>>> g.chromatic_number()4

static Klein3RegularGraph()
Return the Klein 3-regular graph.
The cubic Klein graph has 56 vertices and can be embedded on a surface of genus 3. It is the dual of
Klein7RegularGraph(). For more information, see the Wikipedia article Klein_graphs.
EXAMPLES:
sage: g = graphs.Klein3RegularGraph(); gKlein 3-regular Graph: Graph on 56 vertices
sage: g.order(), g.size()(56, 84)
sage: g.girth()7
sage: g.automorphism_group().cardinality()˓→# needs sage.groups336
sage: g.chromatic_number()3

␣>>> from sage.all import *>>> g = graphs.Klein3RegularGraph(); gKlein 3-regular Graph: Graph on 56 vertices>>> g.order(), g.size()(56, 84)>>> g.girth()7>>> g.automorphism_group().cardinality()
˓→# needs sage.groups336>>> 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(); gKlein 7-regular Graph: Graph on 24 vertices(continues on next page)2.1. Common graphs901

Graph Theory, Release 10.4

(continued from previous page)

sage: g.order(), g.size()(24, 84)
sage: g.girth()3
sage: g.automorphism_group().cardinality()˓→# needs sage.groups336
sage: g.chromatic_number()4␣>>> from sage.all import *>>> g = graphs.Klein7RegularGraph(); gKlein 7-regular Graph: Graph on 24 vertices>>> g.order(), g.size()(24, 84)>>> g.girth()3>>> g.automorphism_group().cardinality()
˓→# needs sage.groups336>>> g.chromatic_number()4

static KneserGraph(n, k)
Returns the Kneser Graph with parameters 𝑛, 𝑘.
The Kneser Graph with parameters 𝑛, 𝑘 is the graph whose vertices are the 𝑘-subsets of [0, 1, . . . , 𝑛 − 1],and such that two vertices are adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Kneser Graph with parameters 5, 2.
EXAMPLES:
sage: KG = graphs.KneserGraph(5,2)
sage: sorted(KG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(KG)
True>>> from sage.all import *>>> KG = graphs.KneserGraph(Integer(5),Integer(2))>>> sorted(KG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]>>> P = graphs.PetersenGraph()>>> P.is_isomorphic(KG)
True

static KnightGraph(dim_list, one=1, two=2, relabel=False)
Return 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 withprescribed dimensions, and each edge corresponds to a legal move by a knight in any pairs of dimensions.
902

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

The (𝑛, 𝑛)-Knight Graph is Hamiltonian for even 𝑛 > 4.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of thechessboard• one – integer (default: 1); indicates the number of steps in the first dimension• two – integer (default: 2); indicates the number of steps in the second dimension• relabel – boolean (default: False); indicates whether the 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>>> from sage.all import *>>> G = graphs.KnightGraph( [Integer(3), Integer(3)] )>>> G.degree( (Integer(1),Integer(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>>> from sage.all import *>>> G = graphs.KnightGraph( [Integer(3), Integer(3)] )>>> G.delete_vertex( (Integer(1),Integer(1)) )>>> G.is_isomorphic( graphs.CycleGraph(Integer(8)) )True

The (6, 6)-Knight Graph is Hamiltonian:sage: G = graphs.KnightGraph( [6, 6] )sage: G.is_hamiltonian()˓→# needs sage.numerical.mip
True␣

>>> from sage.all import *>>> G = graphs.KnightGraph( [Integer(6), Integer(6)] )>>> G.is_hamiltonian()
˓→# needs sage.numerical.mip
Truestatic KrackhardtKiteGraph()
Return a Krackhardt kite graph with 10 nodes.
The Krackhardt kite graph was originally developed by David Krackhardt for the purpose of studying social
networks (see [Kre2002] and the Wikipedia article Krackhardt_kite_graph). It is used to show the distinction
between degree centrality, betweenness centrality, and closeness centrality. For more information read theplotting section below in conjunction with the example.

2.1. Common graphs903

Graph Theory, Release 10.4

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 eachrow. 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 graphsage: g = graphs.KrackhardtKiteGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.KrackhardtKiteGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

static LCFGraph(n, shift_list, repeats)
Return the cubic graph specified in LCF notation.
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 𝑛 nodes.
The variable shift_list = [𝑠0 , 𝑠1 , ..., 𝑠𝑘−1 ] describes edges to be created by the following scheme: foreach 𝑖 ∈ {0, 1, . . . , 𝑘 − 1}, connect vertex 𝑖 to vertex (𝑖 + 𝑠𝑖 ) (mod 𝑛). Then, repeats specifies thenumber of times to repeat this process, where on the 𝑗-th repeat we connect vertex (𝑖 + 𝑗𝑘) (mod 𝑛) tovertex (𝑖 + 𝑗𝑘 + 𝑠𝑖 ) (mod 𝑛).
For more details, see the Wikipedia article LCF_notation and [Fru1977], [Gru2003] pp. 357-365, and[Led1965].
INPUT:• n – the number of nodes.
• shift_list – a list of integer shifts mod 𝑛.
• repeats – the number of times to repeat the process.
EXAMPLES:
sage: G = graphs.LCFGraph(4, [2,-2], 2)˓→# needs networkx
sage: G.is_isomorphic(graphs.TetrahedralGraph())˓→# needs networkx
True>>> from sage.all import *>>> G = graphs.LCFGraph(Integer(4), [Integer(2),-Integer(2)], Integer(2))˓→# needs networkx>>> G.is_isomorphic(graphs.TetrahedralGraph())˓→# needs networkx
True

904

␣
␣

␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2)˓→# needs networkx
sage: G.is_isomorphic(graphs.DodecahedralGraph())˓→# needs networkx
True

␣
␣

>>> from sage.all import *>>> G = graphs.LCFGraph(Integer(20), [Integer(10),Integer(7),Integer(4),˓→Integer(4),-Integer(7),Integer(10),-Integer(4),Integer(7),-Integer(7),˓→Integer(4)], Integer(2))# needs networkx>>> G.is_isomorphic(graphs.DodecahedralGraph())˓→# needs networkx
True
sage: G = graphs.LCFGraph(14, [5,-5], 7)˓→# needs networkx
sage: G.is_isomorphic(graphs.HeawoodGraph())˓→# needs networkx
True>>> from sage.all import *>>> G = graphs.LCFGraph(Integer(14), [Integer(5),-Integer(5)], Integer(7))˓→# needs networkx>>> G.is_isomorphic(graphs.HeawoodGraph())˓→# needs networkx
True

␣
␣

␣

The largest cubic nonplanar graph of diameter three:sage: # needs networkx
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˓→# needs sage.plot␣>>> from sage.all import *>>> # needs networkx>>> G = graphs.LCFGraph(Integer(20), [-Integer(10),-Integer(7),-Integer(5),˓→Integer(4),Integer(7),-Integer(10),-Integer(7),-Integer(4),Integer(5),˓→Integer(7),...
-Integer(10),-Integer(7),Integer(6),-Integer(5),˓→Integer(7),-Integer(10),-Integer(7),Integer(5),-Integer(6),Integer(7)],␣
˓→Integer(1))>>> G.degree()[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]>>> G.diameter()3>>> G.show()# long time
˓→# needs sage.plot

PLOTTING: LCF Graphs are plotted as an 𝑛-cycle with edges in the middle, as described above.

2.1. Common graphs905

Graph Theory, Release 10.4

static LadderGraph(n)Return a ladder graph with 2 * 𝑛 nodes.
A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected at each corresponding node pair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on
the top horizontal line.
EXAMPLES:
Construct and show a ladder graph with 14 nodes:
sage: g = graphs.LadderGraph(7)sage: g.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> g = graphs.LadderGraph(Integer(7))>>> g.show()# long time
˓→# needs sage.plot

Create several ladder graphs in a Sage graphics array:sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.LadderGraph(i+2)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.LadderGraph(i+Integer(2))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static LargeWittGraph()
Return the large Witt graph.
This is a distance-regular graph with intersection array [30, 28, 24; 1, 3, 15].
906

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
sage: g = graphs.LargeWittGraph()˓→# needs sage.libs.pari sage.modules
sage: g.is_distance_regular(True)˓→# needs sage.libs.pari sage.modules([30, 28, 24, None], [None, 1, 3, 15])␣␣>>> from sage.all import *>>> g = graphs.LargeWittGraph()˓→# needs sage.libs.pari sage.modules>>> g.is_distance_regular(True)
˓→# needs sage.libs.pari sage.modules([30, 28, 24, None], [None, 1, 3, 15])

REFERENCES:
A description of this graph can be found in [BCN1989] p. 366. This construction is taken from http://mathworld.wolfram.com/LargeWittGraph.html
static LeonardGraph()
Return the Leonard graph.
The graph is distance-regular with intersection array [12, 11, 10, 7; 1, 2, 5, 12].
EXAMPLES:
sage: G = graphs.LeonardGraph()
˓→ # needs sage.combinat sage.modules
sage: G.is_distance_regular(True)
˓→ # needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])␣␣>>> from sage.all import *>>> G = graphs.LeonardGraph()˓→# needs sage.combinat sage.modules>>> G.is_distance_regular(True)
˓→# needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])REFERENCES:
For a description of this graph see [BCN1989] p. 371.
static LivingstoneGraph()
Return the Livingstone Graph.
The Livingstone graph is a distance-transitive graph on 266 vertices whose automorphism group is the J1
group. For more information, see the Wikipedia article Livingstone_graph.
EXAMPLES:
sage: # optional - internet
sage: g = graphs.LivingstoneGraph()
sage: g.order()266
sage: g.size()
1463
sage: g.girth()(continues on next page)2.1. Common graphs907

Graph Theory, Release 10.4

(continued from previous page)5
sage: g.is_vertex_transitive()
True
sage: g.is_distance_regular()True>>> from sage.all import *>>> # optional - internet>>> g = graphs.LivingstoneGraph()>>> g.order()266>>> g.size()1463>>> g.girth()5>>> g.is_vertex_transitive()
True>>> g.is_distance_regular()Truestatic LjubljanaGraph(embedding=1)
Return the Ljubljana Graph.
The Ljubljana graph is a bipartite 3-regular graph on 112 vertices and 168 edges. It is not vertex-transitive as
it has two orbits which are also independent sets of size 56. See the Wikipedia article Ljubljana_graph.
The default embedding is obtained from the Heawood graph.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.LjubljanaGraph()
sage: g.order()112
sage: g.size()
168
sage: g.girth()10
sage: g.diameter()8
sage: g.show(figsize=[10, 10])# long time˓→# needs sage.plot
sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10])˓→long time, needs sage.plot␣#␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.LjubljanaGraph()>>> g.order()112>>> g.size()
168(continues on next page)

908

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.girth()
10>>> g.diameter()8>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot>>> graphs.LjubljanaGraph(embedding=Integer(2)).show(figsize=[Integer(10),␣
˓→Integer(10)])# long time, needs sage.plot

␣

static LocalMcLaughlinGraph()
Return the local McLaughlin graph.
The local McLaughlin graph is a strongly regular graph with parameters (162, 56, 10, 24). It can be obtained
from McLaughlinGraph() by considering the stabilizer of a point: one of its orbits has cardinality 162.
EXAMPLES:
sage: g = graphs.LocalMcLaughlinGraph(); g˓→package_design
Local McLaughlin Graph: Graph on 162 vertices
sage: g.is_strongly_regular(parameters=True)
˓→package_design(162, 56, 10, 24)# long time, optional - gap_

# long time, optional - gap_>>> from sage.all import *>>> g = graphs.LocalMcLaughlinGraph(); g# long time, optional - gap_
˓→package_design
Local McLaughlin Graph: Graph on 162 vertices>>> g.is_strongly_regular(parameters=True)# long time, optional - gap_
˓→package_design(162, 56, 10, 24)

static LollipopGraph(n1, n2)
Returns a lollipop graph with 𝑛1 + 𝑛2 nodes.
A lollipop graph is a path graph (order 𝑛2 ) connected to a complete graph (order 𝑛1 ). (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 𝑛1 -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˓→# needs sage.plot␣>>> from sage.all import *>>> g = graphs.LollipopGraph(Integer(13),Integer(4)); g
Lollipop graph: Graph on 17 vertices>>> g.show()# long time
˓→# needs sage.plot

2.1. Common graphs909

Graph Theory, Release 10.4

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: # needs sage.groups
sage: g = graphs.M22Graph()
sage: g.order()77sage: g.size()616
sage: g.is_strongly_regular(parameters=True)(77, 16, 0, 4)>>> from sage.all import *>>> # needs sage.groups>>> g = graphs.M22Graph()>>> g.order()77>>> g.size()616>>> g.is_strongly_regular(parameters=True)(77, 16, 0, 4)

static MarkstroemGraph()
Return the Markström Graph.
The Markström Graph is a cubic planar graph with no cycles of length 4 nor 8, but containing cycles of length
16. For more information, see the Wolfram page about the Markström Graph.
EXAMPLES:
sage: g = graphs.MarkstroemGraph()
sage: g.order()24
sage: g.size()36
sage: g.is_planar()True
sage: g.is_regular(3)True
sage: g.subgraph_search(graphs.CycleGraph(4)) is None˓→# needs sage.modules
True
sage: g.subgraph_search(graphs.CycleGraph(8)) is None˓→# needs sage.modules
True
sage: g.subgraph_search(graphs.CycleGraph(16))˓→# needs sage.modules
Subgraph of (Markstroem Graph): Graph on 16 vertices

␣

␣

␣

>>> from sage.all import *>>> g = graphs.MarkstroemGraph()>>> g.order()(continues on next page)

910

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)24>>> g.size()36>>> g.is_planar()True>>> g.is_regular(Integer(3))
True>>> g.subgraph_search(graphs.CycleGraph(Integer(4))) is None˓→# needs sage.modules
True>>> g.subgraph_search(graphs.CycleGraph(Integer(8))) is None˓→# needs sage.modules
True>>> g.subgraph_search(graphs.CycleGraph(Integer(16)))˓→# needs sage.modules
Subgraph of (Markstroem Graph): Graph on 16 vertices

␣

␣

␣

static MathonPseudocyclicMergingGraph(M, t)
Mathon’s merging of classes in a pseudo-cyclic 3-class association scheme
Construct strongly regular graphs from p.97 of [BL1984].
INPUT:• M – the list of matrices in a pseudo-cyclic 3-class association scheme. The identity matrix must be thefirst 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 [Mat1978].
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 [Mat1978]. With this input, Mathon[Mat1978] 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 oforder 4𝑡 + 1, with entries in −2𝑡, ..., −1, 0, 1, ..., 2𝑡.
Our implementation follows a description given in [ST1981].
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 – leadto non-isomorphic graphs.
See also:• is_mathon_PC_srg()

2.1. Common graphs911

Graph Theory, Release 10.4

EXAMPLES:
Using default G and L.
sage: from sage.graphs.generators.families import␣
˓→MathonPseudocyclicStronglyRegularGraphsage: G = MathonPseudocyclicStronglyRegularGraph(1); G˓→# needs sage.modules sage.rings.finite_rings
Mathon s PC SRG on 45 vertices: Graph on 45 vertices
sage: G.is_strongly_regular(parameters=True)˓→# needs sage.modules sage.rings.finite_rings(45, 22, 10, 11)␣␣>>> from sage.all import *>>> from sage.graphs.generators.families import␣
˓→MathonPseudocyclicStronglyRegularGraph>>> G = MathonPseudocyclicStronglyRegularGraph(Integer(1)); G˓→# needs sage.modules sage.rings.finite_rings
Mathon s PC SRG on 45 vertices: Graph on 45 vertices>>> G.is_strongly_regular(parameters=True)
˓→# needs sage.modules sage.rings.finite_rings(45, 22, 10, 11)␣Supplying G and L (constructed from the automorphism group of G). The entries of L can’t be tested directly because there’s some unpredictability in the way that GAP chooses a representative in NormalSubgroups(), the function that underlies our own normal_subgroups() method:
sage: # needs sage.groups sage.libs.gap sage.rings.finite_rings
sage: G = graphs.PaleyGraph(9)sage: a = G.automorphism_group(partition=[sorted(G)])
sage: it = (x for x in a.normal_subgroups() if x.order() == 9)sage: subg = next(iter(it))
sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage())....:
for z in subg]
sage: ff = list(map(lambda y: (y[0]-1,y[1]-1),....:
Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_
˓→tuples()[1:]))
sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff))
sage: G.relabel(range(9))
sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L)
sage: G3x3.is_strongly_regular(parameters=True)(441, 220, 109, 110)
sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27
sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2)sage: G9.is_strongly_regular(parameters=True)(441, 220, 109, 110)
sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss
9>>> from sage.all import *>>> # needs sage.groups sage.libs.gap sage.rings.finite_rings>>> G = graphs.PaleyGraph(Integer(9))>>> a = G.automorphism_group(partition=[sorted(G)])>>> it = (x for x in a.normal_subgroups() if x.order() == Integer(9))>>> subg = next(iter(it))>>> r = [matrix(libgap.PermutationMat(libgap(z), Integer(9)).sage())(continues on next page)

912

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)...
for z in subg]>>> ff = list(map(lambda y: (y[Integer(0)]-Integer(1),y[Integer(1)]˓→Integer(1)),...
Permutation(map(lambda x: Integer(1)+r.index(x**-Integer(1)),␣
˓→r)).cycle_tuples()[Integer(1):]))>>> L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(Integer(1),˓→len(ff)+Integer(1)), ff))>>> G.relabel(range(Integer(9)))>>> G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(Integer(2), G=G, L=L)>>> G3x3.is_strongly_regular(parameters=True)(441, 220, 109, 110)>>> G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27>>> G9 = graphs.MathonPseudocyclicStronglyRegularGraph(Integer(2))>>> G9.is_strongly_regular(parameters=True)(441, 220, 109, 110)>>> G9.automorphism_group(algorithm="bliss").order() # optional - bliss
9

static MathonStronglyRegularGraph(t)Return one of Mathon’s graphs on 784 vertices.
INPUT:• t – integer; the number of the graph, from 0 to 2
EXAMPLES:
sage: # long time, needs sage.libs.gap
sage: from sage.graphs.generators.smallgraphs import␣
˓→MathonStronglyRegularGraphsage: G = MathonStronglyRegularGraph(0)sage: G.is_strongly_regular(parameters=True)(784, 243, 82, 72)>>> from sage.all import *>>> # long time, needs sage.libs.gap>>> from sage.graphs.generators.smallgraphs import MathonStronglyRegularGraph>>> G = MathonStronglyRegularGraph(Integer(0))>>> G.is_strongly_regular(parameters=True)(784, 243, 82, 72)

static McGeeGraph(embedding=2)
Return the McGee Graph.
See the Wikipedia article McGee_graph.
INPUT:• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.McGeeGraph()
sage: g.order()24(continues on next page)2.1. Common graphs913

Graph Theory, Release 10.4

(continued from previous page)

sage: g.size()36
sage: g.girth()7
sage: g.diameter()4
sage: g.show()˓→# needs sage.plot
sage: graphs.McGeeGraph(embedding=1).show()˓→# needs sage.plot

␣# long time>>> from sage.all import *>>> # needs networkx>>> g = graphs.McGeeGraph()>>> g.order()24>>> g.size()36>>> g.girth()7>>> g.diameter()4>>> g.show()˓→# needs sage.plot>>> graphs.McGeeGraph(embedding=Integer(1)).show()˓→# needs sage.plot# long time␣␣

static McLaughlinGraph()
Return the McLaughlin Graph.
The McLaughlin Graph is the unique strongly regular graph of parameters (275, 112, 30, 56).
For more information on the McLaughlin Graph, see its web page on Andries Brouwer’s website which gives
the definition that this method implements.
Note: To create this graph you must have the gap_packages spkg installed.
EXAMPLES:
sage: g = graphs.McLaughlinGraph()
˓→design
sage: g.is_strongly_regular(parameters=True)
˓→design(275, 112, 30, 56)
sage: set(g.spectrum()) == {112, 2, -28}
˓→design
True# optional - gap_package_# optional - gap_package_# optional - gap_package_>>> from sage.all import *>>> g = graphs.McLaughlinGraph()# optional - gap_package_design>>> g.is_strongly_regular(parameters=True)# optional - gap_package_design(275, 112, 30, 56)>>> set(g.spectrum()) == {Integer(112), Integer(2), -Integer(28)}#␣˓→optional - gap_package_design
True

914

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

static MeredithGraph()
Return the Meredith Graph.
The Meredith Graph is a 4-regular 4-connected non-hamiltonian graph. For more information on the Meredith Graph, see the Wikipedia article Meredith_graph.
EXAMPLES:
sage: g = graphs.MeredithGraph()
sage: g.is_regular(4)True
sage: g.order()70sage: g.size()140
sage: g.radius()
7
sage: g.diameter()8
sage: g.girth()4
sage: g.chromatic_number()3
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
False>>> from sage.all import *>>> g = graphs.MeredithGraph()>>> g.is_regular(Integer(4))
True>>> g.order()70>>> g.size()140>>> g.radius()
7>>> g.diameter()8>>> g.girth()4>>> g.chromatic_number()3>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
False# long time␣# long time

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:

2.1. Common graphs915

Graph Theory, Release 10.4

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()˓→# needs sage.plot# long time>>> from sage.all import *>>> MK = graphs.MoebiusKantorGraph()>>> MK
Moebius-Kantor Graph: Graph on 16 vertices>>> MK.graph6_string()
OhCGKE?O@?ACAC@I?Q_AS>>> (graphs.MoebiusKantorGraph()).show()˓→# needs sage.plot

␣# long time

static MoebiusLadderGraph(n)Return a Möbius ladder graph with 2𝑛 nodes
A Möbius ladder graph of order 2𝑛 is a ladder graph of the same order that is connected at the ends with asingle twist, i.e., a ladder graph bent around so that top meets bottom with a single twist. Alternatively, it
can be described as a single cycle graph (of order 2𝑛) with the addition of edges (called 𝑟𝑢𝑛𝑔𝑠) joining theantipodal pairs of nodes. Also, note that the Möbius ladder graph graphs.MoebiusLadderGraph(n)is precisely the same graph as the circulant graph graphs.CirculantGraph(2 * n, [1, n]).
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention,
each Möbius ladder graph will be displayed with the first (0) node at the top, with the rest following in acounterclockwise manner.
INPUT:• n – a non negative integer; number of nodes is 2𝑛
OUTPUT:• G – a Möbius ladder graph of order 2𝑛; note that a ValueError is returned if 𝑛 < 0
EXAMPLES:
Construct and show a Möbius ladder graph with 26 nodes:
sage: g = graphs.MoebiusLadderGraph(13)sage: g.show()# long time˓→# needs sage.plot␣>>> from sage.all import *>>> g = graphs.MoebiusLadderGraph(Integer(13))>>> g.show()# long time
˓→# needs sage.plot

Create several Möbius ladder graphs in a Sage graphics array:sage: # needs sage.plots
sage: g = []sage: j = []sage: for i in range(9):(continues on next page)

916

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)....:k = graphs.MoebiusLadderGraph(i+3)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plots>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.MoebiusLadderGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

REFERENCES:• Wikipedia article Möbius_ladder
See also:
LadderGraph(), CircularLadderGraph(), CirculantGraph()
AUTHORS:• Janmenjaya Panda (2024-05-26)
static MoserSpindle()
Return the Moser spindle.
For more information, see the Wikipedia article Moser_spindle.
EXAMPLES:
The Moser spindle is a planar graph having 7 vertices and 11 edges:
sage: # needs sage.symbolic
sage: G = graphs.MoserSpindle(); G
Moser spindle: Graph on 7 vertices
sage: G.is_planar()True
sage: G.order()7
sage: G.size()
11>>> from sage.all import *>>> # needs sage.symbolic(continues on next page)2.1. Common graphs917

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphs.MoserSpindle(); G
Moser spindle: Graph on 7 vertices>>> G.is_planar()
True>>> G.order()7>>> G.size()11

It is a Hamiltonian graph with radius 2, diameter 2, and girth 3:
sage: # needs sage.symbolic
sage: G.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: G.radius()
2
sage: G.diameter()2
sage: G.girth()3

␣>>> from sage.all import *>>> # needs sage.symbolic>>> G.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> G.radius()
2>>> G.diameter()2>>> G.girth()
3

The Moser spindle can be drawn in the plane as a unit distance graph, has chromatic number 4, and its
automorphism group is isomorphic to the dihedral group 𝐷4 :sage: # needs sage.symbolic
sage: pos = G.get_pos()sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1....:
for u, v in G.edge_iterator(labels=None))True
sage: G.chromatic_number()4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(4))
True>>> from sage.all import *>>> # needs sage.symbolic>>> pos = G.get_pos()>>> all(sum((ui-vi)**Integer(2) for ui, vi in zip(pos[u], pos[v])) ==␣
˓→Integer(1)...
for u, v in G.edge_iterator(labels=None))
True>>> G.chromatic_number()(continues on next page)

918

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)4>>> ag = G.automorphism_group()>>> ag.is_isomorphic(DihedralGroup(Integer(4)))
True

static MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False)
Return a strongly regular graph of S6 type from [Muz2007] on 𝑛𝑑 ((𝑛𝑑 − 1)/(𝑛 − 1) + 1) vertices.
The construction depends upon a number of parameters, two of them, 𝑛 and 𝑑, mandatory, and Φ and Σ
mappings defined in [Muz2007]. These graphs have parameters (𝑚𝑛𝑑 , 𝑛𝑑−1 (𝑚 − 1) − 1, 𝜇 − 2, 𝜇), where𝑑−1𝑑−1
𝜇 = 𝑛 𝑛−1−1 𝑛𝑑−1 and 𝑚 := 𝑛𝑛−1
+ 1.
Some details on Φ and Σ are as follows. Let 𝐿 be the complete graph on 𝑀 := {0, ..., 𝑚 − 1} with thematching {(2𝑖, 2𝑖 + 1)|𝑖 = 0, ..., 𝑚/2} removed. Then one arbitrarily chooses injections Φ𝑖 from the edgesof 𝐿 on 𝑖 ∈ 𝑀 into sets of parallel classes of affine 𝑑-dimensional designs; our implementation uses thedesigns of hyperplanes in 𝑑-dimensional affine geometries over 𝐺𝐹 (𝑛). Finally, for each edge 𝑖𝑗 of 𝐿 one
arbitrarily chooses bijections Σ𝑖𝑗 between Φ𝑖 and Φ𝑗 . More details, in particular how these choices lead to
non-isomorphic graphs, are in [Muz2007].
INPUT:• n (integer) – a prime power• d (integer) – must be odd if 𝑛 is odd• Phi is an optional parameter of the construction; it must be either–

fixed – this will generate fixed default Φ𝑖 , for 𝑖 ∈ 𝑀 , or–random – Φ𝑖 are generated at random, or– A dictionary describing the functions Φ𝑖 ; for 𝑖 ∈ 𝑀 , Phi[(i, T)] in 𝑀 , for each edge T of 𝐿 on 𝑖.
Also, each Φ𝑖 must be injective.
• Sigma is an optional parameter of the construction; it must be either–

fixed – this will generate a fixed default Σ, or–random – Σ is generated at random.

• verbose (Boolean) – default is False. If True, print progress information
See also:• is_muzychuk_S6()

Todo: Implement the possibility to explicitly supply the parameter Σ of the construction.
EXAMPLES:
sage: # needs sage.combinat sage.modules sage.rings.finite_rings
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)

2.1. Common graphs919

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.combinat sage.modules sage.rings.finite_rings>>> graphs.MuzychukS6Graph(Integer(3), Integer(3)).is_strongly_
˓→regular(parameters=True)(378, 116, 34, 36)>>> phi = {(Integer(2),(Integer(0),Integer(2))):Integer(0), (Integer(1),˓→(Integer(1),Integer(3))):Integer(1), (Integer(0),(Integer(0),˓→Integer(3))):Integer(1), (Integer(2),(Integer(1),Integer(2))):Integer(1),...
(Integer(1),(Integer(1),Integer(2))):Integer(0), (Integer(0),˓→(Integer(0),Integer(2))):Integer(0), (Integer(3),(Integer(0),˓→Integer(3))):Integer(0), (Integer(3),(Integer(1),Integer(3))):Integer(1)}>>> graphs.MuzychukS6Graph(Integer(2), Integer(2), Phi=phi).is_strongly_
˓→regular(parameters=True)(16, 5, 0, 2)

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 𝑣𝑗 .
For more details, see the Wikipedia article Mycielskian.
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 ofvertices 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>>> from sage.all import *>>> g = graphs.MycielskiGraph(Integer(5))>>> g.is_triangle_free()True>>> 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

920

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.MycielskiGraph(Integer(4))>>> g.is_isomorphic(graphs.GrotzschGraph())
True

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 casethey may find it useful.
EXAMPLE. One iteration of the Mycielski step applied to the 5-cycle yields a graph isomorphic to the
Grotzsch graphsage: g = graphs.CycleGraph(5)sage: h = graphs.MycielskiStep(g)sage: h.is_isomorphic(graphs.GrotzschGraph())
True>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> h = graphs.MycielskiStep(g)>>> h.is_isomorphic(graphs.GrotzschGraph())
True

static NKStarGraph(n, k)
Returns the (𝑛, 𝑘)-star graph.
The vertices of the (𝑛, 𝑘)-star graph are the set of all arrangements of 𝑛 symbols into labels of length 𝑘.
There are two adjacency rules for the (𝑛, 𝑘)-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 – integer; number of symbols• k – integer; length of the labels of the vertices
EXAMPLES:
sage: g = graphs.NKStarGraph(4,2)
sage: g.plot()# long time˓→# needs sage.plot
Graphics object consisting of 31 graphics primitives␣>>> from sage.all import *>>> g = graphs.NKStarGraph(Integer(4),Integer(2))>>> g.plot()# long time
˓→# needs sage.plot
Graphics object consisting of 31 graphics primitives

REFERENCES:[CC1995]
AUTHORS:• Michael Yurko (2009-09-01)
2.1. Common graphs921

Graph Theory, Release 10.4

static NStarGraph(n)Returns the 𝑛-star graph.
The vertices of the 𝑛-star graph are the set of permutations on 𝑛 symbols. There is an edge between two
vertices if their labels differ only in the first and one other position.
INPUT:• n – integer; number of symbols
EXAMPLES:
sage: g = graphs.NStarGraph(4)sage: g.plot()# long time˓→# needs sage.plot
Graphics object consisting of 61 graphics primitives␣>>> from sage.all import *>>> g = graphs.NStarGraph(Integer(4))>>> g.plot()# long time
˓→# needs sage.plot
Graphics object consisting of 61 graphics primitives

REFERENCES:[AHK1994]
AUTHORS:• Michael Yurko (2009-09-01)
static NauruGraph(embedding=2)
Return the Nauru Graph.
See the Wikipedia article Nauru_graph.
INPUT:• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: g = graphs.NauruGraph()
sage: g.order()24
sage: g.size()36
sage: g.girth()6
sage: g.diameter()4
sage: g.show()˓→# needs sage.plot
sage: graphs.NauruGraph(embedding=1).show()˓→# needs sage.plot

␣# long time␣>>> from sage.all import *>>> g = graphs.NauruGraph()>>> g.order()24(continues on next page)922

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.size()36>>> g.girth()6>>> g.diameter()4>>> g.show()˓→# needs sage.plot>>> graphs.NauruGraph(embedding=Integer(1)).show()˓→# needs sage.plot# long time␣

static NonisotropicOrthogonalPolarGraph(m, q, sign='+', perp=None)𝜖,⊥Return the Graph 𝑁 𝑂𝑚(𝑞)

Let the vectorspace of dimension 𝑚 over 𝐹𝑞 be endowed with a nondegenerate quadratic form 𝐹 , of typesign for 𝑚 even.
• 𝑚 even: assume further that 𝑞 = 2 or 3. Returns the graph of the points (in the underlying projective
space) 𝑥 satisfying 𝐹 (𝑥) = 1, with adjacency given by orthogonality w.r.t. 𝐹 . Parameter perp is
ignored.
• 𝑚 odd: if perp is not None, then we assume that 𝑞 = 5 and return the graph of the points 𝑥 satisfying
𝐹 (𝑥) = ±1 if sign="+", respectively 𝐹 (𝑥) ∈ {2, 3} if sign="-", with adjacency given by orthogonality w.r.t. 𝐹 (cf. Sect 7.D of [BL1984]). Otherwise return the graph of nongenerate hyperplanes oftype sign, adjacent whenever the intersection is degenerate (cf. Sect. 7.C of [BL1984]). Note that for
𝑞 = 2 one will get a complete graph.
For more information, see Sect. 9.9 of [BH2012] and [BL1984]. Note that the page of Andries Brouwer’s
website uses different notation.
INPUT:• m – integer; half the dimension of the underlying vectorspace• q – a power of a prime number, the size of the underlying field• sign – string (default: "+"); must be either "+" or "-"EXAMPLES:𝑁 𝑂− (4, 2) is isomorphic to Petersen graph:
sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2, - ); g˓→
# needs sage.libs.gap
NO^-(4, 2): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)˓→# needs sage.libs.gap(10, 3, 0, 1)

␣␣>>> from sage.all import *>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(4),Integer(2), - ); g␣˓→# needs sage.libs.gap
NO^-(4, 2): Graph on 10 vertices>>> g.is_strongly_regular(parameters=True)
˓→# needs sage.libs.gap(10, 3, 0, 1)

𝑁 𝑂− (6, 2) and 𝑁 𝑂+ (6, 2):

2.1. Common graphs923

Graph Theory, Release 10.4

sage: # needs sage.libs.gap
sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2, - )sage: g.is_strongly_regular(parameters=True)(36, 15, 6, 6)
sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2, + ); gNO^+(6, 2): Graph on 28 vertices
sage: g.is_strongly_regular(parameters=True)(28, 15, 6, 10)>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(6),Integer(2), - )>>> g.is_strongly_regular(parameters=True)(36, 15, 6, 6)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(6),Integer(2), + ); gNO^+(6, 2): Graph on 28 vertices>>> g.is_strongly_regular(parameters=True)(28, 15, 6, 10)

𝑁 𝑂+ (8, 2):
sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2, + )˓→# needs sage.libs.gap
sage: g.is_strongly_regular(parameters=True)˓→# needs sage.libs.gap(120, 63, 30, 36)>>> from sage.all import *>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(8),Integer(2), + )˓→# needs sage.libs.gap>>> g.is_strongly_regular(parameters=True)
˓→# needs sage.libs.gap(120, 63, 30, 36)␣␣␣Wilbrink’s graphs for 𝑞 = 5:
sage: # needs sage.libs.gap
sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1)
sage: g.is_strongly_regular(parameters=True)# long time
(325, 60, 15, 10)
sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5, - ,perp=1)
sage: g.is_strongly_regular(parameters=True)# long time
(300, 65, 10, 15)>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(5),˓→perp=Integer(1))>>> g.is_strongly_regular(parameters=True)# long time
(325, 60, 15, 10)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(5), - ,˓→perp=Integer(1))>>> g.is_strongly_regular(parameters=True)# long time
(300, 65, 10, 15)

Wilbrink’s graphs:

924

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.libs.gap
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˓→tested (long time)NO^+(7, 4): Graph on 2080 vertices
sage: g.is_strongly_regular(parameters=True)
˓→tested (long time)(2080, 1071, 558, 544)

# not␣

# not␣

>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(4), + )>>> g.is_strongly_regular(parameters=True)(136, 75, 42, 40)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(4), - )>>> g.is_strongly_regular(parameters=True)(120, 51, 18, 24)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(7),Integer(4), + ); g␣˓→# not tested (long time)NO^+(7, 4): Graph on 2080 vertices>>> g.is_strongly_regular(parameters=True)# not␣
˓→tested (long time)(2080, 1071, 558, 544)

static NonisotropicUnitaryPolarGraph(m, q)
Return the Graph 𝑁 𝑈 (𝑚, 𝑞).
This returns the graph on nonisotropic, with respect to a nondegenerate Hermitean form, points of the (𝑚 −1)-dimensional projective space over 𝐹𝑞 , with points adjacent whenever they lie on a tangent (to the set ofisotropic points) line. For more information, see Sect. 9.9 of [BH2012] and series C14 in [Hub1975].
INPUT:• m, q – integers; 𝑞 must be a prime power
EXAMPLES:
sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g˓→# needs sage.libs.gap
NU(5, 2): Graph on 176 vertices
sage: g.is_strongly_regular(parameters=True)˓→# needs sage.libs.gap(176, 135, 102, 108)>>> from sage.all import *>>> g = graphs.NonisotropicUnitaryPolarGraph(Integer(5),Integer(2)); g˓→# needs sage.libs.gap
NU(5, 2): Graph on 176 vertices>>> g.is_strongly_regular(parameters=True)
˓→# needs sage.libs.gap(176, 135, 102, 108)

␣

␣

␣

static Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None,check_hyperoval=True)
2.1. Common graphs925Graph Theory, Release 10.4

Return the subgraph of nowhere 0 words from two-weight code of projective plane hyperoval.
Let 𝑞 = 2𝑘 and Π = 𝑃 𝐺(2, 𝑞). Fix a hyperoval 𝑂 ⊂ Π. Let 𝑉 = 𝐹𝑞3 and 𝐶 the two-weight 3-dimensional
linear code over 𝐹𝑞 with words 𝑐(𝑣) obtained from 𝑣 ∈ 𝑉 by computing𝑐(𝑣) = (⟨𝑣, 𝑜1 ⟩, ..., ⟨𝑣, 𝑜𝑞+2 ⟩), 𝑜𝑗 ∈ 𝑂.
𝐶 contains 𝑞(𝑞 − 1)2 /2 words without 0 entries. The subgraph of the strongly regular graph of 𝐶 inducedon the latter words is also strongly regular, assuming 𝑞 > 4. This is a construction due to A.E.Brouwer[Bro2016], and leads to graphs with parameters also given by a construction in [HHL2009]. According to[Bro2016], these two constructions are likely to produce isomorphic graphs.
INPUT:• q – a power of two• hyperoval – a hyperoval (i.e. a complete 2-arc; a set of points in the plane meeting every line in 0 or
2 points) in 𝑃 𝐺(2, 𝑞) over the field field. Each point of hyperoval must be a length 3 vector overfield 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 thepoint of intersection of its tangent lines.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided.
• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness ornot
See also:• is_nowhere0_twoweight()
EXAMPLES:
using the built-in construction:
sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.Nowhere0WordsTwoWeightCodeGraph(Integer(8)); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices>>> g.is_strongly_regular(parameters=True)(196, 60, 14, 20)>>> g = graphs.Nowhere0WordsTwoWeightCodeGraph(Integer(16)) # not tested␣
˓→(long time)>>> g.is_strongly_regular(parameters=True)# not tested (long time)(1800, 728, 268, 312)

supplying your own hyperoval:

926

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> F = GF(Integer(8))>>> O = [vector(F,(Integer(0),Integer(0),Integer(1))),vector(F,(Integer(0),˓→Integer(1),Integer(0)))] + [vector(F, (Integer(1),x**Integer(2),x))...
for x in F]>>> g = graphs.Nowhere0WordsTwoWeightCodeGraph(Integer(8),hyperoval=O,
˓→field=F); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices>>> g.is_strongly_regular(parameters=True)(196, 60, 14, 20)

static OctahedralGraph()
Return an Octahedral graph (with 6 nodes).
The regular octahedron is an 8-sided polyhedron with triangular faces. The octahedral graph corresponds tothe connectivity of the vertices of the octahedron. It is the line graph of the tetrahedral graph. The octahedral
is symmetric, so the spring-layout algorithm will be very effective for display.
PLOTTING: The Octahedral graph should be viewed in 3 dimensions. We choose to use a planar embeddingof the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will
be added to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.OctahedralGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.OctahedralGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

Create several octahedral graphs in a Sage graphics array They will be drawn differently due to the use of thespring-layout algorithm:
sage: # needs sage.plot
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):(continues on next page)2.1. Common graphs927

Graph Theory, Release 10.4

(continued from previous page)....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.OctahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static OddGraph(n)Returns the Odd Graph with parameter 𝑛.
The Odd Graph with parameter 𝑛 is defined as the Kneser Graph with parameters 2𝑛−1, 𝑛−1. Equivalently,
the Odd Graph is the graph whose vertices are the 𝑛 − 1-subsets of [0, 1, . . . , 2(𝑛 − 1)], and such that two
vertices are adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Odd Graph with parameter 3.
EXAMPLES:
sage: OG = graphs.OddGraph(3)sage: sorted(OG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(OG)True>>> from sage.all import *>>> OG = graphs.OddGraph(Integer(3))>>> sorted(OG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]>>> P = graphs.PetersenGraph()>>> P.is_isomorphic(OG)Truestatic OrthogonalArrayBlockGraph(k, n, OA=None)
Return the graph of an 𝑂𝐴(𝑘, 𝑛).
The intersection graph of the blocks of a transversal design with parameters (𝑘, 𝑛), or 𝑇 𝐷(𝑘, 𝑛) for short,
is a strongly regular graph (unless it is a complete graph). Its parameters (𝑣, 𝑘 ′ , 𝜆, 𝜇) are determined by theparameters 𝑘, 𝑛 via:
𝑣 = 𝑛2 , 𝑘 ′ = 𝑘(𝑛 − 1), 𝜆 = (𝑘 − 1)(𝑘 − 2) + 𝑛 − 2, 𝜇 = 𝑘(𝑘 − 1)
928

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

As transversal designs and orthogonal arrays (OA for short) are equivalent objects, this graph can also be built
from the blocks of an 𝑂𝐴(𝑘, 𝑛), two of them being adjacent if one of their coordinates match.
For more information on these graphs, see Andries Brouwer’s page on Orthogonal Array graphs.
Warning:• Brouwer’s website uses the notation 𝑂𝐴(𝑛, 𝑘) instead of 𝑂𝐴(𝑘, 𝑛)• For given parameters 𝑘 and 𝑛 there can be many 𝑂𝐴(𝑘, 𝑛) : the graphs returned are not uniquely
defined by their parameters (see the examples below).
• If the function is called only with the parameter k and n the results might be different with two
versions of Sage, or even worse : some could not be available anymore.
See also:
sage.combinat.designs.orthogonal_arrays
INPUT:• k, n – integers• OA – An orthogonal array. If set to None (default) then orthogonal_array() is called to compute
an 𝑂𝐴(𝑘, 𝑛).
EXAMPLES:
sage: # needs sage.modules
sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G˓→# needs sage.schemes
OA(5,5): Graph on 25 vertices
sage: G.is_strongly_regular(parameters=True)˓→# needs sage.schemes(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)␣␣>>> from sage.all import *>>> # needs sage.modules>>> G = graphs.OrthogonalArrayBlockGraph(Integer(5),Integer(5)); G˓→# needs sage.schemes
OA(5,5): Graph on 25 vertices>>> G.is_strongly_regular(parameters=True)
˓→# needs sage.schemes(25, 20, 15, 20)>>> G = graphs.OrthogonalArrayBlockGraph(Integer(4),Integer(10)); G
OA(4,10): Graph on 100 vertices>>> G.is_strongly_regular(parameters=True)(100, 36, 14, 12)␣Two graphs built from different orthogonal arrays are also different:
sage: # needs sage.modules
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](continues on next page)2.1. Common graphs929

Graph Theory, Release 10.4

(continued from previous page)

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>>> from sage.all import *>>> # needs sage.modules>>> k = Integer(4); n = Integer(10)>>> OAa = designs.orthogonal_arrays.build(k,n)>>> OAb = [[(x+Integer(1))%n for x in R] for R in OAa]>>> set(map(tuple,OAa)) == set(map(tuple,OAb))
False>>> Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa)>>> Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb)>>> Ga == GbFalse

As OAb was obtained from OAa by a relabelling the two graphs are isomorphic:
sage: Ga.is_isomorphic(Gb)˓→# needs sage.modules
True␣>>> from sage.all import *>>> Ga.is_isomorphic(Gb)˓→# needs sage.modules
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)˓→# needs sage.modules
sage: g1 = graphs.OrthogonalArrayBlockGraph(3, 4, oa1)˓→# needs sage.modules
sage: g0.is_isomorphic(g1)˓→# needs sage.modules
False

␣
␣
␣

>>> from sage.all import *>>> oa0 = [[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1),␣
˓→Integer(3)], [Integer(0), Integer(2), Integer(0)], [Integer(0), Integer(3),␣
˓→Integer(2)],...
[Integer(1), Integer(0), Integer(3)], [Integer(1), Integer(1),␣
˓→Integer(1)], [Integer(1), Integer(2), Integer(2)], [Integer(1), Integer(3),␣
˓→Integer(0)],(continues on next page)

930

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)...
[Integer(2), Integer(0), Integer(0)], [Integer(2), Integer(1),␣
˓→Integer(2)], [Integer(2), Integer(2), Integer(1)], [Integer(2), Integer(3),␣
˓→Integer(3)],...
[Integer(3), Integer(0), Integer(2)], [Integer(3), Integer(1),␣
˓→Integer(0)], [Integer(3), Integer(2), Integer(3)], [Integer(3), Integer(3),␣
˓→Integer(1)]]>>> oa1 = [[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1),␣
˓→Integer(0)], [Integer(0), Integer(2), Integer(3)], [Integer(0), Integer(3),␣
˓→Integer(2)],...
[Integer(1), Integer(0), Integer(3)], [Integer(1), Integer(1),␣
˓→Integer(2)], [Integer(1), Integer(2), Integer(0)], [Integer(1), Integer(3),␣
˓→Integer(1)],...
[Integer(2), Integer(0), Integer(0)], [Integer(2), Integer(1),␣
˓→Integer(1)], [Integer(2), Integer(2), Integer(2)], [Integer(2), Integer(3),␣
˓→Integer(3)],...
[Integer(3), Integer(0), Integer(2)], [Integer(3), Integer(1),␣
˓→Integer(3)], [Integer(3), Integer(2), Integer(1)], [Integer(3), Integer(3),␣
˓→Integer(0)]]>>> g0 = graphs.OrthogonalArrayBlockGraph(Integer(3), Integer(4), oa0)␣˓→# needs sage.modules>>> g1 = graphs.OrthogonalArrayBlockGraph(Integer(3), Integer(4), oa1)␣˓→# needs sage.modules>>> g0.is_isomorphic(g1)˓→# needs sage.modules
False

But nevertheless isospectral:sage: g0.spectrum()˓→# needs sage.modules sage.rings.number_field[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
sage: g1.spectrum()˓→# needs sage.modules sage.rings.number_field[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]␣␣>>> from sage.all import *>>> g0.spectrum()˓→# needs sage.modules sage.rings.number_field[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]>>> g1.spectrum()˓→# needs sage.modules sage.rings.number_field[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)˓→# needs sage.libs.gap sage.modules
True␣>>> from sage.all import *>>> graphs.AffineOrthogonalPolarGraph(Integer(4),Integer(2), + ).is_˓→isomorphic(g0)# needs sage.libs.gap sage.modules
True

static OrthogonalDualPolarGraph(e, d, q)
Return the dual polar graph on 𝐺𝑂𝑒 (𝑛, 𝑞) of diameter 𝑑.
2.1. Common graphs931

Graph Theory, Release 10.4

The value of 𝑛 is determined by 𝑑 and 𝑒.
The graph is distance-regular with classical parameters (𝑑, 𝑞, 0, 𝑞 𝑒 ).
INPUT:• e – integer; type of the orthogonal polar space to consider; must be −1, 0 or 1.
• d – integer; diameter of the graph• q – integer; prime power; order of the finite field over which to build the polar space
EXAMPLES:
sage: # needs sage.libs.gap
sage: G = graphs.OrthogonalDualPolarGraph(1,3,2)
sage: G.is_distance_regular(True)([7, 6, 4, None], [None, 1, 3, 7])
sage: G = graphs.OrthogonalDualPolarGraph(0,3,3)
sage: G.is_distance_regular(True)([39, 36, 27, None], [None, 1, 4, 13])sage: G.order()1120# long time
# long time
# long time>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.OrthogonalDualPolarGraph(Integer(1),Integer(3),Integer(2))>>> G.is_distance_regular(True)([7, 6, 4, None], [None, 1, 3, 7])>>> G = graphs.OrthogonalDualPolarGraph(Integer(0),Integer(3),Integer(3))˓→# long time>>> G.is_distance_regular(True)# long time([39, 36, 27, None], [None, 1, 4, 13])>>> G.order()# long time1120

␣

REFERENCES:
See [BCN1989] pp. 274-279 or [VDKT2016] p. 22.
static OrthogonalPolarGraph(m, q, sign='+')
Return the Orthogonal Polar Graph 𝑂𝜖 (𝑚, 𝑞).
For more information on Orthogonal Polar graphs, see the page of Andries Brouwer’s website.
INPUT:• m, q – integers; 𝑞 must be a prime power• sign – string (default: "+"); must be "+" or "-" if 𝑚 is even, "+" (default) otherwise
EXAMPLES:
sage: # needs sage.libs.gap
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)(continues on next page)932

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

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)>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.OrthogonalPolarGraph(Integer(6),Integer(3),"+"); G
Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices>>> G.is_strongly_regular(parameters=True)(130, 48, 20, 16)>>> G = graphs.OrthogonalPolarGraph(Integer(6),Integer(3),"-"); G
Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices>>> G.is_strongly_regular(parameters=True)(112, 30, 2, 10)>>> G = graphs.OrthogonalPolarGraph(Integer(5),Integer(3)); G
Orthogonal Polar Graph O(5, 3): Graph on 40 vertices>>> G.is_strongly_regular(parameters=True)(40, 12, 2, 4)>>> G = graphs.OrthogonalPolarGraph(Integer(8),Integer(2),"+"); G
Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices>>> G.is_strongly_regular(parameters=True)(135, 70, 37, 35)>>> G = graphs.OrthogonalPolarGraph(Integer(8),Integer(2),"-"); G
Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices>>> 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˓→# needs sage.rings.finite_rings
Paley graph with parameter 9: Graph on 9 vertices
sage: G.is_regular()˓→# needs sage.rings.finite_rings
True>>> from sage.all import *>>> G = graphs.PaleyGraph(Integer(9)); G˓→# needs sage.rings.finite_rings
Paley graph with parameter 9: Graph on 9 vertices>>> G.is_regular()˓→# needs sage.rings.finite_rings
True

2.1. Common graphs

␣

␣

␣

933

Graph Theory, Release 10.4

A Paley graph is always self-complementary:sage: G.is_self_complementary()˓→# needs sage.rings.finite_rings
True␣>>> from sage.all import *>>> G.is_self_complementary()
˓→# needs sage.rings.finite_rings
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˓→# needs sage.plot
sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3)˓→# needs networkx
sage: L.show()# long time˓→# needs networkx sage.plot
sage: G.is_isomorphic(L)˓→# needs networkx
True

␣
␣
␣
␣

>>> from sage.all import *>>> G = graphs.PappusGraph()>>> G.show()# long time
˓→# needs sage.plot>>> L = graphs.LCFGraph(Integer(18), [Integer(5),Integer(7),-Integer(7),˓→Integer(7),-Integer(7),-Integer(5)], Integer(3))˓→# needs networkx>>> L.show()# long time
˓→# needs networkx sage.plot>>> G.is_isomorphic(L)˓→# needs networkx
True␣

static PasechnikGraph(n)Pasechnik strongly regular graph on (4𝑛 − 1)2 vertices
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(), also known as pseudo Latin squares graph 𝐿2𝑛−1 (4𝑛 − 1), constructed from a skew Hadamard
matrix of order 4𝑛 following [Pas1992].
See also:• is_orthogonal_array_block_graph()
EXAMPLES:
sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True)˓→# needs sage.combinat sage.modules␣(continues on next page)934

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)(225, 98, 43, 42)
sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True)
˓→long time, needs sage.combinat sage.modules(361, 162, 73, 72)
sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True)
˓→tested(1225, 578, 273, 272)#␣# not␣

>>> from sage.all import *>>> graphs.PasechnikGraph(Integer(4)).is_strongly_regular(parameters=True)˓→# needs sage.combinat sage.modules(225, 98, 43, 42)>>> graphs.PasechnikGraph(Integer(5)).is_strongly_regular(parameters=True)
˓→ # long time, needs sage.combinat sage.modules(361, 162, 73, 72)>>> graphs.PasechnikGraph(Integer(9)).is_strongly_regular(parameters=True)
˓→not tested(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 areconnected to their one inner neighbors (i.e.: a cycle graph without the first and last node connected).
INPUT:• n – number of nodes of the path graph• pos – string (default: None); indicates the embedding to use between ‘circle’, ‘line’ or the default algorithm. See the plotting section below for more detail.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the graph may be drawn in one of two ways: The ‘line’ argument will draw the graph in a horizontal
line (left to right) if there are less than 11 nodes. Otherwise the ‘line’ argument will append horizontal lines
of length 10 nodes below, alternating left to right and right to left. The ‘circle’ argument will cause the graphto be drawn in a cycle-shape, with the first node at the top and then about the circle in a clockwise manner.
By default (without an appropriate string argument) the graph will be drawn as a ‘circle’ if 10 < 𝑛 < 41 andas a ‘line’ for all other 𝑛.
EXAMPLES: Show default drawing by size: ‘line’: 𝑛 ≤ 10
sage: p = graphs.PathGraph(10)sage: p.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> p = graphs.PathGraph(Integer(10))>>> p.show()# long time
˓→# needs sage.plot‘circle’: 10 < 𝑛 < 41sage: q = graphs.PathGraph(25)sage: q.show()˓→# needs sage.plot

2.1. Common graphs# long time␣935Graph Theory, Release 10.4>>> from sage.all import *>>> q = graphs.PathGraph(Integer(25))>>> q.show()# long time
˓→# needs sage.plot‘line’: 𝑛 ≥ 41
sage: r = graphs.PathGraph(55)sage: r.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> r = graphs.PathGraph(Integer(55))>>> r.show()# long time
˓→# needs sage.plot

Override the default drawing:
sage: s = graphs.PathGraph(5, circle )sage: s.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> s = graphs.PathGraph(Integer(5), circle )>>> s.show()# long time
˓→# needs sage.plot

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 graphwith 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])>>> from sage.all import *>>> g = graphs.PerkelGraph(); g
Perkel Graph: Graph on 57 vertices>>> 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 thefirst of them. On the second one, still from left to right, mark 𝑛 points 𝜎(1), 𝜎(2), . . . , 𝜎(𝑛). Now,
936

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

link by a segment the two points marked with 1, then link together the points marked with 2, andso 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 twovertices 𝑖 and 𝑗 are connected by an edge if and only if the order in which these vertices appear in thelist (𝑎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 anythingelse. We can still use the above visual description to construct the permutation graph, but now we have tomark points 𝑎1 , 𝑎2 , . . . , 𝑎𝑛 from left to right on the first horizontal line and points 𝑏1 , 𝑏2 , . . . , 𝑏𝑛 from left toright 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(sort=True, labels=False)
sage: set(edges) == set(p.inverse().inversions())
Truesage: PG = graphs.PermutationGraph([3,4,5,1,2])
sage: sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 4, None),(2, 5, None)]sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3])
sage: sorted(PG.edges(sort=True))[(1, 3, None),(continues on next page)2.1. Common graphs937

Graph Theory, Release 10.4

(continued from previous page)(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]sage: PG = graphs.PermutationGraph([1,4,2,5,3], [3,4,5,1,2])
sage: sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]sage: PG = graphs.PermutationGraph(Permutation([1,3,2]), Permutation([1,2,3]))
sage: sorted(PG.edges(sort=True))[(2, 3, None)]sage: graphs.PermutationGraph([]).edges(sort=True)[]
sage: graphs.PermutationGraph([], []).edges(sort=True)[]
sage: PG = graphs.PermutationGraph("graph", "phrag")sage: sorted(PG.edges(sort=True))[( a , g , None),( a , h , None),( a , p , None),( g , h , None),( g , p , None),( g , r , None),( h , r , None),( p , r , None)]>>> from sage.all import *>>> p = Permutations(Integer(5)).random_element()>>> PG = graphs.PermutationGraph(p)>>> edges = PG.edges(sort=True, labels=False)>>> set(edges) == set(p.inverse().inversions())
True>>> PG = graphs.PermutationGraph([Integer(3),Integer(4),Integer(5),Integer(1),˓→Integer(2)])>>> sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 4, None),(2, 5, None)]>>> PG = graphs.PermutationGraph([Integer(3),Integer(4),Integer(5),Integer(1),˓→Integer(2)], [Integer(1),Integer(4),Integer(2),Integer(5),Integer(3)])>>> sorted(PG.edges(sort=True))[(1, 3, None),(continues on next page)

938

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]>>> PG = graphs.PermutationGraph([Integer(1),Integer(4),Integer(2),Integer(5),˓→Integer(3)], [Integer(3),Integer(4),Integer(5),Integer(1),Integer(2)])>>> sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]>>> PG = graphs.PermutationGraph(Permutation([Integer(1),Integer(3),˓→Integer(2)]), Permutation([Integer(1),Integer(2),Integer(3)]))>>> sorted(PG.edges(sort=True))[(2, 3, None)]>>> graphs.PermutationGraph([]).edges(sort=True)[]>>> graphs.PermutationGraph([], []).edges(sort=True)[]>>> PG = graphs.PermutationGraph("graph", "phrag")>>> sorted(PG.edges(sort=True))[( 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-pointstar embedded in a pentagon.
The Petersen Graph is a common counterexample. For example, it is not Hamiltonian.
PLOTTING: See the plotting section for the generalized Petersen graphs.
EXAMPLES: We compare below the Petersen graph with the default spring-layout versus a planned position
dictionary of (𝑥, 𝑦) tuples:sage: 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˓→# needs sage.plot
sage: petersen_database = graphs.PetersenGraph()␣(continues on next page)2.1. Common graphs939

Graph Theory, Release 10.4

(continued from previous page)

sage: petersen_database.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> petersen_spring = Graph({Integer(0):[Integer(1),Integer(4),Integer(5)],␣
˓→Integer(1):[Integer(0),Integer(2),Integer(6)], Integer(2):[Integer(1),˓→Integer(3),Integer(7)],...
Integer(3):[Integer(2),Integer(4),Integer(8)],␣
˓→Integer(4):[Integer(0),Integer(3),Integer(9)], Integer(5):[Integer(0),˓→Integer(7),Integer(8)],...
Integer(6):[Integer(1),Integer(8),Integer(9)],␣
˓→Integer(7):[Integer(2),Integer(5),Integer(9)], Integer(8):[Integer(3),˓→Integer(5),Integer(6)],...
Integer(9):[Integer(4),Integer(6),Integer(7)]})>>> petersen_spring.show()# long time
˓→# needs sage.plot>>> petersen_database = graphs.PetersenGraph()>>> petersen_database.show()# long time
˓→# needs sage.plot

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>>> from sage.all import *>>> g = graphs.PoussinGraph()>>> g.order()15>>> g.is_planar()Truestatic QueenGraph(dim_list, radius=None, relabel=False)
Return the 𝑑-dimensional Queen Graph with prescribed dimensions.
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 withprescribed dimensions, and each edge corresponds to a legal move by a queen in either one or two dimensions.
All 2-dimensional Queen Graphs are Hamiltonian and biconnected. The chromatic number of a (𝑛, 𝑛)-Queen
Graph is at least 𝑛, and it is exactly 𝑛 when 𝑛 ≡ 1, 5 mod 6.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of thechessboard• radius – integer (default: None); by setting the radius to a positive integer, one may reduce thevisibility of the queen to at most radius steps. When radius is 1, the resulting graph is a King Graph.
940

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (2, 2)-Queen Graph is isomorphic to the complete graph on 4 vertices:sage: G = graphs.QueenGraph([2, 2])
sage: G.is_isomorphic(graphs.CompleteGraph(4))
True>>> from sage.all import *>>> G = graphs.QueenGraph([Integer(2), Integer(2)])>>> G.is_isomorphic(graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> G = graphs.QueenGraph([Integer(4), Integer(5)], radius=Integer(1))>>> H = graphs.KingGraph([Integer(5), Integer(4)])>>> 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>>> from sage.all import *>>> G = graphs.QueenGraph([Integer(3), Integer(4), Integer(5)],␣
˓→radius=Integer(1))>>> H = graphs.KingGraph([Integer(5), Integer(3), Integer(4)])>>> 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(sort=False))....:
if not G.is_isomorphic(H):....:print("that s not good!")>>> from sage.all import *>>> for d in range(Integer(3),Integer(12)):# long time...
for r in range(Integer(1),d+Integer(1)):...
G = graphs.QueenGraph([d,d],radius=r)(continues on next page)2.1. Common graphs941

Graph Theory, Release 10.4

(continued from previous page)

...
...
...
...
...

H = graphs.RookGraph([d,d],radius=r)
B = graphs.BishopGraph([d,d],radius=r)
H.add_edges(B.edges(sort=False))
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 𝑚 vertices and no edges is initialized, and a graph of 𝑛 vertices is grown by attaching newvertices each with 𝑚 edges that are attached to existing vertices, preferentially with high degree.
INPUT:• n – number of vertices in the graph• m – number of edges to attach from each new node
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We show the edge list of a random graph on 6 nodes with 𝑚 = 2:
sage: G = graphs.RandomBarabasiAlbert(6,2)˓→# needs networkx
sage: G.order(), G.size()˓→# needs networkx(6, 8)
sage: G.degree_sequence() # random˓→# needs networkx[4, 3, 3, 2, 2, 2]␣␣␣>>> from sage.all import *>>> G = graphs.RandomBarabasiAlbert(Integer(6),Integer(2))˓→# needs networkx>>> G.order(), G.size()
˓→# needs networkx(6, 8)>>> G.degree_sequence() # random
˓→# needs networkx[4, 3, 3, 2, 2, 2]

␣We plot a random graph on 12 nodes with 𝑚 = 3:
sage: ba = graphs.RandomBarabasiAlbert(12,3)˓→# needs networkx
sage: ba.show()# long time˓→# needs networkx sage.plot>>> from sage.all import *>>> ba = graphs.RandomBarabasiAlbert(Integer(12),Integer(3))˓→# needs networkx>>> ba.show()# long time
˓→# needs networkx sage.plot

␣␣␣

We view many random graphs using a graphics array:942

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(1,10):....:k = graphs.RandomBarabasiAlbert(i+3, 3)....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(1),Integer(10)):...
k = graphs.RandomBarabasiAlbert(i+Integer(3), Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

When 𝑚 = 1, the generated graph is a tree:
sage: graphs.RandomBarabasiAlbert(6, 1).is_tree()˓→# needs networkx
True>>> from sage.all import *>>> graphs.RandomBarabasiAlbert(Integer(6), Integer(1)).is_tree()˓→# needs networkx
True

␣

␣

static RandomBicubicPlanar(n, seed=None)
Return the graph of a random bipartite cubic map with 3𝑛 edges.
INPUT:
𝑛 – an integer (at least 1)• seed – a random.Random seed or a Python int for the random number generator (default: None)OUTPUT:a graph with multiple edges (no embedding is provided)
The algorithm used is described in [Sch1999]. This samples a random rooted bipartite cubic map, chosen
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.

2.1. Common graphs943

Graph Theory, Release 10.4

Then one performs a rotation on this word so that this becomes a balanced word. There are three ways todo that, one is picked at random. Then a graph is build from the balanced word by iterated closure (addingedges).
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: # needs sage.combinat
sage: n = randint(200, 300)
sage: G = graphs.RandomBicubicPlanar(n)sage: G.order() == 2*nTrue
sage: G.size() == 3*nTrue
sage: G.is_bipartite() and G.is_planar() and G.is_regular(3)True
sage: dic = { red : [v for v in G.vertices(sort=False) if v[0] == n ],....:blue : [v for v in G.vertices(sort=False) if v[0] != n ]}sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic)˓→# needs sage.plot
Graphics object consisting of ... graphics primitives␣>>> from sage.all import *>>> # needs sage.combinat>>> n = randint(Integer(200), Integer(300))>>> G = graphs.RandomBicubicPlanar(n)>>> G.order() == Integer(2)*nTrue>>> G.size() == Integer(3)*nTrue>>> G.is_bipartite() and G.is_planar() and G.is_regular(Integer(3))
True>>> dic = { red : [v for v in G.vertices(sort=False) if v[Integer(0)] == n ],...
blue : [v for v in G.vertices(sort=False) if v[Integer(0)] != n
˓→ ]}>>> G.plot(vertex_labels=False, vertex_size=Integer(20), vertex_colors=dic) ␣˓→# needs sage.plot
Graphics object consisting of ... graphics primitives

944

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

static RandomBipartite(n1, n2, p, set_position=False, seed=None)
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 thatthe set of cardinality 𝑛1 is on the line 𝑦 = 1 and the set of cardinality 𝑛2 is on the line 𝑦 = 0.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: g = graphs.RandomBipartite(5, 2, 0.5)˓→# needs numpy
sage: g.vertices(sort=True)˓→# needs numpy[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]>>> from sage.all import *>>> g = graphs.RandomBipartite(Integer(5), Integer(2), RealNumber( 0.5 ))˓→# needs numpy>>> g.vertices(sort=True)
˓→# needs numpy[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]␣␣␣

static RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None)
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• 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. Thisis useful for the creation of some hypergraphs.
• seed – a random.Random seed or a Python int for the random number generator (default: None)

2.1. Common graphs945

Graph Theory, Release 10.4

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>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(1), Integer(4))>>> 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>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(10), Integer(2))>>> 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>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(5), Integer(3), kmax=Integer(6))>>> blocks,cuts = B.blocks_and_cut_vertices()>>> 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>>> from sage.all import *>>> m, k = Integer(6), Integer(4)>>> B = graphs.RandomBlockGraph(m, k)>>> B.order() == m*(k-Integer(1))+Integer(1)True

Test recognition methods:

946

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: B = graphs.RandomBlockGraph(6, 2, kmax=6)
sage: B.is_block_graph()
True
sage: B in graph_classes.Block
True>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(6), Integer(2), kmax=Integer(6))>>> B.is_block_graph()
True>>> B in graph_classes.Block
True

Asking for the incidence structure: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)˓→# needs sage.modules
Incidence structure with 19 points and 6 blocks
sage: m*(k-1)+1
19

␣>>> from sage.all import *>>> m, k = Integer(6), Integer(4)>>> IS = graphs.RandomBlockGraph(m, k, incidence_structure=True)>>> from sage.combinat.designs.incidence_structures import IncidenceStructure>>> IncidenceStructure(IS)˓→# needs sage.modules
Incidence structure with 19 points and 6 blocks>>> m*(k-Integer(1))+Integer(1)19static RandomBoundedToleranceGraph(n, seed=None)
Return a random bounded tolerance graph.
The random tolerance graph is built from a random bounded tolerance representation by using the function
𝑇 𝑜𝑙𝑒𝑟𝑎𝑛𝑐𝑒𝐺𝑟𝑎𝑝ℎ. This representation is a list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), ..., (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where 𝑘 = 𝑛 − 1
and 𝐼𝑖 = (𝑙𝑖 , 𝑟𝑖 ) denotes a random interval and 𝑡𝑖 a random positive value less than or equal to the length of
the interval 𝐼𝑖 . The width of the representation is limited to 𝑛2 * 2𝑛 .
Note: The tolerance representation used to create the graph can be recovered using get_vertex() or
get_vertices().
INPUT:• n – number of vertices of the random graph.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
Every (bounded) tolerance graph is perfect. Hence, the chromatic number is equal to the clique number

2.1. Common graphs947

Graph Theory, Release 10.4

sage: g = graphs.RandomBoundedToleranceGraph(8)sage: g.clique_number() == g.chromatic_number()True>>> from sage.all import *>>> g = graphs.RandomBoundedToleranceGraph(Integer(8))>>> g.clique_number() == g.chromatic_number()Truestatic RandomChordalGraph(n, algorithm='growing', k=None, l=None, f=None, s=None, seed=None)
Return a random chordal graph of order n.
A Graph 𝐺 is said to be chordal if it contains no induced hole (a cycle of length at least 4). Equivalently, 𝐺 ischordal if it has a perfect elimination orderings, if each minimal separator is a clique, or if it is the intersection
graphs of subtrees of a tree. See the Wikipedia article Chordal_graph.
This generator implements the algorithms proposed in [SHET2018] for generating random chordal graphs as
the intersection graph of 𝑛 subtrees of a tree of order 𝑛.
The returned graph is not necessarily connected.
INPUT:• n – integer; the number of nodes of the graph• algorithm – string (default: "growing"); the choice of the algorithm for randomly selecting 𝑛subtrees of a random tree of order 𝑛. Possible choices are:– "growing" – for each subtree 𝑇𝑖 , the algorithm picks a size 𝑘𝑖 randomly from [1, 𝑘]. Then arandom node of 𝑇 is chosen as the first node of 𝑇𝑖 . In each of the subsequent 𝑘𝑖 − 1 iterations, it
picks a random node in the neighborhood of 𝑇𝑖 and adds it to 𝑇𝑖 .
– "connecting" – for each subtree 𝑇𝑖 , it first selects 𝑘𝑖 nodes of 𝑇 , where 𝑘𝑖 is a random integer
from a Poisson distribution with mean 𝑙. 𝑇𝑖 is then generated to be the minimal subtree containing
the selected 𝑘𝑖 nodes. This implies that a subtree will most likely have many more nodes than those
selected initially, and this must be taken into consideration when choosing 𝑙.
– "pruned" – for each subtree 𝑇𝑖 , it randomly selects a fraction 𝑓 of the edges on the tree andremoves them. The number of edges to delete, say 𝑙, is calculated as ⌊(𝑛 − 1)𝑓 ⌋, which will leave𝑙 + 1 subtrees in total. Then, it determines the sizes of the 𝑙 + 1 subtrees and stores the distinct
values. Finally, it picks a random size 𝑘𝑖 from the set of largest 100(1 − 𝑠)% of distinct values, andrandomly chooses a subtree with size 𝑘𝑖 .
• k –√integer (default: None); maximum size of a subtree. If not specified (None), the maximum size is set
to 𝑛. This parameter is used only when algorithm="growing". See growing_subtrees()
for more details.
• l – a strictly positive real number (default: None); mean of a Poisson distribution. If not specified,
the mean in set to log2 𝑛. This parameter is used only when algorithm="connecting". Seeconnecting_nodes() for more details.
• f – a rational number (default: None); the edge deletion fraction. This value must be chosen in [0..1]. If
1
not specified, this parameter is set to 𝑛−1. This parameter is used only when algorithm="pruned".
See pruned_tree() for more details.
• s – a real number between 0 and 1 (default: None); selection barrier for the size of trees. If not
specified, this parameter is set to 0.5. This parameter is used only when algorithm="pruned".
See pruned_tree() for more details.
• seed – a random.Random seed or a Python int for the random number generator (default: None)

948

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
sage: from sage.graphs.generators.random import RandomChordalGraphsage: T = RandomChordalGraph(20, algorithm="growing", k=5)
sage: T.is_chordal()Truesage: T = RandomChordalGraph(20, algorithm="connecting", l=3)˓→# needs numpy
sage: T.is_chordal()˓→# needs numpy
True
sage: T = RandomChordalGraph(20, algorithm="pruned", f=1/3, s=.5)
sage: T.is_chordal()
True

␣
␣

>>> from sage.all import *>>> from sage.graphs.generators.random import RandomChordalGraph>>> T = RandomChordalGraph(Integer(20), algorithm="growing", k=Integer(5))>>> T.is_chordal()True>>> T = RandomChordalGraph(Integer(20), algorithm="connecting", l=Integer(3))␣
˓→# needs numpy>>> T.is_chordal()˓→# needs numpy
True>>> T = RandomChordalGraph(Integer(20), algorithm="pruned", f=Integer(1)/˓→Integer(3), s=RealNumber( .5 ))>>> T.is_chordal()True

See also:• growing_subtrees()• connecting_nodes()• pruned_tree()• Wikipedia article Chordal_graph• is_chordal()• IntersectionGraph()static RandomGNM(n, m, dense=False, seed=None)
Return a graph randomly picked out of all graphs on 𝑛 vertices with 𝑚 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 – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We show the edge list of a random graph on 5 nodes with 10 edges:

2.1. Common graphs949

Graph Theory, Release 10.4

sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False)␣˓→# needs networkx[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3,␣˓→4)]>>> from sage.all import *>>> graphs.RandomGNM(Integer(5), Integer(10)).edges(sort=True, labels=False) ␣˓→# needs networkx[(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 and 12 edges:
sage: gnm = graphs.RandomGNM(12, 12)˓→# needs networkx
sage: gnm.show()˓→# needs networkx sage.plot

␣# long time>>> from sage.all import *>>> gnm = graphs.RandomGNM(Integer(12), Integer(12))˓→# needs networkx>>> gnm.show()# long time
˓→# needs networkx sage.plot

␣␣

We view many random graphs using a graphics array:sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.RandomGNM(i+3, i^2-i)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.RandomGNM(i+Integer(3), i**Integer(2)-i)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static RandomGNP(n, p, seed=None, fast=True, algorithm='Sage')
950

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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 – a random.Random seed or a Python int for the random number generator (default: None)• fast – boolean set to True (default) to use the algorithm with time complexity in 𝑂(𝑛 + 𝑚) proposedin [BB2005a]. 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 , thisfunction calls the NetworkX function fast_gnp_random_graph, unless fast=False, thengnp_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:• [ER1959]• [Gil1959]
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(sort=true, labels=False)[(0, 3), (1, 2), (2, 3), (2, 4)]>>> from sage.all import *>>> set_random_seed(Integer(0))>>> graphs.RandomGNP(Integer(6), RealNumber( .4 )).edges(sort=true,␣
˓→labels=False)[(0, 3), (1, 2), (2, 3), (2, 4)]

We plot a random graph on 12 nodes with probability 𝑝 = .71:
sage: gnp = graphs.RandomGNP(12,.71)
sage: gnp.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> gnp = graphs.RandomGNP(Integer(12),RealNumber( .71 ))>>> gnp.show()# long time
˓→# needs sage.plot

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)(continues on next page)2.1. Common graphs951

Graph Theory, Release 10.4

(continued from previous page)

sage: for i in range(3):␣˓→# needs sage.plot....:
n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)␣˓→# needs sage.plot
sage: G.show()# long time␣˓→# needs sage.plot
sage: graphs.RandomGNP(4,1)
Complete graph: Graph on 4 vertices>>> from sage.all import *>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.RandomGNP(i+Integer(3),RealNumber( .43 ))...
g.append(k)>>> for i in range(Integer(3)):␣˓→# needs sage.plot...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)˓→# needs sage.plot>>> G.show()# long time
˓→# needs sage.plot>>> graphs.RandomGNP(Integer(4),Integer(1))
Complete graph: Graph on 4 vertices

static RandomHolmeKim(n, m, p, seed=None)
Return a random graph generated by the Holme and Kim algorithm for graphs with power law degree distribution and approximate average clustering.
INPUT:• n – number of vertices• m – number of random edges to add for each new node
• p – probability of adding a triangle after adding a random edge
• seed – a random.Random seed or a Python int for the random number generator (default: None)
From the NetworkX documentation: the average clustering has a hard time getting above a certain cutoffthat depends on 𝑚. This cutoff is often quite low. Note that the transitivity (fraction of triangles to possible
triangles) seems to go down with network size. It is essentially the Barabasi-Albert growth model with an
extra step that each random edge is followed by a chance of making an edge to one of its neighbors too (andthus a triangle). This algorithm improves on B-A in the sense that it enables a higher average clustering to
be attained if desired. It seems possible to have a disconnected graph with this algorithm since the initial 𝑚nodes may not be all linked to a new node on the first iteration like the BA model.
EXAMPLES:

952

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.RandomHolmeKim(12, 3, .3)
˓→# needs networkx
sage: G.show()# long time˓→# needs networkx sage.plot>>> from sage.all import *>>> G = graphs.RandomHolmeKim(Integer(12), Integer(3), RealNumber( .3 ))˓→# needs networkx>>> G.show()# long time
˓→# needs networkx sage.plot␣␣␣

REFERENCE:[HK2002a]
static RandomIntervalGraph(n, seed=None)
Returns a random interval graph.
An interval graph is built from a list (𝑎𝑖 , 𝑏𝑖 )1≤𝑖≤𝑛 of intervals : to each interval of the list is associated one
vertex, two vertices being adjacent if the two corresponding intervals intersect.
A random interval graph of order 𝑛 is generated by picking random values for the (𝑎𝑖 , 𝑏𝑗 ), each of the twocoordinates being generated from the uniform distribution on the interval [0, 1].
This definitions follows [BF2001].
Note: The vertices are named 0, 1, 2, and so on. The intervals used to create the graph are saved with thegraph and can be recovered using get_vertex() or get_vertices().
INPUT:• n – integer; the number of vertices in the random graph• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
As for any interval graph, the chromatic number is equal to the clique number
sage: g = graphs.RandomIntervalGraph(8)sage: g.clique_number() == g.chromatic_number()True>>> from sage.all import *>>> g = graphs.RandomIntervalGraph(Integer(8))>>> g.clique_number() == g.chromatic_number()Truestatic RandomKTree(n, k, seed=None)
Return a random 𝑘-tree on 𝑛 nodes numbered 0 through 𝑛 − 1.
ALGORITHM:
The algorithm first generates a complete graph on 𝑘 + 1 vertices. Vertices are subsequently generated byrandomly choosing one of the existing cliques in the graph, and creating a new clique by replacing one of thevertices in the selected clique with a newly created one.
INPUT:

2.1. Common graphs953

Graph Theory, Release 10.4

• n – number of vertices in the 𝑘-tree• k – within a clique each vertex is connected to 𝑘 vertices. 𝑘 also corresponds to the treewidth of the𝑘-tree• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomKTree(50, 5)
sage: G.treewidth()5
sage: G.show() # not tested>>> from sage.all import *>>> G = graphs.RandomKTree(Integer(50), Integer(5))>>> G.treewidth()5>>> G.show() # not tested

static RandomLobster(n, p, q, seed=None)
Return 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 (𝑞 = 0).
INPUT:• n – expected number of vertices in the backbone• p – probability of adding an edge to the backbone• q – probability of adding an edge (claw) to the arms
• seed – a random.Random seed or a Python int for the random number generator (default: None).
EXAMPLES:
We check a random graph with 12 backbone nodes and probabilities 𝑝 = 0.7 and 𝑞 = 0.3:
sage: # needs networkx
sage: G = graphs.RandomLobster(12, 0.7, 0.3)
sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1]
sage: G.delete_vertices(leaves)# caterpillar
sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1]
sage: G.delete_vertices(leaves)# pathsage: s = G.degree_sequence()
sage: if G:....:
if G.num_verts() == 1:....:
assert s == [0]
....:
else:
....:
assert s[-2:] == [1, 1]....:
assert all(d == 2 for d in s[:-2])>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomLobster(Integer(12), RealNumber( 0.7 ), RealNumber( 0.3
˓→ ))>>> leaves = [v for v in G.vertices(sort=False) if G.degree(v) == Integer(1)]>>> G.delete_vertices(leaves)# caterpillar>>> leaves = [v for v in G.vertices(sort=False) if G.degree(v) == Integer(1)](continues on next page)954

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G.delete_vertices(leaves)# path>>> s = G.degree_sequence()>>> if G:...
if G.num_verts() == Integer(1):...
assert s == [Integer(0)]
...
else:
...
assert s[-Integer(2):] == [Integer(1), Integer(1)]...
assert all(d == Integer(2) for d in s[:-Integer(2)])
sage: G = graphs.RandomLobster(9, .6, .3)
˓→# needs networkx
sage: G.show()# long time˓→# needs networkx sage.plot␣␣>>> from sage.all import *>>> G = graphs.RandomLobster(Integer(9), RealNumber( .6 ), RealNumber( .3 )) ␣˓→
# needs networkx>>> G.show()# long time
˓→# needs networkx sage.plot

static RandomNewmanWattsStrogatz(n, k, p, seed=None)
Return a Newman-Watts-Strogatz small world random graph on 𝑛 vertices.
From the NetworkX documentation: first create a ring over 𝑛 nodes. Then each node in the ring is connectedwith its 𝑘 nearest neighbors. Then shortcuts are created by adding new edges as follows: for each edge𝑢 − 𝑣 in the underlying “𝑛-ring with 𝑘 nearest neighbors”; with probability 𝑝 add a new edge 𝑢 − 𝑤 withrandomly-chosen existing node 𝑤. In contrast with networkx.watts_strogatz_graph(), no edges
are removed.
INPUT:• n – number of vertices• k – each vertex is connected to its 𝑘 nearest neighbors• p – the probability of adding a new edge for each edge
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that the generated graph contains a cycle of order 𝑛:sage: # needs networkx
sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2)
sage: G.order()7
sage: C7 = graphs.CycleGraph(7)sage: G.subgraph_search(C7)Subgraph of (): Graph on 7 vertices
sage: G.diameter() <= C7.diameter()True>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomNewmanWattsStrogatz(Integer(7), Integer(2), RealNumber(
˓→ 0.2 ))>>> G.order()(continues on next page)2.1. Common graphs955

Graph Theory, Release 10.4

(continued from previous page)

7>>> C7 = graphs.CycleGraph(Integer(7))>>> G.subgraph_search(C7)Subgraph of (): Graph on 7 vertices>>> G.diameter() <= C7.diameter()Truesage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3)
˓→# needs networkx
sage: G.show()# long time˓→# needs networkx sage.plot␣␣>>> from sage.all import *>>> G = graphs.RandomNewmanWattsStrogatz(Integer(12), Integer(2), RealNumber(
˓→ .3 ))
# needs networkx>>> G.show()# long time
˓→# needs networkx sage.plot

REFERENCE:[NWS2002]
static RandomPartialKTree(n, k, x, seed=None)
Return a random partial 𝑘-tree on 𝑛 nodes.
A partial 𝑘-tree is defined as a subgraph of a 𝑘-tree. This can also be described as a graph with treewidth at
most 𝑘.
INPUT:• n – number of vertices in the 𝑘-tree• k – within a clique each vertex is connected to 𝑘 vertices. 𝑘 also corresponds to the treewidth of the𝑘-tree• x – how many edges are deleted from the 𝑘-tree• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomPartialKTree(50,5,2)
sage: G.treewidth()5
sage: G.show() # not tested>>> from sage.all import *>>> G = graphs.RandomPartialKTree(Integer(50),Integer(5),Integer(2))>>> G.treewidth()5>>> G.show() # not tested

static RandomRegular(d, n, seed=None)
Return a random 𝑑-regular graph on 𝑛 vertices, or False on failure.
Since every edge is incident to two vertices, 𝑛 × 𝑑 must be even.
INPUT:• d – degree
956

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• n – number of vertices• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that a random graph with 8 nodes each of degree 3 is 3-regular:
sage: G = graphs.RandomRegular(3, 8)˓→# needs networkx
sage: G.is_regular(k=3)˓→# needs networkx
True
sage: G.degree_histogram()˓→# needs networkx[0, 0, 0, 8]␣␣␣>>> from sage.all import *>>> G = graphs.RandomRegular(Integer(3), Integer(8))˓→# needs networkx>>> G.is_regular(k=Integer(3))˓→# needs networkx
True>>> G.degree_histogram()˓→# needs networkx[0, 0, 0, 8]
sage: G = graphs.RandomRegular(3, 20)˓→# needs networkx
sage: if G:
˓→needs networkx sage.plot....:
G.show()␣␣␣# random output>>> from sage.all import *>>> G = graphs.RandomRegular(Integer(3), Integer(20))˓→# needs networkx>>> if G:# random output
˓→needs networkx sage.plot...
G.show()# long time,␣␣# long time,␣

REFERENCES:• [KV2003]• [SW1999]
static RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None)
Return a random regular bipartite graph on 𝑛1 + 𝑛2 vertices.
The bipartite graph has 𝑛1*𝑑1 edges. Hence, 𝑛2 must divide 𝑛1*𝑑1. Each vertex of the set of cardinality 𝑛1
has degree 𝑑1 (which can be at most 𝑛2) and each vertex in the set of cardinality 𝑛2 has degree (𝑛1 * 𝑑1)/𝑛2.
The bipartite graph has no multiple edges.
This generator implements an algorithm inspired by that of [MW1990] for the uniform generation of random
regular bipartite graphs. It performs well when 𝑑1 = 𝑜(𝑛21/3 ) or (𝑛2 − 𝑑1 = 𝑜(𝑛21/3 )). In other cases,
the running time can be huge. Note that the currently implemented algorithm does not generate uniformly
random graphs.
INPUT:

2.1. Common graphs957

Graph Theory, Release 10.4

• 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 thatthe set of cardinality 𝑛1 is on the line 𝑦 = 1 and the set of cardinality 𝑛2 is on the line 𝑦 = 0.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: g = graphs.RandomRegularBipartite(4, 6, 3)
sage: g.order(), g.size()(10, 12)sage: set(g.degree()){2, 3}
sage: graphs.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()>>> from sage.all import *>>> g = graphs.RandomRegularBipartite(Integer(4), Integer(6), Integer(3))>>> g.order(), g.size()(10, 12)>>> set(g.degree()){2, 3}>>> graphs.RandomRegularBipartite(Integer(1), Integer(2), Integer(2), set_
˓→position=True).get_pos(){0: (1, 1.0), 1: (0, 0), 2: (2.0, 0.0)}>>> graphs.RandomRegularBipartite(Integer(2), Integer(1), Integer(1), set_
˓→position=True).get_pos(){0: (0, 1), 1: (2.0, 1.0), 2: (1, 0.0)}>>> graphs.RandomRegularBipartite(Integer(2), Integer(3), Integer(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)}>>> graphs.RandomRegularBipartite(Integer(2), Integer(3), Integer(3), set_
˓→position=False).get_pos()static RandomShell(constructor, seed=None)
Return a random shell graph for the constructor given.
INPUT:• constructor – a list of 3-tuples (𝑛, 𝑚, 𝑑), each representing a shell, where:– n – the number of vertices in the shell– m – the number of edges in the shell– d – the ratio of inter (next) shell edges to intra shell edges• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:

958

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)])˓→# needs networkx
sage: G.order(), G.size()˓→# needs networkx(30, 52)
sage: G.show()# long time˓→# needs networkx sage.plot␣␣␣>>> from sage.all import *>>> G = graphs.RandomShell([(Integer(10),Integer(20),RealNumber( 0.8 )),˓→(Integer(20),Integer(40),RealNumber( 0.8 ))])
#␣
˓→needs networkx>>> G.order(), G.size()
˓→# needs networkx(30, 52)>>> G.show()# long time
˓→# needs networkx sage.plot

static RandomToleranceGraph(n, seed=None)
Return a random tolerance graph.
The random tolerance graph is built from a random tolerance representation by using the function ToleranceGraph(). 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 islimited to 𝑛2 * 2𝑛 .
Note: The vertices are named 0, 1, · · · , 𝑛−1. The tolerance representation used to create the graph is savedwith the graph and can be recovered using get_vertex() or get_vertices().
INPUT:• n – number of vertices of the random graph• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
Every tolerance graph is perfect. Hence, the chromatic number is equal to the clique number
sage: g = graphs.RandomToleranceGraph(8)sage: g.clique_number() == g.chromatic_number()True>>> from sage.all import *>>> g = graphs.RandomToleranceGraph(Integer(8))>>> g.clique_number() == g.chromatic_number()Truestatic RandomTree(n, seed=None)
Returns a random tree on 𝑛 nodes numbered 0 through 𝑛 − 1.
By Cayley’s theorem, there are 𝑛𝑛−2 trees with vertex set {0, 1, . . . , 𝑛 − 1}. This constructor chooses oneof these uniformly at random.
ALGORITHM:
The algorithm works by generating an (𝑛 − 2)-long random sequence of numbers chosen independently anduniformly from {0, 1, . . . , 𝑛 − 1} and then applies an inverse Prufer transformation.
2.1. Common graphs959

Graph Theory, Release 10.4

INPUT:• n – number of vertices in the tree
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomTree(10)sage: G.is_tree()True
sage: G.show()˓→# needs sage.plot# long time␣>>> from sage.all import *>>> G = graphs.RandomTree(Integer(10))>>> G.is_tree()True>>> G.show()# long time
˓→# needs sage.plot

static RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None)
Return a tree with a power law degree distribution, or False on failure.
From the NetworkX documentation: a trial power law degree sequence is chosen and then elements areswapped 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 distribution• tries – number of attempts to adjust sequence to make a tree
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that the generated graph is a tree:
sage: G = graphs.RandomTreePowerlaw(10, 3)˓→# needs networkx
sage: G.is_tree()˓→# needs networkx
True
sage: G.order(), G.size()˓→# needs networkx(10, 9)␣␣␣>>> from sage.all import *>>> G = graphs.RandomTreePowerlaw(Integer(10), Integer(3))˓→# needs networkx>>> G.is_tree()˓→# needs networkx
True>>> G.order(), G.size()
˓→# needs networkx(10, 9)960

␣Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.RandomTreePowerlaw(15, 2)˓→# needs networkx
sage: if G:# random output
˓→needs networkx sage.plot....:
G.show()>>> from sage.all import *>>> G = graphs.RandomTreePowerlaw(Integer(15), Integer(2))˓→# needs networkx>>> if G:# random output
˓→needs networkx sage.plot...
G.show()␣# long time,␣␣# long time,␣

static RandomTriangulation(n, set_position=False, k=3, seed=None)
Return a random inner triangulation of an outer face of degree k with n vertices in total.
An inner triangulation is a plane graph all of whose faces (except the outer/unbounded face) are triangles(3-cycles).
INPUT:• n – the number of vertices of the graph• k – the size of the outer face
• set_position – boolean (default False); if set to True, this will compute coordinates for a planardrawing of the graph.
• seed – a random.Random seed or a Python int for the random number generator (default: None)OUTPUT:
A random graph chosen uniformly among the inner triangulations of a rooted 𝑘-gon with 𝑛 vertices (including
the 𝑘 vertices from the outer face). This is a planar graph and comes with a combinatorial embedding. The
vertices of the root edge are labelled -1 and -2 and the outer face is the face returned by Graph.faces()in which -1 and -2 are consecutive vertices in this order.
Because some triangulations have nontrivial automorphism groups, this may not be equal to the uniform
distribution among inner triangulations of unrooted 𝑘-gons.
ALGORITHM:
The algorithm is taken from [PS2006], Section 5.
Starting from a planar 𝑘-gonal forest (represented by its contour as a sequence of vertices), one performs local
closures, until no one is possible. A local closure amounts to replace in the cyclic contour word a sequencein1, in2, in3, lf, in3 by in1, in3.
At every step of the algorithm, newly created edges are recorded in a graph, which will be returned at theend. 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()(continues on next page)2.1. Common graphs961

Graph Theory, Release 10.4

(continued from previous page)3
sage: G.plot(vertex_size=0, vertex_labels=False)˓→# needs sage.plot
Graphics object consisting of 13 graphics primitives

␣sage: H = graphs.RandomTriangulation(7, k=5)
sage: sorted(len(f) for f in H.faces())[3, 3, 3, 3, 3, 3, 3, 5]>>> from sage.all import *>>> G = graphs.RandomTriangulation(Integer(6), True); G
Graph on 6 vertices>>> G.is_planar()
True>>> G.girth()3>>> G.plot(vertex_size=Integer(0), vertex_labels=False)˓→# needs sage.plot
Graphics object consisting of 13 graphics primitives

␣>>> H = graphs.RandomTriangulation(Integer(7), k=Integer(5))>>> sorted(len(f) for f in H.faces())[3, 3, 3, 3, 3, 3, 3, 5]

static RandomUnitDiskGraph(n, radius=0.1, side=1, seed=None)
Return a random unit disk graph of order 𝑛.
A unit disk graph is the intersection graph of a family of unit disks in the Euclidean plane. That is a graph with
one vertex per disk of the family and an edge between two vertices whenever they lie within a unit distanceof each other. See the Wikipedia article Unit_disk_graph for more details.
INPUT:• n – number of nodes• radius – float (default: 0.1); two vertices at distance less than radius are connected by an edge
• side – float (default: 1); indicate the side of the area in which the points are drawn• seed – seed of the random number generator
EXAMPLES:
When using twice the same seed, the vertices get the same positions:sage: # needs scipy
sage: from sage.misc.randstate import current_randstate
sage: seed = current_randstate().seed()sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed)sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed)sage: H.is_subgraph(G, induced=False)
True
sage: H.size() <= G.size()
True
sage: Gpos = G.get_pos()sage: Hpos = H.get_pos()sage: all(Gpos[u] == Hpos[u] for u in G)
True

962

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs scipy>>> from sage.misc.randstate import current_randstate>>> seed = current_randstate().seed()>>> G = graphs.RandomUnitDiskGraph(Integer(20), radius=RealNumber( .5 ),␣
˓→side=Integer(1), seed=seed)>>> H = graphs.RandomUnitDiskGraph(Integer(20), radius=RealNumber( .2 ),␣
˓→side=Integer(1), seed=seed)>>> H.is_subgraph(G, induced=False)
True>>> H.size() <= G.size()
True>>> Gpos = G.get_pos()>>> Hpos = H.get_pos()>>> all(Gpos[u] == Hpos[u] for u in G)
True

When the radius is more than√

2side, the graph is a clique:sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1)˓→# needs scipy
sage: G.is_clique()˓→# needs scipy
True

␣
␣

>>> from sage.all import *>>> G = graphs.RandomUnitDiskGraph(Integer(10), radius=Integer(2),␣
˓→side=Integer(1))# needs scipy>>> G.is_clique()
˓→# needs scipy
Truestatic 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 thesame 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 [CFHM2013].
INPUT:• k – the number of levels of the ringed tree.
• vertex_labels (boolean) – whether to label vertices as binary words (default) or as integers.
EXAMPLES:
sage: # needs networkx
sage: G = graphs.RingedTree(5)sage: P = G.plot(vertex_labels=False, vertex_size=10)˓→# needs sage.plot
sage: P.show()# long time˓→# needs sage.plot
sage: G.vertices(sort=True)[ , 0 , 00 , 000 , 0000 , 0001 , 001 , 0010 ,␣␣0011 ,

01 ,(continues on next page)2.1. Common graphs963

Graph Theory, Release 10.4

(continued from previous page)

010 , 0100 , 0101 ,1000 , 1001 , 101 ,
111 , 1110 , 1111 ]

011 , 0110 , 0111 , 1 , 10 , 100 ,
1010 , 1011 , 11 , 110 , 1100 , 1101 ,>>> from sage.all import *>>> # needs networkx>>> G = graphs.RingedTree(Integer(5))>>> P = G.plot(vertex_labels=False, vertex_size=Integer(10))˓→# needs sage.plot>>> P.show()# long time
˓→# needs sage.plot>>> G.vertices(sort=True)[ , 0 , 00 , 000 , 0000 , 0001 , 001 , 0010 , 0011 , 01 ,
010 , 0100 , 0101 , 011 , 0110 , 0111 , 1 , 10 , 100 ,1000 , 1001 , 101 , 1010 , 1011 , 11 , 110 , 1100 , 1101 ,
111 , 1110 , 1111 ]␣

static RobertsonGraph()
Return the Robertson graph.
See the Wikipedia article Robertson_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.RobertsonGraph()
sage: g.order()19sage: 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()˓→# needs sage.numerical.mip
True
sage: g.is_vertex_transitive()
False

␣

>>> from sage.all import *>>> # needs networkx>>> g = graphs.RobertsonGraph()>>> g.order()19>>> g.size()38>>> g.diameter()3>>> g.girth()
5(continues on next page)

964

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> 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>>> g.chromatic_number()3>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> g.is_vertex_transitive()
False

static RookGraph(dim_list, radius=None, relabel=False)
Return 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 completegraphs 𝐾𝑛 𝐾𝑚 .
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of thechessboard• radius – integer (default: None); by setting the radius to a positive integer, one may decrease thepower of the rook to at most radius steps. When the radius is 1, the resulting graph is a 𝑑-dimensionalgrid.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (𝑛, 𝑚)-Rook’s Graph is isomorphic to the Cartesian product of two complete graphs:
sage: G = graphs.RookGraph( [3, 4] )sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.
˓→CompleteGraph(4) )sage: G.is_isomorphic( H )True>>> from sage.all import *>>> G = graphs.RookGraph( [Integer(3), Integer(4)] )>>> H = ( graphs.CompleteGraph(Integer(3)) ).cartesian_product( graphs.
˓→CompleteGraph(Integer(4)) )>>> 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

2.1. Common graphs965

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.RookGraph( [Integer(3), Integer(3), Integer(4)],␣
˓→radius=Integer(1) )>>> H = graphs.GridGraph( [Integer(3), Integer(4), Integer(3)] )>>> G.is_isomorphic( H )Truestatic RoseWindowGraph(n, a, r)
Return a rose window graph with 2𝑛 nodes.
The rose window graphs is a family of tetravalant graphs introduced in [Wilson2008]. The parameters 𝑛, 𝑎and 𝑟 are integers such that 𝑛 > 2, 1 ≤ 𝑎, 𝑟 < 𝑛, and 𝑟 ̸= 𝑛/2.
INPUT:• n – the number of nodes is 2 * 𝑛• a – integer such that 1 ≤ 𝑎 < 𝑛 determining a-spoke edges• r – integer such that 1 ≤ 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first 𝑛 nodes drawn
on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after
that. The inner circle is drawn with the (𝑛)th node at the top, then counterclockwise as well. Vertices in theouter circle are connected in the circular manner, vertices in the inner circle are connected when their label
have difference 𝑟 (mod 𝑛). Vertices on the outer rim are connected with the vertices on the inner rim when
they are at the same position and when they are 𝑎 apart.
EXAMPLES:
The vertices of a rose window graph have all degree 4:
sage: G = graphs.RoseWindowGraph(5, 1, 2)
sage: all(G.degree(u) == 4 for u in G)
True>>> from sage.all import *>>> G = graphs.RoseWindowGraph(Integer(5), Integer(1), Integer(2))>>> all(G.degree(u) == Integer(4) for u in G)
True

The smallest rose window graph as parameters (3, 2, 1):
sage: G = graphs.RoseWindowGraph(3, 2, 1)
sage: all(G.degree(u) == 4 for u in G)
True>>> from sage.all import *>>> G = graphs.RoseWindowGraph(Integer(3), Integer(2), Integer(1))>>> all(G.degree(u) == Integer(4) for u in G)
Truestatic 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.

966

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
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)>>> from sage.all import *>>> S = graphs.SchlaefliGraph()>>> S.is_strongly_regular(parameters=True)(27, 16, 10, 8)

The graph is vertex-transitive:
sage: S.is_vertex_transitive()˓→# needs sage.groupsTrue␣>>> from sage.all import *>>> S.is_vertex_transitive()
˓→# needs sage.groups
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>>> from sage.all import *>>> neighborhood = S.subgraph(vertices=S.neighbors(Integer(0)))>>> graphs.ClebschGraph().complement().is_isomorphic(neighborhood)Truestatic ShrikhandeGraph()
Return the Shrikhande graph.
For more information, see the MathWorld article on the Shrikhande graph or the Wikipedia article
Shrikhande_graph.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:The Shrikhande graph was defined by S. S. Shrikhande in 1959. It has 16 vertices and 48 edges, and isstrongly regular of degree 6 with parameters (2, 2):

2.1. Common graphs

967

Graph Theory, Release 10.4

sage: G = graphs.ShrikhandeGraph(); G
Shrikhande graph: Graph on 16 vertices
sage: G.order()16
sage: G.size()48
sage: G.is_regular(6)Truesage: set([ len([x for x in G.neighbors(i) if x in G.neighbors(j)])....:
for i in range(G.order())....:
for j in range(i) ]){2}>>> from sage.all import *>>> G = graphs.ShrikhandeGraph(); G
Shrikhande graph: Graph on 16 vertices>>> G.order()16>>> G.size()48>>> G.is_regular(Integer(6))
True>>> set([ len([x for x in G.neighbors(i) if x in G.neighbors(j)])...
for i in range(G.order())...
for j in range(i) ]){2}

It is non-planar, and both Hamiltonian and Eulerian:sage: G.is_planar()False
sage: G.is_hamiltonian()˓→# needs sage.numerical.mip
True
sage: G.is_eulerian()True␣>>> from sage.all import *>>> G.is_planar()
False>>> G.is_hamiltonian()
˓→# needs sage.numerical.mip
True>>> 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>>> from sage.all import *(continues on next page)

968

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G.radius()
2>>> G.diameter()2>>> 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()˓→# needs sage.groups192␣>>> from sage.all import *>>> G.chromatic_number()4>>> G.automorphism_group().cardinality()
˓→# needs sage.groups
192

It is an integral graph since it has only integral eigenvalues:
sage: G.characteristic_polynomial().factor()˓→# needs sage.libs.pari sage.modules(x - 6) * (x - 2)^6 * (x + 2)^9␣>>> from sage.all import *>>> G.characteristic_polynomial().factor()˓→# needs sage.libs.pari sage.modules(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 ofvertices: the top vertex of A with the bottom left vertex of B, the bottom right vertex of B with the top vertexof C, and the bottom left vertex of C with the bottom right vertex of A.
See also:

2.1. Common graphs969

Graph Theory, Release 10.4

970

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• HanoiTowerGraph(). There is another family of graphs called Sierpinski graphs, where all vertices
but 3 have valence 3. They are available using graphs.HanoiTowerGraph(3, n).
• GeneralizedSierpinskiGraph()
EXAMPLES:
sage: # needs sage.modules
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>>> from sage.all import *>>> # needs sage.modules>>> s4 = graphs.SierpinskiGasketGraph(Integer(4)); s4
Graph on 42 vertices>>> s4.size()81>>> s4.degree_histogram()[0, 0, 3, 0, 39]>>> s4.is_hamiltonian()
True

REFERENCES:[LLWC2011]
static SimsGewirtzGraph()
Return the Sims-Gewirtz Graph.
This graph is obtained from the Higman Sims graph by considering the graph induced by the vertices at
distance two from the vertices of an (any) edge. It is the only strongly regular graph with parameters 𝑣 = 56,
𝑘 = 10, 𝜆 = 0, 𝜇 = 2
For more information on the Sylvester graph, see https://www.win.tue.nl/ aeb/graphs/Sims-Gewirtz.html or
its Wikipedia article Gewirtz_graph.
See also:• HigmanSimsGraph().
EXAMPLES:
sage: g = graphs.SimsGewirtzGraph(); gSims-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)

2.1. Common graphs971

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.SimsGewirtzGraph(); gSims-Gewirtz Graph: Graph on 56 vertices>>> g.order()56>>> g.size()
280>>> g.is_strongly_regular(parameters = True)(56, 10, 0, 2)

static SousselierGraph()
Return the Sousselier Graph.
The Sousselier graph is a hypohamiltonian graph on 16 vertices and 27 edges. For more information, see
Wikipedia article Sousselier_graph or the corresponding French Wikipedia page.
EXAMPLES:
sage: g = graphs.SousselierGraph()
sage: g.order()16
sage: g.size()27
sage: g.radius()
2
sage: g.diameter()3
sage: g.automorphism_group().cardinality()˓→# needs sage.groups2
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
True

␣

␣

␣

>>> from sage.all import *>>> g = graphs.SousselierGraph()>>> g.order()16>>> g.size()27>>> g.radius()
2>>> g.diameter()3>>> g.automorphism_group().cardinality()
˓→# needs sage.groups2>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
False>>> g.delete_vertex(g.random_vertex())>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
True

972

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

static SquaredSkewHadamardMatrixGraph(n)Pseudo-𝑂𝐴(2𝑛, 4𝑛 − 1)-graph from a skew Hadamard matrix of order 4𝑛
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(), also known as pseudo Latin squares graph 𝐿2𝑛 (4𝑛 − 1), constructed from a skew Hadamard
matrix of order 4𝑛, due to Goethals and Seidel, see [BL1984].
See also:• is_orthogonal_array_block_graph()
EXAMPLES:
sage: # needs sage.combinat sage.modules
sage: G = graphs.SquaredSkewHadamardMatrixGraph(4)sage: G.is_strongly_regular(parameters=True)(225, 112, 55, 56)
sage: G = graphs.SquaredSkewHadamardMatrixGraph(5)sage: G.is_strongly_regular(parameters=True)# long time(361, 180, 89, 90)
sage: G = graphs.SquaredSkewHadamardMatrixGraph(9)sage: G.is_strongly_regular(parameters=True)# not tested(1225, 612, 305, 306)>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> G = graphs.SquaredSkewHadamardMatrixGraph(Integer(4))>>> G.is_strongly_regular(parameters=True)(225, 112, 55, 56)>>> G = graphs.SquaredSkewHadamardMatrixGraph(Integer(5))>>> G.is_strongly_regular(parameters=True)# long time(361, 180, 89, 90)>>> G = graphs.SquaredSkewHadamardMatrixGraph(Integer(9))>>> G.is_strongly_regular(parameters=True)# not tested(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 thetop, 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 thespring-layout algorithm for plotting. As far as display, the spring-layout should push all other nodes awayfrom the (0) node, and thus look very similar to this constructor’s positioning.
EXAMPLES:
sage: import networkx
˓→# needs networkx␣>>> from sage.all import *>>> import networkx
˓→# needs networkx

Compare the plots:
2.1. Common graphs973

Graph Theory, Release 10.4

sage: # needs networkx sage.plot
sage: n = networkx.star_graph(23)sage: spring23 = Graph(n)sage: posdict23 = graphs.StarGraph(23)sage: spring23.show()
sage: posdict23.show() # long time

# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> n = networkx.star_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.StarGraph(Integer(23))>>> spring23.show()# long time>>> posdict23.show() # long time

View many star graphs as a Sage Graphics Array
With this constructor (i.e., the position dictionary filled)
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.StarGraph(i+3)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.StarGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

Compared to plotting with the spring-layout algorithm
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.star_graph(i+3)....:
k = Graph(spr)(continues on next page)

974

Chapter 2. Constructors and databases

Graph Theory, Release 10.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 = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.star_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

static SuzukiGraph()
Return the Suzuki Graph.
The Suzuki graph has 1782 vertices, and is strongly regular with parameters (1782, 416, 100, 96). Known as
S.15 in [Hub1975].
Note: It takes approximately 50 seconds to build this graph. Do not be too impatient.
EXAMPLES:
sage: g = graphs.SuzukiGraph(); g # optional internet # not tested
Suzuki graph: Graph on 1782 vertices
sage: g.is_strongly_regular(parameters=True) # optional internet # not tested(1782, 416, 100, 96)>>> from sage.all import *>>> g = graphs.SuzukiGraph(); g # optional internet # not tested
Suzuki graph: Graph on 1782 vertices>>> g.is_strongly_regular(parameters=True) # optional internet # not tested(1782, 416, 100, 96)

static SwitchedSquaredSkewHadamardMatrixGraph(n)A strongly regular graph in Seidel switching class of SquaredSkewHadamardMatrixGraph().
A strongly regular graph in the Seidel switching class of the disjoint union of a 1-vertex graph andthe 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 thelatter graph (see [BH2012]) coincides with the set of parameters of the complement of the graph returned by
2.1. Common graphs975

Graph Theory, Release 10.4

this function.
See also:• is_switch_skewhad()
EXAMPLES:
sage: # needs sage.combinat sage.modules
sage: g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(4)sage: g.is_strongly_regular(parameters=True)(226, 105, 48, 49)
sage: from sage.combinat.designs.twographs import twograph_descendantsage: twograph_descendant(g, 0).is_strongly_regular(parameters=True)(225, 112, 55, 56)
sage: gc = g.complement()
sage: twograph_descendant(gc, 0).is_strongly_regular(parameters=True)(225, 112, 55, 56)>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(Integer(4))>>> g.is_strongly_regular(parameters=True)(226, 105, 48, 49)>>> from sage.combinat.designs.twographs import twograph_descendant>>> twograph_descendant(g, Integer(0)).is_strongly_regular(parameters=True)(225, 112, 55, 56)>>> gc = g.complement()>>> twograph_descendant(gc, Integer(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(); gSylvester Graph: Graph on 36 vertices
sage: g.order()36sage: g.size()90
sage: g.is_regular(k=5)
True>>> from sage.all import *>>> g = graphs.SylvesterGraph(); gSylvester Graph: Graph on 36 vertices(continues on next page)

976

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.order()36>>> g.size()90>>> g.is_regular(k=Integer(5))
Truestatic SymplecticDualPolarGraph(m, q)
Return the Symplectic Dual Polar Graph 𝐷𝑆𝑝(𝑚, 𝑞).
For more information on Symplectic Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:• m, q – integers; 𝑞 must be a prime power, and 𝑚 must be even
EXAMPLES:
sage: G = graphs.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])>>> from sage.all import *>>> G = graphs.SymplecticDualPolarGraph(Integer(6),Integer(3)); G# not␣
˓→tested (long time)
Symplectic Dual Polar Graph DSp(6, 3): Graph on 1120 vertices>>> G.is_distance_regular(parameters=True)# not tested (long time)([39, 36, 27, None], [None, 1, 4, 13])

static SymplecticPolarGraph(d, q, algorithm=None)
Return the Symplectic Polar Graph 𝑆𝑝(𝑑, 𝑞).
The Symplectic Polar Graph 𝑆𝑝(𝑑, 𝑞) is built from a projective space of dimension 𝑑 − 1 over a field 𝐹𝑞 , anda symplectic form 𝑓 . Two vertices 𝑢, 𝑣 are made adjacent if 𝑓 (𝑢, 𝑣) = 0.
See the page on symplectic graphs on Andries Brouwer’s website.
INPUT:• d, q – integers; note that only even values of 𝑑 are accepted by the function.
• algorithm – string (default: None); if set to gap , then the computation is carried via GAP libraryinterface, 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}˓→# needs sage.rings.number_field
True

2.1. Common graphs␣977

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.SymplecticPolarGraph(Integer(6), Integer(2))>>> g.is_strongly_regular(parameters=True)(63, 30, 13, 15)>>> set(g.spectrum()) == {-Integer(5), Integer(3), Integer(30)}˓→# needs sage.rings.number_fieldTrue␣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: # needs sage.libs.gap
sage: O = graphs.OrthogonalPolarGraph(5, 3)
sage: O.is_strongly_regular(parameters=True)(40, 12, 2, 4)
sage: O.is_isomorphic(G)False
sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap")
˓→(long time)
sage: S.is_strongly_regular(parameters=True)
˓→(long time)(1365, 340, 83, 85)# not tested␣# not tested␣>>> from sage.all import *>>> G = graphs.SymplecticPolarGraph(Integer(4), Integer(3))>>> G.is_strongly_regular(parameters=True)(40, 12, 2, 4)>>> # needs sage.libs.gap>>> O = graphs.OrthogonalPolarGraph(Integer(5), Integer(3))>>> O.is_strongly_regular(parameters=True)(40, 12, 2, 4)>>> O.is_isomorphic(G)False>>> S = graphs.SymplecticPolarGraph(Integer(6), Integer(4), algorithm="gap") ␣˓→# not tested (long time)>>> S.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()50sage: g.size()75
sage: g.chromatic_number()
3

978

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.SzekeresSnarkGraph()>>> g.order()50>>> g.size()75>>> 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 (Wikipedia article Generalized_quadrangle) of order (𝑞 − 1, 𝑞 + 1), see 3.1.3 in [PT2009]. Fix a plane Π ⊂ Θ and a hyperoval 𝑂 ⊂ Π. The pointsof 𝑇2* (𝑞) := 𝑇2* (𝑂) are the points of Θ outside Π, and the lines are the lines of Θ outside Π that meet Π ina point of 𝑂.
INPUT:• q – a power of two• dual – boolean (default: False); whether to return the graph of 𝑇2* (𝑂) or of the dual 𝑇2* (𝑂) (whenTrue)• 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 ofhyperoval 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 webuild is the classical one, i.e. a conic with the point of intersection of its tangent lines.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness ornot
EXAMPLES:
using the built-in construction:
sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.T2starGeneralizedQuadrangleGraph(Integer(4)); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 18, 2, 6)>>> g = graphs.T2starGeneralizedQuadrangleGraph(Integer(4), dual=True); g
T2*(O,4)*; GQ(5, 3): Graph on 96 vertices(continues on next page)2.1. Common graphs979

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_strongly_regular(parameters=True)(96, 20, 4, 4)

supplying your own hyperoval:
sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> F = GF(Integer(4), b )>>> O = [vector(F,(Integer(0),Integer(0),Integer(0),Integer(1))),vector(F,˓→(Integer(0),Integer(0),Integer(1),Integer(0)))] + [vector(F, (Integer(0),˓→Integer(1),x**Integer(2),x))...
for x in F]>>> g = graphs.T2starGeneralizedQuadrangleGraph(Integer(4), hyperoval=O,␣
˓→field=F); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 18, 2, 6)

static TabacjnGraph(n, a, b, r)
Return a Tabačjn graph with 2𝑛 nodes.
The Tabačjn graphs is a family of pentavalent bicirculants graphs proposed in [AHKOS2014] as a generalization of generalized Petersen graphs. The parameters 𝑛, 𝑎, 𝑏, 𝑟 are integers such that 𝑛 ≥ 3,
1 ≤ 𝑎, 𝑏, 𝑟 ≤ 𝑛 − 1, with 𝑎 ̸= 𝑏 and 𝑟 ̸= 𝑛/2.
INPUT:• n – the number of nodes is 2 * 𝑛• a – integer such that 0 < 𝑎 < 𝑛 and 𝑎 ̸= 𝑏, that determines a-spoke edges• b – integer such that 0 < 𝑏 < 𝑛 and 𝑏 ̸= 𝑎, that determines b-spoke edges• r – integer such that 0 < 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By
convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first 𝑛 nodes drawn
on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after
that. The inner circle is drawn with the (𝑛)th node at the top, then counterclockwise as well. Vertices in theouter circle are connected in the circular manner, vertices in the inner circle are connected when their label
have difference 𝑟 (mod 𝑛). Vertices on the outer rim are connected with the vertices on the inner rim when
they are at the same position and when they are 𝑎 and 𝑏 apart.
EXAMPLES:
sage: G = graphs.TabacjnGraph(3, 1, 2, 1)
sage: G.degree()[5, 5, 5, 5, 5, 5]
sage: G.is_isomorphic(graphs.CompleteGraph(6))(continues on next page)

980

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)True
sage: G = graphs.TabacjnGraph(6, 1, 5, 2)
sage: I = graphs.IcosahedralGraph()
sage: G.is_isomorphic(I)
True>>> from sage.all import *>>> G = graphs.TabacjnGraph(Integer(3), Integer(1), Integer(2), Integer(1))>>> G.degree()[5, 5, 5, 5, 5, 5]>>> G.is_isomorphic(graphs.CompleteGraph(Integer(6)))
True>>> G = graphs.TabacjnGraph(Integer(6), Integer(1), Integer(5), Integer(2))>>> I = graphs.IcosahedralGraph()>>> G.is_isomorphic(I)True

static TadpoleGraph(n1, n2)
Return a tadpole graph with 𝑛1 + 𝑛2 nodes.
A tadpole graph is a path graph (order 𝑛2 ) connected to a cycle graph (order 𝑛1 ).
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 𝑛1 -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˓→# needs sage.plot␣>>> from sage.all import *>>> g = graphs.TadpoleGraph(Integer(13), Integer(4)); g
Tadpole graph: Graph on 17 vertices>>> g.show()# long time
˓→# needs sage.plot

static TaylorTwographDescendantSRG(q, clique_partition=False)
Return the descendant graph of the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd.
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 , (𝑞 2 + 1)(𝑞 − 1)/2, (𝑞 − 1)3 /4 − 1, (𝑞 2 +1)(𝑞 − 1)/4) obtained as a two-graph descendant of the Taylor s two-graph 𝑇 . This graph admits
a partition into cliques of size 𝑞, which are useful in TaylorTwographSRG(), a strongly regular graphon 𝑞 3 + 1 vertices in the Seidel switching class of 𝑇 , for which we need (𝑞 2 + 1)/2 cliques. The cliques are
the 𝑞 2 lines on 𝑣0 of the projective plane containing the unital for 𝑈3 (𝑞), and intersecting the unital (i.e. thevertices of the graph and the point we remove) in 𝑞 + 1 points. This is all taken from §7E of [BL1984].
INPUT:• q – a power of an odd prime number• clique_partition – boolean (default: False); when set to True, return 𝑞 2 − 1 cliques of size
𝑞 with empty pairwise intersection. (Removing all of them leaves a clique, too), and the point removed
from the unital.
2.1. Common graphs981

Graph Theory, Release 10.4

EXAMPLES:
sage: # needs sage.rings.finite_rings
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_twographsage: T = taylor_twograph(3)# long time
sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long timeTrue
sage: g = graphs.TaylorTwographDescendantSRG(5)# not tested (long␣˓→time)sage: g.is_strongly_regular(parameters=True)# not tested (long␣˓→time)(125, 52, 15, 26)>>> from sage.all import *>>> # needs sage.rings.finite_rings>>> g = graphs.TaylorTwographDescendantSRG(Integer(3)); g
Taylor two-graph descendant SRG: Graph on 27 vertices>>> g.is_strongly_regular(parameters=True)(27, 10, 1, 5)>>> from sage.combinat.designs.twographs import taylor_twograph>>> T = taylor_twograph(Integer(3))# long time>>> g.is_isomorphic(T.descendant(T.ground_set()[Integer(1)])) # long timeTrue>>> g = graphs.TaylorTwographDescendantSRG(Integer(5))# not tested␣
˓→(long time)>>> g.is_strongly_regular(parameters=True)# not tested (long time)(125, 52, 15, 26)

static TaylorTwographSRG(q)Return a strongly regular graph from the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 + 1, 𝑞(𝑞 2 + 1)/2, (𝑞 2 + 3)(𝑞 − 1)/4, (𝑞 2 +1)(𝑞 + 1)/4) in the Seidel switching class of Taylor two-graph. Details are in §7E of [BL1984].
INPUT:• q – a power of an odd prime number
See also:• TaylorTwographDescendantSRG()
EXAMPLES:
sage: t = graphs.TaylorTwographSRG(3); t˓→# needs sage.rings.finite_rings
Taylor two-graph SRG: Graph on 28 vertices
sage: t.is_strongly_regular(parameters=True)˓→# needs sage.rings.finite_rings(28, 15, 6, 10)>>> from sage.all import *>>> t = graphs.TaylorTwographSRG(Integer(3)); t˓→# needs sage.rings.finite_rings␣␣␣(continues on next page)982

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

Taylor two-graph SRG: Graph on 28 vertices>>> t.is_strongly_regular(parameters=True)
˓→# needs sage.rings.finite_rings(28, 15, 6, 10)

static TetrahedralGraph()
Return a tetrahedral graph (with 4 nodes).
A tetrahedron is a 4-sided triangular pyramid. The tetrahedral graph corresponds to the connectivity of thevertices of the tetrahedron. This graph is equivalent to a wheel graph with 4 nodes and also a complete graphon four nodes. (See examples below).
PLOTTING: The Tetrahedral graph should be viewed in 3 dimensions. We choose to use a planar embeddingof the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will
be added to select the desired layout.
EXAMPLES:
Construct and show a Tetrahedral graph:
sage: g = graphs.TetrahedralGraph()
sage: g.show()˓→# needs sage.plot>>> from sage.all import *>>> g = graphs.TetrahedralGraph()>>> g.show()˓→# needs sage.plot# long time␣# long time

The following example requires networkx:
sage: import networkx as NX
˓→# needs networkx␣>>> from sage.all import *>>> import networkx as NX
˓→# needs networkx

Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm below in a Sage graphics array:sage: # needs networkx sage.plot
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 = graphics_array(j)sage: G.show()# long time

2.1. Common graphs983

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs networkx sage.plot>>> tetra_pos = graphs.TetrahedralGraph()>>> tetra_spring = Graph(NX.tetrahedral_graph())>>> wheel = graphs.WheelGraph(Integer(4))>>> complete = graphs.CompleteGraph(Integer(4))>>> g = [tetra_pos, tetra_spring, wheel, complete]>>> j = []>>> for i in range(Integer(2)):...
n = []...
for m in range(Integer(2)):...
n.append(g[i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> 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()˓→# needs sage.plot>>> from sage.all import *>>> T = graphs.ThomsenGraph()>>> T
Thomsen graph: Graph on 6 vertices>>> T.graph6_string()EFz_>>> (graphs.ThomsenGraph()).show()˓→# needs sage.plot# long time␣# long time

static TietzeGraph()
Return the Tietze Graph.
For more information on the Tietze Graph, see the Wikipedia article Tietze%27s_graph.
EXAMPLES:
sage: g = graphs.TietzeGraph()
sage: g.order()12sage: g.size()18
sage: g.diameter()3(continues on next page)984

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: g.girth()3
sage: g.automorphism_group().cardinality()˓→# needs sage.groups
12
sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6))˓→# needs sage.groups
True

␣

␣

>>> from sage.all import *>>> g = graphs.TietzeGraph()>>> g.order()12>>> g.size()18>>> g.diameter()3>>> g.girth()3>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
12>>> g.automorphism_group().is_isomorphic(groups.permutation.
˓→Dihedral(Integer(6)))# needs sage.groups
Truestatic ToleranceGraph(tolrep)
Return the graph generated by the tolerance representation tolrep.
The tolerance representation tolrep is described by the list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), . . . , (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where
𝐼𝑖 = (𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line with 𝑙𝑖 < 𝑟𝑖 and 𝑡𝑖 a strictly positive value, called
tolerance. This representation generates the tolerance graph with the vertex set {0, 1, . . . , 𝑘} and the edge
set {(𝑖, 𝑗) : |𝐼𝑖 ∩ 𝐼𝑗 | ≥ min{𝑡𝑖 , 𝑡𝑗 }} where |𝐼𝑖 ∩ 𝐼𝑗 | denotes the length of the intersection of 𝐼𝑖 and 𝐼𝑗 .
INPUT:• tolrep – list of triples (𝑙𝑖 , 𝑟𝑖 , 𝑡𝑖 ) where (𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line and 𝑡𝑖 a positive
value.
Note: The vertices are named 0, 1, . . . , 𝑘. The tolerance representation used to create the graph is savedwith 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)(continues on next page)2.1. Common graphs985

Graph Theory, Release 10.4

(continued from previous page)

sage: g.is_interval()
False
sage: g.is_weakly_chordal()True>>> from sage.all import *>>> tolrep = [(Integer(1),Integer(4),Integer(3)),(Integer(1),Integer(2),˓→Integer(1)),(Integer(2),Integer(3),Integer(1)),(Integer(0),Integer(3),˓→Integer(3))]>>> g = graphs.ToleranceGraph(tolrep)>>> g.get_vertex(Integer(3))(0, 3, 3)>>> neigh = g.neighbors(Integer(3))>>> for v in neigh: print(g.get_vertex(v))(1, 2, 1)(2, 3, 1)>>> g.is_interval()
False>>> 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>>> from sage.all import *>>> tolrep2 = [(Integer(0),Integer(4),Integer(5)),(Integer(1),Integer(2),˓→Integer(1)),(Integer(2),Integer(3),Integer(1)),(Integer(0),Integer(4),˓→Integer(5))]>>> g2 = graphs.ToleranceGraph(tolrep2)>>> g2.get_vertices(){0: (0, 4, 5), 1: (1, 2, 1), 2: (2, 3, 1), 3: (0, 4, 5)}>>> g2.is_isomorphic(g)TrueReal 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>>> from sage.all import *>>> tolrep = [(RealNumber( 0.1 ),RealNumber( 3.3 ),RealNumber( 4.4 )),˓→(RealNumber( 1.1 ),RealNumber( 2.5 ),RealNumber( 1.1 )),(RealNumber( 1.4 ),˓→RealNumber( 4.4 ),RealNumber( 3.3 ))]>>> g = graphs.ToleranceGraph(tolrep)>>> g.is_isomorphic(graphs.PathGraph(Integer(3)))
True

static Toroidal6RegularGrid2dGraph(p, q)
986

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

Return a toroidal 6-regular grid.
The toroidal 6-regular grid is a 6-regular graph on 𝑝 × 𝑞 vertices and its elements have coordinates (𝑖, 𝑗) for𝑖 ∈ {0...𝑝 − 1} and 𝑗 ∈ {0...𝑞 − 1}.
Its edges are those of the ToroidalGrid2dGraph(), to which are added the edges between (𝑖, 𝑗) and((𝑖 + 1)%𝑝, (𝑗 + 1)%𝑞).
INPUT:• p, q – integers
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()˓→# needs sage.groupsTrue
sage: g.line_graph().is_vertex_transitive()˓→# needs sage.groupsTrue
sage: g.automorphism_group().cardinality()˓→# needs sage.groups
300
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
True

␣

␣

␣

␣

>>> from sage.all import *>>> g = graphs.Toroidal6RegularGrid2dGraph(Integer(5),Integer(5))>>> g.is_regular(k=Integer(6))
True>>> g.is_vertex_transitive()
˓→# needs sage.groupsTrue>>> g.line_graph().is_vertex_transitive()
˓→# needs sage.groupsTrue>>> g.automorphism_group().cardinality()
˓→# needs sage.groups
300>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
Truestatic ToroidalGrid2dGraph(p, q)
Return a toroidal 2-dimensional grid graph with 𝑝 × 𝑞 nodes (𝑝 rows and 𝑞 columns).
The toroidal 2-dimensional grid with parameters 𝑝, 𝑞 is the 2-dimensional grid graph with identical parameters
to which are added the edges ((𝑖, 0), (𝑖, 𝑞 − 1)) and ((0, 𝑖), (𝑝 − 1, 𝑖)).
EXAMPLES:
The toroidal 2-dimensional grid is a regular graph, while the usual 2-dimensional grid is not

2.1. Common graphs987

Graph Theory, Release 10.4

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>>> from sage.all import *>>> tgrid = graphs.ToroidalGrid2dGraph(Integer(8),Integer(9))>>> print(tgrid)
Toroidal 2D Grid Graph with parameters 8,9>>> grid = graphs.Grid2dGraph(Integer(8),Integer(9))>>> grid.is_regular()False>>> tgrid.is_regular()Truestatic 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˓→# needs sage.geometry.polyhedron sage.groups sage.rings.number_field
Traceback (most recent call last):...
ValueError: *Error: Numerical inconsistency is found. Use the GMP exact␣˓→arithmetic.
sage: g.order(), g.size()# not tested˓→# needs sage.geometry.polyhedron sage.groups sage.rings.number_field(120, 180)␣␣>>> from sage.all import *>>> g = graphs.TruncatedIcosidodecahedralGraph(); g˓→# needs sage.geometry.polyhedron sage.groups sage.rings.number_field
Traceback (most recent call last):...
ValueError: *Error: Numerical inconsistency is found. Use the GMP exact␣˓→arithmetic.
>>> g.order(), g.size()# not tested
˓→# needs sage.geometry.polyhedron sage.groups sage.rings.number_field(120, 180)

static TruncatedTetrahedralGraph()
Return the truncated tetrahedron.
The truncated tetrahedron is an Archimedean solid with 12 vertices and 18 edges. For more information, see
the Wikipedia article Truncated_tetrahedron.
EXAMPLES:
988

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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())˓→# needs sage.geometry.polyhedron
True>>> from sage.all import *>>> g = graphs.TruncatedTetrahedralGraph(); g
Truncated Tetrahedron: Graph on 12 vertices>>> g.order(), g.size()(12, 18)>>> g.is_isomorphic(polytopes.simplex(Integer(3)).truncation().graph())˓→# needs sage.geometry.polyhedron
True

␣

␣

static TruncatedWittGraph()
Return the truncated Witt graph.
This builds the large Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [15, 14, 12; 1, 1, 9].
EXAMPLES:
sage: # long time, needs sage.libs.pari sage.modules
sage: G = graphs.TruncatedWittGraph()
sage: G.is_distance_regular(True)([15, 14, 12, None], [None, 1, 1, 9])>>> from sage.all import *>>> # long time, needs sage.libs.pari sage.modules>>> G = graphs.TruncatedWittGraph()>>> G.is_distance_regular(True)([15, 14, 12, None], [None, 1, 1, 9])

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 367.
static TuranGraph(n, r)
Returns the Turan graph with parameters 𝑛, 𝑟.
Turan graphs are complete multipartite graphs with 𝑛 vertices and 𝑟 subsets, denoted 𝑇 (𝑛, 𝑟), with the property that the sizes of the subsets are as close to equal as possible. The graph 𝑇 (𝑛, 𝑟) will have 𝑛 (mod 𝑟)
subsets of size ⌊𝑛/𝑟⌋ and 𝑟 − (𝑛 (mod 𝑟)) subsets of size ⌈𝑛/𝑟⌉. See the Wikipedia article Turan_graphfor 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:2.1. Common graphs989

Graph Theory, Release 10.4

sage: g = graphs.TuranGraph(13, 4)
sage: k = graphs.CompleteMultipartiteGraph([3,3,3,4])
sage: g.is_isomorphic(k)True>>> from sage.all import *>>> g = graphs.TuranGraph(Integer(13), Integer(4))>>> k = graphs.CompleteMultipartiteGraph([Integer(3),Integer(3),Integer(3),˓→Integer(4)])>>> g.is_isomorphic(k)
True
2

2

−𝑠 )
The Turan graph 𝑇 (𝑛, 𝑟) has (𝑟−1)(𝑛+ 𝑠(𝑠−1)edges, where 𝑠 = 𝑛 mod 𝑟 (Issue #34249):2𝑟
2

sage: n = 12
sage: r = 8
sage: g = graphs.TuranGraph(n, r)
sage: def count(n, r):....:s = n % r....:
return (r - 1) * (n**2 - s**2) / (2*r) + s*(s - 1)/2
sage: g.size() == count(n, r)
True
sage: n = randint(3, 100)
sage: r = randint(2, n - 1)sage: g = graphs.TuranGraph(n, r)
sage: g.size() == count(n, r)
True>>> from sage.all import *>>> n = Integer(12)>>> r = Integer(8)>>> g = graphs.TuranGraph(n, r)>>> def count(n, r):...
s = n % r...
return (r - Integer(1)) * (n**Integer(2) - s**Integer(2)) /␣˓→(Integer(2)*r) + s*(s - Integer(1))/Integer(2)>>> g.size() == count(n, r)
True>>> n = randint(Integer(3), Integer(100))>>> r = randint(Integer(2), n - Integer(1))>>> g = graphs.TuranGraph(n, r)>>> g.size() == count(n, r)
True

static Tutte12Cage()
Return the Tutte 12-Cage.
See the Wikipedia article Tutte_12-cage.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.Tutte12Cage()sage: g.order()126
sage: g.size()
189(continues on next page)

990

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: g.girth()12
sage: g.diameter()6
sage: g.show()˓→# needs sage.plot␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.Tutte12Cage()>>> g.order()126>>> g.size()
189>>> g.girth()
12>>> g.diameter()6>>> g.show()˓→# needs sage.plot

static TutteCoxeterGraph(embedding=2)
Return the Tutte-Coxeter graph.
See the Wikipedia article Tutte-Coxeter_graph.
INPUT:• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.TutteCoxeterGraph()
sage: g.order()30
sage: g.size()
45
sage: g.girth()8
sage: g.diameter()4
sage: g.show()˓→# needs sage.plot
sage: graphs.TutteCoxeterGraph(embedding=1).show()˓→# needs sage.plot

␣# long time␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.TutteCoxeterGraph()>>> g.order()30>>> g.size()45>>> g.girth()
8(continues on next page)2.1. Common graphs991

Graph Theory, Release 10.4

(continued from previous page)>>> g.diameter()4>>> g.show()˓→# needs sage.plot>>> graphs.TutteCoxeterGraph(embedding=Integer(1)).show()˓→# needs sage.plot# long time␣

static TutteGraph()
Return the Tutte Graph.
The Tutte graph is a 3-regular, 3-connected, and planar non-hamiltonian graph. For more information on the
Tutte Graph, see the Wikipedia article Tutte_graph.
EXAMPLES:
sage: g = graphs.TutteGraph()
sage: g.order()46
sage: g.size()69
sage: g.is_planar()True
sage: g.vertex_connectivity()# long time˓→# needs sage.numerical.mip
3
sage: g.girth()4
sage: g.automorphism_group().cardinality()˓→# needs sage.groups3
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
False

␣

␣

␣

>>> from sage.all import *>>> g = graphs.TutteGraph()>>> g.order()46>>> g.size()69>>> g.is_planar()True>>> g.vertex_connectivity()# long time
˓→# needs sage.numerical.mip
3>>> g.girth()4>>> g.automorphism_group().cardinality()
˓→# needs sage.groups3>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
False

static U42Graph216()
Return a (216,40,4,8)-strongly regular graph from [CRS2016].

992

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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 graphwith the parameters in question.
EXAMPLES:
sage: G=graphs.U42Graph216()
sage: G.is_strongly_regular(parameters=True)(216, 40, 4, 8)>>> from sage.all import *>>> G=graphs.U42Graph216()>>> G.is_strongly_regular(parameters=True)(216, 40, 4, 8)# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grapestatic U42Graph540()
Return a (540,187,58,68)-strongly regular graph from [CRS2016].
Build the graph, interpreting the 𝑈4 (2)-action considered in [CRS2016] as the action of 𝑈4 (2) = 𝑆𝑝4 (3) <𝑈4 (3) on the nonsingular, w.r.t. to the Hermitean form stabilised by 𝑈4 (3), points of the 3-dimensional
projective space over 𝐺𝐹 (9). There are several possible mergings of orbitals, some leading to non-isomorphic
graphs with the same parameters. We found the merging here using [FK1991].
EXAMPLES:
sage: G = graphs.U42Graph540()
sage: G.is_strongly_regular(parameters=True)(540, 187, 58, 68)>>> from sage.all import *>>> G = graphs.U42Graph540()>>> G.is_strongly_regular(parameters=True)(540, 187, 58, 68)# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grapestatic USAMap(continental=False)
Return states of USA as a graph of common border.
The graph has an edge between those states that have common land border line or point. Hence for example
Colorado and Arizona are marked as neighbors, but Michigan and Minnesota are not.
INPUT:• continental – boolean (default: False); whether to exclude Alaska and Hawaii
EXAMPLES:
How many states are neighbor’s neighbor for Pennsylvania:
sage: USA = graphs.USAMap()sage: distance = USA.shortest_path_lengths( Pennsylvania )sage: len([n2 for n2, d in distance.items() if d == 2])7>>> from sage.all import *>>> USA = graphs.USAMap()>>> distance = USA.shortest_path_lengths( Pennsylvania )>>> len([n2 for n2, d in distance.items() if d == Integer(2)])
7

2.1. Common graphs993

Graph Theory, Release 10.4

Diameter for continental USA:sage: USAcont = graphs.USAMap(continental=True)
sage: USAcont.diameter()11>>> from sage.all import *>>> USAcont = graphs.USAMap(continental=True)>>> USAcont.diameter()11

static UnitaryDualPolarGraph(m, q)
Return the Dual Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:• m, q – integers; 𝑞 must be a prime power
EXAMPLES:
The point graph of a generalized quadrangle (see Wikipedia article Generalized_quadrangle, [PT2009]) oforder (8,4):
sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time˓→# needs sage.libs.gap
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices
sage: G.is_strongly_regular(parameters=True)# long time˓→# needs sage.libs.gap(297, 40, 7, 5)>>> from sage.all import *>>> G = graphs.UnitaryDualPolarGraph(Integer(5),Integer(2)); G # long time˓→# needs sage.libs.gap
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices>>> G.is_strongly_regular(parameters=True)# long time
˓→# needs sage.libs.gap(297, 40, 7, 5)

␣

␣

␣

Another way to get the generalized quadrangle of order (2,4):
sage: G = graphs.UnitaryDualPolarGraph(4,2); G˓→# needs sage.libs.gap
Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices
sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2, - ))˓→# needs sage.libs.gap
True>>> from sage.all import *>>> G = graphs.UnitaryDualPolarGraph(Integer(4),Integer(2)); G˓→# needs sage.libs.gap
Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices>>> G.is_isomorphic(graphs.OrthogonalPolarGraph(Integer(6),Integer(2), - ))˓→# needs sage.libs.gap
True

␣

␣

␣

␣

A bigger graph:

994

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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])>>> from sage.all import *>>> G = graphs.UnitaryDualPolarGraph(Integer(6),Integer(2)); G# not tested␣
˓→(long time)
Unitary Dual Polar Graph DU(6, 2): Graph on 891 vertices>>> G.is_distance_regular(parameters=True)# not tested (long time)([42, 40, 32, None], [None, 1, 5, 21])static UnitaryPolarGraph(m, q, algorithm='gap')
Return the Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Polar graphs, see the page of Andries Brouwer’s website.
INPUT:• m, q – integers; 𝑞 must be a prime power• algorithm – string (default: "gap"); if set to ‘gap’ then the computation is carried via GAP libraryinterface, computing totally singular subspaces, which is faster for large examples (especially with 𝑞 > 2).
Otherwise it is done directly.
EXAMPLES:
sage: # needs sage.libs.gap
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>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.UnitaryPolarGraph(Integer(4),Integer(2)); G
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices>>> G.is_strongly_regular(parameters=True)(45, 12, 3, 3)>>> graphs.UnitaryPolarGraph(Integer(5),Integer(2)).is_strongly_
˓→regular(parameters=True)(165, 36, 3, 9)>>> graphs.UnitaryPolarGraph(Integer(6),Integer(2))# not tested (long␣˓→time)Unitary Polar Graph U(6, 2): Graph on 693 vertices

static UstimenkoGraph(m, q)
Return the Ustimenko graph with parameters (𝑚, 𝑞).
This is the distance(︀ )︀1 or 2 graph(︀)︀of the dual polar(︀𝑛)︀ graph 𝐶𝑚−1 (𝑞). The graph is distance-regular withparameters (𝑑, 𝑞 2 , 31 𝑞 − 1, 𝑚+1
−
1),
where
1
𝑘 𝑞 is the 𝑞-binomial coefficient.
𝑞
INPUT:• m, q – integers; 𝑞 must be a prime power and 𝑚 > 1
2.1. Common graphs995

Graph Theory, Release 10.4

EXAMPLES:
sage: G = graphs.UstimenkoGraph(4, 2)˓→# needs sage.libs.gap
sage: G.is_distance_regular(True)˓→# needs sage.libs.gap([70, 32, None], [None, 1, 35])␣␣>>> from sage.all import *>>> G = graphs.UstimenkoGraph(Integer(4), Integer(2))˓→# needs sage.libs.gap>>> G.is_distance_regular(True)
˓→# needs sage.libs.gap([70, 32, None], [None, 1, 35])␣

REFERENCES:
See [BCN1989] p. 279 or [VDKT2016] p. 22.
static WagnerGraph()
Return the Wagner Graph.
See the Wikipedia article Wagner_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.WagnerGraph()
sage: g.order()8sage: g.size()12
sage: g.girth()4
sage: g.diameter()2
sage: g.show()˓→# needs sage.plot␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.WagnerGraph()>>> g.order()8>>> g.size()12>>> g.girth()4>>> g.diameter()2>>> g.show()˓→# needs sage.plot

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

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: g = graphs.WatkinsSnarkGraph()
sage: g.order()50sage: g.size()75
sage: g.chromatic_number()3>>> from sage.all import *>>> g = graphs.WatkinsSnarkGraph()>>> g.order()50>>> g.size()75>>> 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 intermediate graphs and run a small isomorphism test, while everything could be replaced by a pre-computed listof 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(); gWells 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>>> from sage.all import *>>> g = graphs.WellsGraph(); gWells graph: Graph on 32 vertices>>> g.order()32>>> g.size()
80>>> g.girth()5>>> g.diameter()4>>> g.chromatic_number()(continues on next page)2.1. Common graphs997

Graph Theory, Release 10.4

(continued from previous page)4>>> g.is_regular(k=Integer(5))
Truestatic 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 thetop, and the rest following in a counterclockwise manner.
With the wheel graph, we see that it doesn’t take a very large 𝑛 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: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....: k = graphs.WheelGraph(i+3)....: g.append(k)...
sage: for i in range(3):....: n = []....: for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....: j.append(n)...
sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):... k = graphs.WheelGraph(i+Integer(3))... g.append(k)...
>>> for i in range(Integer(3)):... n = []... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)...
>>> G = graphics_array(j)>>> G.show()# long time

Next, using the spring-layout algorithm:

998

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs networkx sage.plot
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 = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> import networkx>>> g = []>>> j = []>>> for i in range(Integer(9)):... spr = networkx.wheel_graph(i+Integer(3))... k = Graph(spr)... g.append(k)...
>>> for i in range(Integer(3)):... n = []... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)...
>>> G = graphics_array(j)>>> G.show()# long time

Compare the plotting:sage: # needs networkx sage.plot
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>>> from sage.all import *>>> # needs networkx sage.plot>>> n = networkx.wheel_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.WheelGraph(Integer(23))>>> spring23.show()# long time>>> posdict23.show() # long time

static WienerArayaGraph()
Return the Wiener-Araya Graph.
2.1. Common graphs

999

Graph Theory, Release 10.4

The Wiener-Araya Graph is a planar hypohamiltonian graph on 42 vertices and 67 edges. For more information, see the Wolfram Page on the Wiener-Araya Graph or Wikipedia article Wiener-Araya_graph.
EXAMPLES:
sage: g = graphs.WienerArayaGraph()
sage: g.order()42sage: g.size()
67
sage: g.girth()4
sage: g.is_planar()True
sage: g.is_hamiltonian()# not tested (30s)˓→# needs sage.numerical.mip
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()˓→# needs sage.numerical.mip
True

␣

␣

>>> from sage.all import *>>> g = graphs.WienerArayaGraph()>>> g.order()42>>> g.size()67>>> g.girth()4>>> g.is_planar()True>>> g.is_hamiltonian()# not tested (30s)˓→# needs sage.numerical.mip
False>>> g.delete_vertex(g.random_vertex())>>> g.is_hamiltonian()
˓→# needs sage.numerical.mip
Truestatic WindmillGraph(k, n)
Return the Windmill graph 𝑊 𝑑(𝑘, 𝑛).
The windmill graph 𝑊 𝑑(𝑘, 𝑛) is an undirected graph constructed for 𝑘 ≥ 2 and 𝑛 ≥ 2 by joining 𝑛 copiesof 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 triviallyperfect and a block graph.
See also:• Wikipedia article Windmill_graph• GraphGenerators.StarGraph()• GraphGenerators.FriendshipGraph()
EXAMPLES:

1000

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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>>> from sage.all import *>>> n = Integer(5)>>> W = graphs.WindmillGraph(Integer(2), n)>>> 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>>> from sage.all import *>>> n = Integer(5)>>> W = graphs.WindmillGraph(Integer(3), n)>>> 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>>> from sage.all import *>>> W = graphs.WindmillGraph(Integer(3), Integer(2))>>> 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() == kTrue>>> from sage.all import *>>> n,k = Integer(5),Integer(6)>>> W = graphs.WindmillGraph(k, n)>>> W.chromatic_number() == kTruestatic WorldMap()
Return the Graph of all the countries, in which two countries are adjacent in the graph if they have a common
boundary.
This graph has been built from the data available in The CIA World Factbook [CIA] (2009-08-21).
The returned graph G has a member G.gps_coordinates equal to a dictionary containing the GPS
coordinates of each country’s capital city.
2.1. Common graphs

1001

Graph Theory, Release 10.4

EXAMPLES:
sage: g = graphs.WorldMap()sage: g.has_edge("France", "Italy")Truesage: g.gps_coordinates["Bolivia"][[17, S ], [65, W ]]sage: g.connected_component_containing_vertex( Ireland , sort=True)[ Ireland , United Kingdom ]>>> from sage.all import *>>> g = graphs.WorldMap()>>> g.has_edge("France", "Italy")True>>> g.gps_coordinates["Bolivia"][[17, S ], [65, W ]]>>> g.connected_component_containing_vertex( Ireland , sort=True)[ Ireland , United Kingdom ]basic = <module sage.graphs.generators.basic from/home/user/sage-git/src/sage/graphs/generators/basic.py >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)>>> from sage.all import *>>> chang_graphs = graphs.chang_graphs()>>> K8 = graphs.CompleteGraph(Integer(8))>>> T8 = K8.line_graph()>>> four_srg = chang_graphs + [T8]>>> 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)>>> from itertools import combinations(continues on next page)

1002

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> for g1,g2 in combinations(four_srg,Integer(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(sort=False),˓→# needs sage.modules....:[(0,1,None),(2,3,None),(4,5,None),(6,7,None)],....:K8.subgraph_search(c3c5).edges(sort=False)]
sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G)˓→# needs sage.modules....: for x, G in zip(s, chang_graphs)][True, True, True]␣␣>>> from sage.all import *>>> c3c5 = graphs.CycleGraph(Integer(3)).disjoint_union(graphs.
˓→CycleGraph(Integer(5)))>>> c8 = graphs.CycleGraph(Integer(8))>>> s = [K8.subgraph_search(c8).edges(sort=False),
˓→# needs sage.modules...
[(Integer(0),Integer(1),None),(Integer(2),Integer(3),None),
˓→(Integer(4),Integer(5),None),(Integer(6),Integer(7),None)],...
K8.subgraph_search(c3c5).edges(sort=False)]>>> [T8.seidel_switching(x, inplace=False).is_isomorphic(G)˓→# needs sage.modules... for x, G in zip(s, chang_graphs)][True, True, True]chessboard = <module sage.graphs.generators.chessboard from/home/user/sage-git/src/sage/graphs/generators/chessboard.py >classical_geometries = <module
sage.graphs.generators.classical_geometries from/home/user/sage-git/src/sage/graphs/generators/classical_geometries.py >static cocliques_HoffmannSingleton()
Return the graph obtained from the cocliques of the Hoffmann-Singleton graph.
This is a distance-regular graph with intersection array [15, 14, 10, 3; 1, 5, 12, 15].
EXAMPLES:
sage: G = graphs.cocliques_HoffmannSingleton()sage: G.is_distance_regular(True)([15, 14, 10, 3, None], [None, 1, 5, 12, 15])>>> from sage.all import *>>> G = graphs.cocliques_HoffmannSingleton()>>> G.is_distance_regular(True)([15, 14, 10, 3, None], [None, 1, 5, 12, 15])

REFERENCES:
The construction of this graph can be found in [BCN1989] p. 392.

2.1. Common graphs1003

Graph Theory, Release 10.4

static cographs(n, as_graph=True, immutable=False)
Return an iterator over the cographs of order 𝑛.
A cograph is a 𝑃4 -free graph, that is a graph without induced path of order 4. Any cograph may be constructed, starting from the single vertex graph, by a sequence of sage.graphs.graph.Graph.join()and sage.graphs.generic_graph.GenericGraph.disjoint_union() operations. See the
Wikipedia article Cograph for more details.
This method implements the generator of all cographs of order 𝑛 proposed in [JPD2018]. The algorithm
generates one by one every cotree with 𝑛 nodes, and each cotree is generated by using its previous cotree.
The time to construct the first cotree is 𝑂(𝑛) and the time spent between two consecutive outputs is 𝑂(𝑛).
Hence, the overall complexity of the algorithm is 𝑂(𝑛 * 𝑀𝑛 ), where 𝑛 is the number of nodes and 𝑀𝑛 is thetotal number of cographs with 𝑛 nodes (see OEIS sequence A000084).
INPUT:• n – an integer larger or equal to 1
• as_graph – boolean (default: True); whether to return graphs or the tree data structure encoding thegraph• immutable – boolean (default: False); whether to return an immutable or a mutable graph. Thisparameter is used only when as_graph is True.
EXAMPLES:
The output can be either cotrees or graphs:
sage: for t in graphs.cographs(3, as_graph=False):....:
print(t)[ J ( 0 ) ( 1 ) ( 2 ) ][ J [ U ( 0 ) ( 1 ) ( 2 ) ] ][ J ( 0 ) [ U ( 1 ) ( 2 ) ] ][ J [ U ( 0 ) [ J ( 1 ) ( 2 ) ] ] ]sage: for g in graphs.cographs(3, as_graph=True):....:
print(g.edges(labels=False, sort=True))[(0, 1), (0, 2), (1, 2)][][(0, 1), (0, 2)][(1, 2)]>>> from sage.all import *>>> for t in graphs.cographs(Integer(3), as_graph=False):...
print(t)[ J ( 0 ) ( 1 ) ( 2 ) ][ J [ U ( 0 ) ( 1 ) ( 2 ) ] ][ J ( 0 ) [ U ( 1 ) ( 2 ) ] ][ J [ U ( 0 ) [ J ( 1 ) ( 2 ) ] ] ]>>> for g in graphs.cographs(Integer(3), as_graph=True):...
print(g.edges(labels=False, sort=True))[(0, 1), (0, 2), (1, 2)][][(0, 1), (0, 2)][(1, 2)]Check that we agree with OEIS sequence A000084:
sage: [sum(1 for _ in graphs.cographs(n, as_graph=False))....: for n in range(1, 8)][1, 2, 4, 10, 24, 66, 180]

1004

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> [sum(Integer(1) for _ in graphs.cographs(n, as_graph=False))... for n in range(Integer(1), Integer(8))][1, 2, 4, 10, 24, 66, 180]

cographs_module = <module sage.graphs.cographs from/home/user/sage-git/src/sage/graphs/cographs.py >cospectral_graphs(vertices, matrix_function=None, 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
– a list of graphs (or other iterable object) – these graphs are tested for cospectral sets. In this case,vertices is ignored.
OUTPUT:
A list of lists of graphs. Each sublist will be a list of cospectral graphs (lists of cardinality 1 being
omitted).
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
sage: g = graphs.cospectral_graphs(5)˓→needs sage.modules
sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
˓→needs sage.modules[[ Dr? , Ds_ ]]sage: g[0][1].am().charpoly()==g[0][1].am().charpoly()
˓→needs sage.modules
True

#␣
#␣

#␣

>>> from sage.all import *>>> g = graphs.cospectral_graphs(Integer(5))␣˓→# needs sage.modules>>> sorted(sorted(g.graph6_string() for g in glist) for glist in g)#␣˓→needs sage.modules[[ Dr? , Ds_ ]]>>> g[Integer(0)][Integer(1)].am().charpoly()==g[Integer(0)][Integer(1)].am().
˓→charpoly()# needs sage.modules
True

There are two sets of cospectral graphs on six vertices with no isolated vertices:
2.1. Common graphs

1005

Graph Theory, Release 10.4

sage: # needs sage.modules
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>>> from sage.all import *>>> # needs sage.modules>>> g = graphs.cospectral_graphs(Integer(6), graphs=lambda x: min(x.degree())>˓→Integer(0))>>> sorted(sorted(g.graph6_string() for g in glist) for glist in g)[[ Ep__ , Er?G ], [ ExGg , ExoG ]]>>> g[Integer(0)][Integer(1)].am().charpoly()==g[Integer(0)][Integer(1)].am().
˓→charpoly()
True>>> g[Integer(1)][Integer(1)].am().charpoly()==g[Integer(1)][Integer(1)].am().
˓→charpoly()
True

There is one pair of cospectral trees on eight vertices:sage: g = graphs.cospectral_graphs(6, graphs=graphs.trees(8))˓→needs sage.modules
sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
˓→needs sage.modules[[ GiPC?C , GiQCC? ]]sage: g[0][1].am().charpoly()==g[0][1].am().charpoly()
˓→needs sage.modules
True

#␣
#␣

#␣

>>> from sage.all import *>>> g = graphs.cospectral_graphs(Integer(6), graphs=graphs.trees(Integer(8)))␣
˓→# needs sage.modules>>> sorted(sorted(g.graph6_string() for g in glist) for glist in g)#␣˓→needs sage.modules[[ GiPC?C , GiQCC? ]]>>> g[Integer(0)][Integer(1)].am().charpoly()==g[Integer(0)][Integer(1)].am().
˓→charpoly()# needs sage.modules
True

There are two sets of cospectral graphs (with respect to the Laplacian matrix) on six vertices:sage: # needs sage.modules
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

1006

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.modules>>> g = graphs.cospectral_graphs(Integer(6), matrix_function=lambda g: g.
˓→laplacian_matrix())>>> sorted(sorted(g.graph6_string() for g in glist) for glist in g)[[ Edq_ , ErcG ], [ Exoo , EzcG ]]>>> g[Integer(0)][Integer(1)].laplacian_matrix().
˓→charpoly()==g[Integer(0)][Integer(1)].laplacian_matrix().charpoly()
True>>> g[Integer(1)][Integer(1)].laplacian_matrix().
˓→charpoly()==g[Integer(1)][Integer(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 matrixof 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)....:
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,
˓→needs sage.libs.pari sage.modules....:
graphs=lambda g: min(g.degree()) > 0)sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
˓→needs sage.modules[[ Dlg , Ds_ ]]sage: (g[0][1].laplacian_matrix(normalized=True).charpoly()
˓→needs sage.modules sage.symbolic....:== g[0][1].laplacian_matrix(normalized=True).charpoly())
True

#␣

#␣

#␣

>>> from sage.all import *>>> def DinverseA(g):...
A = g.adjacency_matrix().change_ring(QQ)...
for i in range(g.order()):...
A.rescale_row(i, Integer(1) / len(A.nonzero_positions_in_row(i)))...
return A>>> g = graphs.cospectral_graphs(Integer(5), matrix_function=DinverseA,␣˓→# needs sage.libs.pari sage.modules...
graphs=lambda g: min(g.degree()) >␣
˓→Integer(0))>>> sorted(sorted(g.graph6_string() for g in glist) for glist in g)#␣˓→needs sage.modules[[ Dlg , Ds_ ]]>>> (g[Integer(0)][Integer(1)].laplacian_matrix(normalized=True).charpoly() ␣˓→# needs sage.modules sage.symbolic...
== g[Integer(0)][Integer(1)].laplacian_matrix(normalized=True).
˓→charpoly())
True

degree_sequence = <module sage.graphs.generators.degree_sequence from/home/user/sage-git/src/sage/graphs/generators/degree_sequence.py >static distance_3_doubly_truncated_Golay_code_graph()2.1. Common graphs

1007

Graph Theory, Release 10.4

Return a distance-regular graph with intersection array [9, 8, 6, 3; 1, 1, 3, 8].
EXAMPLES:
sage: # long time, needs sage.modules sage.rings.finite_rings
sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph()
sage: G.is_distance_regular(True)# long time (due to above)([9, 8, 6, 3, None], [None, 1, 1, 3, 8])>>> from sage.all import *>>> # long time, needs sage.modules sage.rings.finite_rings>>> G = graphs.distance_3_doubly_truncated_Golay_code_graph()>>> G.is_distance_regular(True)# long time (due to above)([9, 8, 6, 3, None], [None, 1, 1, 3, 8])

ALGORITHM:
Compute the binary Golay code and truncate it twice. Compute its coset graph. Take a vertex and compute the set of vertices at distance 3 from the vertex chosen. This set constitutes the set of vertices of ourdistance-regular graph. Moreover we have an edge (𝑢, 𝑣) if the coset graph contains such edge.
REFERENCES:
Description and construction of this graph are taken from [BCN1989] p. 364.
distance_regular = <module sage.graphs.generators.distance_regular/home/user/sage-git/src/sage/graphs/generators/distance_regular.
cpython-310-x86_64-linux-gnu.so >fromstatic distance_regular_graph(arr, existence=False, check=True)
Return a distance-regular graph with the intersection array given.
INPUT:• arr – list; intersection array of the graph• existence – boolean (optional); instead of building the graph return:– True – if a graph with the given intersection array exists;– False – if there is no graph with the given intersection array;– Unknown – if Sage doesn’t know if such a graph exists.
• check – boolean (default: True); if True, then checks that the result of this function has the given
intersection array
EXAMPLES:
sage: graphs.distance_regular_graph([21,20,16,1,2,12], existence=True)
True
sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False)˓→# needs sage.combinat sage.modules
sage: G.is_distance_regular(True)˓→# needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])␣␣>>> from sage.all import *>>> graphs.distance_regular_graph([Integer(21),Integer(20),Integer(16),
˓→Integer(1),Integer(2),Integer(12)], existence=True)
True(continues on next page)

1008

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphs.distance_regular_graph([Integer(12),Integer(11),Integer(10),
˓→Integer(7),Integer(1),Integer(2),Integer(5),Integer(12)], check=False)
˓→# needs sage.combinat sage.modules>>> G.is_distance_regular(True)
˓→# needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])REFERENCES:
See [BCN1989] and [VDKT2016].
families = <module sage.graphs.generators.families from/home/user/sage-git/src/sage/graphs/generators/families.py >fullerenes(order, ipr=False)
Returns a generator which creates fullerene graphs using the buckygen generator (see [BGM2012]).
INPUT:• order – a positive even integer smaller than or equal to 254. This specifies the number of vertices in
the generated fullerenes.
• ipr – (default: False); if True only fullerenes that satisfy the Isolated Pentagon Rule are generated.
This means that no pentagonal faces share an edge.
OUTPUT:
A generator which will produce the fullerene graphs as Sage graphs with an embedding set. These will be
simple graphs: no loops, no multiple edges, no directed edges.
See also:• 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)sage: len(list(gen))1812# optional - buckygen# optional - buckygen>>> from sage.all import *>>> gen = graphs.fullerenes(Integer(60)) # optional - buckygen>>> 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)
sage: next(gen)Graph on 60 vertices
sage: next(gen)Traceback (most recent call last):...
StopIteration

2.1. Common graphs# optional - buckygen# optional - buckygen# optional - buckygen

1009

Graph Theory, Release 10.4>>> from sage.all import *>>> gen = graphs.fullerenes(Integer(60), ipr=True) # optional - buckygen>>> next(gen)# optional - buckygen
Graph on 60 vertices>>> next(gen)# optional - buckygen
Traceback (most recent call last):...
StopIteration

The unique fullerene graph on 20 vertices is isomorphic to the dodecahedron graph.
sage: # optional - buckygensage: gen = graphs.fullerenes(20)sage: g = next(gen)sage: g.is_isomorphic(graphs.DodecahedralGraph())
True
sage: g.get_embedding(){1: [2, 3, 4],
2: [1, 5, 6],
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 )Graphics3d Object>>> from sage.all import *>>> # optional - buckygen>>> gen = graphs.fullerenes(Integer(20))>>> g = next(gen)>>> g.is_isomorphic(graphs.DodecahedralGraph())
True>>> g.get_embedding(){1: [2, 3, 4],
2: [1, 5, 6],
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],(continues on next page)

1010

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

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]}>>> g.plot3d(layout= spring )Graphics3d Object

fusenes(hexagon_count, benzenoids=False)
Returns a generator which creates fusenes and benzenoids using the benzene generator (see [BCH2002]).
Fusenes are planar polycyclic hydrocarbons with all bounded faces hexagons. Benzenoids are fusenes that are
subgraphs of the hexagonal lattice.
INPUT:• hexagon_count – a positive integer smaller than or equal to 30. This specifies the number ofhexagons 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)sage: len(list(gen))1# optional - benzene# optional - benzene>>> from sage.all import *>>> gen = graphs.fusenes(Integer(2)) # optional - benzene>>> len(list(gen))# optional - benzene
1This fusene is naphthalene (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
sage: next(gen)# optional - benzene
Traceback (most recent call last):...
StopIteration

2.1. Common graphs

1011

Graph Theory, Release 10.4>>> from sage.all import *>>> gen = graphs.fusenes(Integer(2)) # optional - benzene>>> next(gen)# optional - benzene
Graph on 10 vertices>>> next(gen)# optional - benzene
Traceback (most recent call last):...
StopIteration

There are 6505 benzenoids with 9 hexagons:
sage: gen = graphs.fusenes(9, benzenoids=True)
sage: len(list(gen))6505# optional - benzene# optional - benzene>>> from sage.all import *>>> gen = graphs.fusenes(Integer(9), benzenoids=True) # optional - benzene>>> len(list(gen))# optional - benzene
6505

static graph_3O73()
Return the graph related to the group 3𝑂(7, 3).
This graph is distance-regular with intersection array [117, 80, 24, 1; 1, 12, 80, 117].
The graph is also distance transitive with 3.𝑂(7, 3) as automorphism group
EXAMPLES:
sage: G = graphs.graph_3O73()
˓→gap_package_atlasrep
sage: G.is_distance_regular(True)
˓→gap_package_atlasrep([117, 80, 24, 1, None], [None, 1, 12, 80, 117])>>> from sage.all import *>>> G = graphs.graph_3O73()
˓→gap_package_atlasrep>>> G.is_distance_regular(True)
˓→gap_package_atlasrep([117, 80, 24, 1, None], [None, 1, 12, 80, 117])# optional - internet␣
# optional - internet␣

# optional - internet␣
# optional - internet␣

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 400.
intersection = <module sage.graphs.generators.intersection from/home/user/sage-git/src/sage/graphs/generators/intersection.py >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:

1012

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> graphs.line_graph_forbidden_subgraphs()[Claw graph: Graph on 4 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 5 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 6 vertices,
Graph on 5 vertices]

static locally_GQ42_distance_transitive_graph()
Return the unique amply regular graph with 𝜇 = 6 which is locally a generalised quadrangle.
This graph is distance-regular with intersection array [45, 32, 12, 1; 1, 6, 32, 45].
This graph is also distance-transitive.
EXAMPLES:
sage: G = graphs.locally_GQ42_distance_transitive_graph()
˓→internet gap_package_atlasrep
sage: G.is_distance_regular(True)
˓→internet gap_package_atlasrep([45, 32, 12, 1, None], [None, 1, 6, 32, 45])>>> from sage.all import *>>> G = graphs.locally_GQ42_distance_transitive_graph()
˓→internet gap_package_atlasrep>>> G.is_distance_regular(True)
˓→internet gap_package_atlasrep([45, 32, 12, 1, None], [None, 1, 6, 32, 45])

# optional -␣# optional -␣# optional -␣# optional -␣

REFERENCES:
A description of this graph can be found in [BCN1989] p.399. This construction is due to Dima Pasechnik.
nauty_genbg(options='', debug=False)
Return a generator which creates bipartite graphs from nauty’s genbg program.
INPUT:• options – string (default: ""); a string passed to genbg as if it was run at a system command line.
At a minimum, you must pass the number of vertices you desire in each side. Sage expects the bipartite
graphs to be in nauty’s “graph6” format, do not set an option to change this default or results will be
unpredictable.

2.1. Common graphs1013

Graph Theory, Release 10.4

• debug – boolean (default: False); if True the first line of geng’s output to standard error is captured
and the first call to the generator’s next() function will return this line as a string. A line leading with“>A” indicates a successful initiation of the program with some information on the arguments, while aline beginning with “>E” indicates an error with the input.
The possible options, obtained as output of genbg --help:n1n2
mine:maxe
res/mod
-c
-z
-F
-L

-Y<int>-Z<int>-A-D<int>-d<int>-v-l: the number of vertices in the first class.
We must have n1=1..24.
: the number of vertices in the second class.
We must have n2=0..32 and n1+n2=1..32.
: <int>:<int> a range for the number of edges<int>:0 means <int> or more except in the case 0:0: only generate subset res out of subsets 0..mod-1: only write connected graphs: all the vertices in the second class must havedifferent neighbourhoods: the vertices in the second class must have at least
two neighbours of degree at least 2: there is no vertex in the first class whose removal
leaves the vertices in the second class unreachable
from each other: two vertices in the second class must have at least<int> common neighbours: two vertices in the second class must have at most<int> common neighbours: no vertex in the second class has a neighbourhood
which is a subset of another vertex s neighbourhoodin the second class: specify an upper bound for the maximum degree
Example: -D6. You can also give separate maxima forthe two parts, for example: -D5:6: specify a lower bound for the minimum degree
Again, you can specify it separately for the two parts,for example -d1:2: display counts by number of edges to stderr: canonically label output graphs

Options which cause genbg to use an output format different than the graph6 format are not listed above(-s, -a) as they will confuse the creation of a Sage graph. Option -q which suppress auxiliary output (except
from -v) should never be used as we are unable to recover the partition of the vertices of the bipartite graphwithout the auxiliary output. Hence the partition of the vertices of returned bipartite graphs might not respect
the requirement.
The res/mod option can be useful when using the output in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as BipartiteGraph. These will be simple bipartite graphs:
no loops, no multiple edges, no directed edges.
EXAMPLES:
The generator can be used to construct biparrtite graphs for testing, one at a time (usually inside a loop). Or
it can be used to create an entire list all at once if there is sufficient memory to contain it:
sage: gen = graphs.nauty_genbg("1 1")
sage: next(gen)Bipartite graph on 2 vertices(continues on next page)

1014

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: next(gen)Bipartite graph on 2 vertices
sage: next(gen)Traceback (most recent call last):...
StopIteration>>> from sage.all import *>>> gen = graphs.nauty_genbg("1 1")>>> next(gen)Bipartite graph on 2 vertices>>> next(gen)Bipartite graph on 2 vertices>>> next(gen)Traceback (most recent call last):...
StopIteration

Connected bipartite graphs of order 6 with different number of vertices in each side:
sage: gen = graphs.nauty_genbg("1 5 -c")sage: len(list(gen))1
sage: gen = graphs.nauty_genbg("2 4 -c")sage: len(list(gen))6
sage: gen = graphs.nauty_genbg("3 3 -c")sage: len(list(gen))13>>> from sage.all import *>>> gen = graphs.nauty_genbg("1 5 -c")>>> len(list(gen))1>>> gen = graphs.nauty_genbg("2 4 -c")>>> len(list(gen))6>>> gen = graphs.nauty_genbg("3 3 -c")>>> len(list(gen))13

Use nauty_geng() instead if you want the list of all bipartite graphs of order 𝑛. For instance, the list of
all connected bipartite graphs of order 6, which agrees with OEIS sequence A005142:
sage: gen = graphs.nauty_geng("-b -c 6")
sage: len(list(gen))17>>> from sage.all import *>>> gen = graphs.nauty_geng("-b -c 6")>>> len(list(gen))17

The debug switch can be used to examine genbg’s reaction to the input in the options string. A message
starting with “>A” indicates success and a message starting with “>E” indicates a failure:

2.1. Common graphs

1015

Graph Theory, Release 10.4

sage: gen = graphs.nauty_genbg("2 3", debug=True)
sage: print(next(gen))>A ...genbg n=2+3 e=0:6 d=0:0 D=3:2
sage: gen = graphs.nauty_genbg("-c2 3", debug=True)
sage: next(gen)>E Usage: ...genbg [-c -ugs -vq -lzF] [-Z#] [-D#] [-A] [-d#|-d#:#] [-D#|-D#:
˓→#] n1 n2...
>>> from sage.all import *>>> gen = graphs.nauty_genbg("2 3", debug=True)>>> print(next(gen))>A ...genbg n=2+3 e=0:6 d=0:0 D=3:2>>> gen = graphs.nauty_genbg("-c2 3", debug=True)>>> next(gen)>E Usage: ...genbg [-c -ugs -vq -lzF] [-Z#] [-D#] [-A] [-d#|-d#:#] [-D#|-D#:
˓→#] n1 n2...

Check that the partition of the bipartite graph is consistent:
sage: gen = graphs.nauty_genbg("3 3")
sage: left = set(range(3))
sage: for g in gen:....:if g.left != left:....:raise ValueError( wrong partition )>>> from sage.all import *>>> gen = graphs.nauty_genbg("3 3")>>> left = set(range(Integer(3)))>>> for g in gen:...
if g.left != left:...
raise ValueError( wrong partition )nauty_geng(options='', debug=False)
Return a generator which creates graphs from nauty’s geng program.
INPUT:• options – string (default: ""); a string passed to geng as if it was run at a system command line. At
a minimum, you must pass the number of vertices you desire. Sage expects the graphs to be in nauty’s“graph6” format, do not set an option to change this default or results will be unpredictable.
• debug – boolean (default: False); if True the first line of geng’s output to standard error is captured
and the first call to the generator’s next() function will return this line as a string. A line leading with“>A” indicates a successful initiation of the program with some information on the arguments, while aline beginning with “>E” indicates an error with the input.
The possible options, obtained as output of geng --help:nmine:maxe: the number of vertices: <int>:<int> a range for the number of edges<int>:0 means <int> or more except in the case 0:0
res/mod : only generate subset res out of subsets 0..mod-1
-c
-C
-t
-f

: only write connected graphs: only write biconnected graphs: only generate triangle-free graphs: only generate 4-cycle-free graphs(continues on next page)

1016

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)-b-d<int>-D<int>-v-l: only generate bipartite graphs(-t, -f and -b can be used in any combination): save memory at the expense of time (only makes adifference in the absence of -b, -t, -f and n <= 28).
: a lower bound for the minimum degree: a upper bound for the maximum degree: display counts by number of edges: canonically label output graphs-q: suppress auxiliary output (except from -v)-mOptions which cause geng to use an output format different than the graph6 format are not listed above (-u,-g, -s, -y, -h) as they will confuse the creation of a Sage graph. The res/mod option can be useful when using
the output in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as Sage graphs. These will be simple graphs: no loops, no multiple
edges, no directed edges.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:
The generator can be used to construct graphs for testing, one at a time (usually inside a loop). Or it can beused 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>>> from sage.all import *>>> gen = graphs.nauty_geng("2")>>> next(gen)Graph on 2 vertices>>> next(gen)Graph on 2 vertices>>> 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

2.1. Common graphs

1017

Graph Theory, Release 10.4>>> from sage.all import *>>> gen = graphs.nauty_geng("7")>>> 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>>> from sage.all import *>>> gen = graphs.nauty_geng("7 -c")>>> len(list(gen))853

A list of connected degree exactly 2 graphs on 5 vertices.
sage: gen = graphs.nauty_geng("5 -c -d2 -D2")
sage: len(list(gen))1>>> from sage.all import *>>> gen = graphs.nauty_geng("5 -c -d2 -D2")>>> len(list(gen))1

The debug switch can be used to examine geng’s reaction to the input in the options string. We illustrate
success. (A failure will be a string beginning with “>E”.) Passing the “-q” switch to geng will suppress theindicator of a successful initiation, and so the first returned value might be an empty string if debug is True:
sage: gen = graphs.nauty_geng("4", debug=True)
sage: print(next(gen))>A ...geng -d0D3 n=4 e=0-6
sage: gen = graphs.nauty_geng("4 -q", debug=True)
sage: next(gen)>>> from sage.all import *>>> gen = graphs.nauty_geng("4", debug=True)>>> print(next(gen))>A ...geng -d0D3 n=4 e=0-6>>> gen = graphs.nauty_geng("4 -q", debug=True)>>> next(gen)nauty_genktreeg(options='', debug=False)
Return a generator which creates all 𝑘-trees using nauty..
A 𝑘-tree is an undirected graph formed by starting with a complete graph on 𝑘+1 vertices and then repeatedly
add vertices in such a way that each added vertex 𝑣 has exactly 𝑘 neighbors 𝑈 such that, together, the 𝑘 + 1
vertices formed by 𝑣 and 𝑈 form a clique. See the Wikipedia article K-tree for more details.
INPUT:• options – string (default: ""); a string passed to genktreeg as if it was run at a system commandline. At a minimum, you must pass the number of vertices you desire. Sage expects the graphs to be in
1018

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

nauty’s “graph6” format, do not set an option to change this default or results will be unpredictable.
• debug – boolean (default: False); if True the first line of genktreeg’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 thearguments, while a line beginning with “>E” indicates an error with the input.
The possible options, obtained as output of genktreeg --help:n-k<int>res/mod-l: the number of vertices: the value of k (default: 2): only generate subset res out of subsets 0..mod-1: canonically label output graphs

Options which cause genktreeg to use an output format different than the graph6 format are not listed
above (-u, -s, -h) as they will confuse the creation of a Sage graph. The res/mod option can be useful whenusing 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.
EXAMPLES:
A 𝑘-tree is a maximal graph with treewidth 𝑘:sage: # needs nauty
sage: gen = graphs.nauty_genktreeg("10 -k4")
sage: G = next(gen); G
Graph on 10 vertices
sage: G.treewidth()4>>> from sage.all import *>>> # needs nauty>>> gen = graphs.nauty_genktreeg("10 -k4")>>> G = next(gen); G
Graph on 10 vertices>>> G.treewidth()4

A list of all 2-trees with 6, 7 and 8 vertices. This agrees with OEIS sequence A054581:
sage: # needs nauty
sage: gen = graphs.nauty_genktreeg("6")
sage: len(list(gen))5
sage: gen = graphs.nauty_genktreeg("7")
sage: len(list(gen))12
sage: gen = graphs.nauty_genktreeg("8")
sage: len(list(gen))39>>> from sage.all import *>>> # needs nauty>>> gen = graphs.nauty_genktreeg("6")>>> len(list(gen))(continues on next page)2.1. Common graphs1019

Graph Theory, Release 10.4

(continued from previous page)5>>> gen = graphs.nauty_genktreeg("7")>>> len(list(gen))12>>> gen = graphs.nauty_genktreeg("8")>>> len(list(gen))39

The debug switch can be used to examine geng’s reaction to the input in the options string. We illustrate
success. (A failure will be a string beginning with “>E”.) Passing the “-q” switch to geng will suppress theindicator of a successful initiation, and so the first returned value might be an empty string if debug is True:
sage: gen = graphs.nauty_genktreeg("7", debug=True)
˓→needs nauty
sage: print(next(gen))˓→needs nauty>A ...genktreeg k=2 n=7>>> from sage.all import *>>> gen = graphs.nauty_genktreeg("7", debug=True)
˓→needs nauty>>> print(next(gen))˓→needs nauty>A ...genktreeg k=2 n=7

#␣
#␣

#␣
#␣

static nauty_gentreeg(options='', debug=False)
Return a generator which creates non-isomorphic trees from nauty’s gentreeg program.
INPUT:• options – string (default: ""); a string passed to gentreeg as if it was run at a system commandline. At a minimum, you must pass the number of vertices you desire. Sage expects the graphs to be innauty’s “sparse6” format, do not set an option to change this default or results will be unpredictable.
• debug – boolean (default: False); if True the first line of gentreeg’s output to standard error
is captured and the first call to the generator’s next() function will return this line as a string. A
line leading with “>A” indicates a successful initiation of the program with some information on thearguments, while a line beginning with “>E” indicates an error with the input.
The possible options, obtained as output of gentreeg -help:n: the number of vertices. Must be in range 1..128
res/mod: only generate subset res out of subsets 0..mod-1-D<int>: an upper bound for the maximum degree-Z<int>:<int> : bounds on the diameter-q: suppress auxiliary output

Options which cause gentreeg to use an output format different than the sparse6 format are not listed
above (-p, -l, -u) as they will confuse the creation of a Sage graph. The res/mod option can be useful whenusing the output in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as Sage graphs. These will be simple graphs: no loops, no multiple
edges, no directed edges.
See also:
trees() – another generator of trees
1020

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
The generator can be used to construct trees for testing, one at a time (usually inside a loop). Or it can beused to create an entire list all at once if there is sufficient memory to contain it:
sage: gen = graphs.nauty_gentreeg("4")
sage: next(gen)Graph on 4 vertices
sage: next(gen)Graph on 4 vertices
sage: next(gen)Traceback (most recent call last):...
StopIteration>>> from sage.all import *>>> gen = graphs.nauty_gentreeg("4")>>> next(gen)Graph on 4 vertices>>> next(gen)Graph on 4 vertices>>> next(gen)Traceback (most recent call last):...
StopIteration

The number of trees on the first few vertex counts. This agrees with OEIS sequence A000055:
sage: [len(list(graphs.nauty_gentreeg(str(i)))) for i in range(1, 15)]
[1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]>>> from sage.all import *>>> [len(list(graphs.nauty_gentreeg(str(i)))) for i in range(Integer(1),␣
˓→Integer(15))][1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]

The debug switch can be used to examine gentreeg’s reaction to the input in the options string. We
illustrate success. (A failure will be a string beginning with “>E”.) Passing the “-q” switch to gentreeg
will suppress the indicator of a successful initiation, and so the first returned value might be an empty string
if debug is True:
sage: gen = graphs.nauty_gentreeg("4", debug=True)
sage: print(next(gen))>A ...gentreeg ...
sage: gen = graphs.nauty_gentreeg("4 -q", debug=True)
sage: next(gen)>>> from sage.all import *>>> gen = graphs.nauty_gentreeg("4", debug=True)>>> print(next(gen))>A ...gentreeg ...
>>> gen = graphs.nauty_gentreeg("4 -q", debug=True)>>> next(gen)static petersen_family(generate=False)

2.1. Common graphs1021

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> 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)˓→# needs sage.modules
sage: F1 = [g.canonical_label().graph6_string() for g in F1]
sage: F2 = [g.canonical_label().graph6_string() for g in F2]
˓→# needs sage.modules
sage: set(F1) == set(F2)˓→# needs sage.modules
True

␣

␣
␣

>>> from sage.all import *>>> F1 = graphs.petersen_family(generate=False)>>> F2 = graphs.petersen_family(generate=True)
˓→# needs sage.modules>>> F1 = [g.canonical_label().graph6_string() for g in F1]>>> F2 = [g.canonical_label().graph6_string() for g in F2]
˓→# needs sage.modules>>> set(F1) == set(F2)˓→# needs sage.modules
True

planar_graphs(order, minimum_degree=None, minimum_connectivity=None, exact_connectivity=False,
minimum_edges=None, maximum_edges=None, maximum_face_size=None,
only_bipartite=False, dual=False)
An iterator over connected planar graphs using the plantri generator.
1022

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

This uses the plantri generator (see [BM2007]) 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 thegenerated 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 andthe 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 theminimum 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 toNone, then this is set to 1.
• exact_connectivity – (default: False); if True only graphs with exactly the specified connectivity will be generated. This option cannot be used with minimum_connectivity=3, or if theminimum connectivity is not explicitly set.
• minimum_edges – integer (default: None); lower bound on the number of edges• maximum_edges – integer (default: None); upper bound on the number of edges• maximum_face_size – integer (default: None); upper bound on the size of a face and so on the
maximum degree of the dual graph• only_bipartite – (default: False); if True only bipartite graphs will be generated. This option
cannot be used for graphs with a minimum degree larger than 3.
• dual – (default: False); if True return instead the planar duals of the generated graphs.
OUTPUT:
An iterator which will produce all planar graphs with the given number of vertices as Sage graphs with anembedding set. These will be simple graphs (no loops, no multiple edges, no directed edges) unless the optiondual=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)sage: len(list(gen))6# optional - plantri# optional - plantri>>> from sage.all import *>>> gen = graphs.planar_graphs(Integer(4)) # optional - plantri>>> len(list(gen))# optional - plantri
6

Three of these planar graphs are bipartite:

2.1. Common graphs1023

Graph Theory, Release 10.4

sage: gen = graphs.planar_graphs(4, only_bipartite=True)
sage: len(list(gen))3# optional - plantri# optional - plantri>>> from sage.all import *>>> gen = graphs.planar_graphs(Integer(4), only_bipartite=True) # optional -␣˓→plantri>>> len(list(gen))# optional - plantri
3

Setting dual=True gives the planar dual graphs:
sage: gen = graphs.planar_graphs(4, dual=True)
sage: [u for u in list(gen)][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]# optional - plantri# optional - plantri>>> from sage.all import *>>> gen = graphs.planar_graphs(Integer(4), dual=True) # optional - plantri>>> [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]}␣>>> from sage.all import *>>> l = list(graphs.planar_graphs(Integer(4), minimum_connectivity=Integer(2),˓→ only_bipartite=True))# optional - plantri>>> l[Integer(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))[Graph on 1 vertex]# optional - plantri(continues on next page)

1024

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: list(graphs.planar_graphs(1, minimum_degree=1))[]# optional - plantri>>> from sage.all import *>>> list(graphs.planar_graphs(Integer(1)))# optional -␣˓→plantri[Graph on 1 vertex]>>> list(graphs.planar_graphs(Integer(1), minimum_degree=Integer(1))) #␣˓→optional - plantri[]

Specifying lower and upper bounds on the number of edges:
sage: # optional - plantri
sage: len(list(graphs.planar_graphs(4)))
6sage: len(list(graphs.planar_graphs(4, minimum_edges=4)))
4
sage: len(list(graphs.planar_graphs(4, maximum_edges=4)))
4
sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4)))
2>>> from sage.all import *>>> # optional - plantri>>> len(list(graphs.planar_graphs(Integer(4))))6>>> len(list(graphs.planar_graphs(Integer(4), minimum_edges=Integer(4))))4>>> len(list(graphs.planar_graphs(Integer(4), maximum_edges=Integer(4))))4>>> len(list(graphs.planar_graphs(Integer(4), minimum_edges=Integer(4),␣
˓→maximum_edges=Integer(4))))
2

Specifying the maximum size of a face:sage: len(list(graphs.planar_graphs(4, maximum_face_size=3)))
˓→plantri1
sage: len(list(graphs.planar_graphs(4, maximum_face_size=4)))
˓→plantri
3# optional -␣# optional -␣

>>> from sage.all import *>>> len(list(graphs.planar_graphs(Integer(4), maximum_face_size=Integer(3))))␣
˓→ # optional - plantri
1>>> len(list(graphs.planar_graphs(Integer(4), maximum_face_size=Integer(4))))␣
˓→ # optional - plantri
3

plantri_gen(options='')
Iterator over planar graphs created using the plantri generator.
plantri is a (optional) program that generates certain types of graphs that are embedded on the sphere. It
2.1. Common graphs1025Graph Theory, Release 10.4

outputs exactly one member of each isomorphism class, using an amount of memory almost independent of
the number of graphs produced. Isomorphisms are defined with respect to the embeddings, so in some cases
outputs may be isomorphic as abstract graphs.
This method allows for passing command directly to plantry, similarly to method nauty_geng(),provide that the output format is not changed.
INPUT:• options – string (default: ""); a string passed to plantri as if it was run at a system command line.
At a minimum, you must pass the number of vertices you desire. Sage expects the output of plantri to
be in “planar code” format, so do not set an option to change this default or results will be unpredictable.
The possible options are:n

: the number of vertices (the only compulsory parameter).
This number must be in range 3\cdots 64 .
It can also be given as "nd", where the suffix "d" means"dual", in which case it is converted by adding 4 thendividing by 2, i.e., (28+4)/2 = 16 . In the case oftriangulations, this calculation yields the number offaces, which is the number of vertices in the dual cubic
graph.

-d: output the dual instead of the original graph.
Note that it is applied only at the output stage. Allother switches refer to the original graph before the dual
is taken.

-o: Normally, one member of each isomorphism class is written.
If this switch is given, one member of each O-P
isomorphism class is written.

-V: output only graphs with non-trivial group. If -o isgiven the O-P group is used, the full group otherwise.

-m<int> : lower bound on the minimum degree. The default is -m3.
In the dual graph, this means a lower bound on the minimum
face size.
-c<int> : lower bound on the connectivity. The default is -c3.
-x

: when used in combination with -cN, the connectivity must
be exactly N rather than at least N.

-e: used to specify bounds on the number of edges.
There are four possible forms:-e<int>exactly <int> edges-e:<int>
at most <int> edges-e<int>:at least <int> edges-e<int>:<int> between <int> and <int> edges-f<int> : upper bound on the size of a face, and so on the maximum
degree of the dual.
-b but not -p : select eulerian triangulations, where "eulerian"means that every vertex has even degree.
This parameter can be used in combination withparameters -c and -x.
(continues on next page)

1026

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)-p but not -b : select general planar simple graphs.
This parameter can be used in combination withparameters -m, -c, -x, -e and -f.
-bp or -pb: select general planar simple bipartite graphs.
This parameter can be used in combination withparameters -m, -c, -x, -e and -f, except -c4, -m4,
-m5 and -f3.

-P<int> : select triangulations of a disk. These are embedded simple
graphs with a distinguished "outer" face. The outer facecan be of any size (here called the disk size) but theother faces must be triangles. The argument <int> to -P
is the disk size. If no argument (or 0) is given, all disk
sizes are permitted.
This parameter can be used in combination withparameters -m, -c, and -x.
-q: select simple quadrangulations. These are planar simple
graphs for which every face has length 4.
This parameter can be used in combination with parameters-c and -m.

-A: select Appolonian networks. These are simple planar
triangulations that can be formed starting with K_4 thenrepeatedly dividing a face into three by addition of a newvertex. They all have minimum degree and connectivity
equal to 3.

res/mod : only generate subset res out of subsets 0..mod-1.
The set of objects is divided into mod disjoint classes
and only the res-th class is generated.

If -b, -q, -p, -P and -A are absent, the graphs found are triangulations only restricted by connectivity andminimum degree. In this case, there is the possibility of connectivity lower than 3.
Other options listed in the plantri guide might cause unpredictable behavior, in particular those changing
the output format of plantri as they will confuse the creation of a Sage graph.
OUTPUT:
An iterator which yields the graphs generated by plantri as Sage Graph.
See also:• planar_graphs() – iterator over connected planar graphs using the plantri generator• triangulations() – iterator over connected planar triangulations using the plantri generator• quadrangulations() – iterator over connected planar quadrangulations using the plantri generator
EXAMPLES:
The generator can be used to construct graphs for testing, one at a time (usually inside a loop). Or it can beused to create an entire list all at once if there is sufficient memory to contain it:

2.1. Common graphs1027Graph Theory, Release 10.4

sage: # optional - plantri
sage: gen = graphs.plantri_gen("6")
sage: next(gen)Graph on 6 vertices
sage: next(gen)Graph on 6 vertices
sage: next(gen)Traceback (most recent call last):...
StopIteration>>> from sage.all import *>>> # optional - plantri>>> gen = graphs.plantri_gen("6")>>> next(gen)Graph on 6 vertices>>> next(gen)Graph on 6 vertices>>> next(gen)Traceback (most recent call last):...
StopIteration

An overview of the number of quadrangulations on up to 12 vertices. This agrees with OEIS sequence
A113201:
sage: for i in range(4, 13):....:
cmd = -qm2c2 {} .format(i)....:L = len(list(graphs.plantri_gen(cmd)))....:
print("{:2d}{:3d}".format(i, L))
4
1
5
1
6
2
7
3
8
9
9
18
10
62
11
198
12
803
>>> from sage.all import *>>> for i in range(Integer(4), Integer(13)):
˓→optional - plantri...
cmd = -qm2c2 {} .format(i)...
L = len(list(graphs.plantri_gen(cmd)))...
print("{:2d}{:3d}".format(i, L))
4
1
5
1
6
2
7
3
8
9
9
18
10
62
11
198
12
803

# optional - plantri#␣

platonic_solids = <module sage.graphs.generators.platonic_solids from/home/user/sage-git/src/sage/graphs/generators/platonic_solids.py >1028

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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 [BM2007]) 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 thegenerated 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 specifies theminimum 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 nonon-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 graphswith 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: # optional - plantri
sage: gen = graphs.quadrangulations(8, minimum_connectivity=3)
sage: g = next(gen)sage: g.is_isomorphic(graphs.CubeGraph(3))
True
sage: next(gen)Traceback (most recent call last):...
StopIteration>>> from sage.all import *>>> # optional - plantri>>> gen = graphs.quadrangulations(Integer(8), minimum_connectivity=Integer(3))>>> g = next(gen)>>> g.is_isomorphic(graphs.CubeGraph(Integer(3)))
True>>> next(gen)(continues on next page)2.1. Common graphs1029Graph Theory, Release 10.4

(continued from previous page)

Traceback (most recent call last):...
StopIteration

An overview of the number of quadrangulations on up to 12 vertices. This agrees with OEIS sequence
A113201:
sage: for i in range(4,13):# optional - plantri....:
L = len(list(graphs.quadrangulations(i)))....:
print("{:2d}{:3d}".format(i,L))
4
1
5
1
6
2
7
3
8
9
9
18
10
62
11
198
12
803
>>> from sage.all import *>>> for i in range(Integer(4),Integer(13)):
˓→optional - plantri...
L = len(list(graphs.quadrangulations(i)))...
print("{:2d}{:3d}".format(i,L))
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>>> from sage.all import *>>> len([g for g in graphs.quadrangulations(Integer(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]>>> from sage.all import *>>> [len(g) for g in graphs.quadrangulations(Integer(12), no_nonfacial_
˓→quadrangles=True, dual=True)]# optional - plantri[10, 10]1030

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

random = <module sage.graphs.generators.random from/home/user/sage-git/src/sage/graphs/generators/random.py >static shortened_000_111_extended_binary_Golay_code_graph()
Return a distance-regular graph with intersection array [21, 20, 16, 9, 2, 1; 1, 2, 3, 16, 20, 21].
EXAMPLES:
sage: # long time, needs sage.modules sage.rings.finite_rings
sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph()
sage: G.is_distance_regular(True)([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21])>>> from sage.all import *>>> # long time, needs sage.modules sage.rings.finite_rings>>> G = graphs.shortened_000_111_extended_binary_Golay_code_graph()>>> G.is_distance_regular(True)([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21])

# 25 s# 25 sALGORITHM:
Compute the extended binary Golay code. Compute its subcode whose codewords start with 000 or 111.
Remove the first 3 entries from all the codewords from the new linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
static shortened_00_11_binary_Golay_code_graph()
Return a distance-regular graph with intersection array [21, 20, 16, 6, 2, 1; 1, 2, 6, 16, 20, 21].
EXAMPLES:
sage: # long time, needs sage.modules sage.rings.finite_rings
sage: G = graphs.shortened_00_11_binary_Golay_code_graph()
sage: G.is_distance_regular(True)([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21])>>> from sage.all import *>>> # long time, needs sage.modules sage.rings.finite_rings>>> G = graphs.shortened_00_11_binary_Golay_code_graph()>>> G.is_distance_regular(True)([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21])

# 9 s

# 9 s

ALGORITHM:
Compute the binary Golay code. Compute the subcode whose codewords start with 00 or 11. Remove thefirst two entries from all codewords of the newly found linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
smallgraphs = <module sage.graphs.generators.smallgraphs from/home/user/sage-git/src/sage/graphs/generators/smallgraphs.py >strongly_regular_db = <module sage.graphs.strongly_regular_db/home/user/sage-git/src/sage/graphs/strongly_regular_db.
cpython-310-x86_64-linux-gnu.so >2.1. Common graphs

from

1031

Graph Theory, Release 10.4

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 documentationof 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 Trueby default.
EXAMPLES:Petersen’s graph from its set of parameters:sage: graphs.strongly_regular_graph(10,3,0,1,existence=True)˓→# needs sage.libs.pari
True
sage: graphs.strongly_regular_graph(10,3,0,1)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(10),Integer(3),Integer(0),˓→Integer(1),existence=True)# needs sage.libs.pari
True>>> graphs.strongly_regular_graph(Integer(10),Integer(3),Integer(0),˓→Integer(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>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(10),Integer(3),Integer(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

1032

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(5),Integer(5),Integer(5),Integer(5),˓→existence=True)
False>>> graphs.strongly_regular_graph(Integer(5),Integer(5),Integer(5),Integer(5))
Traceback (most recent call last):...
ValueError: There exists no (5, 5, 5, 5)-strongly regular graph

A set of parameters proved in a paper to be infeasible:
sage: graphs.strongly_regular_graph(324,57,0,12,existence=True)˓→# needs sage.combinat sage.modules
False
sage: graphs.strongly_regular_graph(324,57,0,12)˓→# needs sage.combinat sage.modules
Traceback (most recent call last):...
EmptySetError: Andries Brouwer s database reports that no (324, 57, 0,12)-strongly regular graph exists. Comments: <ahref="srgtabrefs.html#GavrilyukMakhnev05">Gavrilyuk & Makhnev</a> ...

␣␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(324),Integer(57),Integer(0),˓→Integer(12),existence=True)# needs sage.combinat sage.
˓→modules
False>>> graphs.strongly_regular_graph(Integer(324),Integer(57),Integer(0),˓→Integer(12))# needs sage.combinat sage.
˓→modules
Traceback (most recent call last):...
EmptySetError: Andries Brouwer s database reports that no (324, 57, 0,12)-strongly regular graph exists. Comments: <ahref="srgtabrefs.html#GavrilyukMakhnev05">Gavrilyuk & Makhnev</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)˓→# needs sage.combinat
Unknown
sage: graphs.strongly_regular_graph(324,95,22,30)
˓→# needs sage.combinat
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:␣␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(324),Integer(95),Integer(22),
˓→Integer(30),existence=True)# needs sage.combinat
Unknown>>> graphs.strongly_regular_graph(Integer(324),Integer(95),Integer(22),
˓→Integer(30))# needs sage.combinat
Traceback (most recent call last):...
(continues on next page)2.1. Common graphs1033

Graph Theory, Release 10.4

(continued from previous page)

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)˓→# needs sage.combinat
Unknown
sage: graphs.strongly_regular_graph(1394,175,0,25)˓→# needs sage.combinat
Traceback (most recent call last):...
RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly
regular graph exists.

␣␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(1394),Integer(175),Integer(0),˓→Integer(25),existence=True)# needs sage.combinat
Unknown>>> graphs.strongly_regular_graph(Integer(1394),Integer(175),Integer(0),˓→Integer(25))# needs sage.combinat
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 [BL1984]):
sage: graphs.strongly_regular_graph(2058,242,91,20,existence=True)
False>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(2058),Integer(242),Integer(91),
˓→Integer(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 withvertices number of vertices. A tree is a graph with no cycles.
ALGORITHM:
Uses an algorithm that generates each new tree in constant time. See the documentation for, and implementation of, the sage.graphs.trees module, including a citation.
EXAMPLES:
We create an iterator, then loop over its elements.

1034

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> tree_iterator = graphs.trees(Integer(7))>>> 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]>>> from sage.all import *>>> [len(list(graphs.trees(i))) for i in range(Integer(0), Integer(15))][1, 1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]

triangulations(order, minimum_degree=None, minimum_connectivity=None, exact_connectivity=False,
only_eulerian=False, dual=False)
An iterator over connected planar triangulations using the plantri generator.
This uses the plantri generator (see [BM2007]) 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 thegenerated 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, thenthis is set to the same value as the minimum connectivity. If the minimum connectivity is also equal toNone, then this is set to 3.
• minimum_connectivity – (default: None); a value ≥ 3 and ≤ 5, or None. This specifies theminimum connectivity of the generated triangulations. If this is None and the minimum degree is
2.1. Common graphs1035

Graph Theory, Release 10.4

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 explicitly set.
• only_eulerian – (default: False); if True only Eulerian triangulations will be generated. This
option cannot be used if the minimum degree is explicitly 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).
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]}]>>> from sage.all import *>>> gen = graphs.triangulations(Integer(4))# optional - plantri>>> [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)
sage: len(list(gen))0# optional - plantri# optional - plantri>>> from sage.all import *>>> gen = graphs.triangulations(Integer(4), only_eulerian=True) # optional -␣˓→plantri>>> len(list(gen))# optional - plantri0

The unique Eulerian triangulation on 6 vertices is isomorphic to the octahedral graph.
sage: gen = graphs.triangulations(6, only_eulerian=True)
sage: g = next(gen)sage: g.is_isomorphic(graphs.OctahedralGraph())
True# optional - plantri# optional - plantri# optional - plantri>>> from sage.all import *>>> gen = graphs.triangulations(Integer(6), only_eulerian=True) # optional -␣˓→plantri>>> g = next(gen)# optional - plantri(continues on next page)

1036

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_isomorphic(graphs.OctahedralGraph())
True# optional - plantri

The minimum degree of a triangulation is 3, so the method can not output a triangle:
sage: list(graphs.triangulations(3))[]# optional - plantri>>> from sage.all import *>>> list(graphs.triangulations(Integer(3)))˓→plantri[]# optional -␣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)))....:
print("{}{:3d}".format(i,L))
12
1
13
0
14
1
15
1
16
3
17
4
18
12
19
23
20
71
21
187
22
627
>>> from sage.all import *>>> for i in range(Integer(12), Integer(23)):˓→# optional - plantri...
L = len(list(graphs.triangulations(i, minimum_
˓→connectivity=Integer(5))))...
print("{}{:3d}".format(i,L))
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,
˓→plantri....:
minimum_connectivity=5))
Traceback (most recent call last):# optional -␣(continues on next page)2.1. Common graphs

1037

Graph Theory, Release 10.4

(continued from previous page)...
ValueError: Minimum connectivity can be at most the minimum degree.
>>> from sage.all import *>>> gen = next(graphs.triangulations(Integer(10), minimum_degree=Integer(3), ␣˓→# optional - plantri...
minimum_connectivity=Integer(5)))
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 oneof them is not 4-connected:
sage: len([g for g in graphs.triangulations(9, minimum_degree=4,
˓→optional - plantri....:
minimum_connectivity=3)])5
sage: len([g for g in graphs.triangulations(9, minimum_degree=4,
˓→optional - plantri....:
minimum_connectivity=3,....:
exact_connectivity=True)])
1

#␣

#␣

>>> from sage.all import *>>> len([g for g in graphs.triangulations(Integer(9), minimum_
˓→degree=Integer(4),# optional - plantri...
minimum_connectivity=Integer(3))])5>>> len([g for g in graphs.triangulations(Integer(9), minimum_
˓→degree=Integer(4),# optional - plantri...
minimum_connectivity=Integer(3),...
exact_connectivity=True)])
1

Setting dual=True gives the planar dual graphs:
sage: [len(g) for g in graphs.triangulations(9, minimum_degree=4,
˓→optional plantri....:
minimum_connectivity=3,␣˓→dual=True)][14, 14, 14, 14, 14]#␣>>> from sage.all import *>>> [len(g) for g in graphs.triangulations(Integer(9), minimum_
˓→degree=Integer(4),# optional plantri...
minimum_connectivity=Integer(3),␣
˓→dual=True)][14, 14, 14, 14, 14]

static vanLintSchrijverGraph()
Return the van Lint-Schrijver graph.
The graph is distance-regular with intersection array [6, 5, 5, 4; 1, 1, 2, 6].
EXAMPLES:

1038

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.vanLintSchrijverGraph()
˓→ # needs sage.modules
sage: G.is_distance_regular(True)
˓→ # needs sage.modules([6, 5, 5, 4, None], [None, 1, 1, 2, 6])␣␣>>> from sage.all import *>>> G = graphs.vanLintSchrijverGraph()˓→# needs sage.modules>>> G.is_distance_regular(True)
˓→# needs sage.modules([6, 5, 5, 4, None], [None, 1, 1, 2, 6])

REFERENCES:
For a description of this graph see [BCN1989] p. 373.
world_map = <module sage.graphs.generators.world_map from/home/user/sage-git/src/sage/graphs/generators/world_map.py >sage.graphs.graph_generators.canaug_traverse_edge(g, aut_gens, property, dig=False,
loops=False, sparse=True)
Main function for exhaustive generation. Recursive traversal of a canonically generated tree of isomorph free graphs
satisfying a given property.
INPUT:• g – current position on the tree.
• aut_gens – list of generators of Aut(g), in list notation.
• property – check before traversing below g.
EXAMPLES:
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]>>> from sage.all import *>>> from sage.graphs.graph_generators import canaug_traverse_edge>>> G = Graph(Integer(3))>>> 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

2.1. Common graphs1039

Graph Theory, Release 10.4>>> from sage.all import *>>> for G in graphs(Integer(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>>> from sage.all import *>>> for G in digraphs(Integer(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, sparse=True)
Main function for exhaustive generation. Recursive traversal of a canonically generated tree of isomorph free(di)graphs satisfying a given property.
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]>>> from sage.all import *>>> from sage.graphs.graph_generators import canaug_traverse_vert>>> list(canaug_traverse_vert(Graph(), [], Integer(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.

1040

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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>>> from sage.all import *>>> for G in graphs(Integer(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>>> from sage.all import *>>> for D in digraphs(Integer(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 arelooking 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 startingat 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.1. Common graphs1041

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_generators import check_aut>>> list( check_aut( [ [Integer(0), Integer(3), Integer(2), Integer(1)],␣
˓→[Integer(1), Integer(0), Integer(3), Integer(2)], [Integer(2), Integer(1),␣
˓→Integer(0), Integer(3)] ], Integer(2), Integer(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.
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 startingat 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]]>>> from sage.all import *>>> from sage.graphs.graph_generators import check_aut>>> list( check_aut( [ [Integer(0), Integer(3), Integer(2), Integer(1)],␣
˓→[Integer(1), Integer(0), Integer(3), Integer(2)], [Integer(2), Integer(1),␣
˓→Integer(0), Integer(3)] ], Integer(2), Integer(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)>>> from sage.all import *>>> g = digraphs.Circuit(Integer(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])>>> from sage.all import *>>> p = digraphs.Circulant(Integer(10),[Integer(2),Integer(3)])

More interestingly, one can get the list of all digraphs that Sage knows how to build by typing digraphs. in Sage andthen hitting Tab.

1042

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

ButterflyGraph()
Circuit()Circulant()
Complete()
DeBruijn()
GeneralizedDeBruijn()
ImaseItoh()
Kautz()
nauty_directg()
Paley()
Path()
RandomDirectedAcyclicGraph()
RandomDirectedGNC()
RandomDirectedGNM()
RandomDirectedGNP()
RandomDirectedGN()
RandomDirectedGNR()
RandomSemiComplete()
RandomTournament()
TransitiveTournament()
tournaments_nauty()

Return a 𝑛-dimensional butterfly graph.
Return the circuit on 𝑛 vertices.
Return a circulant digraph on 𝑛 vertices from a set of integers.
Return a complete digraph on 𝑛 vertices.
Return the De Bruijn digraph with parameters 𝑘, 𝑛.
Return the generalized de Bruijn digraph of order 𝑛 and degree 𝑑.
Return the digraph of Imase and Itoh of order 𝑛 and degree 𝑑.
Return the Kautz digraph of degree 𝑑 and diameter 𝐷.
Return an iterator yielding digraphs using nauty’s directg program.
Return a Paley digraph on 𝑞 vertices.
Return a directed path on 𝑛 vertices.
Return a random (weighted) directed acyclic graph of order 𝑛.
Return a random growing network with copying (GNC) digraph with 𝑛 vertices.
Return a random labelled digraph on 𝑛 nodes and 𝑚 arcs.
Return a random digraph on 𝑛 nodes.
Return a random growing network (GN) digraph with 𝑛 vertices.
Return a random growing network with redirection (GNR) digraph.
Return a random semi-complete digraph of order 𝑛.
Return a random tournament on 𝑛 vertices.
Return a transitive tournament on 𝑛 vertices.
Iterator over all tournaments on 𝑛 vertices using Nauty.

AUTHORS:• Robert L. Miller (2006)• Emily A. Kirkman (2006)• Michael C. Yurko (2009)• David Coudert (2012)

2.2.1 Functions and methods
class sage.graphs.digraph_generators.DiGraphGenerators
Bases: object
A class consisting of constructors for several common digraphs, including orderly generation of isomorphism classrepresentatives.
A list of all graphs and graph structures in this database is available via tab completion. Type digraphs. andthen hit Tab to see which digraphs 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:- RandomDirectedAcyclicGraph- RandomDirectedGN- RandomDirectedGNC- RandomDirectedGNP(continues on next page)2.2. Common digraphs1043

Graph Theory, Release 10.4

(continued from previous page)- 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 [McK1998]. 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 digraphs
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 will generate
all digraphs with that property. If this does not hold, then all the digraphs generated will satisfy theproperty, but there will be some missing.

• implementation – which underlying implementation to use (see DiGraph?)• sparse – boolean (default: True); whether to use a sparse or dense data structure. See the documentationof 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

1044

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> for D in digraphs(Integer(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

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>>> from sage.all import *>>> for D in digraphs(Integer(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>>> from sage.all import *>>> L = digraphs(Integer(4), size=Integer(3))>>> 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
˓→needs sage.plot>>> from sage.all import *>>> L = list(digraphs(Integer(4), lambda G: G.size() <= Integer(3)))>>> len(L)20>>> graphs_list.show_graphs(L)# long time
˓→needs sage.plot#␣#␣

Generate all digraphs with degree at most 2, up to 5 vertices:

2.2. Common digraphs1045

Graph Theory, Release 10.4

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>>> from sage.all import *>>> property = lambda G: (max([G.degree(v) for v in G] + [Integer(0)]) <=␣
˓→Integer(2))>>> L = list(digraphs(Integer(5), property, augment= vertices ))>>> len(L)75

Generate digraphs on the fly (see http://oeis.org/classic/A000273):
sage: for i in range(5):....:print(len(list(digraphs(i))))
1
1
3
16
218
>>> from sage.all import *>>> for i in range(Integer(5)):...
print(len(list(digraphs(i))))
1
1
3
16
218

ButterflyGraph(n, vertices='strings')
Return a 𝑛-dimensional butterfly graph.
The vertices consist of pairs (𝑣, 𝑖), where 𝑣 is an 𝑛-dimensional tuple (vector) with binary entries (or a string
representation of such) and 𝑖 is an integer in [0..𝑛]. A directed edge goes from (𝑣, 𝑖) to (𝑤, 𝑖 + 1) if 𝑣 and 𝑤
are identical except for possibly when 𝑣[𝑖] ̸= 𝑤[𝑖].
A butterfly graph has (2𝑛 )(𝑛 + 1) vertices and 𝑛2𝑛+1 edges.
INPUT:• n – a non negative integer; the dimension of the butterfly graph• vertices – string (default: strings ); specifies whether the vertices are zero-one strings (default)
or tuples over GF(2) (vertices= vectors )EXAMPLES:
sage: digraphs.ButterflyGraph(2).edges(sort=True, 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)),
(continues on next page)1046

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)(( 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(sort=True,
˓→needs sage.modules sage.rings.finite_rings....:
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)),(((1, 1), 1), ((1, 0), 2)),(((1, 1), 1), ((1, 1), 2))]sage: pos = digraphs.ButterflyGraph(2).get_pos()sage: pos[ 11 , 0](0, 0)#␣>>> from sage.all import *>>> digraphs.ButterflyGraph(Integer(2)).edges(sort=True, 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))]>>> digraphs.ButterflyGraph(Integer(2), vertices= vectors ).edges(sort=True, ␣˓→# needs sage.modules sage.rings.finite_rings...
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)),
(continues on next page)2.2. Common digraphs

1047

Graph Theory, Release 10.4

(continued from previous page)(((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)),(((1, 1), 1), ((1, 0), 2)),(((1, 1), 1), ((1, 1), 2))]>>> pos = digraphs.ButterflyGraph(Integer(2)).get_pos()>>> pos[ 11 , Integer(0)](0, 0)

Circuit(n)Return 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>>> from sage.all import *>>> circuit = digraphs.Circuit(Integer(15))>>> len(circuit.strongly_connected_components()) == Integer(1)True

Circulant(n, integers)
Return a circulant digraph on 𝑛 vertices from a set of integers.
INPUT:• n – integer; number of vertices• integers – iterable container (list, set, etc.) of integers such that there is an edge from 𝑖 to 𝑗 if andonly if (𝑗 − 𝑖) (mod 𝑛) is an integer
EXAMPLES:
sage: digraphs.Circulant(13,[3,5,7])
Circulant graph ([3, 5, 7]): Digraph on 13 vertices>>> from sage.all import *>>> digraphs.Circulant(Integer(13),[Integer(3),Integer(5),Integer(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
1048

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• loops – boolean (default: False); whether to add loops or not, i.e., edges from 𝑢 to itself
See also:• RandomSemiComplete()• RandomTournament()
EXAMPLES:
sage: n = 10
sage: G = digraphs.Complete(n); G
Complete digraph: Digraph on 10 vertices
sage: G.size() == n*(n-1)
True
sage: G = digraphs.Complete(n, loops=True); G
Complete digraph with loops: Looped digraph on 10 vertices
sage: G.size() == n*n
True
sage: digraphs.Complete(-1)
Traceback (most recent call last):...
ValueError: the number of vertices cannot be strictly negative>>> from sage.all import *>>> n = Integer(10)>>> G = digraphs.Complete(n); G
Complete digraph: Digraph on 10 vertices>>> G.size() == n*(n-Integer(1))
True>>> G = digraphs.Complete(n, loops=True); G
Complete digraph with loops: Looped digraph on 10 vertices>>> G.size() == n*n
True>>> digraphs.Complete(-Integer(1))
Traceback (most recent call last):...
ValueError: the number of vertices cannot be strictly negative

DeBruijn(k, n, vertices='strings')
Return the De Bruijn digraph with parameters 𝑘, 𝑛.
The De Bruijn digraph with parameters 𝑘, 𝑛 is built upon a set of vertices equal to the set of words of length𝑛 from a dictionary of 𝑘 letters.
In this digraph, there is an arc 𝑤1 𝑤2 if 𝑤2 can be obtained from 𝑤1 by removing the leftmost letter andadding a new letter at its right end. For more information, see the Wikipedia article De_Bruijn_graph.
INPUT:• k – two possibilities for this parameter :– An integer equal to the cardinality of the alphabet to use, that is, the degree of the digraph to be
produced.
– An iterable object to be used as the set of letters. The degree of the resulting digraph is the
cardinality of the set of letters.
• n – integer; length of words in the De Bruijn digraph when vertices ==the diameter of the digraph.

2.2. Common digraphs

strings , and also1049

Graph Theory, Release 10.4

• vertices – string (default: strings ); whether the vertices are words over an alphabet (default)
or integers (vertices= string )EXAMPLES:de Bruijn digraph of degree 2 and diameter 2:
sage: db = digraphs.DeBruijn(2, 2); db
˓→needs sage.combinat
De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices
sage: db.order(), db.size()
˓→needs sage.combinat(4, 8)
sage: db.diameter()˓→needs sage.combinat
2>>> from sage.all import *>>> db = digraphs.DeBruijn(Integer(2), Integer(2)); db˓→# needs sage.combinat
De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices>>> db.order(), db.size()
˓→needs sage.combinat(4, 8)>>> db.diameter()˓→needs sage.combinat
2

#␣

#␣

#␣

␣

#␣

#␣

Building a de Bruijn digraph on a different alphabet:sage: # needs sage.combinat
sage: g = digraphs.DeBruijn([ a , b ], 2)
sage: g.vertices(sort=True)[ aa , ab , ba , bb ]sage: g.is_isomorphic(db)Truesage: g = digraphs.DeBruijn([ AA , BB ], 2)
sage: g.vertices(sort=True)[ AA,AA , AA,BB , BB,AA , BB,BB ]sage: g.is_isomorphic(db)True>>> from sage.all import *>>> # needs sage.combinat>>> g = digraphs.DeBruijn([ a , b ], Integer(2))>>> g.vertices(sort=True)[ aa , ab , ba , bb ]>>> g.is_isomorphic(db)True>>> g = digraphs.DeBruijn([ AA , BB ], Integer(2))>>> g.vertices(sort=True)[ AA,AA , AA,BB , BB,AA , BB,BB ]>>> g.is_isomorphic(db)True

GeneralizedDeBruijn(n, d)
Return the generalized de Bruijn digraph of order 𝑛 and degree 𝑑.
The generalized de Bruijn digraph was defined in [RPK1980] [RPK1983]. It has vertex set 𝑉 = {0, 1, ..., 𝑛−
1050

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

1} and there is an arc from vertex 𝑢 ∈ 𝑉 to all vertices 𝑣 ∈ 𝑉 such that 𝑣 ≡ (𝑢 * 𝑑 + 𝑎) mod 𝑛 with0 ≤ 𝑎 < 𝑑.
When 𝑛 = 𝑑𝐷 , the generalized de Bruijn digraph is isomorphic to the de Bruijn digraph of degree 𝑑 anddiameter 𝐷.
INPUT:• n – integer; number of vertices of the digraph (must be at least one)• d – integer; degree of the digraph (must be at least one)See also:• 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)
˓→needs sage.combinat(True, {0: 000 , 1: 001 , 2: 010 , 3: 011 ,4: 100 , 5: 101 , 6: 110 , 7: 111 })#␣>>> from sage.all import *>>> GB = digraphs.GeneralizedDeBruijn(Integer(8), Integer(2))>>> GB.is_isomorphic(digraphs.DeBruijn(Integer(2), Integer(3)),␣
˓→certificate=True)# needs sage.combinat(True, {0: 000 , 1: 001 , 2: 010 , 3: 011 ,4: 100 , 5: 101 , 6: 110 , 7: 111 })ImaseItoh(n, d)
Return the Imase-Itoh digraph of order 𝑛 and degree 𝑑.
The Imase-Itoh digraph was defined in [II1983]. It has vertex set 𝑉 = {0, 1, ..., 𝑛 − 1} and there is an arc
from vertex 𝑢 ∈ 𝑉 to all vertices 𝑣 ∈ 𝑉 such that 𝑣 ≡ (−𝑢 * 𝑑 − 𝑎 − 1) mod 𝑛 with 0 ≤ 𝑎 < 𝑑.
When 𝑛 = 𝑑𝐷 , the Imase-Itoh digraph is isomorphic to the de Bruijn digraph of degree 𝑑 and diameter 𝐷.
When 𝑛 = 𝑑𝐷−1 (𝑑 + 1), the Imase-Itoh digraph is isomorphic to the Kautz digraph [Kau1968] of degree 𝑑
and diameter 𝐷.
INPUT:• n – integer; number of vertices of the digraph (must be greater than or equal to two)
• d – integer; degree of the digraph (must be greater than or equal to one)
EXAMPLES:
sage: II = digraphs.ImaseItoh(8, 2)
sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True)
˓→needs sage.combinat(True, {0: 010 , 1: 011 , 2: 000 , 3: 001 ,4: 110 , 5: 111 , 6: 100 , 7: 101 })sage: II = digraphs.ImaseItoh(12, 2)
sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True)
˓→needs sage.combinat
sage: b#␣#␣#␣(continues on next page)2.2. Common digraphs1051

Graph Theory, Release 10.4

(continued from previous page)needs sage.combinat
Truesage: D# random isomorphism
˓→needs sage.combinat{0: 202 , 1: 201 , 2: 210 , 3:
5: 120 , 6: 102 , 7: 101 , 8:
10: 021 , 11: 020 }˓→#␣
212 , 4:010 , 9:

121 ,
012 ,

>>> from sage.all import *>>> II = digraphs.ImaseItoh(Integer(8), Integer(2))>>> II.is_isomorphic(digraphs.DeBruijn(Integer(2), Integer(3)),␣
˓→certificate=True)# needs sage.combinat(True, {0: 010 , 1: 011 , 2: 000 , 3: 001 ,4: 110 , 5: 111 , 6: 100 , 7: 101 })>>> II = digraphs.ImaseItoh(Integer(12), Integer(2))>>> b,D = II.is_isomorphic(digraphs.Kautz(Integer(2), Integer(3)),␣
˓→certificate=True)# needs sage.combinat>>> b
˓→needs sage.combinat
True
>>> D
# random isomorphism
˓→needs sage.combinat{0: 202 , 1: 201 , 2: 210 , 3: 212 , 4: 121 ,5: 120 , 6: 102 , 7: 101 , 8: 010 , 9: 012 ,10: 021 , 11: 020 }#␣#␣Kautz(k, D, vertices='strings')
Return the Kautz digraph of degree 𝑑 and diameter 𝐷.
The Kautz digraph has been defined in [Kau1968]. The Kautz digraph of degree 𝑑 and diameter 𝐷 has
𝑑𝐷−1 (𝑑 + 1) vertices. This digraph is built from a set of vertices equal to the set of words of length 𝐷
over an alphabet of 𝑑 + 1 letters such that consecutive letters are different. There is an arc from vertex 𝑢 tovertex 𝑣 if 𝑣 can be obtained from 𝑢 by removing the leftmost letter and adding a new letter, distinct fromthe rightmost letter of 𝑢, at the right end.
The Kautz digraph of degree 𝑑 and diameter 𝐷 is isomorphic to the Imase-Itoh digraph [II1983] of degree 𝑑and order 𝑑𝐷−1 (𝑑 + 1).
See the Wikipedia article Kautz_graph for more information.
INPUT:• k – two possibilities for this parameter. In either case the degree must be at least one:
– An integer equal to the degree of the digraph to be produced, that is, the cardinality of the alphabet
to be used minus one.
– An iterable object to be used as the set of letters. The degree of the resulting digraph is the cardinalityof the set of letters minus one.
• D – integer; diameter of the digraph, and length of a vertex label when vertices ==(must be at least one)strings• vertices – string (default: strings ); whether the vertices are words over an alphabet (default)
or integers (vertices= strings )EXAMPLES:

1052

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.combinat
sage: K = digraphs.Kautz(2, 3)
sage: b, D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True)
sage: bTrue
sage: D # random isomorphism{ 010 : 8, 012 : 9, 020 : 11, 021 : 10, 101 : 7,
102 : 6,
120 : 5, 121 : 4, 201 : 1, 202 : 0, 210 : 2, 212 : 3}sage: K = digraphs.Kautz([1, a , B ], 2)
˓→needs sage.combinat
sage: K.edges(sort=True)
˓→needs sage.combinat[( 1B , B1 , 1 ), ( 1B , Ba , a ), ( 1a ,( 1a , aB , B ), ( B1 , 1B , B ), ( B1 ,( Ba , a1 , 1 ), ( Ba , aB , B ), ( a1 ,( a1 , 1a , a ), ( aB , B1 , 1 ), ( aB ,

#␣
#␣
a1 ,
1a ,
1B ,
Ba ,

1 ),
a ),
B ),
a )]

sage: K = digraphs.Kautz([1, aA , BB ], 2)
˓→needs sage.combinat
sage: K.edges(sort=True)
˓→needs sage.combinat[( 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 )]#␣#␣>>> from sage.all import *>>> # needs sage.combinat>>> K = digraphs.Kautz(Integer(2), Integer(3))>>> b, D = K.is_isomorphic(digraphs.ImaseItoh(Integer(12), Integer(2)),␣
˓→certificate=True)
>>> b
True
>>> D # random isomorphism{ 010 : 8, 012 : 9, 020 : 11, 021 : 10, 101 : 7,
102 : 6,
120 : 5, 121 : 4, 201 : 1, 202 : 0, 210 : 2, 212 : 3}>>> K = digraphs.Kautz([Integer(1), a , B ], Integer(2))˓→# needs sage.combinat>>> K.edges(sort=True)
˓→needs sage.combinat[( 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 )]>>> K = digraphs.Kautz([Integer(1), aA , BB ], Integer(2))˓→# needs sage.combinat>>> K.edges(sort=True)
˓→needs sage.combinat[( 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 ),

␣
#␣

␣
#␣

(continues on next page)2.2. Common digraphs1053

Graph Theory, Release 10.4

(continued from previous page)( aA,1 , 1,BB , BB ), ( aA,1 , 1,aA , aA ),( aA,BB , BB,1 , 1 ), ( aA,BB , BB,aA , aA )]Paley(q)Return a Paley digraph on 𝑞 vertices.
Parameter 𝑞 must be the power of a prime number and congruent to 3 mod 4.
See also:• 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:
sage: g = digraphs.Paley(7); g˓→needs sage.rings.finite_rings
Paley digraph with parameter 7: Digraph on 7 vertices
sage: g.size() == g.order() * (g.order() - 1) / 2
˓→needs sage.rings.finite_rings
True
sage: g.to_undirected().is_clique()
˓→needs sage.rings.finite_rings
True>>> from sage.all import *>>> g = digraphs.Paley(Integer(7)); g˓→# needs sage.rings.finite_rings
Paley digraph with parameter 7: Digraph on 7 vertices>>> g.size() == g.order() * (g.order() - Integer(1)) / Integer(2)˓→# needs sage.rings.finite_rings
True>>> g.to_undirected().is_clique()
˓→needs sage.rings.finite_rings
True

#␣

#␣

#␣

␣

␣

#␣

A Paley digraph is always self-complementary:sage: g.complement().is_isomorphic(g)˓→needs sage.rings.finite_rings
True>>> from sage.all import *>>> g.complement().is_isomorphic(g)˓→needs sage.rings.finite_rings
True

#␣

#␣

Path(n)Return a directed path on 𝑛 vertices.
INPUT:• n – integer; number of vertices in the path
EXAMPLES:
1054

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: g = digraphs.Path(5)sage: g.vertices(sort=True)[0, 1, 2, 3, 4]
sage: g.size()4
sage: g.automorphism_group().cardinality()
˓→needs sage.groups1>>> from sage.all import *>>> g = digraphs.Path(Integer(5))>>> g.vertices(sort=True)[0, 1, 2, 3, 4]>>> g.size()4>>> g.automorphism_group().cardinality()
˓→needs sage.groups
1

#␣

#␣

RandomDirectedAcyclicGraph(n, p, weight_max=None)
Return a random (weighted) directed acyclic graph of order 𝑛.
The method starts with the sink vertex and adds vertices one at a time. A vertex is connected only to previously
defined vertices, and the probability of each possible connection is given by the probability 𝑝. The weight ofan edge is a random integer between 1 and weight_max.
INPUT:• n – number of nodes of the graph• p – probability of an edge
• weight_max – (default: None); by default, the returned DAG is unweighted. When weight_max
is set to a positive integer, edges are assigned a random integer weight between 1 and weight_max.
EXAMPLES:
sage: D = digraphs.RandomDirectedAcyclicGraph(5, .5); D
RandomDAG(5, 0.500000000000000): Digraph on 5 vertices
sage: D.is_directed_acyclic()Truesage: D = digraphs.RandomDirectedAcyclicGraph(5, .5, weight_max=3); D
RandomWeightedDAG(5, 0.500000000000000, 3): Digraph on 5 vertices
sage: D.is_directed_acyclic()True>>> from sage.all import *>>> D = digraphs.RandomDirectedAcyclicGraph(Integer(5), RealNumber( .5 )); D
RandomDAG(5, 0.500000000000000): Digraph on 5 vertices>>> D.is_directed_acyclic()
True>>> D = digraphs.RandomDirectedAcyclicGraph(Integer(5), RealNumber( .5 ),␣
˓→weight_max=Integer(3)); D
RandomWeightedDAG(5, 0.500000000000000, 3): Digraph on 5 vertices>>> D.is_directed_acyclic()
True

RandomDirectedGN(n, kernel=None, seed=None)
Return a random growing network (GN) digraph with 𝑛 vertices.
2.2. Common digraphs

1055

Graph Theory, Release 10.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 default
attachment kernel is a linear function of degree. The digraph is always a tree, so in particular it is a directed
acyclic graph. See [KR2001b] for more details.
INPUT:• n – integer; number of vertices• kernel – the attachment kernel (default: identity function)• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: # needs networkx
sage: D = digraphs.RandomDirectedGN(25)sage: D.num_verts()
25
sage: D.num_edges()24
sage: D.is_connected()Truesage: D.parent() is DiGraph
True
sage: D.show()# long time>>> from sage.all import *>>> # needs networkx>>> D = digraphs.RandomDirectedGN(Integer(25))>>> D.num_verts()
25>>> D.num_edges()24>>> D.is_connected()True>>> D.parent() is DiGraph
True>>> D.show()# long time

RandomDirectedGNC(n, seed=None)
Return a random growing network with copying (GNC) digraph with 𝑛 vertices.
The digraph is constructed by adding vertices with a link to one previously added vertex. The vertex to link
to is chosen with a preferential attachment model, i.e. probability is proportional to degree. The new vertex
is also linked to all of the previously added vertex’s successors. See [KR2005] for more details.
INPUT:• n – integer; number of vertices• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: # needs networkx
sage: D = digraphs.RandomDirectedGNC(25)sage: D.is_directed_acyclic()Truesage: D.topological_sort()(continues on next page)

1056

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)[24, 23, ..., 1, 0]
sage: D.show()# long time>>> from sage.all import *>>> # needs networkx>>> D = digraphs.RandomDirectedGNC(Integer(25))>>> D.is_directed_acyclic()
True>>> D.topological_sort()[24, 23, ..., 1, 0]>>> D.show()# long time

RandomDirectedGNM(n, m, loops=False)
Return a random labelled digraph on 𝑛 nodes and 𝑚 arcs.
INPUT:• n – integer; number of vertices• m – integer; number of edges• loops – boolean (default: False); whether to allow loops
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary is specified.
EXAMPLES:
sage: D = digraphs.RandomDirectedGNM(10, 5)
sage: D.num_verts()
10
sage: D.num_edges()5>>> from sage.all import *>>> D = digraphs.RandomDirectedGNM(Integer(10), Integer(5))>>> D.num_verts()
10>>> D.num_edges()
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)]>>> from sage.all import *>>> D = digraphs.RandomDirectedGNM(Integer(10), Integer(100), loops = True)>>> D.num_verts()
10>>> 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

1057

Graph Theory, Release 10.4

RandomDirectedGNP(n, p, loops=False, seed=None)
Return a random digraph on 𝑛 nodes.
Each edge is inserted independently with probability 𝑝. See [ER1959] and [Gil1959] for more details.
INPUT:• n – integer; number of nodes of the digraph• p – float; probability of an edge
• loops – boolean (default: False); whether the random digraph may have loops• seed – integer (default: None); seed for random number generator
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary is specified.
EXAMPLES:
sage: D = digraphs.RandomDirectedGNP(10, .2)
sage: D.num_verts()
10
sage: D.parent() is DiGraph
True>>> from sage.all import *>>> D = digraphs.RandomDirectedGNP(Integer(10), RealNumber( .2 ))>>> D.num_verts()
10>>> D.parent() is DiGraph
True

RandomDirectedGNR(n, p, seed=None)
Return a random growing network with redirection (GNR) digraph with 𝑛 vertices and redirection probability𝑝.
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 digraphis always a tree. See [KR2001b] for more details.
INPUT:• n – integer; number of vertices• p – redirection probability• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: # needs networkx
sage: D = digraphs.RandomDirectedGNR(25, .2)
sage: D.is_directed_acyclic()Truesage: D.to_undirected().is_tree()True
sage: D.show()# long time
˓→needs sage.plot

1058

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs networkx>>> D = digraphs.RandomDirectedGNR(Integer(25), RealNumber( .2 ))>>> D.is_directed_acyclic()
True>>> D.to_undirected().is_tree()True>>> D.show()# long time
˓→needs sage.plot#␣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)
˓→needs sage.symbolicTruesage: digraphs.RandomSemiComplete(-1)
Traceback (most recent call last):...
ValueError: the number of vertices cannot be strictly negative>>> from sage.all import *>>> SC = digraphs.RandomSemiComplete(Integer(10)); SC
Random Semi-Complete digraph: Digraph on 10 vertices>>> SC.size() >= binomial(Integer(10), Integer(2))˓→# needs sage.symbolicTrue>>> digraphs.RandomSemiComplete(-Integer(1))
Traceback (most recent call last):...
ValueError: the number of vertices cannot be strictly negative#␣␣

RandomTournament(n)Return a random tournament on 𝑛 vertices.

2.2. Common digraphs1059

Graph Theory, Release 10.4

For every pair of vertices, the tournament has an edge from 𝑖 to 𝑗 with probability 1/2, otherwise it has anedge 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)
˓→needs sage.symbolicTruesage: T.is_tournament()
True
sage: digraphs.RandomTournament(-1)
Traceback (most recent call last):...
ValueError: the number of vertices cannot be strictly negative>>> from sage.all import *>>> T = digraphs.RandomTournament(Integer(10)); T
Random Tournament: Digraph on 10 vertices>>> T.size() == binomial(Integer(10), Integer(2))˓→# needs sage.symbolic
True>>> T.is_tournament()True>>> digraphs.RandomTournament(-Integer(1))
Traceback (most recent call last):...
ValueError: the number of vertices cannot be strictly negative#␣␣

See also:• Wikipedia article Tournament_(graph_theory)• is_tournament()• TransitiveTournament()• Complete()• RandomSemiComplete()
StronglyRegular(n)Return a Strongly Regular digraph with 𝑛 vertices.
The adjacency matrix of the graph is constructed from a skew Hadamard matrix of order 𝑛 + 1. These graphs
were first constructed in [Duv1988].
INPUT:• n – integer, the number of vertices of the digraph.
See also:• sage.combinat.matrices.hadamard_matrix.skew_hadamard_matrix()• Paley()1060

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
A Strongly Regular digraph satisfies the condition 𝐴𝐽 = 𝐽𝐴 = 𝑘𝐽 where 𝐴 is the adjacency matrix:
sage: # needs sage.combinat sage.modules
sage: g = digraphs.StronglyRegular(7); g
Strongly regular digraph: Digraph on 7 vertices
sage: A = g.adjacency_matrix()*ones_matrix(7)sage: B = ones_matrix(7)*g.adjacency_matrix()
sage: A == B == A[0, 0]*ones_matrix(7)True>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> g = digraphs.StronglyRegular(Integer(7)); g
Strongly regular digraph: Digraph on 7 vertices>>> A = g.adjacency_matrix()*ones_matrix(Integer(7))>>> B = ones_matrix(Integer(7))*g.adjacency_matrix()>>> A == B == A[Integer(0), Integer(0)]*ones_matrix(Integer(7))
True

TransitiveTournament(n)Return a transitive tournament on 𝑛 vertices.
In this tournament there is an edge from 𝑖 to 𝑗 if 𝑖 < 𝑗.
See the Wikipedia article Tournament_(graph_theory) for more information.
INPUT:• n – integer; number of vertices in the tournament
EXAMPLES:
sage: g = digraphs.TransitiveTournament(5)sage: g.vertices(sort=True)[0, 1, 2, 3, 4]
sage: g.size()
10
sage: g.automorphism_group().cardinality()
˓→needs sage.groups1>>> from sage.all import *>>> g = digraphs.TransitiveTournament(Integer(5))>>> g.vertices(sort=True)[0, 1, 2, 3, 4]>>> g.size()
10>>> g.automorphism_group().cardinality()
˓→needs sage.groups
1

#␣

#␣

See also:• Wikipedia article Tournament_(graph_theory)• is_tournament()• is_transitive()2.2. Common digraphs1061

Graph Theory, Release 10.4

• RandomTournament()
nauty_directg(graphs, options='', debug=False)
Return an iterator yielding digraphs using nauty’s directg program.
Description from directg --help: Read undirected graphs and orient their edges in all possible ways.
Edges can be oriented in either or both directions (3 possibilities). Isomorphic directed graphs derived fromthe same input are suppressed. If the input graphs are non-isomorphic then the output graphs are also.
INPUT:• graphs – a Graph or an iterable containing Graph. The graph6 string of these graphs is used as an
input for directg.
• options – a string passed to directg as if it was run at a system command line. Available options
from directg --help:-e<int> | -e<int>:<int> specify a value or range of the total number of␣˓→arcs-oorient each edge in only one direction, never both-aonly make acyclic orientations (implies -o)-f<int> Use only the subgroup that fixes the first <int> vertices setwise-V
only output graphs with nontrivial groups (including exchange ofisolated vertices). The -f option is respected.
-s<int>/<int> Make only a fraction of the orientations: The first␣
˓→integer isthe part number (first is 0) and the second is the number ofparts. Splitting is done per input graph independently.

• debug – boolean (default: False); if True directg standard error and standard output are displayed.
EXAMPLES:
sage: gen = graphs.nauty_geng("-c 3")
sage: dgs = list(digraphs.nauty_directg(gen))sage: len(dgs)13sage: dgs[0]Digraph on 3 vertices
sage: dgs[0]._bit_vector()
001001000
sage: len(list(digraphs.nauty_directg(graphs.PetersenGraph(), options="-o")))324>>> from sage.all import *>>> gen = graphs.nauty_geng("-c 3")>>> dgs = list(digraphs.nauty_directg(gen))>>> len(dgs)13>>> dgs[Integer(0)]Digraph on 3 vertices>>> dgs[Integer(0)]._bit_vector()
001001000>>> len(list(digraphs.nauty_directg(graphs.PetersenGraph(), options="-o")))324

Generate non-isomorphic acyclic orientations:1062

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: K = graphs.CompleteGraph(4)sage: all(d.is_directed_acyclic() for d in digraphs.nauty_directg(K, options=
˓→ -a ))
True
sage: sum(1 for _ in digraphs.nauty_directg(K, options= -a ))1
sage: S = graphs.StarGraph(4)sage: all(d.is_directed_acyclic() for d in digraphs.nauty_directg(S, options=
˓→ -a ))
True
sage: sum(1 for _ in digraphs.nauty_directg(S, options= -a ))5>>> from sage.all import *>>> K = graphs.CompleteGraph(Integer(4))>>> all(d.is_directed_acyclic() for d in digraphs.nauty_directg(K, options= -a
˓→ ))
True
>>> sum(Integer(1) for _ in digraphs.nauty_directg(K, options= -a ))1>>> S = graphs.StarGraph(Integer(4))>>> all(d.is_directed_acyclic() for d in digraphs.nauty_directg(S, options= -a
˓→ ))
True
>>> sum(Integer(1) for _ in digraphs.nauty_directg(S, options= -a ))5

See also:• orientations()• strong_orientation()• strong_orientations_iterator()• random_orientation()
tournaments_nauty(n, min_out_degree=None, max_out_degree=None, strongly_connected=False,debug=False, options='')
Iterator over 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 (default: False); 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 aline 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 documentation for more information : https://pallini.di.uniroma1.it.
EXAMPLES:

2.2. Common digraphs1063

Graph Theory, Release 10.4

sage: for g in digraphs.tournaments_nauty(4):....:print(g.edges(sort=True, 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]>>> from sage.all import *>>> for g in digraphs.tournaments_nauty(Integer(4)):...
print(g.edges(sort=True, 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)]>>> tournaments = digraphs.tournaments_nauty>>> [len(list(tournaments(x))) for x in range(Integer(1),Integer(8))][1, 1, 2, 4, 12, 56, 456]>>> [len(list(tournaments(x, strongly_connected = True))) for x in␣˓→range(Integer(1),Integer(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, seed=None)
Return a random graph or a digraph on 𝑛 nodes.
Each edge is inserted independently with probability 𝑝.
INPUT:• n – number of nodes of the digraph• p – probability of an edge
• directed – boolean (default: False); whether the random graph is directed or undirected (default)• loops – boolean (default: False); whether the random digraph may have loops or not. This value is used
only when directed == True
• seed – a random.Random seed or a Python int for the random number generator (default: None)
REFERENCES:• [ER1959]• [Gil1959]
EXAMPLES:

1064

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: from sage.graphs.graph_generators_pyx import RandomGNP
sage: D = RandomGNP(10, .2, directed=True, seed=0)
sage: D.num_verts()
10
sage: D.edges(sort=True, 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)]>>> from sage.all import *>>> from sage.graphs.graph_generators_pyx import RandomGNP>>> D = RandomGNP(Integer(10), RealNumber( .2 ), directed=True, seed=Integer(0))>>> D.num_verts()
10>>> D.edges(sort=True, 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
This module implements classes (GraphDatabase, GraphQuery, GenericGraphQuery) for interfacing withthe sqlite database graphs.db.
The GraphDatabase class interfaces with the sqlite database graphs.db. It is an immutable database that
inherits from SQLDatabase (see sage.databases.sql_db).
The database contains all unlabeled graphs with 7 or fewer nodes. This class will also interface with the optional databasepackage containing all unlabeled graphs with 8 or fewer nodes. The database(s) consists of five tables, and has the structure given by the function graph_db_info() (For a full description including column data types, create a GraphDatabase instance and call the method get_skeleton()).
AUTHORS:• Emily A. Kirkman (2008-09-20): first version of interactive queries, cleaned up code and generalized many elements to sage.databases.sql_db.py• Emily A. Kirkman (2007-07-23): inherits GenericSQLDatabase, also added classes: GraphQuery and GenericGraphQuery• 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: SQLQuery
A query for a GraphDatabase.
INPUT:• query_string – a string representing the SQL query• database – (default: None); the GraphDatabase instance to query (if None then a new instance iscreated)2.4. Graph database1065

Graph Theory, Release 10.4

• param_tuple – a tuple of strings (default: None); what to replace question marks in query_stringwith (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.
EXAMPLES:
See GraphDatabase class docstrings or enter:sage: G = GraphDatabase()sage: G.get_skeleton(){...
>>> from sage.all import *>>> G = GraphDatabase()>>> G.get_skeleton(){...

to see the underlying structure of the database. Also see sage.databases.sql_db.SQLQuery in sage.
databases.sql_db for more info and a tutorial.
A piece of advice about ‘?’ and param_tuple: it is generally considered safer to query with a ‘?’ in place of eachvalue 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-------------------------------------------------------------------------------18
D??
5
0
19
D?C
5
1
20
D?K
5
2
21
D@O
5
2
22
D?[
5
3
>>> from sage.all import *>>> G = GraphDatabase()>>> q = select graph_id,graph6,num_vertices,num_edges from graph_data where␣˓→graph_id<=(?) and num_vertices=(?)>>> param = (Integer(22),Integer(5))>>> Q = SQLQuery(G, q, param)>>> Q.show()graph_id
graph6
num_vertices
num_edges-------------------------------------------------------------------------------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: SQLDatabase
1066

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

Graph Database
This class interfaces with the sqlite database graphs.db. It is an immutable database that inherits from
SQLDatabase (see sage.databases.sql_db). The display functions and get_graphs_list create their own
queries, but it is also possible to query the database by constructing either a SQLQuery.
The database contains all unlabeled graphs with 7 or fewer nodes. This class will also interface with the optional
database package containing all unlabeled graphs with 8 or fewer nodes. The database consists of five tables. Fora full table and column structure, call graph_db_info().
The tables are associated by the unique primary key graph_id (int).
To query this database, we create a GraphQuery. This can be done directly with the query() method or byinitializing one of:• GenericGraphQuery – allows direct entry of a query string and tuple of parameters. This is the routefor more advanced users that are familiar with SQL• GraphQuery – a wrapper of SQLQuery, a general database/query wrapper of SQLite for new users
REFERENCES:• Data provided by Jason Grout (Brigham Young University). [Online] Available: http://artsci.drake.edu/grout/graphs/
EXAMPLES:
sage: G = GraphDatabase()sage: G.get_skeleton(){ aut_grp : { aut_grp_size : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
edge_transitive : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
num_fixed_points : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_orbits : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},vertex_transitive : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False}},degrees : { average_degree : { index : True,
primary_key : False,
sql : REAL ,unique : False},
degree_sequence : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},(continues on next page)2.4. Graph database1067

Graph Theory, Release 10.4

(continued from previous page)degrees_sd : { index : True,
primary_key : False,
sql : REAL ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
max_degree : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
min_degree : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
regular : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False}},graph_data : { complement_graph6 : { index : True,
primary_key : False,
sql : TEXT ,unique : False},
eulerian : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False},graph6 : { index : True,
primary_key : False,
sql : TEXT ,unique : False},graph_id : { index : True,
primary_key : False,
sql : INTEGER ,unique : True},
lovasz_number : { index : True,
primary_key : False,
sql : REAL ,unique : False},
num_cycles : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_edges : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_hamiltonian_cycles : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_vertices : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
perfect : { index : True,(continues on next page)

1068

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

primary_key : False,
sql : BOOLEAN ,unique : False},
planar : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False}},misc : { clique_number : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
diameter : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
edge_connectivity : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False},
girth : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
independence_number : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
induced_subgraphs : { index : True,
primary_key : False,
sql : TEXT ,unique : False},
min_vertex_cover_size : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_components : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_cut_vertices : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_spanning_trees : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
radius : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},vertex_connectivity : { index : True,
primary_key : False,(continues on next page)2.4. Graph database1069

Graph Theory, Release 10.4

(continued from previous page)sql : BOOLEAN ,unique : False}},spectrum : { eigenvalues_sd : { index : True,
primary_key : False,
sql : REAL ,unique : False},
energy : { index : True,
primary_key : False,
sql : REAL ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
max_eigenvalue : { index : True,
primary_key : False,
sql : REAL ,unique : False},
min_eigenvalue : { index : True,
primary_key : False,
sql : REAL ,unique : False},
spectrum : { index : False,
primary_key : False,
sql : TEXT ,unique : False}}}>>> from sage.all import *>>> G = GraphDatabase()>>> G.get_skeleton(){ aut_grp : { aut_grp_size : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
edge_transitive : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
num_fixed_points : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_orbits : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},vertex_transitive : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False}},degrees : { average_degree : { index : True,
primary_key : False,(continues on next page)

1070

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)sql : REAL ,unique : False},
degree_sequence : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
degrees_sd : { index : True,
primary_key : False,
sql : REAL ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
max_degree : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
min_degree : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
regular : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False}},graph_data : { complement_graph6 : { index : True,
primary_key : False,
sql : TEXT ,unique : False},
eulerian : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False},graph6 : { index : True,
primary_key : False,
sql : TEXT ,unique : False},graph_id : { index : True,
primary_key : False,
sql : INTEGER ,unique : True},
lovasz_number : { index : True,
primary_key : False,
sql : REAL ,unique : False},
num_cycles : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_edges : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_hamiltonian_cycles : { index : True,
primary_key : False,
sql : INTEGER ,(continues on next page)2.4. Graph database1071

Graph Theory, Release 10.4

(continued from previous page)

unique : False},
num_vertices : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
perfect : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False},
planar : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False}},misc : { clique_number : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
diameter : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
edge_connectivity : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False},
girth : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
independence_number : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
induced_subgraphs : { index : True,
primary_key : False,
sql : TEXT ,unique : False},
min_vertex_cover_size : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_components : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_cut_vertices : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},
num_spanning_trees : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},(continues on next page)1072

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)radius : { index : True,
primary_key : False,
sql : INTEGER ,unique : False},vertex_connectivity : { index : True,
primary_key : False,
sql : BOOLEAN ,unique : False}},spectrum : { eigenvalues_sd : { index : True,
primary_key : False,
sql : REAL ,unique : False},
energy : { index : True,
primary_key : False,
sql : REAL ,unique : False},graph_id : { index : False,
primary_key : False,
sql : INTEGER ,unique : False},
max_eigenvalue : { index : True,
primary_key : False,
sql : REAL ,unique : False},
min_eigenvalue : { index : True,
primary_key : False,
sql : REAL ,unique : False},
spectrum : { index : False,
primary_key : False,
sql : TEXT ,unique : False}}}interactive_query(display_cols, **kwds)
Generate an interact shell to query the database.
Warning: This is no longer implemented since the switch to Python3.
This method generates an interact shell that allows the user to manipulate query parameters and see theupdated results.
Todo: This function could use improvement. Add full options of typical GraphQuery (i.e.: have it accept
list input); and update options in interact to make it less annoying to put in operators.
EXAMPLES:
sage: D = GraphDatabase()sage: D.interactive_query(display_cols=[ graph6 , num_vertices ,˓→sequence ], num_edges=5, max_degree=3)
˓→needs sage.symbolic
Traceback (most recent call last):...
NotImplementedError: not available in Jupyter notebook

2.4. Graph databasedegree_#␣1073

Graph Theory, Release 10.4>>> from sage.all import *>>> D = GraphDatabase()>>> D.interactive_query(display_cols=[ graph6 , num_vertices ,˓→sequence ], num_edges=Integer(5), max_degree=Integer(3))˓→# needs sage.symbolic
Traceback (most recent call last):...
NotImplementedError: not available in Jupyter notebook

degree_␣query(query_dict=None, display_cols=None, **kwds)
Create a GraphQuery on this database.
For full class details, type GraphQuery? and press Shift + Enter.
EXAMPLES:
sage: D = GraphDatabase()sage: q = D.query(display_cols=[ graph6 , num_vertices , degree_sequence ],␣
˓→num_edges=[ <= , 5])# needs sage.symbolic
sage: q.show()#␣˓→needs sage.symbolic
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]
CF4[1, 1, 1, 3]
CJ
4[0, 2, 2, 2]
CK4[1, 1, 1, 1]
CL4[1, 1, 2, 2]
CN4[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@s5[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]
DBk5[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](continues on next page)

1074

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

D_K
D K
E???
E??G
E??W
E??w
E?@w
E?Bw
E?CW
E?C_
E?Cg
E?Cw
E?Dg
E?Dw
E?Fg
E?Ko
E?Kw
E?LO
E?LW
E?N?
E?NG
E@FG
E@HW
E@N?
E@Ow
E@Q?
E@QW
E@T_
E@YO
EG?W
EGCW
E_?w
E_Cg
E_Cw
E_Ko
F????
F???G
F???W
F???w
F??@w
F??Bw
F??GW
F??G_
F??Gg
F??Gw
F??Hg
F??Hw
F??Jg
F??Wo
F??Ww
F??XO
F??XW
F??Z?
F??ZG
F??^?
F?CJG
F?CPW

5
5
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7

[1, 1, 1, 1, 2][1, 1, 2, 2, 2][0, 0, 0, 0, 0, 0][0, 0, 0, 0, 1, 1][0, 0, 0, 1, 1, 2][0, 0, 1, 1, 1, 3][0, 1, 1, 1, 1, 4][1, 1, 1, 1, 1, 5][0, 0, 0, 2, 2, 2][0, 0, 1, 1, 1, 1][0, 0, 1, 1, 2, 2][0, 0, 1, 2, 2, 3][0, 1, 1, 1, 2, 3][0, 1, 1, 2, 2, 4][1, 1, 1, 1, 2, 4][0, 0, 2, 2, 2, 2][0, 0, 2, 2, 3, 3][0, 1, 1, 2, 2, 2][0, 1, 1, 2, 3, 3][1, 1, 1, 1, 2, 2][1, 1, 1, 1, 3, 3][1, 1, 1, 2, 2, 3][0, 1, 2, 2, 2, 3][1, 1, 2, 2, 2, 2][0, 1, 2, 2, 2, 3][1, 1, 1, 1, 1, 1][1, 1, 1, 2, 2, 3][0, 2, 2, 2, 2, 2][1, 1, 2, 2, 2, 2][0, 1, 1, 1, 1, 2][0, 1, 1, 2, 2, 2][1, 1, 1, 1, 1, 3][1, 1, 1, 1, 2, 2][1, 1, 1, 2, 2, 3][1, 1, 2, 2, 2, 2][0, 0, 0, 0, 0, 0, 0][0, 0, 0, 0, 0, 1, 1][0, 0, 0, 0, 1, 1, 2][0, 0, 0, 1, 1, 1, 3][0, 0, 1, 1, 1, 1, 4][0, 1, 1, 1, 1, 1, 5][0, 0, 0, 0, 2, 2, 2][0, 0, 0, 1, 1, 1, 1][0, 0, 0, 1, 1, 2, 2][0, 0, 0, 1, 2, 2, 3][0, 0, 1, 1, 1, 2, 3][0, 0, 1, 1, 2, 2, 4][0, 1, 1, 1, 1, 2, 4][0, 0, 0, 2, 2, 2, 2][0, 0, 0, 2, 2, 3, 3][0, 0, 1, 1, 2, 2, 2][0, 0, 1, 1, 2, 3, 3][0, 1, 1, 1, 1, 2, 2][0, 1, 1, 1, 1, 3, 3][1, 1, 1, 1, 1, 2, 3][0, 1, 1, 1, 2, 2, 3][0, 0, 1, 2, 2, 2, 3](continues on next page)2.4. Graph database1075

Graph Theory, Release 10.4

(continued from previous page)

F?CZ?
F?C_w
F?Ca?
F?CaW
F?Ch_
F?CqO
F?LCG
F@??W
F@?GW
FG??w
FG?Gg
FG?Gw
FG?Wo
FK??W
FK?GW
F_?@w
F_?Hg
F_?XO

7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7

[0, 1, 1, 2, 2, 2, 2][0, 0, 1, 2, 2, 2, 3][0, 1, 1, 1, 1, 1, 1][0, 1, 1, 1, 2, 2, 3][0, 0, 2, 2, 2, 2, 2][0, 1, 1, 2, 2, 2, 2][1, 1, 1, 1, 2, 2, 2][0, 0, 1, 1, 1, 1, 2][0, 0, 1, 1, 2, 2, 2][0, 1, 1, 1, 1, 1, 3][0, 1, 1, 1, 1, 2, 2][0, 1, 1, 1, 2, 2, 3][0, 1, 1, 2, 2, 2, 2][1, 1, 1, 1, 1, 1, 2][1, 1, 1, 1, 2, 2, 2][1, 1, 1, 1, 1, 1, 4][1, 1, 1, 1, 1, 2, 3][1, 1, 1, 1, 2, 2, 2]>>> from sage.all import *>>> D = GraphDatabase()>>> q = D.query(display_cols=[ graph6 , num_vertices , degree_sequence ],␣
˓→num_edges=[ <= , Integer(5)])# needs sage.symbolic>>> q.show()#␣˓→needs sage.symbolic
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]
CF4[1, 1, 1, 3]
CJ
4[0, 2, 2, 2]
CK4[1, 1, 1, 1]
CL4[1, 1, 2, 2]
CN4[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@s5[1, 1, 1, 2, 3]
D@{5[1, 1, 2, 2, 4]
DBW
5[0, 2, 2, 2, 2](continues on next page)

1076

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

DB[
DBg
DBk
DIk
DK[
DLo
D_K
D K
E???
E??G
E??W
E??w
E?@w
E?Bw
E?CW
E?C_
E?Cg
E?Cw
E?Dg
E?Dw
E?Fg
E?Ko
E?Kw
E?LO
E?LW
E?N?
E?NG
E@FG
E@HW
E@N?
E@Ow
E@Q?
E@QW
E@T_
E@YO
EG?W
EGCW
E_?w
E_Cg
E_Cw
E_Ko
F????
F???G
F???W
F???w
F??@w
F??Bw
F??GW
F??G_
F??Gg
F??Gw
F??Hg
F??Hw
F??Jg
F??Wo
F??Ww
F??XO

5
5
5
5
5
5
5
5
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7

[0, 2, 2, 3, 3][1, 1, 2, 2, 2][1, 1, 2, 3, 3][1, 2, 2, 2, 3][1, 2, 2, 2, 3][2, 2, 2, 2, 2][1, 1, 1, 1, 2][1, 1, 2, 2, 2][0, 0, 0, 0, 0, 0][0, 0, 0, 0, 1, 1][0, 0, 0, 1, 1, 2][0, 0, 1, 1, 1, 3][0, 1, 1, 1, 1, 4][1, 1, 1, 1, 1, 5][0, 0, 0, 2, 2, 2][0, 0, 1, 1, 1, 1][0, 0, 1, 1, 2, 2][0, 0, 1, 2, 2, 3][0, 1, 1, 1, 2, 3][0, 1, 1, 2, 2, 4][1, 1, 1, 1, 2, 4][0, 0, 2, 2, 2, 2][0, 0, 2, 2, 3, 3][0, 1, 1, 2, 2, 2][0, 1, 1, 2, 3, 3][1, 1, 1, 1, 2, 2][1, 1, 1, 1, 3, 3][1, 1, 1, 2, 2, 3][0, 1, 2, 2, 2, 3][1, 1, 2, 2, 2, 2][0, 1, 2, 2, 2, 3][1, 1, 1, 1, 1, 1][1, 1, 1, 2, 2, 3][0, 2, 2, 2, 2, 2][1, 1, 2, 2, 2, 2][0, 1, 1, 1, 1, 2][0, 1, 1, 2, 2, 2][1, 1, 1, 1, 1, 3][1, 1, 1, 1, 2, 2][1, 1, 1, 2, 2, 3][1, 1, 2, 2, 2, 2][0, 0, 0, 0, 0, 0, 0][0, 0, 0, 0, 0, 1, 1][0, 0, 0, 0, 1, 1, 2][0, 0, 0, 1, 1, 1, 3][0, 0, 1, 1, 1, 1, 4][0, 1, 1, 1, 1, 1, 5][0, 0, 0, 0, 2, 2, 2][0, 0, 0, 1, 1, 1, 1][0, 0, 0, 1, 1, 2, 2][0, 0, 0, 1, 2, 2, 3][0, 0, 1, 1, 1, 2, 3][0, 0, 1, 1, 2, 2, 4][0, 1, 1, 1, 1, 2, 4][0, 0, 0, 2, 2, 2, 2][0, 0, 0, 2, 2, 3, 3][0, 0, 1, 1, 2, 2, 2](continues on next page)2.4. Graph database1077

Graph Theory, Release 10.4

(continued from previous page)

F??XW
F??Z?
F??ZG
F??^?
F?CJG
F?CPW
F?CZ?
F?C_w
F?Ca?
F?CaW
F?Ch_
F?CqO
F?LCG
F@??W
F@?GW
FG??w
FG?Gg
FG?Gw
FG?Wo
FK??W
FK?GW
F_?@w
F_?Hg
F_?XO

7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7

[0, 0, 1, 1, 2, 3, 3][0, 1, 1, 1, 1, 2, 2][0, 1, 1, 1, 1, 3, 3][1, 1, 1, 1, 1, 2, 3][0, 1, 1, 1, 2, 2, 3][0, 0, 1, 2, 2, 2, 3][0, 1, 1, 2, 2, 2, 2][0, 0, 1, 2, 2, 2, 3][0, 1, 1, 1, 1, 1, 1][0, 1, 1, 1, 2, 2, 3][0, 0, 2, 2, 2, 2, 2][0, 1, 1, 2, 2, 2, 2][1, 1, 1, 1, 2, 2, 2][0, 0, 1, 1, 1, 1, 2][0, 0, 1, 1, 2, 2, 2][0, 1, 1, 1, 1, 1, 3][0, 1, 1, 1, 1, 2, 2][0, 1, 1, 1, 2, 2, 3][0, 1, 1, 2, 2, 2, 2][1, 1, 1, 1, 1, 1, 2][1, 1, 1, 1, 2, 2, 2][1, 1, 1, 1, 1, 1, 4][1, 1, 1, 1, 1, 2, 3][1, 1, 1, 1, 2, 2, 2]class sage.graphs.graph_database.GraphQuery(graph_db=None, query_dict=None,
display_cols=None, **kwds)
Bases: GenericGraphQuery
A query for an instance of GraphDatabase.
This class nicely wraps the sage.databases.sql_db.SQLQuery class located in sage.databases.
sql_db to make the query constraints intuitive and with as many pre-definitions as possible. (i.e.: since it has tobe a GraphDatabase, we already know the table structure and types; and since it is immutable, we can treat
these as a guarantee).
Note: sage.databases.sql_db.SQLQuery functions are available for GraphQuery. See sage.
databases.sql_db for more details.
INPUT:• graph_db – GraphDatabase (default: None); instance to apply the query to (If None, then a new
instance is created)• query_dict – dict (default: None); a dictionary specifying the query itself.
Format is:{ table_name :tblname ,display_cols :[ col1 ,col2 ],
expression : [col, operator, value]}. If not None, query_dict will take precedence over all other arguments.
• display_cols – list of strings (default: None); a list of column names (strings) to display in the result
when running or showing a query• kwds – the columns of the database are all keywords. For a database table/column structure dictionary, callgraph_db_info(). Keywords accept both single values and lists of length 2. The list allows the user tospecify an expression other than equality. Valid expressions are strings, and for numeric values (i.e. Reals and

1078

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

Integers) are: ‘=’,’’,’’,’=’,’=’. String values also accept ‘regexp’ as an expression argument. The only keyword
exception to this format is induced_subgraphs, which accepts one of the following options:– [ one_of , String, ..., String] – will search for graphs containing a subgraph isomorphic
to any of the graph6 strings in the list
– [ all_of , String, ..., String] – will search for graphs containing a subgraph isomorphic
to each of the graph6 strings in the list
EXAMPLES:
sage: Q = 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]
BW3[1, 1, 2]
CF
4[1, 1, 1, 3]
CK4[1, 1, 1, 1]
CL4[1, 1, 2, 2]
CN4[1, 2, 2, 3]
D?{5[1, 1, 1, 1, 4]
D@s5[1, 1, 1, 2, 3]
D@{5[1, 1, 2, 2, 4]
DBg
5[1, 1, 2, 2, 2]
DBk5[1, 1, 2, 3, 3]
DIk
5[1, 2, 2, 2, 3]
DK[5[1, 2, 2, 2, 3]
D_K
5[1, 1, 1, 1, 2]
D K
5[1, 1, 2, 2, 2]
E?Bw
6[1, 1, 1, 1, 1, 5]
E?Fg
6[1, 1, 1, 1, 2, 4]
E?N?
6[1, 1, 1, 1, 2, 2]
E?NG
6[1, 1, 1, 1, 3, 3]
E@FG
6[1, 1, 1, 2, 2, 3]
E@N?
6[1, 1, 2, 2, 2, 2]
E@Q?
6[1, 1, 1, 1, 1, 1]
E@QW
6[1, 1, 1, 2, 2, 3]
E@YO
6[1, 1, 2, 2, 2, 2]
E_?w
6[1, 1, 1, 1, 1, 3]
E_Cg
6[1, 1, 1, 1, 2, 2]
E_Cw
6[1, 1, 1, 2, 2, 3]
E_Ko
6[1, 1, 2, 2, 2, 2]
F??^?
7[1, 1, 1, 1, 1, 2, 3]
F?LCG
7[1, 1, 1, 1, 2, 2, 2]
FK??W
7[1, 1, 1, 1, 1, 1, 2]
FK?GW
7[1, 1, 1, 1, 2, 2, 2]
F_?@w
7[1, 1, 1, 1, 1, 1, 4]
F_?Hg
7[1, 1, 1, 1, 1, 2, 3]
F_?XO
7[1, 1, 1, 1, 2, 2, 2]>>> from sage.all import *>>> Q = GraphQuery(display_cols=[ graph6 , num_vertices ,˓→num_edges=[ <= , Integer(5)], min_degree=Integer(1))>>> Q.number_of()degree_sequence ],␣

(continues on next page)2.4. Graph database1079

Graph Theory, Release 10.4

(continued from previous page)35>>> Q.show()
Graph6
Num Vertices
Degree Sequence-----------------------------------------------------------A_
2[1, 1]
BW3[1, 1, 2]
CF
4[1, 1, 1, 3]
CK4[1, 1, 1, 1]
CL4[1, 1, 2, 2]
CN4[1, 2, 2, 3]
D?{5[1, 1, 1, 1, 4]
D@s5[1, 1, 1, 2, 3]
D@{5[1, 1, 2, 2, 4]
DBg
5[1, 1, 2, 2, 2]
DBk5[1, 1, 2, 3, 3]
DIk
5[1, 2, 2, 2, 3]
DK[5[1, 2, 2, 2, 3]
D_K
5[1, 1, 1, 1, 2]
D K
5[1, 1, 2, 2, 2]
E?Bw
6[1, 1, 1, 1, 1, 5]
E?Fg
6[1, 1, 1, 1, 2, 4]
E?N?
6[1, 1, 1, 1, 2, 2]
E?NG
6[1, 1, 1, 1, 3, 3]
E@FG
6[1, 1, 1, 2, 2, 3]
E@N?
6[1, 1, 2, 2, 2, 2]
E@Q?
6[1, 1, 1, 1, 1, 1]
E@QW
6[1, 1, 1, 2, 2, 3]
E@YO
6[1, 1, 2, 2, 2, 2]
E_?w
6[1, 1, 1, 1, 1, 3]
E_Cg
6[1, 1, 1, 1, 2, 2]
E_Cw
6[1, 1, 1, 2, 2, 3]
E_Ko
6[1, 1, 2, 2, 2, 2]
F??^?
7[1, 1, 1, 1, 1, 2, 3]
F?LCG
7[1, 1, 1, 1, 2, 2, 2]
FK??W
7[1, 1, 1, 1, 1, 1, 2]
FK?GW
7[1, 1, 1, 1, 2, 2, 2]
F_?@w
7[1, 1, 1, 1, 1, 1, 4]
F_?Hg
7[1, 1, 1, 1, 1, 2, 3]
F_?XO
7[1, 1, 1, 1, 2, 2, 2]

get_graphs_list()
Return a list of Sage Graph objects that satisfy the query.
EXAMPLES:
sage: Q = GraphQuery(display_cols=[ graph6 ,˓→ ], num_edges=[ <= , 5], min_degree=1)
sage: L = Q.get_graphs_list()
sage: L[0]Graph on 2 vertices
sage: len(L)35num_vertices ,>>> from sage.all import *>>> Q = GraphQuery(display_cols=[ graph6 , num_vertices ,˓→ num_edges=[ <= , Integer(5)], min_degree=Integer(1))

degree_sequence

degree_sequence ],(continues on next page)1080

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> L = Q.get_graphs_list()>>> L[Integer(0)]Graph on 2 vertices>>> len(L)35number_of()
Return the number of graphs in the database that satisfy the query.
EXAMPLES:
sage: Q = GraphQuery(display_cols=[ graph6 ,˓→ ] ,num_edges=[ <= , 5], min_degree=1)
sage: Q.number_of()
35

num_vertices ,>>> from sage.all import *>>> Q = GraphQuery(display_cols=[ graph6 , num_vertices ,˓→,num_edges=[ <= , Integer(5)], min_degree=Integer(1))>>> Q.number_of()
35

degree_sequence

degree_sequence ]␣

query_iterator()
Return 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
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
>>> from sage.all import *>>> Q = GraphQuery(display_cols=[ graph6 ], num_vertices=Integer(7),␣
(continues on next page)2.4. Graph database1081

Graph Theory, Release 10.4

(continued from previous page)

diameter=Integer(5))>>> for g in Q:...
print(g.graph6_string())
F? po
F?gqg
F@?]O
F@OKg
F@R@o
FA_pW
FEOhW
FGC{o
FIAHo
>>> Q = GraphQuery(display_cols=[ graph6 ], num_vertices=Integer(7),␣
˓→diameter=Integer(5))>>> it = iter(Q)>>> 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)
Display the results of a query in table format.
INPUT:• max_field_size – integer (default: 20); width of fields in command prompt version• with_picture – boolean (default: False); whether or not to display results with a picture of thegraph (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
>>> from sage.all import *>>> G = GraphDatabase()>>> Q = GraphQuery(G, display_cols=[ graph6 , num_vertices , aut_grp_size ],␣
˓→num_vertices=Integer(4), aut_grp_size=Integer(4))>>> Q.show()
Graph6
Num Vertices
Aut Grp Size-----------------------------------------------------------C@
4
4
C^
4
4

1082

Chapter 2. Constructors and databases

Graph Theory, Release 10.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]
CF4[1, 1, 1, 3]
CJ
4[0, 2, 2, 2]
CK4[1, 1, 1, 1]
CL4[1, 1, 2, 2]
CN4[1, 2, 2, 3]
C]4[2, 2, 2, 2]
C^4[2, 2, 3, 3]
C~4[3, 3, 3, 3]>>> from sage.all import *>>> R = GraphQuery(G, display_cols=[ graph6 , num_vertices , degree_sequence
˓→ ], num_vertices=Integer(4))>>> 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]
CF4[1, 1, 1, 3]
CJ
4[0, 2, 2, 2]
CK4[1, 1, 1, 1]
CL4[1, 1, 2, 2]
CN4[1, 2, 2, 3]
C]4[2, 2, 2, 2]
C^4[2, 2, 3, 3]
C~4[3, 3, 3, 3]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.
>>> from sage.all import *>>> S = GraphQuery(G, display_cols=[ graph6 , aut_grp_size ], num_
˓→vertices=Integer(4))>>> 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)
Graph6Aut Grp Size---------------------------------------(continues on next page)2.4. Graph database1083

Graph Theory, Release 10.4

(continued from previous page)

C?
C@
CB
CF
CJ
CK
CL
CN
C]
C^
C~

24
4
2
6
6
8
2
2
8
4
24

>>> from sage.all import *>>> S.show(with_picture=False)
Graph6Aut 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
2211112211112222112222112222112222222222222111111222111122211112221111222221122222112222211(continues on next page)1084

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)222221122222222222222>>> from sage.all import *>>> (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
2211112211112222112222112222112222222222222111111222111122211112221111222221122222112222211222221122222222222222sage.graphs.graph_database.data_to_degseq(data, graph6=None)
Convert a database integer data type to a degree sequence list.
INPUT:• data – integer data type (one digit per vertex representing its degree, sorted high to low) to be converted toa degree sequence list
• graph6 – string (default: None); the graph6 identifier is required for all graphs with no edges, so that thecorrect number of zeros is 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]>>> from sage.all import *>>> from sage.graphs.graph_database import data_to_degseq>>> data_to_degseq(Integer(3221))(continues on next page)2.4. Graph database1085

Graph Theory, Release 10.4

(continued from previous page)[1, 2, 2, 3]>>> data_to_degseq(Integer(0),[0, 0, 0, 0, 0]

D?? )sage.graphs.graph_database.degseq_to_data(degree_sequence)
Convert a degree sequence list to a sorted (max-min) integer data type.
The input degree sequence list (of Integers) is converted to a sorted (max-min) integer data type, as used for faster
access in the underlying database.
INPUT:• degree_sequence – list of integers; input degree sequence list
EXAMPLES:
sage: from sage.graphs.graph_database import degseq_to_data
sage: degseq_to_data([2,2,3,1])
3221>>> from sage.all import *>>> from sage.graphs.graph_database import degseq_to_data>>> degseq_to_data([Integer(2),Integer(2),Integer(3),Integer(1)])
3221

sage.graphs.graph_database.graph6_to_plot(graph6)
Return a Graphics object from a graph6 string.
This method constructs a graph from a graph6 string and returns a sage.plot.graphics.Graphics
object with arguments preset for the sage.plot.graphics.Graphics.show() method.
INPUT:• graph6 – a graph6 string
EXAMPLES:
sage: from sage.graphs.graph_database import graph6_to_plot
sage: type(graph6_to_plot( D?? ))˓→needs sage.plot<class sage.plot.graphics.Graphics >>>> from sage.all import *>>> from sage.graphs.graph_database import graph6_to_plot>>> type(graph6_to_plot( D?? ))˓→needs sage.plot<class sage.plot.graphics.Graphics >#␣#␣sage.graphs.graph_database.graph_db_info(tablename=None)
Return a dictionary of allowed table and column names.
INPUT:• tablename – restricts the output to a single table
EXAMPLES:
sage: sorted(graph_db_info())[ aut_grp , degrees , graph_data ,1086

misc ,

spectrum ]Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> 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 ]>>> from sage.all import *>>> graph_db_info(tablename= graph_data )[ complement_graph6 ,eulerian ,graph6 ,lovasz_number ,num_cycles ,num_edges ,num_hamiltonian_cycles ,num_vertices ,perfect ,planar ]sage.graphs.graph_database.subgraphs_to_query(subgraphs, db)
Return a GraphQuery object required for the induced_subgraphs parameter.
This method constructs and returns a GraphQuery object respecting the special input required for the induced_subgraphs parameter.
INPUT:• subgraphs – list of strings; the list should be of one of the following two formats:– [ one_of , String, ..., String] – will search for graphs containing a subgraph isomorphic
to any of the graph6 strings in the list
– [ all_of , String, ..., String] – will search for graphs containing a subgraph isomorphic
to each of the graph6 strings in the list
• db – a GraphDatabase
Note: This is a helper method called by the GraphQuery constructor to handle this special format. This methodshould not be used on its own because it doesn’t set any display columns in the query string, causing a failure tofetch 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)(continues on next page)2.4. Graph database1087

Graph Theory, Release 10.4

(continued from previous page)

sage: q.get_query_string()
SELECT ,,,,, FROM misc WHERE ( ( misc.induced_subgraphs regexp ? ) AND (misc.induced_subgraphs regexp ? ) ) AND ( misc.induced_subgraphs regexp ? )>>> from sage.all import *>>> from sage.graphs.graph_database import subgraphs_to_query>>> gd = GraphDatabase()>>> q = subgraphs_to_query([ all_of , A? , B? , C? ], gd)>>> 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 theseparameters, when one exists.
Using Andries Brouwer’s database of strongly regular graphs, it can also return non-existence results. Note that someconstructions are missing, and that some strongly regular graphs that exist in the database cannot be automatically built
by Sage. Help us if you know any. An outline of the implementation can be found in [CP2016].
Note: Any missing/incorrect information in the database must be reported to Andries E. Brouwer directly, in order tohave a unique and updated source of information.
REFERENCES:[BL1984]

2.5.1 Functions
sage.graphs.strongly_regular_db.SRG_100_44_18_20()
Return a (100, 44, 18, 20)-strongly regular graph.
This graph is built as a Cayley graph, using the construction for Δ1 with group 𝐻3 presented in Table 8.1 of[JK2003]
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_100_44_18_20
sage: G = SRG_100_44_18_20()# long time
˓→needs sage.groups
sage: G.is_strongly_regular(parameters=True)# long time
˓→needs sage.groups(100, 44, 18, 20)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_100_44_18_20>>> G = SRG_100_44_18_20()# long time
˓→needs sage.groups>>> G.is_strongly_regular(parameters=True)# long time

#␣
#␣

#␣
#␣
(continues on next page)1088

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)needs sage.groups(100, 44, 18, 20)˓→sage.graphs.strongly_regular_db.SRG_100_45_20_20()
Return a (100, 45, 20, 20)-strongly regular graph.
This graph is built as a Cayley graph, using the construction for Γ3 with group 𝐻3 presented in Table 8.1 of[JK2003].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_100_45_20_20
sage: G = SRG_100_45_20_20()# long time
˓→needs sage.groups
sage: G.is_strongly_regular(parameters=True)# long time
˓→needs sage.groups(100, 45, 20, 20)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_100_45_20_20>>> G = SRG_100_45_20_20()# long time
˓→needs sage.groups>>> G.is_strongly_regular(parameters=True)# long time
˓→needs sage.groups(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 [GS1970], and [Coo2006].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_105_32_4_12
sage: G = SRG_105_32_4_12(); G˓→needs sage.rings.finite_rings
Aut L(3,4) on flags: Graph on 105 vertices
sage: G.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(105, 32, 4, 12)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_105_32_4_12>>> G = SRG_105_32_4_12(); G˓→needs sage.rings.finite_rings
Aut L(3,4) on flags: Graph on 105 vertices>>> G.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(105, 32, 4, 12)

#␣

#␣

#␣

#␣

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:

2.5. Database of strongly regular graphs1089

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_120_63_30_36>>> G = SRG_120_63_30_36()>>> 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_package_design
sage: G.is_strongly_regular(parameters=True)# optional - gap_package_design(120, 77, 52, 44)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_120_77_52_44>>> G = SRG_120_77_52_44()# optional - gap_package_design>>> G.is_strongly_regular(parameters=True)# optional - gap_package_design(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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_126_25_8_4>>> G = SRG_126_25_8_4()>>> 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 graphThis graph is a subgraph of SRG_175_72_20_36(). This construction, due to Goethals, is given in §10B.(vii)of [BL1984].
EXAMPLES:

1090

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_126_50_13_24>>> G = SRG_126_50_13_24(); G
Goethals graph: Graph on 126 vertices>>> 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 adjacentif their symmetric difference has weight 12 (cf [BE1992]).
See also:
strongly_regular_from_two_weight_code() – build a strongly regular graph from a two-weightcode.
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_1288_792_476_504
sage: G = SRG_1288_792_476_504()# long time
˓→needs sage.rings.finite_rings
sage: G.is_strongly_regular(parameters=True)# long time
˓→needs sage.rings.finite_rings(1288, 792, 476, 504)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_1288_792_476_504>>> G = SRG_1288_792_476_504()# long time
˓→needs sage.rings.finite_rings>>> G.is_strongly_regular(parameters=True)# long time
˓→needs sage.rings.finite_rings(1288, 792, 476, 504)

#␣
#␣

#␣
#␣

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()
˓→needs sage.libs.gap
sage: G.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(144, 39, 6, 12)2.5. Database of strongly regular graphs

#␣
#␣

1091

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_144_39_6_12>>> G = SRG_144_39_6_12()
˓→needs sage.libs.gap>>> G.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(144, 39, 6, 12)#␣#␣

sage.graphs.strongly_regular_db.SRG_175_72_20_36()
Return a (175, 72, 20, 36)-strongly regular graphThis graph is obtained from the line graph of HoffmanSingletonGraph(). Setting two vertices to be adjacentif their distance in the line graph is exactly 2 yields the graph. For more information, see 10.B.(iv) in [BL1984]
and https://www.win.tue.nl/ aeb/graphs/McL.html.
EXAMPLES:
sage: 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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_175_72_20_36>>> G = SRG_175_72_20_36()>>> 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.
To build this graph, we first build a 2 − (22, 7, 16) design, by removing one point from the WittDesign() on
23 points. We then build the intersection graph of blocks with intersection size 3. Known as S.7 in [Hub1975].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_176_105_68_54
sage: G = SRG_176_105_68_54()# optional - gap_package_design
sage: G.is_strongly_regular(parameters=True)# optional - gap_package_design(176, 105, 68, 54)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_176_105_68_54>>> G = SRG_176_105_68_54()# optional - gap_package_design>>> G.is_strongly_regular(parameters=True)# optional - gap_package_design(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 [Bro1982], it is explained that there exists aninvolution 𝜎 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:

1092

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: from sage.graphs.strongly_regular_db import SRG_176_49_12_14
sage: G = SRG_176_49_12_14()# long time, optional - gap_
˓→package_design
sage: G.is_strongly_regular(parameters=True)# long time, optional - gap_
˓→package_design(176, 49, 12, 14)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_176_49_12_14>>> G = SRG_176_49_12_14()# long time, optional - gap_package_
˓→design>>> G.is_strongly_regular(parameters=True)# long time, optional - gap_package_
˓→design(176, 49, 12, 14)

sage.graphs.strongly_regular_db.SRG_176_90_38_54()
Return a (176, 90, 38, 54)-strongly regular graphThis graph is obtained from SRG_175_72_20_36() by attaching a isolated vertex and doing Seidel switching with respect to disjoint union of 18 maximum cliques, following a construction by W.Haemers given in
Sect.10.B.(vi) of [BL1984].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_176_90_38_54
sage: G = SRG_176_90_38_54(); Ga Seidel switching of Distance graph for distance 2 in : Graph on 176 vertices
sage: G.is_strongly_regular(parameters=True)(176, 90, 38, 54)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_176_90_38_54>>> G = SRG_176_90_38_54(); Ga Seidel switching of Distance graph for distance 2 in : Graph on 176 vertices>>> 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 [IS2006].
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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_196_91_42_42>>> G = SRG_196_91_42_42()>>> G.is_strongly_regular(parameters=True)(196, 91, 42, 42)

sage.graphs.strongly_regular_db.SRG_210_99_48_45()
Return a strongly regular graph with parameters (210, 99, 48, 45)
2.5. Database of strongly regular graphs1093

Graph Theory, Release 10.4

This graph is from Example 4.2 in [KPRWZ2010]. One considers the action of the symmetric group 𝑆7
on the 210 digraphs isomorphic to the disjoint union of 𝐾1 and the circulant 6-vertex digraph digraphs.
Circulant(6,[1,4]). It has 16 orbitals; the package [FK1991] found a megring of them, explicitly describedin [KPRWZ2010], 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()
˓→needs sage.libs.gap
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(210, 99, 48, 45)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_210_99_48_45>>> g = SRG_210_99_48_45()
˓→needs sage.libs.gap>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(210, 99, 48, 45)

#␣
#␣

#␣
#␣

sage.graphs.strongly_regular_db.SRG_220_84_38_28()
Return a (220, 84, 38, 28)-strongly regular graph.
This graph is obtained from the intersection_graph() of a BIBD_45_9_8(). This construction appears
in VII.11.2 from [DesignHandbook]
EXAMPLES:
sage: 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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_220_84_38_28>>> g = SRG_220_84_38_28()>>> 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[GS1975].
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()
˓→needs sage.modules sage.rings.finite_rings
sage: G.is_strongly_regular(parameters=True)#␣#␣(continues on next page)

1094

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules sage.rings.finite_rings(243, 110, 37, 60)
˓→>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_243_110_37_60>>> G = SRG_243_110_37_60()
˓→needs sage.modules sage.rings.finite_rings>>> G.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(243, 110, 37, 60)#␣#␣

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 thenbuild the intersection graph of blocks with intersection size 3. Known as S.6 in [Hub1975].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_253_140_87_65
sage: G = SRG_253_140_87_65()# optional - gap_package_design
sage: G.is_strongly_regular(parameters=True)# optional - gap_package_design(253, 140, 87, 65)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_253_140_87_65>>> G = SRG_253_140_87_65()# optional - gap_package_design>>> G.is_strongly_regular(parameters=True)# optional - gap_package_design(253, 140, 87, 65)

sage.graphs.strongly_regular_db.SRG_276_140_58_84()
Return a (276, 140, 58, 84)-strongly regular graph.
The graph is built from McLaughlinGraph(), with an added isolated vertex. We then perform a seidel_switching() on a set of 28 disjoint 5-cliques, which exist by cf. [HT1996].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_276_140_58_84
sage: g = SRG_276_140_58_84()# long time, optional - gap_
˓→package_design
sage: g.is_strongly_regular(parameters=True)# long time, optional - gap_
˓→package_design(276, 140, 58, 84)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_276_140_58_84>>> g = SRG_276_140_58_84()# long time, optional - gap_package_
˓→design>>> g.is_strongly_regular(parameters=True)# long time, optional - gap_package_
˓→design(276, 140, 58, 84)

sage.graphs.strongly_regular_db.SRG_280_117_44_52()
Return a strongly regular graph with parameters (280, 117, 44, 52).
This graph is built according to a very pretty construction of Mathon and Rosa [MR1985]:
2.5. Database of strongly regular graphs

1095Graph Theory, Release 10.4

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 theirrespective 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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_280_117_44_52>>> g=SRG_280_117_44_52()>>> g.is_strongly_regular(parameters=True)(280, 117, 44, 52)

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 - internet
sage: g.is_strongly_regular(parameters=True)# long time, optional - internet(280, 135, 70, 60)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_280_135_70_60>>> g=SRG_280_135_70_60()# long time, optional - internet>>> g.is_strongly_regular(parameters=True)# long time, optional - internet(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 isisomorphic to the subgraph of the from Suzuki Graph induced on the neighbors of a vertex. Known as S.14 in[Hub1975].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_416_100_36_20
sage: g = SRG_416_100_36_20()# long time, optional - internet,␣
˓→needs sage.libs.gap
sage: g.is_strongly_regular(parameters=True)# long time, optional - internet,␣
˓→needs sage.libs.gap(416, 100, 36, 20)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_416_100_36_20>>> g = SRG_416_100_36_20()# long time, optional - internet,␣
˓→needs sage.libs.gap>>> g.is_strongly_regular(parameters=True)# long time, optional - internet,␣
(continues on next page)

1096

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)needs sage.libs.gap(416, 100, 36, 20)˓→sage.graphs.strongly_regular_db.SRG_560_208_72_80()
Return a (560, 208, 72, 80)-strongly regular graphThis graph is obtained as the union of 4 orbits of sets of cardinality 2 (among the 13 that exist) of the group 𝑆𝑧(8).
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_560_208_72_80
sage: g = SRG_560_208_72_80()# not tested (~2s)˓→needs sage.libs.gap
sage: g.is_strongly_regular(parameters=True)# not tested (~2s)˓→needs sage.libs.gap(560, 208, 72, 80)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_560_208_72_80>>> g = SRG_560_208_72_80()# not tested (~2s)˓→needs sage.libs.gap>>> g.is_strongly_regular(parameters=True)# not tested (~2s)˓→needs sage.libs.gap(560, 208, 72, 80)

#␣
#␣

#␣
#␣

sage.graphs.strongly_regular_db.SRG_630_85_20_10()
Return a (630, 85, 20, 10)-strongly regular graphThis graph is the line graph of 𝑝𝑔(5, 18, 2); its point graph is SRG_175_72_20_36(). One selects a subset of
630 maximum cliques in the latter following a construction by W.Haemers given in Sect.10.B.(v) of [BL1984].
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import SRG_630_85_20_10
sage: G = SRG_630_85_20_10()# long time
˓→needs sage.groups
sage: G.is_strongly_regular(parameters=True)# long time
˓→needs sage.groups(630, 85, 20, 10)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_630_85_20_10>>> G = SRG_630_85_20_10()# long time
˓→needs sage.groups>>> G.is_strongly_regular(parameters=True)# long time
˓→needs sage.groups(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 RSHCDThis construction appears in 8.D of [BL1984].
For more information, see regular_symmetric_hadamard_matrix_with_constant_diagonal().
INPUT:• v, k, l, mu – integers

2.5. Database of strongly regular graphs

1097Graph Theory, Release 10.4

• 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 beuseless (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)
˓→needs sage.combinat sage.modules
False
sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True)
˓→needs sage.combinat sage.modules
True
sage: SRG_from_RSHCD(144, 65, 28, 30)
˓→needs sage.combinat sage.modules
Graph on 144 vertices>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import SRG_from_RSHCD>>> SRG_from_RSHCD(Integer(784), Integer(0), Integer(14), Integer(38),␣
˓→existence=True)# needs sage.combinat sage.modules
False>>> SRG_from_RSHCD(Integer(784), Integer(377), Integer(180), Integer(182),␣
˓→existence=True)# needs sage.combinat sage.modules
True>>> SRG_from_RSHCD(Integer(144), Integer(65), Integer(28), Integer(30))˓→# needs sage.combinat sage.modules
Graph on 144 vertices

#␣

#␣

#␣

␣

an example with vertex-transitive automorphism group, found during the implementation of the case 𝑣 = 324
sage: # long time, needs sage.combinat sage.modules
sage: G = SRG_from_RSHCD(324,152,70,72)
sage: a = G.automorphism_group()
sage: a.order()2592
sage: len(a.orbits())
1>>> from sage.all import *>>> # long time, needs sage.combinat sage.modules>>> G = SRG_from_RSHCD(Integer(324),Integer(152),Integer(70),Integer(72))>>> a = G.automorphism_group()>>> a.order()2592>>> len(a.orbits())
1

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

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• 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) is True#␣˓→needs sage.libs.pari....:for x in small_feasible)
True>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import apparently_feasible_parameters>>> small_feasible = apparently_feasible_parameters(Integer(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)}>>> all(graphs.strongly_regular_graph(*x,existence=True) is True#␣˓→needs sage.libs.pari...
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) is True
˓→needs sage.libs.pari....:for x in small_feasible)
False>>> from sage.all import *>>> small_feasible = apparently_feasible_parameters(Integer(60))>>> all(graphs.strongly_regular_graph(*x,existence=True) is True
˓→needs sage.libs.pari...
for x in small_feasible)#␣#␣(continues on next page)2.5. Database of strongly regular graphs1099

Graph Theory, Release 10.4

(continued from previous page)

False

sage.graphs.strongly_regular_db.eigenmatrix(v, k, l, mu)
Return the first eigenmatrix of a (𝑣, 𝑘, 𝑙, 𝑚𝑢)-strongly regular graph.
The adjacency matrix 𝐴 of an s.r.g. commutes with the adjacency matrix 𝐴′ = 𝐽 − 𝐴 − 𝐼 of its complement (here𝐽 is all-1 matrix, and 𝐼 the identity matrix). Thus, they can be simultaneously diagonalized and so 𝐴 and 𝐴′ shareeigenspaces.
The eigenvalues of 𝐽 are 𝑣 with multiplicity 1, and 0 with multiplicity 𝑣−1. Thus the eigenvalue of 𝐴′ corresponding
to the 1-dimension 𝑘-eigenspace of 𝐴 is 𝑣−𝑘−1. Respectively, the eigenvalues of 𝐴′ corresponding to 𝑡-eigenspaceof 𝐴, with 𝑡 unequal to 𝑘, equals −𝑡 − 1. The 1st eigenmatrix 𝑃 of the C-algebra 𝐶[𝐴] generated by 𝐴 encodes thiseigenvalue information in its three columns; the 2nd (resp. 3rd) column contains distinct eigenvalues of 𝐴 (resp. of𝐴′ ), and the 1st column contains the corresponding eigenvalues of 𝐼. The matrix 𝑣𝑃 −1 is called the 2nd eigenvalue
matrix of 𝐶[𝐴].
The most interesting feature of 𝑣𝑃 −1 is that it is the 1st eigenmatrix of the dual of 𝐶[𝐴] if the dual is generated
by the adjacency matrix of a strongly regular graph. See [BH2012] and [BI1984] for details.
If the set of parameters is not feasible, or if they correspond to a conference graph, the function returns None.
Its output is stable, assuming that the eigenvalues r,s used satisfy r>s; this holds for the current implementation of
eigenvalues().
INPUT:• v, k, l, mu – integers
EXAMPLES:Petersen’s graph’s C-algebra does not have a dual coming from an s.r.g.:
sage: from sage.graphs.strongly_regular_db import eigenmatrix
sage: P = eigenmatrix(10,3,0,1); P˓→needs sage.modules[ 1 3 6]
[ 1 1 -2]
[ 1 -2 1]
sage: 10*P^-1
˓→needs sage.modules
[
1
5
4]
[
1 5/3 -8/3][
1 -5/3 2/3]>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import eigenmatrix>>> P = eigenmatrix(Integer(10),Integer(3),Integer(0),Integer(1)); P˓→# needs sage.modules[ 1 3 6]
[ 1 1 -2]
[ 1 -2 1]>>> Integer(10)*P**-Integer(1)˓→# needs sage.modules
[
1
5
4]
[
1 5/3 -8/3][
1 -5/3 2/3]

#␣

#␣

␣

␣

The line graph of 𝐾3,3 is self-dual:

1100

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: P = eigenmatrix(9,4,1,2); P˓→needs sage.modules[ 1 4 4]
[ 1 1 -2]
[ 1 -2 1]
sage: 9*P^-1
˓→needs sage.modules[ 1 4 4]
[ 1 1 -2]
[ 1 -2 1]#␣#␣>>> from sage.all import *>>> P = eigenmatrix(Integer(9),Integer(4),Integer(1),Integer(2)); P˓→# needs sage.modules[ 1 4 4]
[ 1 1 -2]
[ 1 -2 1]>>> Integer(9)*P**-Integer(1)˓→# needs sage.modules[ 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: # needs sage.modules
sage: graphs.strongly_regular_graph(243,220,199,200, existence=True)
˓→needs sage.combinat
Truesage: graphs.strongly_regular_graph(243,110,37,60, existence=True)
˓→needs sage.combinat
Truesage: P = eigenmatrix(243,220,199,200); P[ 1 220 22]
[ 1
4 -5]
[ 1 -54]sage: 243*P^-1[ 1 110 132]
[ 1
2 -3]
[ 1 -25 24]
sage: 243*P^-1==eigenmatrix(243,110,37,60)
True

#␣

#␣

>>> from sage.all import *>>> # needs sage.modules>>> graphs.strongly_regular_graph(Integer(243),Integer(220),Integer(199),
˓→Integer(200), existence=True)# needs sage.combinat
True>>> graphs.strongly_regular_graph(Integer(243),Integer(110),Integer(37),
˓→Integer(60), existence=True)# needs sage.combinat
True>>> P = eigenmatrix(Integer(243),Integer(220),Integer(199),Integer(200)); P[ 1 220 22]
[ 1
4 -5]
[ 1 -54]>>> Integer(243)*P**-Integer(1)[ 1 110 132]
(continues on next page)2.5. Database of strongly regular graphs1101

Graph Theory, Release 10.4

(continued from previous page)

[ 1
2 -3]
[ 1 -25 24]>>> Integer(243)*P**-Integer(1)==eigenmatrix(Integer(243),Integer(110),
˓→Integer(37),Integer(60))
Truesage.graphs.strongly_regular_db.is_GQqmqp(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: # needs sage.libs.pari
sage: from sage.graphs.strongly_regular_db import is_GQqmqp
sage: t = is_GQqmqp(27,10,1,5); t(<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)>>> from sage.all import *>>> # needs sage.libs.pari>>> from sage.graphs.strongly_regular_db import is_GQqmqp>>> t = is_GQqmqp(Integer(27),Integer(10),Integer(1),Integer(5)); t(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 3, False)>>> g = t[Integer(0)](*t[Integer(1):]); g
AS(3); GQ(2, 4): Graph on 27 vertices>>> t = is_GQqmqp(Integer(45),Integer(12),Integer(3),Integer(3)); t(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 3, True)>>> g = t[Integer(0)](*t[Integer(1):]); g
AS(3)*; GQ(4, 2): Graph on 45 vertices>>> g.is_strongly_regular(parameters=True)(45, 12, 3, 3)>>> t = is_GQqmqp(Integer(16),Integer(6),Integer(2),Integer(2)); t(continues on next page)

1102

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)(<function T2starGeneralizedQuadrangleGraph at ...>, 2, True)>>> g = t[Integer(0)](*t[Integer(1):]); g
T2*(O,2)*; GQ(3, 1): Graph on 16 vertices>>> g.is_strongly_regular(parameters=True)(16, 6, 2, 2)>>> t = is_GQqmqp(Integer(64),Integer(18),Integer(2),Integer(6)); t(<function T2starGeneralizedQuadrangleGraph at ...>, 4, False)>>> g = t[Integer(0)](*t[Integer(1):]); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 18, 2, 6)

sage.graphs.strongly_regular_db.is_NO_F2(k, l, mu)
Test whether some NO^e,perp(2n,2) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For
more
information,seesage.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
˓→needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 2,
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pariNO^-(4, 2): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(10, 3, 0, 1)#␣- )>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_NO_F2>>> t = is_NO_F2(Integer(10), Integer(3), Integer(0), Integer(1)); t˓→# needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 2, - )>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.libs.pariNO^-(4, 2): Graph on 10 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(10, 3, 0, 1)

#␣

#␣

␣

␣

#␣

sage.graphs.strongly_regular_db.is_NO_F3(k, l, mu)
Test whether some NO^e,perp(2n,3) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For
more
information,seesage.graphs.graph_generators.GraphGenerators.
NonisotropicOrthogonalPolarGraph().
INPUT:

2.5. Database of strongly regular graphs1103

Graph Theory, Release 10.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_NO_F3
sage: t = is_NO_F3(15, 6, 1, 3); t˓→needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 3,
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pariNO^-(4, 3): Graph on 15 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(15, 6, 1, 3)

#␣
- )
#␣

#␣

>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_NO_F3>>> t = is_NO_F3(Integer(15), Integer(6), Integer(1), Integer(3)); t˓→# needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 3, - )>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.libs.pariNO^-(4, 3): Graph on 15 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(15, 6, 1, 3)

␣

␣

#␣

sage.graphs.strongly_regular_db.is_NOodd(k, l, mu)
Test whether some NO^e(2n+1,q) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
Here 𝑞 > 2, for in the case 𝑞 = 2 this graph is complete. For more information, see sage.graphs.
graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph() and Sect.
7.C of [BL1984].
INPUT:• v, k, l, mu – integers
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import is_NOodd
sage: t = is_NOodd(120, 51, 18, 24); t˓→needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4,
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pariNO^-(5, 4): Graph on 120 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(120, 51, 18, 24)

1104

#␣
- )
#␣

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_NOodd>>> t = is_NOodd(Integer(120), Integer(51), Integer(18), Integer(24)); t˓→# needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, - )>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.libs.pariNO^-(5, 4): Graph on 120 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(120, 51, 18, 24)

␣

␣

#␣

sage.graphs.strongly_regular_db.is_NOperp_F5(k, l, mu)
Test whether some NO^e,perp(2n+1,5) graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For
more
information,seesage.graphs.graph_generators.GraphGenerators.
NonisotropicOrthogonalPolarGraph() and Sect. 7.D of [BL1984].
INPUT:• v, k, l, mu – integers
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import is_NOperp_F5
sage: t = is_NOperp_F5(10, 3, 0, 1); t
˓→needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 3, 5, - , 1)
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pariNO^-,perp(3, 5): Graph on 10 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(10, 3, 0, 1)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_NOperp_F5>>> t = is_NOperp_F5(Integer(10), Integer(3), Integer(0), Integer(1)); t˓→# needs sage.libs.pari(<function NonisotropicOrthogonalPolarGraph at ...>, 3, 5, - , 1)>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.libs.pariNO^-,perp(3, 5): Graph on 10 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(10, 3, 0, 1)

#␣

#␣

#␣

␣

␣

#␣

sage.graphs.strongly_regular_db.is_NU(k, l, mu)
Test whether some NU(n,q)-graph, is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
Note that n>2; for n=2 there is no s.r.g. For more information, see sage.graphs.graph_generators.
GraphGenerators.NonisotropicUnitaryPolarGraph() and series C14 in [Hub1975].
INPUT:• v, k, l, mu – integers
2.5. Database of strongly regular graphs1105

Graph Theory, Release 10.4

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˓→needs sage.libs.pari(<function NonisotropicUnitaryPolarGraph at ...>, 4, 2)
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pari
NU(4, 2): Graph on 40 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(40, 27, 18, 18)

#␣

#␣

#␣

>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_NU>>> t = is_NU(Integer(40), Integer(27), Integer(18), Integer(18)); t˓→# needs sage.libs.pari(<function NonisotropicUnitaryPolarGraph at ...>, 4, 2)>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.libs.pari
NU(4, 2): Graph on 40 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(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˓→needs sage.combinat sage.modules[<built-in function SRG_from_RSHCD>, 64, 27, 10, 12]
sage: g = t[0](*t[1:]); g˓→needs sage.combinat sage.modules
Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.combinat sage.modules(64, 27, 10, 12)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_RSHCD>>> t = is_RSHCD(Integer(64),Integer(27),Integer(10),Integer(12)); t˓→# needs sage.combinat sage.modules[<built-in function SRG_from_RSHCD>, 64, 27, 10, 12]

#␣

#␣

#␣

␣

(continues on next page)

1106

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.combinat sage.modules
Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.combinat sage.modules(64, 27, 10, 12)␣#␣

sage.graphs.strongly_regular_db.is_affine_polar(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˓→needs sage.rings.finite_rings(..., 4, 3)
sage: g = t[0](*t[1:]); g˓→needs sage.rings.finite_rings
Affine Polar Graph VO^+(4,3): Graph on 81 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(81, 32, 13, 12)

#␣

#␣

#␣

sage: t = is_affine_polar(5,5,5,5); t>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_affine_polar>>> t = is_affine_polar(Integer(81),Integer(32),Integer(13),Integer(12)); t˓→# needs sage.rings.finite_rings(..., 4, 3)>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.rings.finite_rings
Affine Polar Graph VO^+(4,3): Graph on 81 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(81, 32, 13, 12)

␣

␣

#␣

>>> t = is_affine_polar(Integer(5),Integer(5),Integer(5),Integer(5)); t

sage.graphs.strongly_regular_db.is_complete_multipartite(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:2.5. Database of strongly regular graphs

1107

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_complete_multipartite>>> t = is_complete_multipartite(Integer(12),Integer(8),Integer(4),Integer(8)); t(<cyfunction is_complete_multipartite.<locals>.CompleteMultipartiteSRG at ...>,
3,
4)>>> g = t[Integer(0)](*t[Integer(1):]); g
Multipartite Graph with set sizes [4, 4, 4]: Graph on 12 vertices>>> g.is_strongly_regular(parameters=True)(12, 8, 4, 8)

sage.graphs.strongly_regular_db.is_cossidente_penttila(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#␣˓→needs sage.libs.pari(<function CossidentePenttilaGraph at ...>, 5)
sage: g = t[0](*t[1:]); g# optional - gap_package_design,␣
˓→needs sage.libs.pari
CossidentePenttila(5): Graph on 378 vertices
sage: g.is_strongly_regular(parameters=True)# optional - gap_package_design,␣
˓→needs sage.libs.pari(378, 52, 1, 8)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_cossidente_penttila>>> t = is_cossidente_penttila(Integer(378), Integer(52), Integer(1),␣
˓→Integer(8)); t# needs sage.libs.pari(<function CossidentePenttilaGraph at ...>, 5)>>> g = t[Integer(0)](*t[Integer(1):]); g# optional - gap_
˓→package_design, needs sage.libs.pari
CossidentePenttila(5): Graph on 378 vertices(continues on next page)

1108

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(378, 52, 1, 8)# optional - gap_package_design,␣

sage.graphs.strongly_regular_db.is_goethals_seidel(k, l, mu)
Test whether some GoethalsSeidelGraph() graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
INPUT:• v, k, l, mu – integers
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: from sage.graphs.strongly_regular_db import is_goethals_seidel
sage: t = is_goethals_seidel(28, 15, 6, 10); t
˓→needs sage.combinat sage.modules[<function GoethalsSeidelGraph at ...>, 3, 3]
sage: g = t[0](*t[1:]); g˓→needs sage.combinat sage.modules
Graph on 28 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.combinat sage.modules(28, 15, 6, 10)

#␣

#␣

#␣

sage: t = is_goethals_seidel(256, 135, 70, 72); t˓→needs sage.combinat sage.modules[<function GoethalsSeidelGraph at ...>, 2, 15]
sage: g = t[0](*t[1:]); g˓→needs sage.combinat sage.modules
Graph on 256 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.combinat sage.modules(256, 135, 70, 72)#␣sage: t = is_goethals_seidel(5,5,5,5); t˓→needs sage.combinat sage.modules

#␣

#␣

#␣

>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_goethals_seidel>>> t = is_goethals_seidel(Integer(28), Integer(15), Integer(6), Integer(10)); t ␣˓→# needs sage.combinat sage.modules[<function GoethalsSeidelGraph at ...>, 3, 3]>>> g = t[Integer(0)](*t[Integer(1):]); g␣˓→# needs sage.combinat sage.modules
Graph on 28 vertices>>> g.is_strongly_regular(parameters=True)#␣˓→needs sage.combinat sage.modules(28, 15, 6, 10)>>> t = is_goethals_seidel(Integer(256), Integer(135), Integer(70), Integer(72));␣
˓→t# needs sage.combinat sage.modules[<function GoethalsSeidelGraph at ...>, 2, 15]>>> g = t[Integer(0)](*t[Integer(1):]); g␣˓→# needs sage.combinat sage.modules(continues on next page)2.5. Database of strongly regular graphs1109

Graph Theory, Release 10.4

(continued from previous page)

Graph on 256 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.combinat sage.modules(256, 135, 70, 72)#␣>>> t = is_goethals_seidel(Integer(5),Integer(5),Integer(5),Integer(5)); t˓→# needs sage.combinat sage.modules␣sage.graphs.strongly_regular_db.is_haemers(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˓→needs sage.libs.pari(<function HaemersGraph at ...>, 4)
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pari
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(96, 19, 2, 4)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_haemers>>> t = is_haemers(Integer(96), Integer(19), Integer(2), Integer(4)); t˓→# needs sage.libs.pari(<function HaemersGraph at ...>, 4)>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.libs.pari
Haemers(4): Graph on 96 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(96, 19, 2, 4)

#␣

#␣

#␣

␣

␣

#␣

sage.graphs.strongly_regular_db.is_johnson(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:

1110

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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)
sage: t = is_johnson(5,5,5,5); t>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_johnson>>> t = is_johnson(Integer(10),Integer(6),Integer(3),Integer(4)); t(..., 5)>>> g = t[Integer(0)](*t[Integer(1):]); g
Johnson graph with parameters 5,2: Graph on 10 vertices>>> g.is_strongly_regular(parameters=True)(10, 6, 3, 4)>>> t = is_johnson(Integer(5),Integer(5),Integer(5),Integer(5)); t

sage.graphs.strongly_regular_db.is_mathon_PC_srg(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 thisconstruction. A full implementation should rely on a database of conference matrices (or, equivalently, on a databaseof 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
˓→needs sage.libs.pari(..., 1)
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pari
Mathon s PC SRG on 45 vertices: Graph on 45 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(45, 22, 10, 11)

#␣

#␣

#␣

>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_mathon_PC_srg>>> t = is_mathon_PC_srg(Integer(45),Integer(22),Integer(10),Integer(11)); t˓→# needs sage.libs.pari(..., 1)␣(continues on next page)2.5. Database of strongly regular graphs1111

Graph Theory, Release 10.4

(continued from previous page)>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.libs.pari
Mathon s PC SRG on 45 vertices: Graph on 45 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(45, 22, 10, 11)␣#␣

sage.graphs.strongly_regular_db.is_muzychuk_S6(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: # needs sage.libs.pari
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>>> from sage.all import *>>> # needs sage.libs.pari>>> from sage.graphs.strongly_regular_db import is_muzychuk_S6>>> t = is_muzychuk_S6(Integer(378), Integer(116), Integer(34), Integer(36))>>> G = t[Integer(0)](*t[Integer(1):]); G
Muzychuk S6 graph with parameters (3,3): Graph on 378 vertices>>> G.is_strongly_regular(parameters=True)(378, 116, 34, 36)>>> t = is_muzychuk_S6(Integer(5), Integer(5), Integer(5), Integer(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:• 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)
˓→needs sage.combinat sage.modules
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices

1112

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(196), Integer(60), Integer(14),␣
˓→Integer(20))# needs sage.combinat sage.modules
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices

sage.graphs.strongly_regular_db.is_orthogonal_array_block_graph(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 parametersof an 𝑂𝐴(𝑚, 𝑛)-graph whenever there exists a skew-Hadamard matrix of order 𝑛 + 1, and 𝑚 = (𝑛 + 1)/2 or𝑚 = (𝑛 − 1)/2. The construction in the former case is due to Goethals-Seidel [BL1984], and in the latter casedue to Pasechnik [Pas1992].
INPUT:• v, k, l, mu – integers
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: # needs sage.combinat sage.modules
sage: from sage.graphs.strongly_regular_db import is_orthogonal_array_block_graphsage: 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˓→needs sage.combinat sage.modules#␣>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> from sage.graphs.strongly_regular_db import is_orthogonal_array_block_graph>>> t = is_orthogonal_array_block_graph(Integer(64), Integer(35), Integer(18),␣
˓→Integer(20)); t(..., 5, 8)>>> g = t[Integer(0)](*t[Integer(1):]); g
OA(5,8): Graph on 64 vertices(continues on next page)2.5. Database of strongly regular graphs1113

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_strongly_regular(parameters=True)(64, 35, 18, 20)>>> t = is_orthogonal_array_block_graph(Integer(225),Integer(98),Integer(43),
˓→Integer(42)); t(..., 4)>>> g = t[Integer(0)](*t[Integer(1):]); g
Pasechnik Graph_4: Graph on 225 vertices>>> g.is_strongly_regular(parameters=True)(225, 98, 43, 42)>>> t = is_orthogonal_array_block_graph(Integer(225),Integer(112),Integer(55),
˓→Integer(56)); t(..., 4)>>> g = t[Integer(0)](*t[Integer(1):]); g
skewhad^2_4: Graph on 225 vertices>>> g.is_strongly_regular(parameters=True)(225, 112, 55, 56)>>> t = is_orthogonal_array_block_graph(Integer(5),Integer(5),Integer(5),˓→Integer(5)); t# needs sage.combinat sage.modules

sage.graphs.strongly_regular_db.is_orthogonal_polar(k, l, mu)
Test whether some Orthogonal Polar graph is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see https://www.win.tue.nl/ aeb/graphs/srghub.html.
INPUT:• v, k, l, mu – integers
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph if one exists, and None otherwise.
EXAMPLES:
sage: 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˓→needs sage.rings.finite_rings
Orthogonal Polar Graph O(5, 4): Graph on 85 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(85, 20, 3, 5)
sage: t = is_orthogonal_polar(5,5,5,5); t˓→needs sage.rings.finite_rings

#␣

#␣

#␣

>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_orthogonal_polar>>> t = is_orthogonal_polar(Integer(85), Integer(20), Integer(3), Integer(5)); t(<function OrthogonalPolarGraph at ...>, 5, 4,)>>> g = t[Integer(0)](*t[Integer(1):]); g␣˓→# needs sage.rings.finite_rings
Orthogonal Polar Graph O(5, 4): Graph on 85 vertices>>> g.is_strongly_regular(parameters=True)#␣˓→needs sage.rings.finite_rings(85, 20, 3, 5)(continues on next page)

1114

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> t = is_orthogonal_polar(Integer(5),Integer(5),Integer(5),Integer(5)); t˓→# needs sage.rings.finite_rings␣

sage.graphs.strongly_regular_db.is_paley(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˓→needs sage.rings.finite_rings
Paley graph with parameter 13: Graph on 13 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(13, 6, 2, 3)
sage: t = is_paley(5,5,5,5); t>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_paley>>> t = is_paley(Integer(13),Integer(6),Integer(2),Integer(3)); t(..., 13)>>> g = t[Integer(0)](*t[Integer(1):]); g˓→# needs sage.rings.finite_rings
Paley graph with parameter 13: Graph on 13 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(13, 6, 2, 3)>>> t = is_paley(Integer(5),Integer(5),Integer(5),Integer(5)); t

#␣

#␣

␣

#␣

sage.graphs.strongly_regular_db.is_polhill(k, l, mu)
Test whether some graph from [Pol2009] is (1024, 𝑘, 𝜆, 𝜇)-strongly regular.
Note: This function does not actually explore all strongly regular graphs produced in [Pol2009], but only thoseon 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:

2.5. Database of strongly regular graphs1115

Graph Theory, Release 10.4

sage: # needs sage.rings.finite_rings
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 ...>]>>> from sage.all import *>>> # needs sage.rings.finite_rings>>> from sage.graphs.strongly_regular_db import is_polhill>>> t = is_polhill(Integer(1024), Integer(231), Integer(38), Integer(56)); t[<cyfunction is_polhill.<locals>.<lambda> at ...>]>>> g = t[Integer(0)](*t[Integer(1):]); g# not tested (too long)
Graph on 1024 vertices>>> g.is_strongly_regular(parameters=True)# not tested (too long)(1024, 231, 38, 56)>>> t = is_polhill(Integer(1024), Integer(264), Integer(56), Integer(72)); t[<cyfunction is_polhill.<locals>.<lambda> at ...>]>>> t = is_polhill(Integer(1024), Integer(297), Integer(76), Integer(90)); t[<cyfunction is_polhill.<locals>.<lambda> at ...>]>>> t = is_polhill(Integer(1024), Integer(330), Integer(98), Integer(110)); t[<cyfunction is_polhill.<locals>.<lambda> at ...>]>>> t = is_polhill(Integer(1024), Integer(462), Integer(206), Integer(210)); t[<cyfunction is_polhill.<locals>.<lambda> at ...>]

sage.graphs.strongly_regular_db.is_steiner(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:]); gIntersection Graph: Graph on 26 vertices
sage: g.is_strongly_regular(parameters=True)(26, 15, 8, 9)(continues on next page)

1116

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: t = is_steiner(5,5,5,5); t>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_steiner>>> t = is_steiner(Integer(26),Integer(15),Integer(8),Integer(9)); t(..., 13, 3)>>> g = t[Integer(0)](*t[Integer(1):]); gIntersection Graph: Graph on 26 vertices>>> g.is_strongly_regular(parameters=True)(26, 15, 8, 9)>>> t = is_steiner(Integer(5),Integer(5),Integer(5),Integer(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)
˓→needs sage.combinat sage.modules
Graph on 170 vertices# indirect doctest#␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(170), Integer(78), Integer(35),␣
˓→Integer(36))# indirect doctest# needs sage.combinat sage.modules
Graph on 170 vertices

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)
˓→needs sage.combinat sage.modules
switch skewhad^2+*_4: Graph on 226 vertices

2.5. Database of strongly regular graphs

#␣

1117

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(226), Integer(105), Integer(48),␣
˓→Integer(49))# needs sage.combinat sage.modules
switch skewhad^2+*_4: Graph on 226 vertices

sage.graphs.strongly_regular_db.is_taylor_twograph_srg(k, l, mu)
Test whether some Taylor two-graph SRG is (𝑣, 𝑘, 𝜆, 𝜇)-strongly regular.
For more information, see §7E of [BL1984].
INPUT:• v, k, l, mu – integers
OUTPUT:
A tuple t such that t[0](*t[1:]) builds the requested graph TaylorTwographSRG if the parameters
match, and None otherwise.
EXAMPLES:
sage: # needs sage.libs.pari
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>>> from sage.all import *>>> # needs sage.libs.pari>>> from sage.graphs.strongly_regular_db import is_taylor_twograph_srg>>> t = is_taylor_twograph_srg(Integer(28), Integer(15), Integer(6), Integer(10));˓→ t(<function TaylorTwographSRG at ...>, 3)>>> g = t[Integer(0)](*t[Integer(1):]); g
Taylor two-graph SRG: Graph on 28 vertices>>> g.is_strongly_regular(parameters=True)(28, 15, 6, 10)>>> t = is_taylor_twograph_srg(Integer(5),Integer(5),Integer(5),Integer(5)); t

sage.graphs.strongly_regular_db.is_twograph_descendant_of_srg(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 otherwise.
1118

Chapter 2. Constructors and databases

Graph Theory, Release 10.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#␣˓→needs sage.rings.finite_rings(<cyfunction is_twograph_descendant_of_srg.<locals>.la at...
sage: g = t[0](*t[1:]); g#␣˓→needs sage.rings.finite_rings
descendant of complement(Johnson graph with parameters 8,2) at {0, 1}: Graph on␣
˓→27 vertices
sage: g.is_strongly_regular(parameters=True)#␣˓→needs sage.rings.finite_rings(27, 10, 1, 5)
sage: t = is_twograph_descendant_of_srg(5,5,5,5); t>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_twograph_descendant_of_srg>>> t = is_twograph_descendant_of_srg(Integer(27), Integer(10), Integer(1),␣
˓→Integer(5)); t# needs sage.rings.finite_rings(<cyfunction is_twograph_descendant_of_srg.<locals>.la at...
>>> g = t[Integer(0)](*t[Integer(1):]); g␣˓→# needs sage.rings.finite_rings
descendant of complement(Johnson graph with parameters 8,2) at {0, 1}: Graph on␣
˓→27 vertices>>> g.is_strongly_regular(parameters=True)#␣˓→needs sage.rings.finite_rings(27, 10, 1, 5)>>> t = is_twograph_descendant_of_srg(Integer(5),Integer(5),Integer(5),˓→Integer(5)); t

sage.graphs.strongly_regular_db.is_unitary_dual_polar(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: # needs sage.libs.pari
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>>> from sage.all import *>>> # needs sage.libs.pari>>> from sage.graphs.strongly_regular_db import is_unitary_dual_polar(continues on next page)2.5. Database of strongly regular graphs1119

Graph Theory, Release 10.4

(continued from previous page)>>> t = is_unitary_dual_polar(Integer(297), Integer(40), Integer(7), Integer(5));␣
˓→t(<function UnitaryDualPolarGraph at ...>, 5, 2)>>> g = t[Integer(0)](*t[Integer(1):]); g
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices>>> g.is_strongly_regular(parameters=True)(297, 40, 7, 5)>>> t = is_unitary_dual_polar(Integer(5),Integer(5),Integer(5),Integer(5)); t

sage.graphs.strongly_regular_db.is_unitary_polar(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˓→needs sage.libs.pari(<function UnitaryPolarGraph at ...>, 4, 2)
sage: g = t[0](*t[1:]); g˓→needs sage.libs.pari
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(45, 12, 3, 3)
sage: t = is_unitary_polar(5,5,5,5); t˓→needs sage.libs.pari

#␣

#␣

#␣

#␣

>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import is_unitary_polar>>> t = is_unitary_polar(Integer(45), Integer(12), Integer(3), Integer(3)); t␣˓→# needs sage.libs.pari(<function UnitaryPolarGraph at ...>, 4, 2)>>> g = t[Integer(0)](*t[Integer(1):]); g␣˓→# needs sage.libs.pari
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices>>> g.is_strongly_regular(parameters=True)#␣˓→needs sage.libs.pari(45, 12, 3, 3)>>> t = is_unitary_polar(Integer(5),Integer(5),Integer(5),Integer(5)); t˓→# needs sage.libs.pari␣sage.graphs.strongly_regular_db.latin_squares_graph_parameters(v, k, l, mu)
Check whether (v,k,l,mu)-strongly regular graph has parameters of an 𝐿𝑔 (𝑛) s.r.g.
Also known as pseudo-OA(n,g) case, i.e. s.r.g. with parameters of an OA(n,g)-graph. Return g and n, if they exist.
See Sect. 9.1 of [BH2012] for details.

1120

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

INPUT:• v, k, l, mu – - (integrs) 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 hyperplanein either ℎ1 or ℎ2 points, where ℎ1 , ℎ2 ∈𝑁𝑁.
From a 2-intersection set 𝑆 can be defined a strongly-regular graph in the following way:
• Place the points of 𝑆 on a hyperplane 𝐻 in 𝑃 𝐺(𝑘 + 1, 𝑞)• Define the graph 𝐺 on all points of 𝑃 𝐺(𝑘 + 1, 𝑞)∖𝐻
• Make two points of 𝑉 (𝐺) = 𝑃 𝐺(𝑘 + 1, 𝑞)∖𝐻 adjacent if the line going through them intersects 𝑆
For more information, see e.g. [CD2013] where this explanation has been taken from.
INPUT:• 𝑀 – a |𝑆| × 𝑘 matrix with entries in 𝐹𝑞 representing the points of the 2-intersection set. We assume that thefirst 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 )])˓→needs sage.modules sage.rings.finite_rings
sage: g = strongly_regular_from_two_intersection_set(S); g˓→needs sage.modules sage.rings.finite_rings
two-intersection set in PG(3,4): Graph on 64 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(64, 18, 2, 6)>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import strongly_regular_from_two_
˓→intersection_set>>> S = Matrix([(Integer(0),Integer(0),Integer(1)),(Integer(0),Integer(1),˓→Integer(0))] + [(Integer(1),x**Integer(2),x) for x in GF(Integer(4), b )])˓→# needs sage.modules sage.rings.finite_rings>>> g = strongly_regular_from_two_intersection_set(S); g˓→needs sage.modules sage.rings.finite_rings
two-intersection set in PG(3,4): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(64, 18, 2, 6)

#␣
#␣

#␣

␣
#␣

#␣

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
2.5. Database of strongly regular graphs1121

Graph Theory, Release 10.4

dual code is ≥ 3. A strongly regular graph can be built from a two-weight projective code with weights 𝑤1 , 𝑤2
(assuming 𝑤1 < 𝑤2 ) by adding an edge between any two codewords whose difference has weight 𝑤1 . For more
information, see [LS1981] or [Del1972].
INPUT:• L – a two-weight linear code, or its generating matrix.
EXAMPLES:
sage: 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])
˓→needs sage.modules sage.rings.finite_rings
sage: G = strongly_regular_from_two_weight_code(LinearCode(M))˓→needs sage.modules sage.rings.finite_rings
sage: G.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(81, 50, 31, 30)

#␣
#␣
#␣

>>> from sage.all import *>>> from sage.graphs.strongly_regular_db import strongly_regular_from_two_weight_
˓→code>>> x = ("100022021001111",...
"010011211122000",...
"001021112100011",...
"000110120222220")>>> M = Matrix(GF(Integer(3)),[list(l) for l in x])␣˓→# needs sage.modules sage.rings.finite_rings>>> G = strongly_regular_from_two_weight_code(LinearCode(M))#␣˓→needs sage.modules sage.rings.finite_rings>>> G.is_strongly_regular(parameters=True)#␣˓→needs sage.modules sage.rings.finite_rings(81, 50, 31, 30)

sage.graphs.strongly_regular_db.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 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 beuseless (but we are cautious guys), you may want to disable it whenever you want speed. Set to True by1122

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

default.
EXAMPLES:Petersen’s graph from its set of parameters:sage: graphs.strongly_regular_graph(10,3,0,1,existence=True)
˓→needs sage.libs.pari
True
sage: graphs.strongly_regular_graph(10,3,0,1)
complement(Johnson graph with parameters 5,2): Graph on 10 vertices#␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(10),Integer(3),Integer(0),Integer(1),˓→existence=True)# needs sage.libs.pari
True>>> graphs.strongly_regular_graph(Integer(10),Integer(3),Integer(0),Integer(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>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(10),Integer(3),Integer(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>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(5),Integer(5),Integer(5),Integer(5),˓→existence=True)
False>>> graphs.strongly_regular_graph(Integer(5),Integer(5),Integer(5),Integer(5))
Traceback (most recent call last):...
ValueError: There exists no (5, 5, 5, 5)-strongly regular graph

A set of parameters proved in a paper to be infeasible:
sage: graphs.strongly_regular_graph(324,57,0,12,existence=True)
˓→needs sage.combinat sage.modules
False
sage: graphs.strongly_regular_graph(324,57,0,12)
˓→needs sage.combinat sage.modules
Traceback (most recent call last):...
EmptySetError: Andries Brouwer s database reports that no (324, 57, 0,12)-strongly regular graph exists. Comments: <ahref="srgtabrefs.html#GavrilyukMakhnev05">Gavrilyuk & Makhnev</a> ...

2.5. Database of strongly regular graphs

#␣

#␣

1123

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(324),Integer(57),Integer(0),Integer(12),˓→existence=True)# needs sage.combinat sage.modules
False>>> graphs.strongly_regular_graph(Integer(324),Integer(57),Integer(0),˓→Integer(12))# needs sage.combinat sage.modules
Traceback (most recent call last):...
EmptySetError: Andries Brouwer s database reports that no (324, 57, 0,12)-strongly regular graph exists. Comments: <ahref="srgtabrefs.html#GavrilyukMakhnev05">Gavrilyuk & Makhnev</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)
˓→needs sage.combinat
Unknown
sage: graphs.strongly_regular_graph(324,95,22,30)
˓→needs sage.combinat
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:#␣#␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(324),Integer(95),Integer(22),
˓→Integer(30),existence=True)# needs sage.combinat
Unknown>>> graphs.strongly_regular_graph(Integer(324),Integer(95),Integer(22),
˓→Integer(30))# needs sage.combinat
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)
˓→needs sage.combinat
Unknown
sage: graphs.strongly_regular_graph(1394,175,0,25)
˓→needs sage.combinat
Traceback (most recent call last):...
RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly
regular graph exists.

#␣#␣>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(1394),Integer(175),Integer(0),˓→Integer(25),existence=True)# needs sage.combinat
Unknown>>> graphs.strongly_regular_graph(Integer(1394),Integer(175),Integer(0),˓→Integer(25))# needs sage.combinat
Traceback (most recent call last):...
(continues on next page)1124

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly
regular graph exists.

Test the Claw bound (see 3.D of [BL1984]):
sage: graphs.strongly_regular_graph(2058,242,91,20,existence=True)
False>>> from sage.all import *>>> graphs.strongly_regular_graph(Integer(2058),Integer(242),Integer(91),
˓→Integer(20),existence=True)
False

sage.graphs.strongly_regular_db.strongly_regular_graph_lazy(v, k, l, mu=-1,
existence=False)
return a promise to build an (𝑣, 𝑘, 𝑙, 𝑚𝑢)-srg
Return a promise to build an (𝑣, 𝑘, 𝑙, 𝑚𝑢)-srg as a tuple 𝑡, with 𝑡[0] a function to evaluate on *𝑡[1 :].
Input as in strongly_regular_graph(), although without 𝑐ℎ𝑒𝑐𝑘.

2.6 Database of distance regular graphs
In this module we construct several distance regular graphs and group them in a function that maps intersection arrays tographs.
For a survey on distance-regular graph see [BCN1989] or [VDKT2016].
EXAMPLES:
sage: G = graphs.cocliques_HoffmannSingleton()sage: G.is_distance_regular()True
sage: H = graphs.distance_regular_graph([15, 14, 10, 3, 1, 5, 12, 15])
sage: H == G
True
sage: G = graphs.distance_regular_graph([27, 10, 1, 1, 10, 27])
sage: G.is_distance_regular(True)([27, 10, 1, None], [None, 1, 10, 27])>>> from sage.all import *>>> G = graphs.cocliques_HoffmannSingleton()>>> G.is_distance_regular()True>>> H = graphs.distance_regular_graph([Integer(15), Integer(14), Integer(10),␣
˓→Integer(3), Integer(1), Integer(5), Integer(12), Integer(15)])>>> H == G
True>>> G = graphs.distance_regular_graph([Integer(27), Integer(10), Integer(1),␣
˓→Integer(1), Integer(10), Integer(27)])>>> G.is_distance_regular(True)([27, 10, 1, None], [None, 1, 10, 27])

AUTHORS:2.6. Database of distance regular graphs1125Graph Theory, Release 10.4

• Ivo Maffei (2020-07-28): initial version
sage.graphs.generators.distance_regular.AlternatingFormsGraph(n, q)
Return the alternating forms graph with the given parameters.
This builds a graph whose vertices are all 𝑛`𝑥`𝑛 skew-symmetric matrices over 𝐺𝐹 (𝑞) with zero diagonal. Twovertices are adjacent if and only if the difference of the two matrices has rank 2.
𝑛This grap is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 𝑞 2 , 𝑞 2 − 1, 𝑞 2⌈ 2 ⌉−1 ).
INPUT:• n – integer• q – a prime power
EXAMPLES:
sage: G = graphs.AlternatingFormsGraph(5, 2) # long time
sage: G.is_distance_regular(True) # long time([155, 112, None], [None, 1, 20])>>> from sage.all import *>>> G = graphs.AlternatingFormsGraph(Integer(5), Integer(2))>>> G.is_distance_regular(True) # long time([155, 112, None], [None, 1, 20])# long time

REFERENCES:
See [BCN1989] pp. 282-284 for a rather detailed discussion, otherwise see [VDKT2016] p. 22.
sage.graphs.generators.distance_regular.BilinearFormsGraph(d, e, q)
Return a bilinear forms graph with the given parameters.
This builds a graph whose vertices are all 𝑑`𝑥`𝑒 matrices over 𝐺𝐹 (𝑞). Two vertices are adjacent if the differenceof the two matrices has rank 1.
The graph is distance-regular with classical parameters (min(𝑑, 𝑒), 𝑞, 𝑞 − 1, 𝑞 max(𝑑,𝑒) − 1).
INPUT:• d, e – integers; dimension of the matrices• q – integer; a prime power
EXAMPLES:
sage: # needs sage.modules
sage: G = graphs.BilinearFormsGraph(3, 3, 2)
sage: G.is_distance_regular(True)([49, 36, 16, None], [None, 1, 6, 28])
sage: G = graphs.BilinearFormsGraph(3,3,3)# not tested (20 s)
˓→needs sage.rings.finite_rings
sage: G.order()# not tested (due to above)˓→needs sage.rings.finite_rings
19683
sage: G = graphs.BilinearFormsGraph(3, 4, 2)# long time
˓→needs sage.rings.finite_rings
sage: G.is_distance_regular(True)# long time
˓→needs sage.rings.finite_rings([105, 84, 48, None], [None, 1, 6, 28])

1126

#␣
#␣

#␣
#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.modules>>> G = graphs.BilinearFormsGraph(Integer(3), Integer(3), Integer(2))>>> G.is_distance_regular(True)([49, 36, 16, None], [None, 1, 6, 28])>>> G = graphs.BilinearFormsGraph(Integer(3),Integer(3),Integer(3))˓→tested (20 s)# needs sage.rings.finite_rings>>> G.order()# not tested (due to above)˓→needs sage.rings.finite_rings
19683>>> G = graphs.BilinearFormsGraph(Integer(3), Integer(4), Integer(2))˓→time# needs sage.rings.finite_rings>>> G.is_distance_regular(True)# long time
˓→needs sage.rings.finite_rings([105, 84, 48, None], [None, 1, 6, 28])# not␣
#␣# long␣#␣

REFERENCES:
See [BCN1989] pp. 280-282 for a rather detailed discussion, otherwise see [VDKT2016] p. 21.
sage.graphs.generators.distance_regular.ConwaySmith_for_3S7()
Return the Conway-Smith graph related to 3𝑆𝑦𝑚(7).
This is a distance-regular graph with intersection array [10, 6, 4, 1; 1, 2, 6, 10].
EXAMPLES:
sage: G = graphs.ConwaySmith_for_3S7()
˓→needs sage.modules sage.rings.finite_rings sage.rings.number_fieldsage: G.is_distance_regular(True)
˓→needs sage.modules sage.rings.finite_rings sage.rings.number_field([10, 6, 4, 1, None], [None, 1, 2, 6, 10])>>> from sage.all import *>>> G = graphs.ConwaySmith_for_3S7()
˓→needs sage.modules sage.rings.finite_rings sage.rings.number_field>>> G.is_distance_regular(True)
˓→needs sage.modules sage.rings.finite_rings sage.rings.number_field([10, 6, 4, 1, None], [None, 1, 2, 6, 10])

#␣
#␣

#␣
#␣

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 399.
sage.graphs.generators.distance_regular.DoubleGrassmannGraph(q, e)
Return the bipartite double of the distance-𝑒 graph of the Grassmann graph 𝐽𝑞 (𝑛, 𝑒).
This graph can also be descirbed as follows: Let 𝑉 be the vector space of dimension 𝑛 over 𝐺𝐹 (𝑞). The vertex
set is the set of 𝑒 + 1 or 𝑒 subspaces of 𝑉 . Two vertices are adjacent if one subspace is contained in the other.
This graph is distance-transitive.
INPUT:• q – a prime power• e – integer
EXAMPLES:

2.6. Database of distance regular graphs1127

Graph Theory, Release 10.4

sage: G = graphs.DoubleGrassmannGraph(2,1)˓→needs sage.modules
sage: G.diameter()˓→needs sage.modules3sage: G.is_distance_regular(True)
˓→needs sage.modules([3, 2, 2, None], [None, 1, 1, 3])

#␣
#␣

#␣

>>> from sage.all import *>>> G = graphs.DoubleGrassmannGraph(Integer(2),Integer(1))˓→# needs sage.modules>>> G.diameter()˓→needs sage.modules
3>>> G.is_distance_regular(True)
˓→needs sage.modules([3, 2, 2, None], [None, 1, 1, 3])

␣
#␣

#␣

REFERENCES:
See [BCN1989] pp. 272, 273 or [VDKT2016] p. 25.
sage.graphs.generators.distance_regular.DoubleOddGraph(n)Return the double odd graph on 2𝑛 + 1 points.
The graph is obtained using the subsets of size 𝑛 and 𝑛 + 1 of 1, 2, ..., 2𝑛 + 1 as vertices. Two vertices are adjacent
if one is included in the other.
The graph is distance-transitive.
INPUT:• n – integer; must be greater than 0
EXAMPLES:
sage: G = graphs.DoubleOddGraph(5)sage: G.is_distance_regular(True)([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])
sage: G = graphs.DoubleOddGraph(3)sage: G.diameter()7
sage: G.is_distance_regular(True)([4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4])>>> from sage.all import *>>> G = graphs.DoubleOddGraph(Integer(5))>>> G.is_distance_regular(True)([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])>>> G = graphs.DoubleOddGraph(Integer(3))>>> G.diameter()
7>>> G.is_distance_regular(True)([4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4])

REFERENCES:

1128

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

See [BCN1989] pp. 259-261 or [VDKT2016] p. 25.
sage.graphs.generators.distance_regular.DoublyTruncatedWittGraph()
Return the doubly truncated Witt graph.
This builds the truncated Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [7, 6, 4, 4; 1, 1, 1, 6].
EXAMPLES:
sage: G = graphs.DoublyTruncatedWittGraph()˓→needs sage.libs.pari sage.modules
sage: G.is_distance_regular(True)
˓→needs sage.libs.pari sage.modules([7, 6, 4, 4, None], [None, 1, 1, 1, 6])>>> from sage.all import *>>> G = graphs.DoublyTruncatedWittGraph()˓→needs sage.libs.pari sage.modules>>> G.is_distance_regular(True)
˓→needs sage.libs.pari sage.modules([7, 6, 4, 4, None], [None, 1, 1, 1, 6])

#␣
#␣

#␣
#␣

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 368.
sage.graphs.generators.distance_regular.FosterGraph3S6()
Return the Foster graph for 3.𝑆𝑦𝑚(6).
This graph is distance-regular with intersection array [6, 4, 2, 1; 1, 1, 4, 6].
The graph is also distance transitive.
EXAMPLES:
sage: G = graphs.FosterGraph3S6()
˓→needs sage.libs.gap
sage: G.is_distance_regular(True)
˓→needs sage.libs.gap([6, 4, 2, 1, None], [None, 1, 1, 4, 6])>>> from sage.all import *>>> G = graphs.FosterGraph3S6()
˓→needs sage.libs.gap>>> G.is_distance_regular(True)
˓→needs sage.libs.gap([6, 4, 2, 1, None], [None, 1, 1, 4, 6])

#␣
#␣

#␣
#␣

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 397.
sage.graphs.generators.distance_regular.GeneralisedDodecagonGraph(s, t)
Return the point-graph of a generalised dodecagon of order (𝑠, 𝑡).
INPUT:• s, t – integers; order of the generalised dodecagon
EXAMPLES:
2.6. Database of distance regular graphs1129

Graph Theory, Release 10.4

sage: # optional - gap_package_atlasrep internet
sage: G = graphs.GeneralisedDodecagonGraph(1, 5)
sage: G.is_distance_regular(True)([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6])
sage: H = graphs.GeneralisedDodecagonGraph(5, 1)
sage: H.order()23436
sage: H.is_distance_regular(True)# not tested (6 min)([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2])>>> from sage.all import *>>> # optional - gap_package_atlasrep internet>>> G = graphs.GeneralisedDodecagonGraph(Integer(1), Integer(5))>>> G.is_distance_regular(True)([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6])>>> H = graphs.GeneralisedDodecagonGraph(Integer(5), Integer(1))>>> H.order()23436>>> H.is_distance_regular(True)# not tested (6 min)([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2])Note: This function indirectly uses the GAP’s AtlasRep package. Thus you may need an internet connection andthe optional Sage’s package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
sage.graphs.generators.distance_regular.GeneralisedHexagonGraph(s, t)
Return the point-graph of a generalised hexagon of order (𝑠, 𝑡).
INPUT:• s, t – integers; order of the generalised hexagon
EXAMPLES:
sage: # needs sage.libs.gap
sage: G = graphs.GeneralisedHexagonGraph(5, 5)
˓→atlasrep internet
sage: G.is_distance_regular(True)
˓→atlasrep internet([30, 25, 25, None], [None, 1, 1, 6])
sage: G = graphs.GeneralisedHexagonGraph(7, 1)
sage: G.is_distance_regular(True)([14, 7, 7, None], [None, 1, 1, 2])
sage: graphs.GeneralisedHexagonGraph(1, 1)
Cycle graph: Graph on 6 vertices# optional - gap_package_# optional - gap_package_>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.GeneralisedHexagonGraph(Integer(5), Integer(5))#␣˓→optional - gap_package_atlasrep internet>>> G.is_distance_regular(True)# optional - gap_package_
˓→atlasrep internet([30, 25, 25, None], [None, 1, 1, 6])(continues on next page)

1130

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphs.GeneralisedHexagonGraph(Integer(7), Integer(1))>>> G.is_distance_regular(True)([14, 7, 7, None], [None, 1, 1, 2])>>> graphs.GeneralisedHexagonGraph(Integer(1), Integer(1))
Cycle graph: Graph on 6 vertices

Note: This function uses the GAP’s AtlasRep package to build GHs of order (𝑞, 𝑞), (𝑞, 𝑞 3 ) or (𝑞 3 , 𝑞). For thosegraphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
sage.graphs.generators.distance_regular.GeneralisedOctagonGraph(s, t)
Return the point-graph of a generalised octagon of order (𝑠, 𝑡).
INPUT:• s, t – integers; order of the generalised octagon
EXAMPLES:
sage: # needs sage.libs.gap
sage: G = graphs.GeneralisedOctagonGraph(1, 4)
sage: G.is_distance_regular(True)([5, 4, 4, 4, None], [None, 1, 1, 1, 5])
sage: G = graphs.GeneralisedOctagonGraph(2, 4)
˓→atlasrep internet
sage: G.is_distance_regular(True)
˓→atlasrep internet([10, 8, 8, 8, None], [None, 1, 1, 1, 5])
sage: G = graphs.GeneralisedOctagonGraph(5, 1)
sage: G.is_distance_regular(True)([10, 5, 5, 5, None], [None, 1, 1, 1, 2])# optional - gap_package_# optional - gap_package_>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.GeneralisedOctagonGraph(Integer(1), Integer(4))>>> G.is_distance_regular(True)([5, 4, 4, 4, None], [None, 1, 1, 1, 5])>>> G = graphs.GeneralisedOctagonGraph(Integer(2), Integer(4))#␣˓→optional - gap_package_atlasrep internet>>> G.is_distance_regular(True)# optional - gap_package_
˓→atlasrep internet([10, 8, 8, 8, None], [None, 1, 1, 1, 5])>>> G = graphs.GeneralisedOctagonGraph(Integer(5), Integer(1))>>> G.is_distance_regular(True)([10, 5, 5, 5, None], [None, 1, 1, 1, 2])Note: This function uses the GAP’s AtlasRep package to build the graphs of order (2, 4) or (4, 2). For thosegraphs you need an internet connection and Sage’s optional package gap_packages.
REFERENCES:
See [BCN1989] pp. 200-205 for a discussion of distance-regular graphs from generalised polygons.
2.6. Database of distance regular graphs1131

Graph Theory, Release 10.4

sage.graphs.generators.distance_regular.GrassmannGraph(q, n, input_e)
Return the Grassmann graph with parameters (𝑞, 𝑛, 𝑒).
This builds the Grassmann graph 𝐽𝑞 (𝑛, 𝑒). That is, for a vector space 𝑉 = F(𝑞)𝑛 the output is the graph on thesubspaces of dimension 𝑒 where two subspaces are adjacent if their intersection has dimension 𝑒 − 1.
[︀]︀This graph is distance-regular with classical parameters (min(𝑒, 𝑛 − 𝑒), 𝑞, 𝑞, 𝑛−𝑒+1− 1)1𝑞INPUT:• q – a prime power• n, e – integers with 𝑛 > 𝑒 + 1
EXAMPLES:
sage: G = graphs.GrassmannGraph(2, 4, 2)
˓→needs sage.modules sage.rings.finite_rings
sage: G.is_distance_regular(True)
˓→needs sage.modules sage.rings.finite_rings([18, 8, None], [None, 1, 9])#␣#␣>>> from sage.all import *>>> G = graphs.GrassmannGraph(Integer(2), Integer(4), Integer(2))˓→# needs sage.modules sage.rings.finite_rings>>> G.is_distance_regular(True)
˓→needs sage.modules sage.rings.finite_rings([18, 8, None], [None, 1, 9])␣#␣

REFERENCES:
See [BCN1989] pp. 268-272 or [VDKT2016] p. 21.
sage.graphs.generators.distance_regular.HalfCube(n)Return the halved cube in 𝑛 dimensions.
The graph is distance-regular with classical parameters (⌊ 𝑛2 ⌋, 1, 2, 2⌈ 𝑛2 ⌉ − 1).
INPUT:• n – integer; must be greater than 2
EXAMPLES:
sage: G = graphs.HalfCube(8)sage: G.is_distance_regular(True)([28, 15, 6, 1, None], [None, 1, 6, 15, 28])
sage: G = graphs.HalfCube(4)sage: G.is_distance_regular(True)([6, 1, None], [None, 1, 6])>>> from sage.all import *>>> G = graphs.HalfCube(Integer(8))>>> G.is_distance_regular(True)([28, 15, 6, 1, None], [None, 1, 6, 15, 28])>>> G = graphs.HalfCube(Integer(4))>>> G.is_distance_regular(True)([6, 1, None], [None, 1, 6])

REFERENCES:

1132

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

See [BCN1989] pp. 264, 265 or [VDKT2016] p. 21. This construction can be found on Wikipedia article
Halved_cube_graph#Equivalent_constructions
sage.graphs.generators.distance_regular.HermitianFormsGraph(n, r)
Return the Hermitian forms graph with the given parameters.
We build a graph whose vertices are all 𝑛 × 𝑛 Hermitian matrices over GF(r^2). Two vertices are adjacent if
the difference of the two vertices has rank 1.
This graph is distance-regular with classical parameters (𝑛, −𝑟, −𝑟 − 1, −(−𝑟)𝑑 − 1).
INPUT:• n – integer• r – a prime power
EXAMPLES:
sage: # needs sage.modules sage.rings.finite_rings
sage: G = graphs.HermitianFormsGraph(2, 2)
sage: G.is_distance_regular(True)([5, 4, None], [None, 1, 2])
sage: G = graphs.HermitianFormsGraph(3, 3)# not tested (2 min)sage: G.order()# not tested (bacuase of the above)
19683>>> from sage.all import *>>> # needs sage.modules sage.rings.finite_rings>>> G = graphs.HermitianFormsGraph(Integer(2), Integer(2))>>> G.is_distance_regular(True)([5, 4, None], [None, 1, 2])>>> G = graphs.HermitianFormsGraph(Integer(3), Integer(3))# not tested (2␣˓→min)>>> G.order()# not tested (bacuase of the above)
19683

REFERENCES:
See [BCN1989] p. 285 or [VDKT2016] p. 22.
sage.graphs.generators.distance_regular.IvanovIvanovFaradjevGraph()
Return the IvanovIvanovFaradjev graph.
The graph is distance-transitive with automorphism group 3.𝑀22 .
EXAMPLES:
sage: G = graphs.IvanovIvanovFaradjevGraph()# optional - internet gap_
˓→package_atlasrep
sage: G.is_distance_regular(True)# optional - internet gap_
˓→package_atlasrep([7, 6, 4, 4, 4, 1, 1, 1, None], [None, 1, 1, 1, 2, 4, 4, 6, 7])>>> from sage.all import *>>> G = graphs.IvanovIvanovFaradjevGraph()# optional - internet gap_
˓→package_atlasrep>>> G.is_distance_regular(True)# optional - internet gap_
˓→package_atlasrep([7, 6, 4, 4, 4, 1, 1, 1, None], [None, 1, 1, 1, 2, 4, 4, 6, 7])

2.6. Database of distance regular graphs1133

Graph Theory, Release 10.4

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 369.
sage.graphs.generators.distance_regular.J2Graph()
Return the distance-transitive graph with automorphism group 𝐽2 .
EXAMPLES:
sage: G = graphs.J2Graph()
˓→package_atlasrep
sage: G.is_distance_regular(True)
˓→package_atlasrep([10, 8, 8, 2, None], [None, 1, 1, 4, 5])>>> from sage.all import *>>> G = graphs.J2Graph()
˓→package_atlasrep>>> G.is_distance_regular(True)
˓→package_atlasrep([10, 8, 8, 2, None], [None, 1, 1, 4, 5])# optional - internet gap_
# optional - internet gap_

# optional - internet gap_
# optional - internet gap_

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 408.
sage.graphs.generators.distance_regular.LargeWittGraph()
Return the large Witt graph.
This is a distance-regular graph with intersection array [30, 28, 24; 1, 3, 15].
EXAMPLES:
sage: g = graphs.LargeWittGraph()˓→needs sage.libs.pari sage.modules
sage: g.is_distance_regular(True)
˓→needs sage.libs.pari sage.modules([30, 28, 24, None], [None, 1, 3, 15])#␣#␣>>> from sage.all import *>>> g = graphs.LargeWittGraph()˓→needs sage.libs.pari sage.modules>>> g.is_distance_regular(True)
˓→needs sage.libs.pari sage.modules([30, 28, 24, None], [None, 1, 3, 15])#␣#␣

REFERENCES:
A description of this graph can be found in [BCN1989] p. 366. This construction is taken from http://mathworld.
wolfram.com/LargeWittGraph.html
sage.graphs.generators.distance_regular.LeonardGraph()
Return the Leonard graph.
The graph is distance-regular with intersection array [12, 11, 10, 7; 1, 2, 5, 12].
EXAMPLES:

1134

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.LeonardGraph()˓→needs sage.combinat sage.modules
sage: G.is_distance_regular(True)
˓→needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])>>> from sage.all import *>>> G = graphs.LeonardGraph()˓→needs sage.combinat sage.modules>>> G.is_distance_regular(True)
˓→needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])

#␣
#␣

#␣
#␣

REFERENCES:
For a description of this graph see [BCN1989] p. 371.
sage.graphs.generators.distance_regular.TruncatedWittGraph()
Return the truncated Witt graph.
This builds the large Witt graph, then removes all vertices whose codeword start with a 1.
The graph is distance-regular with intersection array [15, 14, 12; 1, 1, 9].
EXAMPLES:
sage: # long time, needs sage.libs.pari sage.modules
sage: G = graphs.TruncatedWittGraph()
sage: G.is_distance_regular(True)([15, 14, 12, None], [None, 1, 1, 9])>>> from sage.all import *>>> # long time, needs sage.libs.pari sage.modules>>> G = graphs.TruncatedWittGraph()>>> G.is_distance_regular(True)([15, 14, 12, None], [None, 1, 1, 9])

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 367.
sage.graphs.generators.distance_regular.UstimenkoGraph(m, q)
Return the Ustimenko graph with parameters (𝑚, 𝑞).
This is (︀the)︀ distance(︀ 1 or)︀ 2 graph of the(︀𝑛dual)︀ polar graph 𝐶𝑚−1 (𝑞). The graph is distance-regular with parameters(𝑑, 𝑞 2 , 31 𝑞 − 1, 𝑚+1
−
1),
where
1
𝑘 𝑞 is the 𝑞-binomial coefficient.
𝑞
INPUT:• m, q – integers; 𝑞 must be a prime power and 𝑚 > 1
EXAMPLES:
sage: G = graphs.UstimenkoGraph(4, 2)
˓→needs sage.libs.gap
sage: G.is_distance_regular(True)
˓→needs sage.libs.gap([70, 32, None], [None, 1, 35])

2.6. Database of distance regular graphs

#␣
#␣

1135

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.UstimenkoGraph(Integer(4), Integer(2))˓→# needs sage.libs.gap>>> G.is_distance_regular(True)
˓→needs sage.libs.gap([70, 32, None], [None, 1, 35])␣#␣

REFERENCES:
See [BCN1989] p. 279 or [VDKT2016] p. 22.
sage.graphs.generators.distance_regular.cocliques_HoffmannSingleton()
Return the graph obtained from the cocliques of the Hoffmann-Singleton graph.
This is a distance-regular graph with intersection array [15, 14, 10, 3; 1, 5, 12, 15].
EXAMPLES:
sage: G = graphs.cocliques_HoffmannSingleton()sage: G.is_distance_regular(True)([15, 14, 10, 3, None], [None, 1, 5, 12, 15])>>> from sage.all import *>>> G = graphs.cocliques_HoffmannSingleton()>>> G.is_distance_regular(True)([15, 14, 10, 3, None], [None, 1, 5, 12, 15])

REFERENCES:
The construction of this graph can be found in [BCN1989] p. 392.
sage.graphs.generators.distance_regular.distance_3_doubly_truncated_Golay_code_graph()
Return a distance-regular graph with intersection array [9, 8, 6, 3; 1, 1, 3, 8].
EXAMPLES:
sage: # long time, needs sage.modules sage.rings.finite_rings
sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph()
sage: G.is_distance_regular(True)# long time (due to above)([9, 8, 6, 3, None], [None, 1, 1, 3, 8])>>> from sage.all import *>>> # long time, needs sage.modules sage.rings.finite_rings>>> G = graphs.distance_3_doubly_truncated_Golay_code_graph()>>> G.is_distance_regular(True)# long time (due to above)([9, 8, 6, 3, None], [None, 1, 1, 3, 8])

ALGORITHM:
Compute the binary Golay code and truncate it twice. Compute its coset graph. Take a vertex and compute theset of vertices at distance 3 from the vertex chosen. This set constitutes the set of vertices of our distance-regulargraph. Moreover we have an edge (𝑢, 𝑣) if the coset graph contains such edge.
REFERENCES:
Description and construction of this graph are taken from [BCN1989] p. 364.
sage.graphs.generators.distance_regular.distance_regular_graph(arr, existence=False,
check=True)

1136

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

Return a distance-regular graph with the intersection array given.
INPUT:• arr – list; intersection array of the graph• existence – boolean (optional); instead of building the graph return:– True – if a graph with the given intersection array exists;– False – if there is no graph with the given intersection array;– Unknown – if Sage doesn’t know if such a graph exists.
• check – boolean (default: True); if True, then checks that the result of this function has the given intersection array
EXAMPLES:
sage: graphs.distance_regular_graph([21,20,16,1,2,12], existence=True)
True
sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False)
˓→needs sage.combinat sage.modules
sage: G.is_distance_regular(True)
˓→needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])#␣#␣>>> from sage.all import *>>> graphs.distance_regular_graph([Integer(21),Integer(20),Integer(16),Integer(1),˓→Integer(2),Integer(12)], existence=True)
True>>> G = graphs.distance_regular_graph([Integer(12),Integer(11),Integer(10),
˓→Integer(7),Integer(1),Integer(2),Integer(5),Integer(12)], check=False)#␣˓→needs sage.combinat sage.modules>>> G.is_distance_regular(True)#␣˓→needs sage.combinat sage.modules([12, 11, 10, 7, None], [None, 1, 2, 5, 12])REFERENCES:
See [BCN1989] and [VDKT2016].
sage.graphs.generators.distance_regular.graph_3O73()
Return the graph related to the group 3𝑂(7, 3).
This graph is distance-regular with intersection array [117, 80, 24, 1; 1, 12, 80, 117].
The graph is also distance transitive with 3.𝑂(7, 3) as automorphism group
EXAMPLES:
sage: G = graphs.graph_3O73()
˓→package_atlasrep
sage: G.is_distance_regular(True)
˓→package_atlasrep([117, 80, 24, 1, None], [None, 1, 12, 80, 117])>>> from sage.all import *>>> G = graphs.graph_3O73()
˓→package_atlasrep# optional - internet gap_
# optional - internet gap_

# optional - internet gap_
(continues on next page)2.6. Database of distance regular graphs

1137

Graph Theory, Release 10.4

(continued from previous page)>>> G.is_distance_regular(True)
˓→package_atlasrep([117, 80, 24, 1, None], [None, 1, 12, 80, 117])# optional - internet gap_

REFERENCES:
A description and construction of this graph can be found in [BCN1989] p. 400.
sage.graphs.generators.distance_regular.graph_from_GQ_spread(s, t)
Return the point graph of the generalised quadrangle with order (𝑠, 𝑡) after removing one of its spreads.
These graphs are antipodal covers of complete graphs and, in particular, distance-regular graphs of diameter 3.
INPUT:• s, t – integers; order of the generalised quadrangle
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import \....: graph_from_GQ_spreadsage: G = graph_from_GQ_spread(4, 16)
˓→needs sage.libs.pari
sage: G.is_distance_regular(True)
˓→needs sage.libs.pari([64, 60, 1, None], [None, 1, 15, 64])#␣#␣>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import graph_from_GQ_spread>>> G = graph_from_GQ_spread(Integer(4), Integer(16))˓→# needs sage.libs.pari>>> G.is_distance_regular(True)#␣˓→needs sage.libs.pari([64, 60, 1, None], [None, 1, 15, 64])␣REFERENCES:
The graphs constructed here follow [BCN1989] pp. 385, 386.
sage.graphs.generators.distance_regular.graph_with_classical_parameters(d, b,
alpha_in,
beta_in,gamma)
Return the graph with the classical parameters given.
The last parameter gamma is meant to be an element of the enum ClassicalParametersGraph used to
identify the family of graphs to construct. In particular this function doesn’t build any sporadic graph. To build sucha graph use sage.graphs.generators.distance_regular.distance_regular_graph().
INPUT:• d, b, alpha_in, beta_in – numbers; the parameters of the graph; d and b must be integers• gamma – element of the enum ClassicalParametersGraph
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import *sage: graph_with_classical_parameters(3, 1, 1, 3, 1)
Johnson graph with parameters 6,3: Graph on 20 vertices

1138

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import *>>> graph_with_classical_parameters(Integer(3), Integer(1), Integer(1),␣
˓→Integer(3), Integer(1))
Johnson graph with parameters 6,3: Graph on 20 vertices

The last parameter is very important as it takes precedence. This function will not check that the otherfour parameters match the correct family. Use sage.graphs.generators.distance_regular.
is_classical_parameters_graph() to check the parameters:sage: from sage.graphs.generators.distance_regular import *sage: graph_with_classical_parameters(3, 1, 1, 3, 2)
Hamming Graph with parameters 3,4: Graph on 64 vertices
sage: G = _; G.is_distance_regular(True)([9, 6, 3, None], [None, 1, 2, 3])
sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3])
˓→needs sage.combinat(3, 1, 0, 3, 2)#␣>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import *>>> graph_with_classical_parameters(Integer(3), Integer(1), Integer(1),␣
˓→Integer(3), Integer(2))
Hamming Graph with parameters 3,4: Graph on 64 vertices>>> G = _; G.is_distance_regular(True)([9, 6, 3, None], [None, 1, 2, 3])>>> is_classical_parameters_graph([Integer(9), Integer(6), Integer(3), Integer(1),˓→ Integer(2), Integer(3)])# needs sage.combinat(3, 1, 0, 3, 2)

Two families of graphs are not implemented yet:sage: from sage.graphs.generators.distance_regular import *sage: graph_with_classical_parameters(3, 16, 15, 511, 17)Traceback (most recent call last):...
NotImplementedError: Graph would be too big
sage: graph_with_classical_parameters(3, 16, 30, 1022, 16)Traceback (most recent call last):...
NotImplementedError: Graph would be too big>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import *>>> graph_with_classical_parameters(Integer(3), Integer(16), Integer(15),␣
˓→Integer(511), Integer(17))
Traceback (most recent call last):...
NotImplementedError: Graph would be too big>>> graph_with_classical_parameters(Integer(3), Integer(16), Integer(30),␣
˓→Integer(1022), Integer(16))
Traceback (most recent call last):...
NotImplementedError: Graph would be too big

REFERENCES:

2.6. Database of distance regular graphs1139

Graph Theory, Release 10.4

See [BCN1989] chapter 9 for a discussion of distance-regular graphs with classical parameters.
[VDKT2016] section 3.1.1.

See also

sage.graphs.generators.distance_regular.is_classical_parameters_graph(array)
Return a tuple of parameters representing the array given. If such no tuple can be produced, it returns False.
Given an intersection array, if it represents a family of distance-regular graphs with classical parameters, thenthis function returns a tuple consisting of the parameters (𝑑, 𝑏, 𝛼, 𝛽) and a fourth parameter which is the enum
CalssicalParametersGraph indicating the family with the given itersection array. If the array doesn’t
belong to any classical parameter graph, then this function returns False. If the array belongs to a sporadic
graph rather than a family of graphs, then the function returns False. This is to reduce the overlap with sage.
graphs.generators.distance_regular._sporadic_graph_database.
Note: The array given as an input is expected to be an intersection array. If this is not the case, then some
exception may be raised.
INPUT:• array – list; an intersection array
OUTPUT:
False or a tuple (d, b, alpha, beta, gamma).
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import \....: is_classical_parameters_graphsage: G = graphs.HammingGraph(5, 4)
sage: G.is_distance_regular(True)([15, 12, 9, 6, 3, None], [None, 1, 2, 3, 4, 5])
sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5])
˓→needs sage.combinat(5, 1, 0, 3, 2)#␣>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import is_classical_parameters_
˓→graph>>> G = graphs.HammingGraph(Integer(5), Integer(4))>>> G.is_distance_regular(True)([15, 12, 9, 6, 3, None], [None, 1, 2, 3, 4, 5])>>> is_classical_parameters_graph([Integer(15), Integer(12), Integer(9),␣
˓→Integer(6), Integer(3), Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5)])# needs sage.combinat(5, 1, 0, 3, 2)

REFERENCES:
See [BCN1989] chapter 9 for a discussion of distance-regular graphs with classical parameters. See [BCN1989]
chapter 6.2 for a method to compute the classical parameters of a graph. See also [VDKT2016] section 3.1.1.
sage.graphs.generators.distance_regular.is_from_GQ_spread(arr)
Return a pair (𝑠, 𝑡) if the graph obtained from a GQ of order (𝑠, 𝑡) with a spread has the intersection array passed.
We also require that such GQ can be built by Sage. If no such pair exists, then return False.
INPUT:• arr – list; an intersection array

1140

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
sage: from sage.graphs.generators.distance_regular import \....: is_from_GQ_spread, graph_from_GQ_spreadsage: is_from_GQ_spread([125, 120, 1, 1, 24, 125])
˓→needs sage.libs.pari(5, 25)sage: G = graph_from_GQ_spread(5, 25)
˓→needs sage.libs.pari
sage: G.is_distance_regular(True)
˓→needs sage.libs.pari([125, 120, 1, None], [None, 1, 24, 125])

#␣

#␣
#␣

>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import is_from_GQ_spread, graph_
˓→from_GQ_spread>>> is_from_GQ_spread([Integer(125), Integer(120), Integer(1), Integer(1),␣
˓→Integer(24), Integer(125)])# needs sage.libs.pari(5, 25)>>> G = graph_from_GQ_spread(Integer(5), Integer(25))␣˓→# needs sage.libs.pari>>> G.is_distance_regular(True)#␣˓→needs sage.libs.pari([125, 120, 1, None], [None, 1, 24, 125])

REFERENCES:
The graphs we are looking for are antipodal covers of complete graphs. See [BCN1989] pp. 385, 386 for a
discussion on these particular case.
sage.graphs.generators.distance_regular.is_near_polygon(array)
Return a tuple of parameters which identify the near polygon graph with the given intersection array. If such tuple
doesn’t exist, return False.
Note that array may be the intersection array of a near polygon, but if such graph has diameter less than 3, thenthis function will return False.
INPUT:• array – list; intersection array
OUTPUT:
The tuple has the form (id, params) where id is a value of the enum 𝑁 𝑒𝑎𝑟𝑃 𝑜𝑙𝑦𝑔𝑜𝑛𝐺𝑟𝑎𝑝ℎ which identify
a family of graphs and params are all parameters needed to construct the final graph.
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import (....: is_near_polygon, near_polygon_graph)
sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3])
˓→needs sage.combinat(2, 7)
sage: near_polygon_graph(2, 7)
Odd Graph with parameter 7: Graph on 1716 vertices
sage: _.is_distance_regular(True)([7, 6, 6, 5, 5, 4, None], [None, 1, 1, 2, 2, 3, 3])

2.6. Database of distance regular graphs

#␣

1141

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import (... is_near_polygon, near_polygon_graph)>>> is_near_polygon([Integer(7), Integer(6), Integer(6), Integer(5), Integer(5),␣
˓→Integer(4), Integer(1), Integer(1), Integer(2), Integer(2), Integer(3),␣
˓→Integer(3)])# needs sage.combinat(2, 7)>>> near_polygon_graph(Integer(2), Integer(7))
Odd Graph with parameter 7: Graph on 1716 vertices>>> _.is_distance_regular(True)([7, 6, 6, 5, 5, 4, None], [None, 1, 1, 2, 2, 3, 3])

REFERENCES:
See [BCN1989] pp. 198-206 for some theory about near polygons as well as a list of known examples.
sage.graphs.generators.distance_regular.is_pseudo_partition_graph(arr)
Return (𝑚, 𝑎) if the intersection array given satisfies: 𝑏𝑖 = (𝑚 − 𝑖)(1 + 𝑎(𝑚 − 1 − 𝑖)) for 0 ≤ 𝑖 < 𝑑 𝑐𝑖 =𝑖(1 + 𝑎(𝑖 − 1)) for 0 ≤ 𝑖 < 𝑑 𝑐𝑑 = (2𝑑 + 2 − 𝑚)𝑑(1 + 𝑎(𝑑 − 1)) where 𝑑 is the diameter of the graph.
If such pair (𝑚, 𝑎) doesn’t exist or the diameter is less than 3, then this function returns False.
These graphs are called pseudo partition graphs in [BCN1989] chapter 6.3.
INPUT:• arr – list; intersection array
OUTPUT:
A pair (𝑚, 𝑎) of integers or False if such pair doesn’t exist.
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import *sage: is_pseudo_partition_graph([36, 25, 16, 1, 4, 18])
(6, 1)
sage: pseudo_partition_graph(6, 1) # long time
Folded Johnson graph with parameters 12,6: Graph on 462 vertices
sage: _.is_distance_regular(True) # long time([36, 25, 16, None], [None, 1, 4, 18])>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import *>>> is_pseudo_partition_graph([Integer(36), Integer(25), Integer(16), Integer(1),␣
˓→Integer(4), Integer(18)])(6, 1)>>> pseudo_partition_graph(Integer(6), Integer(1)) # long time
Folded Johnson graph with parameters 12,6: Graph on 462 vertices>>> _.is_distance_regular(True) # long time([36, 25, 16, None], [None, 1, 4, 18])

REFERENCE:
See [BCN1989] pp. 197, 198 or [VDKT2016] pp. 38, 39.
sage.graphs.generators.distance_regular.locally_GQ42_distance_transitive_graph()
Return the unique amply regular graph with 𝜇 = 6 which is locally a generalised quadrangle.
This graph is distance-regular with intersection array [45, 32, 12, 1; 1, 6, 32, 45].
This graph is also distance-transitive.
1142

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
sage: G = graphs.locally_GQ42_distance_transitive_graph()
˓→internet gap_package_atlasrep
sage: G.is_distance_regular(True)
˓→internet gap_package_atlasrep([45, 32, 12, 1, None], [None, 1, 6, 32, 45])>>> from sage.all import *>>> G = graphs.locally_GQ42_distance_transitive_graph()
˓→internet gap_package_atlasrep>>> G.is_distance_regular(True)
˓→internet gap_package_atlasrep([45, 32, 12, 1, None], [None, 1, 6, 32, 45])

# optional -␣# optional -␣# optional -␣# optional -␣

REFERENCES:
A description of this graph can be found in [BCN1989] p.399. This construction is due to Dima Pasechnik.
sage.graphs.generators.distance_regular.near_polygon_graph(family, params)
Return the near polygon graph with the given parameters.
The input is expected to be the result of the function sage.graphs.generators.distance_regular.
is_near_polygon().
INPUT:• family – int; an element of the enum NearPolygonGraph.
• params – int or tuple; the parameters needed to construct a graph of the family family.
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import is_near_polygon, near_˓→polygon_graphsage: near_polygon_graph(*is_near_polygon(#␣˓→needs sage.combinat....:[6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]))
Bipartite double of Odd graph on a set of 11 elements: Graph on 924 vertices
sage: G=_; G.is_distance_regular(True)#␣˓→needs sage.combinat([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import is_near_polygon, near_˓→polygon_graph>>> near_polygon_graph(*is_near_polygon(#␣˓→needs sage.combinat...
[Integer(6), Integer(5), Integer(5), Integer(4), Integer(4), Integer(3),␣
˓→Integer(3), Integer(2), Integer(2), Integer(1), Integer(1), Integer(1),␣
˓→Integer(1), Integer(2), Integer(2), Integer(3), Integer(3), Integer(4),␣
˓→Integer(4), Integer(5), Integer(5), Integer(6)]))
Bipartite double of Odd graph on a set of 11 elements: Graph on 924 vertices>>> G=_; G.is_distance_regular(True)#␣˓→needs sage.combinat([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None],[None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])

REFERENCES:
2.6. Database of distance regular graphs1143

Graph Theory, Release 10.4

See [BCN1989] pp. 198-206 for some theory about near polygons as well as a list of known examples.
sage.graphs.generators.distance_regular.pseudo_partition_graph(m, a)
Return a pseudo partition graph with the given parameters.
A graph is a pseudo partition graph if it is distance-regular with diameter at least 3 and whose intersection numbers
satisfy: 𝑏𝑖 = (𝑚 − 𝑖)(1 + 𝑎(𝑚 − 1 − 𝑖)) for 0 ≤ 𝑖 < 𝑑 𝑐𝑖 = 𝑖(1 + 𝑎(𝑖 − 1)) for 0 ≤ 𝑖 < 𝑑 𝑐𝑑 = (2𝑑 + 2 −𝑚)𝑑(1 + 𝑎(𝑑 − 1)) where 𝑑 is the diameter of the graph.
INPUT:• m, a – integers; parameters of the graph
EXAMPLES:
sage: from sage.graphs.generators.distance_regular import *sage: pseudo_partition_graph(6, 1) # long time
Folded Johnson graph with parameters 12,6: Graph on 462 vertices>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import *>>> pseudo_partition_graph(Integer(6), Integer(1)) # long time
Folded Johnson graph with parameters 12,6: Graph on 462 vertices

Not all graphs built with this function are pseudo partition graphs as intended by sage.graphs.generators.
distance_regular.is_pseudo_partition_graph(), since that function requires the diameter to beat least 3:
sage: from sage.graphs.generators.distance_regular import *sage: pseudo_partition_graph(3, 1)
Folded Johnson graph with parameters 6,3: Graph on 10 vertices
sage: G=_; G.is_distance_regular(True)([9, None], [None, 1])
sage: is_pseudo_partition_graph([9, 1])
False>>> from sage.all import *>>> from sage.graphs.generators.distance_regular import *>>> pseudo_partition_graph(Integer(3), Integer(1))
Folded Johnson graph with parameters 6,3: Graph on 10 vertices>>> G=_; G.is_distance_regular(True)([9, None], [None, 1])>>> is_pseudo_partition_graph([Integer(9), Integer(1)])
False

REFERENCES:
See [BCN1989] pp. 197, 198 or [VDKT2016] pp. 38, 39 for a discussion of known pseudo partition graphs.

sage.graphs.generators.distance_regular.shortened_000_111_extended_binary_Golay_code_graph(
Return a distance-regular graph with intersection array [21, 20, 16, 9, 2, 1; 1, 2, 3, 16, 20, 21].
EXAMPLES:
sage: # long time, needs sage.modules sage.rings.finite_rings
sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph()
sage: G.is_distance_regular(True)([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21])1144

# 25 s

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # long time, needs sage.modules sage.rings.finite_rings>>> G = graphs.shortened_000_111_extended_binary_Golay_code_graph()>>> G.is_distance_regular(True)([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21])

# 25 sALGORITHM:
Compute the extended binary Golay code. Compute its subcode whose codewords start with 000 or 111. Remove
the first 3 entries from all the codewords from the new linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
sage.graphs.generators.distance_regular.shortened_00_11_binary_Golay_code_graph()
Return a distance-regular graph with intersection array [21, 20, 16, 6, 2, 1; 1, 2, 6, 16, 20, 21].
EXAMPLES:
sage: # long time, needs sage.modules sage.rings.finite_rings
sage: G = graphs.shortened_00_11_binary_Golay_code_graph()
sage: G.is_distance_regular(True)([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21])>>> from sage.all import *>>> # long time, needs sage.modules sage.rings.finite_rings>>> G = graphs.shortened_00_11_binary_Golay_code_graph()>>> G.is_distance_regular(True)([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21])

# 9 s

# 9 s

ALGORITHM:
Compute the binary Golay code. Compute the subcode whose codewords start with 00 or 11. Remove the first two
entries from all codewords of the newly found linear code and compute its coset graph.
REFERENCES:
Description and construction of this graph can be found in [BCN1989] p. 365.
sage.graphs.generators.distance_regular.vanLintSchrijverGraph()
Return the van Lint-Schrijver graph.
The graph is distance-regular with intersection array [6, 5, 5, 4; 1, 1, 2, 6].
EXAMPLES:
sage: G = graphs.vanLintSchrijverGraph()˓→needs sage.modules
sage: G.is_distance_regular(True)
˓→needs sage.modules([6, 5, 5, 4, None], [None, 1, 1, 2, 6])>>> from sage.all import *>>> G = graphs.vanLintSchrijverGraph()˓→needs sage.modules>>> G.is_distance_regular(True)
˓→needs sage.modules([6, 5, 5, 4, None], [None, 1, 1, 2, 6])

2.6. Database of distance regular graphs

#␣
#␣

#␣
#␣

1145

Graph Theory, Release 10.4

REFERENCES:
For a description of this graph see [BCN1989] p. 373.

2.7 Families of graphs derived from classical geometries over finite
fields
These include graphs of polar spaces, affine polar graphs, graphs related to Hermitean unitals, graphs on nonisotropic
points, etc
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.classical_geometries.AffineOrthogonalPolarGraph(d, q,
sign='+')
Return the affine polar graph 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞).
Affine Polar graphs are built from a 𝑑-dimensional vector space over 𝐹𝑞 , and a quadratic form which is hyperbolic,elliptic or parabolic according to the value of sign.
Note that 𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) are strongly regular graphs, while 𝑉 𝑂(𝑑, 𝑞) is not.
For more information on Affine Polar graphs, see Affine Polar Graphs page of Andries Brouwer’s website.
INPUT:• d – integer; d must be even if sign is not None, and odd otherwise• q – integer; a power of a prime number, as 𝐹𝑞 must exist• sign – string (default: "+"); must be equal to "+", "-", or None to compute (respectively)
𝑉 𝑂+ (𝑑, 𝑞), 𝑉 𝑂− (𝑑, 𝑞) or 𝑉 𝑂(𝑑, 𝑞)Note: The graph 𝑉 𝑂𝜖 (𝑑, 𝑞) is the graph induced by the non-neighbors of a vertex in an Orthogonal Polar
Graph 𝑂𝜖 (𝑑 + 2, 𝑞).
EXAMPLES:
The Brouwer-Haemers graph is isomorphic to 𝑉 𝑂− (4, 3):
sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-")
˓→needs sage.libs.gap
sage: g.is_isomorphic(graphs.BrouwerHaemersGraph())˓→needs sage.libs.gap
True>>> from sage.all import *>>> g = graphs.AffineOrthogonalPolarGraph(Integer(4),Integer(3),"-")
˓→# needs sage.libs.gap>>> g.is_isomorphic(graphs.BrouwerHaemersGraph())˓→needs sage.libs.gap
True

#␣
#␣

␣
#␣

Some examples from Brouwer’s table or strongly regular graphs:

1146

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.libs.gap
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)>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.AffineOrthogonalPolarGraph(Integer(6),Integer(2),"-"); g
Affine Polar Graph VO^-(6,2): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 27, 10, 12)>>> g = graphs.AffineOrthogonalPolarGraph(Integer(6),Integer(2),"+"); g
Affine Polar Graph VO^+(6,2): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 35, 18, 20)

When sign is None:sage: # needs sage.libs.gap
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>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.AffineOrthogonalPolarGraph(Integer(5),Integer(2),None); g
Affine Polar Graph VO^-(5,2): Graph on 32 vertices>>> g.is_strongly_regular(parameters=True)
False>>> g.is_regular()True>>> g.is_vertex_transitive()
True

sage.graphs.generators.classical_geometries.AhrensSzekeresGeneralizedQuadrangleGraph(q,dual=Fa
Return the collinearity graph of the generalized quadrangle 𝐴𝑆(𝑞), or of its dual
Let 𝑞 be an odd prime power. 𝐴𝑆(𝑞) is a generalized quadrangle (Wikipedia article Generalized_quadrangle) oforder (𝑞 − 1, 𝑞 + 1), see 3.1.5 in [PT2009]. Its points are elements of 𝐹𝑞3 , and lines are sets of size 𝑞 of the form
• {(𝜎, 𝑎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }• {(𝑎, 𝜎, 𝑏) | 𝜎 ∈ 𝐹𝑞 }• {(𝑐𝜎 2 − 𝑏𝜎 + 𝑎, −2𝑐𝜎 + 𝑏, 𝜎) | 𝜎 ∈ 𝐹𝑞 },where 𝑎, 𝑏, 𝑐 are arbitrary elements of 𝐹𝑞 .

2.7. Families of graphs derived from classical geometries over finite fields

1147Graph Theory, Release 10.4

INPUT:• q – a power of an odd prime number• dual – boolean (default: False); whether to return the collinearity graph of 𝐴𝑆(𝑞) or of the dual 𝐴𝑆(𝑞)(when True)
EXAMPLES:
sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g
AS(5); GQ(4, 6): Graph on 125 vertices
sage: g.is_strongly_regular(parameters=True)(125, 28, 3, 7)
sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g
AS(5)*; GQ(6, 4): Graph on 175 vertices
sage: g.is_strongly_regular(parameters=True)(175, 30, 5, 5)>>> from sage.all import *>>> g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(Integer(5)); g
AS(5); GQ(4, 6): Graph on 125 vertices>>> g.is_strongly_regular(parameters=True)(125, 28, 3, 7)>>> g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(Integer(5), dual=True); g
AS(5)*; GQ(6, 4): Graph on 175 vertices>>> g.is_strongly_regular(parameters=True)(175, 30, 5, 5)

sage.graphs.generators.classical_geometries.CossidentePenttilaGraph(q)Return the Cossidente-Penttila ((𝑞 3 + 1)(𝑞 + 1)/2, (𝑞 2 + 1)(𝑞 − 1)/2, (𝑞 − 3)/2, (𝑞 − 1)2 /2)-strongly regulargraph
For each odd prime power 𝑞, one can partition the points of the 𝑂6− (𝑞)-generalized quadrangle 𝐺𝑄(𝑞, 𝑞 2 ) into twoparts, so that on any of them the induced subgraph of the point graph of the GQ has parameters as above [CP2005].
Directly following the construction in [CP2005] is not efficient, as one then needs to construct the dual 𝐺𝑄(𝑞 2 , 𝑞).
Thus we describe here a more efficient approach that we came up with, following a suggestion by T.Penttila. Namely,
this partition is invariant under the subgroup 𝐻 = Ω3 (𝑞 2 ) < 𝑂6− (𝑞). We build the appropriate 𝐻, which leaves theform 𝐵(𝑋, 𝑌, 𝑍) = 𝑋𝑌 + 𝑍 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 thelines 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 thediscriminant 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)sage: G.is_strongly_regular(parameters=True)(56, 10, 0, 2)

1148# optional - gap_package_grape# optional - gap_package_grape

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.CossidentePenttilaGraph(Integer(3))# optional - gap_package_
˓→grape>>> G.is_strongly_regular(parameters=True)# optional - gap_package_grape(56, 10, 0, 2)

For 𝑞 > 3 one gets new graphs.
sage: G = graphs.CossidentePenttilaGraph(5)sage: G.is_strongly_regular(parameters=True)(378, 52, 1, 8)# optional - gap_package_grape# optional - gap_package_grape>>> from sage.all import *>>> G = graphs.CossidentePenttilaGraph(Integer(5))# optional - gap_package_
˓→grape>>> G.is_strongly_regular(parameters=True)# optional - gap_package_grape(378, 52, 1, 8)

sage.graphs.generators.classical_geometries.HaemersGraph(q, hyperoval=None,
hyperoval_matching=None,
field=None,check_hyperoval=True)
Return the Haemers graph obtained from 𝑇2* (𝑞)*Let 𝑞 be a power of 2. In Sect. 8.A of [BL1984] one finds a construction of a strongly 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 thepoints (i.e. partitioning into size two parts) of hyperoval defining 𝑇2* (𝑞)* .
While [BL1984] gives the construction in geometric terms, it can be formulated, and is implemented, ingraph-theoretic ones, of re-adjusting the edges. Namely, 𝐺 = 𝑇2* (𝑞)* has a partition into 𝑞 + 2 independent
sets 𝐼𝑘 of size 𝑞 2 each. Each vertex in 𝐼𝑗 is adjacent to 𝑞 vertices from 𝐼𝑘 . Each 𝐼𝑘 is paired to some 𝐼𝑘′ , according
to hyperoval_matching. One adds edges (𝑠, 𝑡) for 𝑠, 𝑡 ∈ 𝐼𝑘 whenever 𝑠 and 𝑡 are adjacent to some 𝑢 ∈ 𝐼𝑘′ ,and removes all the edges between 𝐼𝑘 and 𝐼𝑘′ .
INPUT:• q – a power of two• hyperoval_matching – if None (default), pair each 𝑖-th point of hyperoval with (𝑖 + 1)-th. Otherwise, specifies the pairing in the format ((𝑖1 , 𝑖′1 ), (𝑖2 , 𝑖′2 ), ...).
• hyperoval – a hyperoval defining 𝑇2* (𝑞)* . If None (default), the classical hyperoval obtained from a
conic is used. See the documentation of T2starGeneralizedQuadrangleGraph(), for more information.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
EXAMPLES:
using the built-in constructions:sage: # needs sage.combinat sage.rings.finite_rings
sage: g = graphs.HaemersGraph(4); g
Haemers(4): Graph on 96 vertices
sage: g.is_strongly_regular(parameters=True)(96, 19, 2, 4)

2.7. Families of graphs derived from classical geometries over finite fields

1149

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.HaemersGraph(Integer(4)); g
Haemers(4): Graph on 96 vertices>>> g.is_strongly_regular(parameters=True)(96, 19, 2, 4)

supplying your own hyperoval_matching:sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.HaemersGraph(Integer(4), hyperoval_matching=((Integer(0),˓→Integer(5)),(Integer(1),Integer(4)),(Integer(2),Integer(3)))); g
Haemers(4): Graph on 96 vertices>>> g.is_strongly_regular(parameters=True)(96, 19, 2, 4)

sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph(m,q,sign='+',
perp=None)𝜖,⊥Return the Graph 𝑁 𝑂𝑚(𝑞)

Let the vectorspace of dimension 𝑚 over 𝐹𝑞 be endowed with a nondegenerate quadratic form 𝐹 , of type signfor 𝑚 even.
• 𝑚 even: assume further that 𝑞 = 2 or 3. Returns the graph of the points (in the underlying projective space)𝑥 satisfying 𝐹 (𝑥) = 1, with adjacency given by orthogonality w.r.t. 𝐹 . Parameter perp is ignored.
• 𝑚 odd: if perp is not None, then we assume that 𝑞 = 5 and return the graph of the points 𝑥 satisfying
𝐹 (𝑥) = ±1 if sign="+", respectively 𝐹 (𝑥) ∈ {2, 3} if sign="-", with adjacency given by orthogonality
w.r.t. 𝐹 (cf. Sect 7.D of [BL1984]). Otherwise return the graph of nongenerate hyperplanes of type sign,
adjacent whenever the intersection is degenerate (cf. Sect. 7.C of [BL1984]). Note that for 𝑞 = 2 one will
get a complete graph.
For more information, see Sect. 9.9 of [BH2012] and [BL1984]. Note that the page of Andries Brouwer’s website
uses different notation.
INPUT:• m – integer; half the dimension of the underlying vectorspace• q – a power of a prime number, the size of the underlying field• sign – string (default: "+"); must be either "+" or "-"EXAMPLES:𝑁 𝑂− (4, 2) is isomorphic to Petersen graph:
sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2, - ); g˓→needs sage.libs.gap
NO^-(4, 2): Graph on 10 vertices#␣(continues on next page)

1150

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(10, 3, 0, 1)#␣>>> from sage.all import *>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(4),Integer(2), - ); g␣˓→
# needs sage.libs.gap
NO^-(4, 2): Graph on 10 vertices>>> g.is_strongly_regular(parameters=True)#␣˓→needs sage.libs.gap(10, 3, 0, 1)

𝑁 𝑂− (6, 2) and 𝑁 𝑂+ (6, 2):
sage: # needs sage.libs.gap
sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2, - )sage: g.is_strongly_regular(parameters=True)(36, 15, 6, 6)
sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2, + ); gNO^+(6, 2): Graph on 28 vertices
sage: g.is_strongly_regular(parameters=True)(28, 15, 6, 10)>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(6),Integer(2), - )>>> g.is_strongly_regular(parameters=True)(36, 15, 6, 6)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(6),Integer(2), + ); gNO^+(6, 2): Graph on 28 vertices>>> g.is_strongly_regular(parameters=True)(28, 15, 6, 10)

𝑁 𝑂+ (8, 2):
sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2, + )˓→needs sage.libs.gap
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(120, 63, 30, 36)#␣#␣>>> from sage.all import *>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(8),Integer(2), + )˓→# needs sage.libs.gap>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(120, 63, 30, 36)␣#␣Wilbrink’s graphs for 𝑞 = 5:
sage: # needs sage.libs.gap
sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1)
sage: g.is_strongly_regular(parameters=True)# long time
(325, 60, 15, 10)
sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5, - ,perp=1)(continues on next page)2.7. Families of graphs derived from classical geometries over finite fields

1151

Graph Theory, Release 10.4

(continued from previous page)

sage: g.is_strongly_regular(parameters=True)(300, 65, 10, 15)# long time>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(5),˓→perp=Integer(1))>>> g.is_strongly_regular(parameters=True)# long time
(325, 60, 15, 10)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(5), - ,˓→perp=Integer(1))>>> g.is_strongly_regular(parameters=True)# long time
(300, 65, 10, 15)

Wilbrink’s graphs:
sage: # needs sage.libs.gap
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
˓→(long time)NO^+(7, 4): Graph on 2080 vertices
sage: g.is_strongly_regular(parameters=True)
˓→(long time)(2080, 1071, 558, 544)

# not tested␣# not tested␣>>> from sage.all import *>>> # needs sage.libs.gap>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(4), + )>>> g.is_strongly_regular(parameters=True)(136, 75, 42, 40)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(5),Integer(4), - )>>> g.is_strongly_regular(parameters=True)(120, 51, 18, 24)>>> g = graphs.NonisotropicOrthogonalPolarGraph(Integer(7),Integer(4), + ); g␣˓→# not tested (long time)NO^+(7, 4): Graph on 2080 vertices>>> g.is_strongly_regular(parameters=True)# not tested␣
˓→(long time)(2080, 1071, 558, 544)

sage.graphs.generators.classical_geometries.NonisotropicUnitaryPolarGraph(m, q)
Return the Graph 𝑁 𝑈 (𝑚, 𝑞).
This returns the graph on nonisotropic, with respect to a nondegenerate Hermitean form, points of the (𝑚 −1)-dimensional projective space over 𝐹𝑞 , with points adjacent whenever they lie on a tangent (to the set of isotropic
points) line. For more information, see Sect. 9.9 of [BH2012] and series C14 in [Hub1975].
INPUT:• m, q – integers; 𝑞 must be a prime power
EXAMPLES:

1152

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g˓→needs sage.libs.gap
NU(5, 2): Graph on 176 vertices
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(176, 135, 102, 108)>>> from sage.all import *>>> g = graphs.NonisotropicUnitaryPolarGraph(Integer(5),Integer(2)); g˓→# needs sage.libs.gap
NU(5, 2): Graph on 176 vertices>>> g.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(176, 135, 102, 108)

#␣

#␣

␣

#␣

sage.graphs.generators.classical_geometries.Nowhere0WordsTwoWeightCodeGraph(q,hyperoval=None,
field=None,check_hyperoval=True)
Return the subgraph of nowhere 0 words from two-weight code of projective plane hyperoval.
Let 𝑞 = 2𝑘 and Π = 𝑃 𝐺(2, 𝑞). Fix a hyperoval 𝑂 ⊂ Π. Let 𝑉 = 𝐹𝑞3 and 𝐶 the two-weight 3-dimensional linear
code over 𝐹𝑞 with words 𝑐(𝑣) obtained from 𝑣 ∈ 𝑉 by computing𝑐(𝑣) = (⟨𝑣, 𝑜1 ⟩, ..., ⟨𝑣, 𝑜𝑞+2 ⟩), 𝑜𝑗 ∈ 𝑂.
𝐶 contains 𝑞(𝑞 − 1)2 /2 words without 0 entries. The subgraph of the strongly regular graph of 𝐶 induced on thelatter words is also strongly regular, assuming 𝑞 > 4. This is a construction due to A.E.Brouwer [Bro2016], andleads to graphs with parameters also given by a construction in [HHL2009]. According to [Bro2016], these twoconstructions 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 fieldwith 1st non-0 coordinate equal to 1. By default, hyperoval and field are not specified, and constructedon the fly. In particular, hyperoval we build is the classical one, i.e. a conic with the point of intersectionof its tangent lines.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided.
• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
See also:• is_nowhere0_twoweight()
EXAMPLES:
using the built-in construction:

2.7. Families of graphs derived from classical geometries over finite fields

1153

Graph Theory, Release 10.4

sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.Nowhere0WordsTwoWeightCodeGraph(Integer(8)); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices>>> g.is_strongly_regular(parameters=True)(196, 60, 14, 20)>>> g = graphs.Nowhere0WordsTwoWeightCodeGraph(Integer(16)) # not tested (long␣˓→time)>>> g.is_strongly_regular(parameters=True)# not tested (long time)(1800, 728, 268, 312)

supplying your own hyperoval:
sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> F = GF(Integer(8))>>> O = [vector(F,(Integer(0),Integer(0),Integer(1))),vector(F,(Integer(0),˓→Integer(1),Integer(0)))] + [vector(F, (Integer(1),x**Integer(2),x))...
for x in F]>>> g = graphs.Nowhere0WordsTwoWeightCodeGraph(Integer(8),hyperoval=O,field=F); g
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices>>> g.is_strongly_regular(parameters=True)(196, 60, 14, 20)

sage.graphs.generators.classical_geometries.OrthogonalDualPolarGraph(e, d, q)
Return the dual polar graph on 𝐺𝑂𝑒 (𝑛, 𝑞) of diameter 𝑑.
The value of 𝑛 is determined by 𝑑 and 𝑒.
The graph is distance-regular with classical parameters (𝑑, 𝑞, 0, 𝑞 𝑒 ).
INPUT:• e – integer; type of the orthogonal polar space to consider; must be −1, 0 or 1.
• d – integer; diameter of the graph• q – integer; prime power; order of the finite field over which to build the polar space
EXAMPLES:

1154

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.libs.gap
sage: G = graphs.OrthogonalDualPolarGraph(1,3,2)
sage: G.is_distance_regular(True)([7, 6, 4, None], [None, 1, 3, 7])
sage: G = graphs.OrthogonalDualPolarGraph(0,3,3)
sage: G.is_distance_regular(True)([39, 36, 27, None], [None, 1, 4, 13])sage: G.order()1120# long time
# long time
# long time>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.OrthogonalDualPolarGraph(Integer(1),Integer(3),Integer(2))>>> G.is_distance_regular(True)([7, 6, 4, None], [None, 1, 3, 7])>>> G = graphs.OrthogonalDualPolarGraph(Integer(0),Integer(3),Integer(3))˓→# long time>>> G.is_distance_regular(True)# long time([39, 36, 27, None], [None, 1, 4, 13])>>> G.order()# long time
1120

REFERENCES:
See [BCN1989] pp. 274-279 or [VDKT2016] p. 22.
sage.graphs.generators.classical_geometries.OrthogonalPolarGraph(m, q, sign='+')
Return the Orthogonal Polar Graph 𝑂𝜖 (𝑚, 𝑞).
For more information on Orthogonal Polar graphs, see the page of Andries Brouwer’s website.
INPUT:• m, q – integers; 𝑞 must be a prime power• sign – string (default: "+"); must be "+" or "-" if 𝑚 is even, "+" (default) otherwise
EXAMPLES:
sage: # needs sage.libs.gap
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)

2.7. Families of graphs derived from classical geometries over finite fields

1155

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.OrthogonalPolarGraph(Integer(6),Integer(3),"+"); G
Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices>>> G.is_strongly_regular(parameters=True)(130, 48, 20, 16)>>> G = graphs.OrthogonalPolarGraph(Integer(6),Integer(3),"-"); G
Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices>>> G.is_strongly_regular(parameters=True)(112, 30, 2, 10)>>> G = graphs.OrthogonalPolarGraph(Integer(5),Integer(3)); G
Orthogonal Polar Graph O(5, 3): Graph on 40 vertices>>> G.is_strongly_regular(parameters=True)(40, 12, 2, 4)>>> G = graphs.OrthogonalPolarGraph(Integer(8),Integer(2),"+"); G
Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices>>> G.is_strongly_regular(parameters=True)(135, 70, 37, 35)>>> G = graphs.OrthogonalPolarGraph(Integer(8),Integer(2),"-"); G
Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices>>> G.is_strongly_regular(parameters=True)(119, 54, 21, 27)

sage.graphs.generators.classical_geometries.SymplecticDualPolarGraph(m, q)
Return the Symplectic Dual Polar Graph 𝐷𝑆𝑝(𝑚, 𝑞).
For more information on Symplectic Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:• m, q – integers; 𝑞 must be a prime power, and 𝑚 must be even
EXAMPLES:
sage: 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])>>> from sage.all import *>>> G = graphs.SymplecticDualPolarGraph(Integer(6),Integer(3)); G# not␣
˓→tested (long time)
Symplectic Dual Polar Graph DSp(6, 3): Graph on 1120 vertices>>> G.is_distance_regular(parameters=True)# not tested (long time)([39, 36, 27, None], [None, 1, 4, 13])sage.graphs.generators.classical_geometries.SymplecticPolarGraph(d, q,
algorithm=None)
Return the Symplectic Polar Graph 𝑆𝑝(𝑑, 𝑞).
The Symplectic Polar Graph 𝑆𝑝(𝑑, 𝑞) is built from a projective space of dimension 𝑑 − 1 over a field 𝐹𝑞 , and a
symplectic form 𝑓 . Two vertices 𝑢, 𝑣 are made adjacent if 𝑓 (𝑢, 𝑣) = 0.
See the page on symplectic graphs on Andries Brouwer’s website.
INPUT:• d, q – integers; note that only even values of 𝑑 are accepted by the function.

1156

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• algorithm – string (default: None); if set to gap , then the computation is carried via GAP libraryinterface, 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}
˓→needs sage.rings.number_field
True

#␣

>>> from sage.all import *>>> g = graphs.SymplecticPolarGraph(Integer(6), Integer(2))>>> g.is_strongly_regular(parameters=True)(63, 30, 13, 15)>>> set(g.spectrum()) == {-Integer(5), Integer(3), Integer(30)}˓→# needs sage.rings.number_fieldTrue␣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: # needs sage.libs.gap
sage: O = graphs.OrthogonalPolarGraph(5, 3)
sage: O.is_strongly_regular(parameters=True)(40, 12, 2, 4)
sage: O.is_isomorphic(G)False
sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap")
˓→(long time)
sage: S.is_strongly_regular(parameters=True)
˓→(long time)(1365, 340, 83, 85)# not tested␣# not tested␣>>> from sage.all import *>>> G = graphs.SymplecticPolarGraph(Integer(4), Integer(3))>>> G.is_strongly_regular(parameters=True)(40, 12, 2, 4)>>> # needs sage.libs.gap>>> O = graphs.OrthogonalPolarGraph(Integer(5), Integer(3))>>> O.is_strongly_regular(parameters=True)(40, 12, 2, 4)>>> O.is_isomorphic(G)False>>> S = graphs.SymplecticPolarGraph(Integer(6), Integer(4), algorithm="gap")#␣˓→not tested (long time)>>> S.is_strongly_regular(parameters=True)# not tested (long␣˓→time)(1365, 340, 83, 85)

2.7. Families of graphs derived from classical geometries over finite fields

1157

Graph Theory, Release 10.4

sage.graphs.generators.classical_geometries.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 (Wikipedia article Generalized_quadrangle)of order (𝑞 − 1, 𝑞 + 1), see 3.1.3 in [PT2009]. Fix a plane Π ⊂ Θ and a hyperoval 𝑂 ⊂ Π. The points of𝑇2* (𝑞) := 𝑇2* (𝑂) are the points of Θ outside Π, and the lines are the lines of Θ outside Π that meet Π in a pointof 𝑂.
INPUT:• q – a power of two• dual – boolean (default: False); whether to return the graph of 𝑇2* (𝑂) or of the dual 𝑇2* (𝑂) (when True)• hyperoval – a hyperoval (i.e. a complete 2-arc; a set of points in the plane meeting every line in 0
or 2 points) in the plane of points with 0th coordinate 0 in 𝑃 𝐺(3, 𝑞) over the field field. Each pointof 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 buildis the classical one, i.e. a conic with the point of intersection of its tangent lines.
• field – an instance of a finite field of order 𝑞, must be provided if hyperoval is provided• check_hyperoval – boolean (default: True); whether to check hyperoval for correctness or not
EXAMPLES:
using the built-in construction:
sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> g = graphs.T2starGeneralizedQuadrangleGraph(Integer(4)); g
T2*(O,4); GQ(3, 5): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 18, 2, 6)>>> g = graphs.T2starGeneralizedQuadrangleGraph(Integer(4), dual=True); g
T2*(O,4)*; GQ(5, 3): Graph on 96 vertices>>> g.is_strongly_regular(parameters=True)(96, 20, 4, 4)

supplying your own hyperoval:

1158

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.combinat sage.rings.finite_rings
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)>>> from sage.all import *>>> # needs sage.combinat sage.rings.finite_rings>>> F = GF(Integer(4), b )>>> O = [vector(F,(Integer(0),Integer(0),Integer(0),Integer(1))),vector(F,˓→(Integer(0),Integer(0),Integer(1),Integer(0)))] + [vector(F, (Integer(0),˓→Integer(1),x**Integer(2),x))...
for x in F]>>> g = graphs.T2starGeneralizedQuadrangleGraph(Integer(4), hyperoval=O, field=F);
˓→ g
T2*(O,4); GQ(3, 5): Graph on 64 vertices>>> g.is_strongly_regular(parameters=True)(64, 18, 2, 6)

sage.graphs.generators.classical_geometries.TaylorTwographDescendantSRG(q,clique_partition=False)
Return the descendant graph of the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd.
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 , (𝑞 2 +1)(𝑞 −1)/2, (𝑞 −1)3 /4 −1, (𝑞 2 +1)(𝑞 −1)/4) obtained as a two-graph descendant of the Taylor s two-graph 𝑇 . This graph admits a partition into
cliques of size 𝑞, which are useful in TaylorTwographSRG(), a strongly regular graph on 𝑞 3 + 1 vertices in
the Seidel switching class of 𝑇 , for which we need (𝑞 2 + 1)/2 cliques. The cliques are the 𝑞 2 lines on 𝑣0 of the
projective plane containing the unital for 𝑈3 (𝑞), and intersecting the unital (i.e. the vertices of the graph and thepoint we remove) in 𝑞 + 1 points. This is all taken from §7E of [BL1984].
INPUT:• q – a power of an odd prime number• clique_partition – boolean (default: False); when set to True, return 𝑞 2 − 1 cliques of size 𝑞 withempty pairwise intersection. (Removing all of them leaves a clique, too), and the point removed from theunital.
EXAMPLES:
sage: # needs sage.rings.finite_rings
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_twographsage: T = taylor_twograph(3)# long time
sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long timeTrue
sage: g = graphs.TaylorTwographDescendantSRG(5)# not tested (long time)
sage: g.is_strongly_regular(parameters=True)# not tested (long time)(125, 52, 15, 26)

2.7. Families of graphs derived from classical geometries over finite fields

1159

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.rings.finite_rings>>> g = graphs.TaylorTwographDescendantSRG(Integer(3)); g
Taylor two-graph descendant SRG: Graph on 27 vertices>>> g.is_strongly_regular(parameters=True)(27, 10, 1, 5)>>> from sage.combinat.designs.twographs import taylor_twograph>>> T = taylor_twograph(Integer(3))# long time>>> g.is_isomorphic(T.descendant(T.ground_set()[Integer(1)])) # long timeTrue>>> g = graphs.TaylorTwographDescendantSRG(Integer(5))# not tested (long␣˓→time)>>> g.is_strongly_regular(parameters=True)# not tested (long time)(125, 52, 15, 26)

sage.graphs.generators.classical_geometries.TaylorTwographSRG(q)Return a strongly regular graph from the Taylor’s two-graph for 𝑈3 (𝑞), 𝑞 odd
This is a strongly regular graph with parameters (𝑣, 𝑘, 𝜆, 𝜇) = (𝑞 3 + 1, 𝑞(𝑞 2 + 1)/2, (𝑞 2 + 3)(𝑞 − 1)/4, (𝑞 2 +1)(𝑞 + 1)/4) in the Seidel switching class of Taylor two-graph. Details are in §7E of [BL1984].
INPUT:• q – a power of an odd prime number
See also:• TaylorTwographDescendantSRG()
EXAMPLES:
sage: t = graphs.TaylorTwographSRG(3); t˓→needs sage.rings.finite_rings
Taylor two-graph SRG: Graph on 28 vertices
sage: t.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(28, 15, 6, 10)#␣#␣>>> from sage.all import *>>> t = graphs.TaylorTwographSRG(Integer(3)); t˓→# needs sage.rings.finite_rings
Taylor two-graph SRG: Graph on 28 vertices>>> t.is_strongly_regular(parameters=True)
˓→needs sage.rings.finite_rings(28, 15, 6, 10)␣#␣

sage.graphs.generators.classical_geometries.UnitaryDualPolarGraph(m, q)
Return the Dual Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Dual Polar graphs, see [BCN1989] and Sect. 2.3.1 of [Coh1981].
INPUT:• m, q – integers; 𝑞 must be a prime power
EXAMPLES:
The point graph of a generalized quadrangle (see Wikipedia article Generalized_quadrangle, [PT2009]) of order(8,4):

1160

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time
˓→needs sage.libs.gap
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices
sage: G.is_strongly_regular(parameters=True)# long time
˓→needs sage.libs.gap(297, 40, 7, 5)>>> from sage.all import *>>> G = graphs.UnitaryDualPolarGraph(Integer(5),Integer(2)); G # long time˓→# needs sage.libs.gap
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices>>> G.is_strongly_regular(parameters=True)# long time
˓→needs sage.libs.gap(297, 40, 7, 5)

#␣

#␣

␣

#␣

Another way to get the generalized quadrangle of order (2,4):
sage: G = graphs.UnitaryDualPolarGraph(4,2); G˓→needs sage.libs.gap
Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices
sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2, - ))˓→needs sage.libs.gap
True>>> from sage.all import *>>> G = graphs.UnitaryDualPolarGraph(Integer(4),Integer(2)); G˓→# needs sage.libs.gap
Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices>>> G.is_isomorphic(graphs.OrthogonalPolarGraph(Integer(6),Integer(2), - ))˓→# needs sage.libs.gap
True

#␣

#␣

␣

␣

A bigger graph:
sage: G = graphs.UnitaryDualPolarGraph(6,2); G# not tested (long time)
Unitary Dual Polar Graph DU(6, 2): Graph on 891 vertices
sage: G.is_distance_regular(parameters=True)# not tested (long time)([42, 40, 32, None], [None, 1, 5, 21])>>> from sage.all import *>>> G = graphs.UnitaryDualPolarGraph(Integer(6),Integer(2)); G# not tested␣
˓→(long time)
Unitary Dual Polar Graph DU(6, 2): Graph on 891 vertices>>> G.is_distance_regular(parameters=True)# not tested (long time)([42, 40, 32, None], [None, 1, 5, 21])sage.graphs.generators.classical_geometries.UnitaryPolarGraph(m, q, algorithm='gap')
Return the Unitary Polar Graph 𝑈 (𝑚, 𝑞).
For more information on Unitary Polar graphs, see the page of Andries Brouwer’s website.
INPUT:• m, q – integers; 𝑞 must be a prime power• algorithm – string (default: "gap"); if set to ‘gap’ then the computation is carried via GAP libraryinterface, computing totally singular subspaces, which is faster for large examples (especially with 𝑞 > 2).
Otherwise it is done directly.
2.7. Families of graphs derived from classical geometries over finite fields

1161

Graph Theory, Release 10.4

EXAMPLES:
sage: # needs sage.libs.gap
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>>> from sage.all import *>>> # needs sage.libs.gap>>> G = graphs.UnitaryPolarGraph(Integer(4),Integer(2)); G
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices>>> G.is_strongly_regular(parameters=True)(45, 12, 3, 3)>>> graphs.UnitaryPolarGraph(Integer(5),Integer(2)).is_strongly_
˓→regular(parameters=True)(165, 36, 3, 9)>>> graphs.UnitaryPolarGraph(Integer(6),Integer(2))# not tested (long time)
Unitary Polar Graph U(6, 2): Graph on 693 vertices

2.8 Various families of graphs
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.families.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 2sage: [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>>> from sage.all import *>>> graphs.AztecDiamondGraph(Integer(2))
Aztec Diamond graph of order 2>>> [graphs.AztecDiamondGraph(i).num_verts() for i in range(Integer(8))][0, 4, 12, 24, 40, 60, 84, 112]
(continues on next page)1162

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> [graphs.AztecDiamondGraph(i).num_edges() for i in range(Integer(8))][0, 4, 16, 36, 64, 100, 144, 196]>>> G = graphs.AztecDiamondGraph(Integer(3))>>> sum(Integer(1) for p in G.perfect_matchings())
64

sage.graphs.generators.families.BalancedTree(r, h)Return the perfectly balanced tree of height ℎ ≥ 1, whose root has degree 𝑟 ≥ 2.
ℎ+1

The number of vertices of this graph is 1 + 𝑟 + 𝑟2 + · · · + 𝑟ℎ , that is, 𝑟 𝑟−1−1 . The number of edges is one lessthan 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.
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()3sage: G.size()2
sage: r = 2; h = 1
sage: v = 1 + r
sage: v; v - 1
3
2>>> from sage.all import *>>> G = graphs.BalancedTree(Integer(2), Integer(1)); G
Balanced tree: Graph on 3 vertices>>> G.order()3>>> G.size()2>>> r = Integer(2); h = Integer(1)>>> v = Integer(1) + r>>> v; v - Integer(1)32Plot a balanced tree of height 5, whose root node has degree 𝑟 = 3:
sage: G = graphs.BalancedTree(3, 5)
sage: G.plot()# long time
˓→needs sage.plot
Graphics object consisting of 728 graphics primitives

2.8. Various families of graphs

#␣

1163

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.BalancedTree(Integer(3), Integer(5))>>> G.plot()# long time
˓→needs sage.plot
Graphics object consisting of 728 graphics primitives#␣

A tree is bipartite. If its vertex set is finite, then it is planar.
sage: # needs networkx
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>>> from sage.all import *>>> # needs networkx>>> r = randint(Integer(2), Integer(5)); h = randint(Integer(1), Integer(7))>>> T = graphs.BalancedTree(r, h)>>> T.is_bipartite()
True>>> T.is_planar()True>>> v = (r**(h + Integer(1)) - Integer(1)) / (r - Integer(1))>>> T.order() == v
True>>> T.size() == v - Integer(1)Truesage.graphs.generators.families.BarbellGraph(n1, n2)
Returns a barbell graph with 2 * 𝑛1 + 𝑛2 nodes.
The argument 𝑛1 must be greater than or equal to 2.
A barbell graph is a basic structure that consists of a path graph of order 𝑛2 connecting two complete graphs oforder 𝑛1 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 * 𝑛1 + 𝑛2 . A ValueError is returned if 𝑛1 < 2 or 𝑛2 < 0.
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, eachbarbell graph will be displayed with the two complete graphs in the lower-left and upper-right corners, with thepath graph connecting diagonally between the two. Thus the 𝑛1 -th node will be drawn at a 45 degree angle fromthe horizontal right center of the first complete graph, and the 𝑛1 + 𝑛2 + 1-th node will be drawn 45 degrees below
the left horizontal center of the second complete graph.
1164

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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()˓→needs sage.plot# long time>>> from sage.all import *>>> g = graphs.BarbellGraph(Integer(9), Integer(4)); g
Barbell graph: Graph on 22 vertices>>> g.show()# long time
˓→needs sage.plot#␣#␣

An 𝑛1 ≥ 2, 𝑛2 ≥ 0 barbell graph has order 2 * 𝑛1 + 𝑛2 . It has the complete graph on 𝑛1 vertices as a subgraph.
It also has the path graph on 𝑛2 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)sage: P_n2 = graphs.PathGraph(n2)sage: # needs sage.modules
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>>> from sage.all import *>>> n1 = randint(Integer(2), Integer(2)*Integer(10)**Integer(2))>>> n2 = randint(Integer(0), Integer(2)*Integer(10)**Integer(2))>>> g = graphs.BarbellGraph(n1, n2)>>> v = Integer(2)*n1 + n2>>> g.order() == v
True>>> K_n1 = graphs.CompleteGraph(n1)>>> P_n2 = graphs.PathGraph(n2)>>> # needs sage.modules>>> s_K = g.subgraph_search(K_n1, induced=True)>>> s_P = g.subgraph_search(P_n2, induced=True)>>> K_n1.is_isomorphic(s_K)
True>>> P_n2.is_isomorphic(s_P)
Truesage.graphs.generators.families.BubbleSortGraph(n)Returns the bubble sort graph 𝐵(𝑛).
The vertices of the bubble sort graph are the set of permutations on 𝑛 symbols. Two vertices are adjacent if one
can be obtained from the other by swapping the labels in the 𝑖-th and (𝑖 + 1)-th positions for 1 ≤ 𝑖 ≤ 𝑛 − 1. In
2.8. Various families of graphs1165Graph Theory, Release 10.4

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
˓→needs sage.plot
Graphics object consisting of 61 graphics primitives>>> from sage.all import *>>> g = graphs.BubbleSortGraph(Integer(4)); g
Bubble sort: Graph on 24 vertices>>> g.plot()# long time
˓→needs sage.plot
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>>> from sage.all import *>>> graphs.BubbleSortGraph(Integer(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>>> from sage.all import *>>> n = randint(Integer(1), Integer(8))>>> g = graphs.BubbleSortGraph(n)>>> g.order() == factorial(n)True

See also:• permutahedron()
AUTHORS:• Michael Yurko (2009-09-01)

1166

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage.graphs.generators.families.CaiFurerImmermanGraph(G, twisted=False)
Return the a Cai-Furer-Immerman graph from 𝐺, possibly a twisted one, and a partition of its nodes.
A Cai-Furer-Immerman graph from/on 𝐺 is a graph created by applying the transformation described in [CFI1992]
on a graph 𝐺, that is substituting every vertex v in 𝐺 with a Furer gadget 𝐹 (𝑣) of order d equal to the degree ofthe vertex, and then substituting every edge (𝑣, 𝑢) in 𝐺 with a pair of edges, one connecting the two “a” nodes of𝐹 (𝑣) and 𝐹 (𝑢) and the other their two “b” nodes. The returned coloring of the vertices is made by the union of
the colorings of each single Furer gadget, individualised for each vertex of 𝐺. To understand better what these “a”
and “b” nodes are, see the documentation on Furer gadgets.
Furthermore, this method can apply what is described in the paper mentioned above as a “twist” on an edge, thatis taking only one of the pairs of edges introduced in the new graph and swap two of their extremes, making eachedge 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 theCai-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 thepartition induced by the coloring on H
EXAMPLES:
CaiFurerImmerman graph with no balanced vertex separator smaller than 2
sage: G = graphs.CycleGraph(4)sage: CFI, p = graphs.CaiFurerImmermanGraph(G)sage: sorted(CFI, key=str)[(0, ()), (0, (0, a )), (0, (0, b )), (0, (0, 1)), (0, (1, a )),(0, (1, b )), (1, ()), (1, (0, a )), (1, (0, b )), (1, (0, 1)),
(1, (1, a )), (1, (1, b )), (2, ()), (2, (0, a )), (2, (0, b )),(2, (0, 1)), (2, (1, a )), (2, (1, b )), (3, ()), (3, (0, a )),(3, (0, b )), (3, (0, 1)), (3, (1, a )), (3, (1, b ))]sage: sorted(CFI.edge_iterator(), key=str)[((0, ()), (0, (0, b )), None),((0, ()), (0, (1, b )), None),((0, (0, a )), (1, (0, a )), None),((0, (0, b )), (1, (0, b )), None),((0, (0, 1)), (0, (0, a )), None),((0, (0, 1)), (0, (1, a )), None),((0, (1, a )), (3, (0, a )), None),((0, (1, b )), (3, (0, b )), None),((1, ()), (1, (0, b )), None),((1, ()), (1, (1, b )), None),((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),(continues on next page)2.8. Various families of graphs

1167Graph Theory, Release 10.4

(continued from previous page)((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)]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> CFI, p = graphs.CaiFurerImmermanGraph(G)>>> sorted(CFI, key=str)[(0, ()), (0, (0, a )), (0, (0, b )), (0, (0, 1)), (0, (1, a )),(0, (1, b )), (1, ()), (1, (0, a )), (1, (0, b )), (1, (0, 1)),
(1, (1, a )), (1, (1, b )), (2, ()), (2, (0, a )), (2, (0, b )),(2, (0, 1)), (2, (1, a )), (2, (1, b )), (3, ()), (3, (0, a )),(3, (0, b )), (3, (0, 1)), (3, (1, a )), (3, (1, b ))]>>> sorted(CFI.edge_iterator(), key=str)[((0, ()), (0, (0, b )), None),((0, ()), (0, (1, b )), None),((0, (0, a )), (1, (0, a )), None),((0, (0, b )), (1, (0, b )), None),((0, (0, 1)), (0, (0, a )), None),((0, (0, 1)), (0, (1, a )), None),((0, (1, a )), (3, (0, a )), None),((0, (1, b )), (3, (0, b )), None),((1, ()), (1, (0, b )), None),((1, ()), (1, (1, b )), None),((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)]sage.graphs.generators.families.CirculantGraph(n, adjacency)
Returns a circulant graph with 𝑛 nodes.
A circulant graph has the property that the vertex 𝑖 is connected with the vertices 𝑖 + 𝑗 and 𝑖 − 𝑗 for each 𝑗 inadjacency.
INPUT:• n – number of vertices in the graph• adjacency – the list of 𝑗 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 coun-

1168

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

terclockwise manner.
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor.
See also:• 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: # needs 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>>> from sage.all import *>>> # needs networkx>>> import networkx>>> n = networkx.cycle_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.CirculantGraph(Integer(23),Integer(2))>>> spring23.show()# long time>>> posdict23.show() # long time

We next view many cycle graphs as a Sage graphics array. First we use the CirculantGraph constructor, whichfills in the position dictionary:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.CirculantGraph(i+4, i+1)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CirculantGraph(i+Integer(4), i+Integer(1))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)(continues on next page)2.8. Various families of graphs1169

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphics_array(j)>>> G.show()# long time

Compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.cycle_graph(i+3)....:
k = Graph(spr)....:g.append(k)sage: for i in range(3):....: n = []....: for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....: j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.cycle_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):... n = []... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)>>> G = graphics_array(j)>>> 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(sort=True, labels=false)[(0, 1),(0, 3),(0, 4),(0, 6),(1, 2),(1, 4),(1, 5),(2, 3),(2, 5),(2, 6),(3, 4),(3, 6),(4, 5),(5, 6)]

1170

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> graphs.CirculantGraph(Integer(6),Integer(1)) == graphs.CycleGraph(Integer(6))
True>>> graphs.CirculantGraph(Integer(7),[Integer(1),Integer(3)]).edges(sort=True,␣
˓→labels=false)[(0, 1),(0, 3),(0, 4),(0, 6),(1, 2),(1, 4),(1, 5),(2, 3),(2, 5),(2, 6),(3, 4),(3, 6),(4, 5),(5, 6)]

sage.graphs.generators.families.CubeConnectedCycle(d)Return the cube-connected cycle of dimension 𝑑.
The cube-connected cycle of order 𝑑 is the 𝑑-dimensional hypercube with each of its vertices replaced by a cycleof length 𝑑. This graph has order 𝑑 × 2𝑑 . The construction is as follows: Construct vertex (𝑥, 𝑦) for 0 ≤ 𝑥 < 2𝑑 ,0 ≤ 𝑦 < 𝑑. For each vertex, (𝑥, 𝑦), add an edge between it and (𝑥, (𝑦 − 1) mod 𝑑)), (𝑥, (𝑦 + 1) mod 𝑑), and(𝑥 ⊕ 2𝑦 , 𝑦), where ⊕ is the bitwise xor operator.
For 𝑑 = 1 and 2, the cube-connected cycle graph contains self-loops or multiple edges between a pair of vertices,
but for all other 𝑑, it is simple.
INPUT:• d – The dimension of the desired hypercube as well as the length of the cycle to be placed at each vertex of
the 𝑑-dimensional hypercube. 𝑑 must be a positive integer.
EXAMPLES:
The order of the graph is 𝑑 × 2𝑑
sage: d = 3
sage: g = graphs.CubeConnectedCycle(d)sage: len(g) == d*2**dTrue>>> from sage.all import *>>> d = Integer(3)>>> g = graphs.CubeConnectedCycle(d)>>> len(g) == d*Integer(2)**d
True

The diameter of cube-connected cycles for 𝑑 > 3 is 2𝑑 + ⌊ 𝑑2 ⌋ − 2sage: d = 4
sage: g = graphs.CubeConnectedCycle(d)sage: g.diameter() == 2*d+d//2-2
True

2.8. Various families of graphs1171

Graph Theory, Release 10.4>>> from sage.all import *>>> d = Integer(4)>>> g = graphs.CubeConnectedCycle(d)>>> g.diameter() == Integer(2)*d+d//Integer(2)-Integer(2)True

All vertices have degree 3 when 𝑑 > 1
sage: g = graphs.CubeConnectedCycle(5)sage: all(g.degree(v) == 3 for v in g)
True>>> from sage.all import *>>> g = graphs.CubeConnectedCycle(Integer(5))>>> all(g.degree(v) == Integer(3) for v in g)Truesage.graphs.generators.families.CubeGraph(n, embedding=1)
Return the 𝑛-cube graph, also called the hypercube in 𝑛 dimensions.
The hypercube in 𝑛 dimension is build upon the binary strings on 𝑛 bits, two of them being adjacent if they differ
in exactly one bit. Hence, the distance between two vertices in the hypercube is the Hamming distance.
INPUT:• n – integer; the dimension of the cube graph• embedding – integer (default: 1); two embeddings of the 𝑛-cube are available:– 1: the 𝑛-cube is projected inside a regular 2𝑛-gonal polygon by a skew orthogonal projection. See the
Wikipedia article Hypercube for more details.
– 2: orthogonal projection of the 𝑛-cube. This orientation shows columns of independent vertices such thatthe neighbors of a vertex are located in the columns on the left and on the right. The number of vertices
in each column represents rows in Pascal’s triangle. See for instance the Wikipedia article 10-cube formore details.
– 3: oblique projection of the 𝑛-cube. Oblique projection involves aligning one face parallel to the viewer
and projecting at a specified angle, maintaining equal size for edges parallel to one axis while applying
fixed foreshortening to others. This method simplifies the representation of a four-dimensional hypercube
onto a two-dimensional plane, offering a geometrically consistent visualization.
– None or O: no embedding is provided
EXAMPLES:
The distance between 0100110 and 1011010 is 5, as expected:
sage: g = graphs.CubeGraph(7)sage: g.distance( 0100110 , 1011010 )5>>> from sage.all import *>>> g = graphs.CubeGraph(Integer(7))>>> g.distance( 0100110 , 1011010 )5

Plot several 𝑛-cubes in a Sage Graphics Array:

1172

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(6):....: k = graphs.CubeGraph(i+1)....: g.append(k)...
sage: for i in range(2):....: n = []....: for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....: j.append(n)...
sage: G = graphics_array(j)sage: G.show(figsize=[6,4])# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(6)):... k = graphs.CubeGraph(i+Integer(1))... g.append(k)...
>>> for i in range(Integer(2)):... n = []... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)...
>>> G = graphics_array(j)>>> G.show(figsize=[Integer(6),Integer(4)])# long time

Use the plot options to display larger 𝑛-cubes:
sage: g = graphs.CubeGraph(9, embedding=1)
sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20)
˓→time, needs sage.plot
sage: g = graphs.CubeGraph(9, embedding=2)
sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20)
˓→time, needs sage.plot
sage: g = graphs.CubeGraph(9, embedding=3)
sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20)
˓→time, needs sage.plot# long␣# long␣# long␣

>>> from sage.all import *>>> g = graphs.CubeGraph(Integer(9), embedding=Integer(1))>>> g.show(figsize=[Integer(12),Integer(12)],vertex_labels=False, vertex_
˓→size=Integer(20))# long time, needs sage.plot>>> g = graphs.CubeGraph(Integer(9), embedding=Integer(2))>>> g.show(figsize=[Integer(12),Integer(12)],vertex_labels=False, vertex_
˓→size=Integer(20))# long time, needs sage.plot>>> g = graphs.CubeGraph(Integer(9), embedding=Integer(3))>>> g.show(figsize=[Integer(12),Integer(12)],vertex_labels=False, vertex_
˓→size=Integer(20))# long time, needs sage.plot

2.8. Various families of graphs1173

Graph Theory, Release 10.4

AUTHORS:• Robert Miller• David Coudert
sage.graphs.generators.families.DipoleGraph(n)Returns a dipole graph with n edges.
A dipole graph is a multigraph consisting of 2 vertices connected with n parallel edges.
EXAMPLES:
Construct and show a dipole graph with 13 edges:
sage: g = graphs.DipoleGraph(13); g
Dipole graph: Multi-graph on 2 vertices
sage: g.show()# long time
˓→needs sage.plot>>> from sage.all import *>>> g = graphs.DipoleGraph(Integer(13)); g
Dipole graph: Multi-graph on 2 vertices>>> g.show()# long time
˓→needs sage.plot#␣#␣

sage.graphs.generators.families.DorogovtsevGoltsevMendesGraph(n)Construct the n-th generation of the Dorogovtsev-Goltsev-Mendes graph.
EXAMPLES:
sage: G = graphs.DorogovtsevGoltsevMendesGraph(8)˓→needs networkx
sage: G.size()
˓→needs networkx
6561>>> from sage.all import *>>> G = graphs.DorogovtsevGoltsevMendesGraph(Integer(8))˓→# needs networkx>>> G.size()
˓→needs networkx
6561

#␣
#␣

␣
#␣

REFERENCE:• [1] Dorogovtsev, S. N., Goltsev, A. V., and Mendes, J. F. F., Pseudofractal scale-free web, Phys. Rev. E
066122 (2002).
sage.graphs.generators.families.DoubleGeneralizedPetersenGraph(n, k)
Return a double generalized Petersen graph with 4𝑛 nodes.
The double generalized Petersen graphs is a family of graphs proposed in [ZF2012] as a variant of generalizedPetersen graphs. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋.
INPUT:• n – the number of nodes is 4 * 𝑛• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how vertices on second and third inner rims areconnected

1174

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the double generalized Petersen graphs are displayed as 4 cocentric cycles, with the first n nodes drawn on
the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that. The
second circle is drawn with the (n)th node at the top, then counterclockwise as well. The tird cycle is drawn withthe (2n)th node at the top, then counterclockwise. And the fourth cycle is drawn with the (3n)th node at the top,then again counterclockwise.
EXAMPLES:
When 𝑛 is even the resulting graph will be isomorphic to a double generalized Petersen graph with 𝑘 ′ = 𝑛/2 − 𝑘:sage: g = graphs.DoubleGeneralizedPetersenGraph(10, 2)
sage: g2 = graphs.DoubleGeneralizedPetersenGraph(10, 3)
sage: g.is_isomorphic(g2)
True>>> from sage.all import *>>> g = graphs.DoubleGeneralizedPetersenGraph(Integer(10), Integer(2))>>> g2 = graphs.DoubleGeneralizedPetersenGraph(Integer(10), Integer(3))>>> g.is_isomorphic(g2)True

sage.graphs.generators.families.EgawaGraph(p, s)
Return the Egawa graph with parameters 𝑝, 𝑠.
Egawa graphs are a peculiar family of graphs devised by Yoshimi Egawa in [Ega1981] . The Shrikhande graph isa 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 byk-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 theunderlying 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>>> from sage.all import *>>> g = graphs.EgawaGraph(Integer(1), Integer(2))>>> g.is_distance_regular()True

An Egawa graph with parameters (0,s) is isomorphic to the Hamming graph with parameters (s, 4).
2.8. Various families of graphs

1175Graph Theory, Release 10.4

sage: g = graphs.EgawaGraph(0, 4)
sage: g.is_isomorphic(graphs.HammingGraph(4,4))
True>>> from sage.all import *>>> g = graphs.EgawaGraph(Integer(0), Integer(4))>>> g.is_isomorphic(graphs.HammingGraph(Integer(4),Integer(4)))
Truesage.graphs.generators.families.FibonacciTree(n)Return the graph of the Fibonacci Tree 𝐹𝑖 of order 𝑛.
The Fibonacci tree 𝐹𝑖 is recursively defined as the tree with a root vertex and two attached child trees 𝐹𝑖−1 and𝐹𝑖−2 , where 𝐹1 is just one vertex and 𝐹0 is empty.
INPUT:• n – the recursion depth of the Fibonacci Tree
EXAMPLES:
sage: g = graphs.FibonacciTree(3)˓→needs sage.libs.pari
sage: g.is_tree()
˓→needs sage.libs.pari
True

#␣
#␣

>>> from sage.all import *>>> g = graphs.FibonacciTree(Integer(3))˓→# needs sage.libs.pari>>> g.is_tree()
˓→needs sage.libs.pari
True

␣
#␣

sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ]˓→needs sage.libs.pari
sage: l2 = list(fibonacci_sequence(2,8))
˓→needs sage.libs.pari
sage: l1 == l2
˓→needs sage.libs.pari
True

#␣
#␣
#␣

>>> from sage.all import *>>> l1 = [ len(graphs.FibonacciTree(_)) + Integer(1) for _ in range(Integer(6)) ]␣˓→# needs sage.libs.pari>>> l2 = list(fibonacci_sequence(Integer(2),Integer(8)))␣˓→# needs sage.libs.pari>>> l1 == l2#␣˓→needs sage.libs.pari
True

AUTHORS:• Harald Schilly and Yann Laigle-Chapuy (2010-03-25)
sage.graphs.generators.families.FoldedCubeGraph(n)Returns the folded cube graph of order 2𝑛−1 .

1176

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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>>> from sage.all import *>>> fc = graphs.FoldedCubeGraph(Integer(5))>>> clebsch = graphs.ClebschGraph()>>> fc.is_isomorphic(clebsch)
Truesage.graphs.generators.families.FriendshipGraph(n)Return the friendship graph 𝐹𝑛 .
The friendship graph is also known as the Dutch windmill graph. Let 𝐶3 be the cycle graph on 3 vertices. Then
𝐹𝑛 is constructed by joining 𝑛 ≥ 1 copies of 𝐶3 at a common vertex. If 𝑛 = 1, then 𝐹1 is isomorphic to 𝐶3(the triangle graph). If 𝑛 = 2, then 𝐹2 is the butterfly graph, otherwise known as the bowtie graph. For more
information, see the Wikipedia article Friendship_graph.
INPUT:• n – positive integer; the number of copies of 𝐶3 to use in constructing 𝐹𝑛 .
OUTPUT:• The friendship graph 𝐹𝑛 obtained from 𝑛 copies of the cycle graph 𝐶3 .
See also:• GraphGenerators.ButterflyGraph()
EXAMPLES:
The first few friendship graphs.
sage: # needs sage.plot
sage: A = []; B = []sage: for i in range(9):....:g = graphs.FriendshipGraph(i + 1)....:
A.append(g)sage: for i in range(3):....:n = []....:
for j in range(3):....:n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False))....:
B.append(n)sage: G = graphics_array(B)sage: G.show()# long time

2.8. Various families of graphs

1177Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.plot>>> A = []; B = []>>> for i in range(Integer(9)):...
g = graphs.FriendshipGraph(i + Integer(1))...
A.append(g)>>> for i in range(Integer(3)):...
n = []...
for j in range(Integer(3)):...
n.append(A[Integer(3)*i + j].plot(vertex_size=Integer(20), vertex_
˓→labels=False))...
B.append(n)>>> G = graphics_array(B)>>> 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
˓→needs sage.plot
sage: G.is_isomorphic(graphs.CycleGraph(3))
True>>> from sage.all import *>>> G = graphs.FriendshipGraph(Integer(1)); GFriendship graph: Graph on 3 vertices>>> G.show()# long time
˓→needs sage.plot>>> G.is_isomorphic(graphs.CycleGraph(Integer(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>>> from sage.all import *>>> G = graphs.FriendshipGraph(Integer(2)); GFriendship graph: Graph on 5 vertices>>> G.is_isomorphic(graphs.ButterflyGraph())
True

If 𝑛 ≥ 2, then the friendship graph 𝐹𝑛 has 2𝑛 + 1 vertices and 3𝑛 edges. It has radius 1, diameter 2, girth 3, andchromatic number 3. Furthermore, 𝐹𝑛 is planar and Eulerian.
sage: n = randint(2, 10^3)sage: G = graphs.FriendshipGraph(n)sage: G.order() == 2*n + 1
True
sage: G.size() == 3*nTrue
sage: G.radius()
1(continues on next page)

1178

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: G.diameter()2
sage: G.girth()3
sage: G.chromatic_number()3
sage: G.is_planar()True
sage: G.is_eulerian()True>>> from sage.all import *>>> n = randint(Integer(2), Integer(10)**Integer(3))>>> G = graphs.FriendshipGraph(n)>>> G.order() == Integer(2)*n + Integer(1)True>>> G.size() == Integer(3)*nTrue>>> G.radius()
1>>> G.diameter()2>>> G.girth()3>>> G.chromatic_number()3>>> G.is_planar()
True>>> G.is_eulerian()Truesage.graphs.generators.families.FurerGadget(k, prefix=None)
Return a Furer gadget of order k and their coloring.
Construct the Furer gadget described in [CFI1992], a graph composed by a middle layer of 2( 𝑘 − 1) nodes andtwo sets of nodes (𝑎0 , ..., 𝑎𝑘−1 ) and (𝑏0 , ..., 𝑏𝑘−1 ). Each node in the middle is connected to either 𝑎𝑖 or 𝑏𝑖 , foreach 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 thepartition induced by the coloring of G’s vertices
EXAMPLES:
Furer gadget of order 3, without any prefix.

2.8. Various families of graphs1179

Graph Theory, Release 10.4

sage: G, p = graphs.FurerGadget(3)sage: sorted(G, key=str)[(), (0, a ), (0, b ), (0, 1), (0, 2),(1, a ), (1, b ), (1, 2), (2, a ), (2, b )]sage: sorted(G.edge_iterator(), key=str)[((), (0, b ), None), ((), (1, b ), None),((), (2, b ), None), ((0, b ), (1, 2), None),((0, 1), (0, a ), None), ((0, 1), (1, a ), None),((0, 1), (2, b ), None), ((0, 2), (0, a ), None),((0, 2), (1, b ), None), ((0, 2), (2, a ), None),((1, 2), (1, a ), None), ((1, 2), (2, a ), None)]>>> from sage.all import *>>> G, p = graphs.FurerGadget(Integer(3))>>> sorted(G, key=str)[(), (0, a ), (0, b ), (0, 1), (0, 2),(1, a ), (1, b ), (1, 2), (2, a ), (2, b )]>>> sorted(G.edge_iterator(), key=str)[((), (0, b ), None), ((), (1, b ), None),((), (2, b ), None), ((0, b ), (1, 2), None),((0, 1), (0, a ), None), ((0, 1), (1, a ), None),((0, 1), (2, b ), None), ((0, 2), (0, a ), None),((0, 2), (1, b ), None), ((0, 2), (2, a ), None),((1, 2), (1, a ), None), ((1, 2), (2, a ), None)]

Furer gadget of order 3, with a prefix.
sage: G, p = graphs.FurerGadget(3, Prefix )sage: sorted(G, key=str)[( Prefix , ()), ( Prefix , (0, a )), ( Prefix , (0, b )),( Prefix , (0, 1)), ( Prefix , (0, 2)), ( Prefix , (1, a )),( Prefix , (1, b )), ( Prefix , (1, 2)), ( Prefix , (2, a )),( Prefix , (2, b ))]sage: sorted(G.edge_iterator(), key=str)[(( Prefix , ()), ( Prefix , (0, b )), None),(( Prefix , ()), ( Prefix , (1, b )), None),(( Prefix , ()), ( Prefix , (2, b )), None),(( Prefix , (0, b )), ( Prefix , (1, 2)), None),(( 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 , (1, 2)), ( Prefix , (1, a )), None),(( Prefix , (1, 2)), ( Prefix , (2, a )), None)]>>> from sage.all import *>>> G, p = graphs.FurerGadget(Integer(3), Prefix )>>> sorted(G, key=str)[( Prefix , ()), ( Prefix , (0, a )), ( Prefix , (0, b )),( Prefix , (0, 1)), ( Prefix , (0, 2)), ( Prefix , (1, a )),( Prefix , (1, b )), ( Prefix , (1, 2)), ( Prefix , (2, a )),( Prefix , (2, b ))]>>> sorted(G.edge_iterator(), key=str)[(( Prefix , ()), ( Prefix , (0, b )), None),(( Prefix , ()), ( Prefix , (1, b )), None),(continues on next page)1180

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)(( Prefix , ()), ( Prefix , (2, b )), None),(( Prefix , (0, b )), ( Prefix , (1, 2)), None),(( 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 , (1, 2)), ( Prefix , (1, a )), None),(( Prefix , (1, 2)), ( Prefix , (2, a )), None)]sage.graphs.generators.families.FuzzyBallGraph(partition, q)
Construct a Fuzzy Ball graph with the integer partition partition and q extra vertices.
Let 𝑞 be an integer and let 𝑚1 , 𝑚2 , ..., 𝑚𝑘 be a set of positive integers. Let 𝑛 = 𝑞 + 𝑚1 + ... + 𝑚𝑘 . The Fuzzy
Ball graph with partition 𝑚1 , 𝑚2 , ..., 𝑚𝑘 and 𝑞 extra vertices is the graph constructed from the graph 𝐺 = 𝐾𝑛 byattaching, 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) forall partitions 𝑝 of 𝑚 with 𝑘 parts are cospectral with respect to the normalized Laplacian.
EXAMPLES:
sage: F = graphs.FuzzyBallGraph([3,1],2)
sage: F.adjacency_matrix(vertices=list(F))˓→needs sage.modules[0 0 1 1 1 0 0 0]
[0 0 0 0 0 1 0 0]
[1 0 0 1 1 1 1 1]
[1 0 1 0 1 1 1 1]
[1 0 1 1 0 1 1 1]
[0 1 1 1 1 0 1 1]
[0 0 1 1 1 1 0 1]
[0 0 1 1 1 1 1 0]

#␣>>> from sage.all import *>>> F = graphs.FuzzyBallGraph([Integer(3),Integer(1)],Integer(2))>>> F.adjacency_matrix(vertices=list(F))˓→needs sage.modules[0 0 1 1 1 0 0 0]
[0 0 0 0 0 1 0 0]
[1 0 0 1 1 1 1 1]
[1 0 1 0 1 1 1 1]
[1 0 1 1 0 1 1 1]
[0 1 1 1 1 0 1 1]
[0 0 1 1 1 1 0 1]
[0 0 1 1 1 1 1 0]

#␣

Pick positive integers 𝑚 and 𝑘 and a nonnegative integer 𝑞. All the FuzzyBallGraphs constructed from partitionsof 𝑚 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)˓→needs sage.combinat sage.modules....:
for p in Partitions(m, length=k)]
sage: set(g.laplacian_matrix(normalized=True,# long time (7s on sage.math,␣
˓→2011), needs sage.combinat sage.modules#␣(continues on next page)2.8. Various families of graphs1181

Graph Theory, Release 10.4

(continued from previous page)....:
vertices=list(g)).charpoly()....:
for g in g_list){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}>>> from sage.all import *>>> m = Integer(4); q = Integer(2); k = Integer(2)>>> g_list = [graphs.FuzzyBallGraph(p,q)#␣˓→needs sage.combinat sage.modules...
for p in Partitions(m, length=k)]>>> set(g.laplacian_matrix(normalized=True,# long time (7s on sage.math, 2011),
˓→ needs sage.combinat sage.modules...
vertices=list(g)).charpoly()...
for g in g_list){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}

sage.graphs.generators.families.GeneralizedPetersenGraph(n, k)
Returns a generalized Petersen graph with 2𝑛 nodes. The variables 𝑛, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑘 ≤⌊(𝑛 − 1)/2⌋
For 𝑘 = 1 the result is a graph isomorphic to the circular ladder graph with the same 𝑛. The regular Petersen
Graph has 𝑛 = 5 and 𝑘 = 2. Other named graphs that can be described using this notation include the Desargues
graph and the Möbius-Kantor graph.
INPUT:• n – the number of nodes is 2 * 𝑛.
• k – integer 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. Decides how inner vertices are connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the generalized Petersen graphs are displayed as an inner and outer cycle pair, with the first n nodes drawn
on the outer circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that.
The inner circle is drawn with the (n)th node at the top, then counterclockwise as well.
EXAMPLES: For 𝑘 = 1 the resulting graph will be isomorphic to a circular ladder graph.
sage: g = graphs.GeneralizedPetersenGraph(13,1)
sage: g2 = graphs.CircularLadderGraph(13)sage: g.is_isomorphic(g2)
True>>> from sage.all import *>>> g = graphs.GeneralizedPetersenGraph(Integer(13),Integer(1))>>> g2 = graphs.CircularLadderGraph(Integer(13))>>> g.is_isomorphic(g2)
True

The Desargues graph:
sage: g = graphs.GeneralizedPetersenGraph(10,3)
sage: g.girth()6
sage: g.is_bipartite()
True

1182

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.GeneralizedPetersenGraph(Integer(10),Integer(3))>>> g.girth()6>>> g.is_bipartite()
True

AUTHORS:• Anders Jonsson (2009-10-15)
sage.graphs.generators.families.GeneralizedSierpinskiGraph(G, k, stretch=None)
Return the generalized Sierpinski graph of 𝐺 of dimension 𝑘.
Generalized Sierpinski graphs have been introduced in [GKP2011] to generalize the notion of Sierpinski graphs[KM1997].
Given a graph 𝐺 = (𝑉, 𝐸) of order 𝑛 and a parameter 𝑘, the generalized Sierpinski graph of 𝐺 of dimension 𝑘,
denoted by 𝑆(𝐺, 𝑘), can be constructed recursively from 𝐺 as follows. 𝑆(𝐺, 1) is isomorphic to 𝐺. To construct
𝑆(𝐺, 𝑘) for 𝑘 > 1, copy 𝑛 times 𝑆(𝐺, 𝑘 − 1), once per vertex 𝑢 ∈ 𝑉 , and add 𝑢 at the beginning of the labelsof each vertex in the copy of 𝑆(𝐺, 𝑘 − 1) corresponding to vertex 𝑢. Then for any edge {𝑢, 𝑣} ∈ 𝐸, add an edge
between vertex (𝑢, 𝑣, . . . , 𝑣) and vertex (𝑣, 𝑢, . . . , 𝑢).
INPUT:• G – a sage Graph• k – integer; the dimension• stretch – integer (default: None); stretching factor used to determine the positions of the vertices of theoutput graph. By default (None), this value is set to twice the maximum Euclidean distance between thevertices of 𝐺. This parameter is used only when the vertices of 𝐺 have positions.
See also:• SierpinskiGasketGraph()• HanoiTowerGraph()
EXAMPLES:
The generalized Sierpinski graph of dimension 1 of any graph 𝐺 is isomorphic to 𝐺:
sage: G = graphs.RandomGNP(10, .5)
sage: S = graphs.GeneralizedSierpinskiGraph(G, 1)
sage: S.is_isomorphic(G)True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(10), RealNumber( .5 ))>>> S = graphs.GeneralizedSierpinskiGraph(G, Integer(1))>>> S.is_isomorphic(G)
TrueWhen 𝐺 is a clique of order 3, the generalized Sierpinski graphs of 𝐺 are isomorphic to Hanoi Tower graphs:
sage: k = randint(1, 5)
sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k)
˓→needs sage.modules#␣(continues on next page)2.8. Various families of graphs1183

Graph Theory, Release 10.4

(continued from previous page)

sage: H = graphs.HanoiTowerGraph(3, k)
sage: S.is_isomorphic(H)˓→needs sage.modules
True

#␣

>>> from sage.all import *>>> k = randint(Integer(1), Integer(5))>>> S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(Integer(3)), k)␣˓→# needs sage.modules>>> H = graphs.HanoiTowerGraph(Integer(3), k)>>> S.is_isomorphic(H)#␣˓→needs sage.modules
True

The generalized Sierpinski graph of dimension 𝑘 of any graph 𝐺 with 𝑛 vertices and 𝑚 edges has 𝑛𝑘 vertices and∑︀𝑘−1
𝑚 𝑖=0 𝑛𝑖 edges:
sage: # needs sage.modules
sage: n = randint(2, 6)
sage: k = randint(1, 5)
sage: G = graphs.RandomGNP(n, .5)
sage: m = G.size()
sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == m*sum([n**i for i in range(k)])
Truesage: G = graphs.CompleteGraph(n)sage: S = graphs.GeneralizedSierpinskiGraph(G, k)
sage: S.order() == n**k
True
sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)])
True>>> from sage.all import *>>> # needs sage.modules>>> n = randint(Integer(2), Integer(6))>>> k = randint(Integer(1), Integer(5))>>> G = graphs.RandomGNP(n, RealNumber( .5 ))>>> m = G.size()>>> S = graphs.GeneralizedSierpinskiGraph(G, k)>>> S.order() == n**k
True>>> S.size() == m*sum([n**i for i in range(k)])
True>>> G = graphs.CompleteGraph(n)>>> S = graphs.GeneralizedSierpinskiGraph(G, k)>>> S.order() == n**k
True>>> S.size() == (n*(n - Integer(1))/Integer(2))*sum([n**i for i in range(k)])
True

The positions of the vertices of the output graph are determined from the positions of the vertices of 𝐺, if any:
sage: G = graphs.HouseGraph()
sage: G.get_pos() is not None(continues on next page)1184

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)True
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)
˓→needs sage.symbolic
sage: H.get_pos() is not None˓→needs sage.symbolicTruesage: G = Graph([(0, 1)])
sage: G.get_pos() is not None
False
sage: H = graphs.GeneralizedSierpinskiGraph(G, 2)
˓→needs sage.symbolic
sage: H.get_pos() is not None˓→needs sage.symbolic
False

#␣
#␣

#␣
#␣

>>> from sage.all import *>>> G = graphs.HouseGraph()>>> G.get_pos() is not None
True>>> H = graphs.GeneralizedSierpinskiGraph(G, Integer(2))˓→# needs sage.symbolic>>> H.get_pos() is not None˓→needs sage.symbolic
True>>> G = Graph([(Integer(0), Integer(1))])>>> G.get_pos() is not None
False>>> H = graphs.GeneralizedSierpinskiGraph(G, Integer(2))˓→# needs sage.symbolic>>> H.get_pos() is not None˓→needs sage.symbolic
False

␣
#␣

␣
#␣

sage.graphs.generators.families.GoethalsSeidelGraph(k, r)
Returns the graph Goethals-Seidel(𝑘, 𝑟).
The graph Goethals-Seidel(𝑘, 𝑟) comes from a construction presented in Theorem 2.4 of [GS1970]. It relies on a(v,k)-BIBD with 𝑟 blocks and a hadamard_matrix() of order 𝑟 + 1. The result is a sage.graphs.
strongly_regular_db.strongly_regular_graph() on 𝑣(𝑟 + 1) vertices with degree 𝑘 = (𝑛 + 𝑟 −1)/2.
It appears under this name in Andries Brouwer’s database of strongly regular graphs.
INPUT:• k, r – integers
See also:• is_goethals_seidel()EXAMPLES:
sage: graphs.GoethalsSeidelGraph(3,3)˓→needs sage.combinat sage.modules
Graph on 28 vertices
sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True)#␣#␣(continues on next page)2.8. Various families of graphs1185

Graph Theory, Release 10.4

1186

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)needs sage.combinat sage.modules(28, 15, 6, 10)˓→>>> from sage.all import *>>> graphs.GoethalsSeidelGraph(Integer(3),Integer(3))˓→# needs sage.combinat sage.modules
Graph on 28 vertices>>> graphs.GoethalsSeidelGraph(Integer(3),Integer(3)).is_strongly_
˓→regular(parameters=True)# needs sage.combinat sage.modules(28, 15, 6, 10)␣sage.graphs.generators.families.HammingGraph(n, q, X=None)
Return the Hamming graph with parameters 𝑛, 𝑞 over 𝑋.
Hamming graphs are graphs over the cartesian product of n copies of 𝑋, 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 𝑋.
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 theunderlying 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()
˓→needs sage.groups
True>>> from sage.all import *>>> g = graphs.HammingGraph(Integer(3), Integer(7))>>> g.is_distance_regular()True>>> g.is_regular()True>>> g.is_vertex_transitive()
˓→needs sage.groups
True

#␣

#␣

A Hamming graph with parameters (1, 𝑞) is isomorphic to the Complete graph with parameter 𝑞:

2.8. Various families of graphs

1187

Graph Theory, Release 10.4

sage: g = graphs.HammingGraph(1, 23)
sage: g.is_isomorphic(graphs.CompleteGraph(23))
True>>> from sage.all import *>>> g = graphs.HammingGraph(Integer(1), Integer(23))>>> g.is_isomorphic(graphs.CompleteGraph(Integer(23)))
True

If a parameter 𝑞 is provided which is not equal to 𝑋’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>>> from sage.all import *>>> X = [ a , b , c , d , e ]>>> g = graphs.HammingGraph(Integer(2), Integer(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_graphsage.graphs.generators.families.HanoiTowerGraph(pegs, disks, labels=True, positions=True)
Returns the graph whose vertices are the states of the Tower of Hanoi puzzle, with edges representing legal moves
between states.
INPUT:• pegs – the number of pegs in the puzzle, 2 or greater• disks – the number of disks in the puzzle, 1 or greater• labels – default: True, if True the graph contains more meaningful labels, see explanation below. For
large instances, turn off labels for much faster creation of the graph.
• positions – default: True, if True the graph contains layout information. This creates a planar layout
for the case of three pegs. For large instances, turn off layout information for much faster creation of thegraph.
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 thatthe 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 withlength 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 base1188

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

equal to the number of pegs, and low-order digits to the right.
Two vertices are adjacent if we can change the puzzle from one state to the other by moving a single disk. For
example, (2,0,0) is adjacent to (2,0,1) since we can move the small disk off peg 0 and onto (the empty)
peg 1. So the solution to a 3-disk puzzle (with at least two pegs) can be expressed by the shortest path between(0,0,0) and (1,1,1). For more on this representation of the graph, or its properties, see [AD2010].
For greatest speed we create graphs with integer vertices, where we encode the tuples as integers with a base equal
to the number of pegs, and low-order digits to the right. So for example, in a 3-peg puzzle with 5 disks, the state(1,2,0,1,1) is encoded as 1 * 34 + 2 * 33 + 0 * 32 + 1 * 31 + 1 * 30 = 139.
For smaller graphs, the labels that are the tuples are informative, but slow down creation of the graph. Likewisecomputing 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 thepadsto option is a quick way to do this, though you may want to reverse the list that is output.
See also:• GeneralizedSierpinskiGraph()
PLOTTING:
The layout computed when positions = True will look especially good for the three-peg case, when thegraph 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 ofmoves 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>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(3), Integer(5), labels=False,␣
˓→positions=False)>>> H.distance(Integer(0), Integer(3)**Integer(5)-Integer(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>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(4), Integer(6), labels=False,␣
˓→positions=False)>>> H.num_verts()
4096>>> H.distance(Integer(0), Integer(4)**Integer(6)-Integer(1))
17

For a small graph, labels and layout information can be useful. Here we explicitly list a solution as a list of states.

2.8. Various families of graphs1189

Graph Theory, Release 10.4

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)]>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(3), Integer(3), labels=True,␣
˓→positions=True)>>> H.shortest_path((Integer(0),Integer(0),Integer(0)), (Integer(1),Integer(1),˓→Integer(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))˓→needs sage.groupsTrue
sage: H.chromatic_number()3
sage: len(H.independent_set()) == 3^(4-1)
True>>> from sage.all import *>>> H = graphs.HanoiTowerGraph(Integer(3), Integer(4), labels=False,␣
˓→positions=False)>>> H.automorphism_group().is_isomorphic(SymmetricGroup(Integer(3)))˓→# needs sage.groups
True>>> H.chromatic_number()3>>> len(H.independent_set()) == Integer(3)**(Integer(4)-Integer(1))
True

#␣

␣

AUTHOR:• Rob Beezer, (2009-12-26), with assistance from Su Doreesage.graphs.generators.families.HararyGraph(k, n)
Returns the Harary graph on 𝑛 vertices and connectivity 𝑘, where 2 ≤ 𝑘 < 𝑛.
A 𝑘-connected graph 𝐺 on 𝑛 vertices requires the minimum degree 𝛿(𝐺) ≥ 𝑘, so the minimum number of edges
𝐺 should have is ⌈𝑘𝑛/2⌉. Harary graphs achieve this lower bound, that is, Harary graphs are minimal 𝑘-connected
graphs on 𝑛 vertices.
The construction provided uses the method CirculantGraph. For more details, see the book [West2001] or the
MathWorld article on Harary graphs.
EXAMPLES:
Harary graphs 𝐻𝑘,𝑛 :1190

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: h = graphs.HararyGraph(5,9); hHarary graph 5, 9: Graph on 9 vertices
sage: h.order()9sage: h.size()23
sage: h.vertex_connectivity()
˓→needs sage.numerical.mip
5>>> from sage.all import *>>> h = graphs.HararyGraph(Integer(5),Integer(9)); hHarary graph 5, 9: Graph on 9 vertices>>> h.order()9>>> h.size()23>>> h.vertex_connectivity()
˓→needs sage.numerical.mip
5

#␣

#␣

sage.graphs.generators.families.HyperStarGraph(n, k)
Return the hyper-star graph 𝐻𝑆(𝑛, 𝑘).
The vertices of the hyper-star graph are the set of binary strings of length 𝑛 which contain 𝑘 1s. Two vertices, 𝑢 and𝑣, are adjacent only if 𝑢 can be obtained from 𝑣 by swapping the first bit with a different symbol in another position.
For instance, vertex 011100 of 𝐻𝑆(6, 3) is adjacent to vertices 101100 , 110100 and 111000 .
See [LKOL2002] for more details.
INPUT:• n – non-negative integer; length of the binary strings• k – non-negative integer; number of 1s per binary string
EXAMPLES:
sage: g = graphs.HyperStarGraph(6,3)
sage: sorted(g.neighbors( 011100 ))[ 101100 , 110100 , 111000 ]sage: g.plot()# long time
˓→needs sage.plot
Graphics object consisting of 51 graphics primitives>>> from sage.all import *>>> g = graphs.HyperStarGraph(Integer(6),Integer(3))>>> sorted(g.neighbors( 011100 ))[ 101100 , 110100 , 111000 ]>>> g.plot()# long time
˓→needs sage.plot
Graphics object consisting of 51 graphics primitives#␣#␣

AUTHORS:• Michael Yurko (2009-09-01)
sage.graphs.generators.families.IGraph(n, j, k)
Return an I-graph with 2𝑛 nodes.

2.8. Various families of graphs

1191

Graph Theory, Release 10.4

The I-Graph family as been proposed in [BCMS1988] as a generalization of the generalized Petersen graphs. The
variables 𝑛, 𝑗, 𝑘 are integers such that 𝑛 > 2 and 0 < 𝑗, 𝑘 ≤ ⌊(𝑛 − 1)/2⌋. When 𝑗 = 1 the resulting graph isisomorphic to the generalized Petersen graph with the same 𝑛 and 𝑘.
INPUT:• n – the number of nodes is 2 * 𝑛• j – integer such that 0 < 𝑗 ≤ ⌊(𝑛 − 1)/2⌋ determining how outer vertices are connected• k – integer such that 0 < 𝑘 ≤ ⌊(𝑛 − 1)/2⌋ determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the I-graphs are displayed as an inner and outer cycle pair, with the first n nodes drawn on the outer circle.
The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that. The inner circle isdrawn with the (n)th node at the top, then counterclockwise as well.
EXAMPLES:
When 𝑗 = 1 the resulting graph will be isomorphic to a generalized Petersen graph:
sage: g = graphs.IGraph(7,1,2)
sage: g2 = graphs.GeneralizedPetersenGraph(7,2)
sage: g.is_isomorphic(g2)
True>>> from sage.all import *>>> g = graphs.IGraph(Integer(7),Integer(1),Integer(2))>>> g2 = graphs.GeneralizedPetersenGraph(Integer(7),Integer(2))>>> g.is_isomorphic(g2)
True

The IGraph with parameters (𝑛, 𝑗, 𝑘) is isomorphic to the IGraph with parameters (𝑛, 𝑘, 𝑗):sage: g = graphs.IGraph(7, 2, 3)
sage: h = graphs.IGraph(7, 3, 2)
sage: g.is_isomorphic(h)True>>> from sage.all import *>>> g = graphs.IGraph(Integer(7), Integer(2), Integer(3))>>> h = graphs.IGraph(Integer(7), Integer(3), Integer(2))>>> g.is_isomorphic(h)Truesage.graphs.generators.families.JohnsonGraph(n, k)
Returns the Johnson graph with parameters 𝑛, 𝑘.
Johnson graphs are a special class of undirected graphs defined from systems of sets. The vertices of the Johnson
graph 𝐽(𝑛, 𝑘) are the 𝑘-element subsets of an 𝑛-element set; two vertices are adjacent when they meet in a (𝑘 −1)-element set. See the Wikipedia article Johnson_graph for more information.
EXAMPLES:The Johnson graph is a Hamiltonian graph:
sage: g = graphs.JohnsonGraph(7, 3)
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
True

1192

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.JohnsonGraph(Integer(7), Integer(3))>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

Every Johnson graph is vertex transitive:
sage: g = graphs.JohnsonGraph(6, 4)
sage: g.is_vertex_transitive()
˓→needs sage.groups
True>>> from sage.all import *>>> g = graphs.JohnsonGraph(Integer(6), Integer(4))>>> g.is_vertex_transitive()
˓→needs sage.groups
True

#␣

#␣

The complement of the Johnson graph 𝐽(𝑛, 2) is isomorphic to the Kneser Graph 𝐾(𝑛, 2). In particular thecomplement of 𝐽(5, 2) is isomorphic to the Petersen graph.:
sage: g = graphs.JohnsonGraph(5,2)
sage: g.complement().is_isomorphic(graphs.PetersenGraph())
True>>> from sage.all import *>>> g = graphs.JohnsonGraph(Integer(5),Integer(2))>>> g.complement().is_isomorphic(graphs.PetersenGraph())
True

sage.graphs.generators.families.KneserGraph(n, k)
Returns the Kneser Graph with parameters 𝑛, 𝑘.
The Kneser Graph with parameters 𝑛, 𝑘 is the graph whose vertices are the 𝑘-subsets of [0, 1, . . . , 𝑛 − 1], and suchthat two vertices are adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Kneser Graph with parameters 5, 2.
EXAMPLES:
sage: KG = graphs.KneserGraph(5,2)
sage: sorted(KG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(KG)
True>>> from sage.all import *>>> KG = graphs.KneserGraph(Integer(5),Integer(2))>>> sorted(KG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]>>> P = graphs.PetersenGraph()>>> P.is_isomorphic(KG)
True

2.8. Various families of graphs

1193

Graph Theory, Release 10.4

sage.graphs.generators.families.LCFGraph(n, shift_list, repeats)
Return the cubic graph specified in LCF notation.
LCF (Lederberg-Coxeter-Fruchte) notation is a concise way of describing cubic Hamiltonian graphs. The way agraph is constructed is as follows. Since there is a Hamiltonian cycle, we first create a cycle on 𝑛 nodes. The
variable shift_list = [𝑠0 , 𝑠1 , ..., 𝑠𝑘−1 ] describes edges to be created by the following scheme: for each 𝑖 ∈{0, 1, . . . , 𝑘 − 1}, connect vertex 𝑖 to vertex (𝑖 + 𝑠𝑖 ) (mod 𝑛). Then, repeats specifies the number of times torepeat this process, where on the 𝑗-th repeat we connect vertex (𝑖 + 𝑗𝑘) (mod 𝑛) to vertex (𝑖 + 𝑗𝑘 + 𝑠𝑖 ) (mod 𝑛).
For more details, see the Wikipedia article LCF_notation and [Fru1977], [Gru2003] pp. 357-365, and [Led1965].
INPUT:• n – the number of nodes.
• shift_list – a list of integer shifts mod 𝑛.
• repeats – the number of times to repeat the process.
EXAMPLES:
sage: G = graphs.LCFGraph(4, [2,-2], 2)
˓→needs networkx
sage: G.is_isomorphic(graphs.TetrahedralGraph())˓→needs networkx
True

#␣
#␣

>>> from sage.all import *>>> G = graphs.LCFGraph(Integer(4), [Integer(2),-Integer(2)], Integer(2))˓→# needs networkx>>> G.is_isomorphic(graphs.TetrahedralGraph())˓→needs networkx
True

␣
#␣

sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2)
˓→needs networkx
sage: G.is_isomorphic(graphs.DodecahedralGraph())˓→needs networkx
True

#␣
#␣

>>> from sage.all import *>>> G = graphs.LCFGraph(Integer(20), [Integer(10),Integer(7),Integer(4),˓→Integer(4),-Integer(7),Integer(10),-Integer(4),Integer(7),-Integer(7),˓→Integer(4)], Integer(2))# needs networkx>>> G.is_isomorphic(graphs.DodecahedralGraph())˓→needs networkx
True

#␣

sage: G = graphs.LCFGraph(14, [5,-5], 7)
˓→needs networkx
sage: G.is_isomorphic(graphs.HeawoodGraph())˓→needs networkx
True

#␣
#␣

>>> from sage.all import *>>> G = graphs.LCFGraph(Integer(14), [Integer(5),-Integer(5)], Integer(7))˓→# needs networkx>>> G.is_isomorphic(graphs.HeawoodGraph())␣#␣(continues on next page)

1194

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)needs networkx
True˓→The largest cubic nonplanar graph of diameter three:sage: # needs networkx
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
˓→needs sage.plot#␣>>> from sage.all import *>>> # needs networkx>>> G = graphs.LCFGraph(Integer(20), [-Integer(10),-Integer(7),-Integer(5),˓→Integer(4),Integer(7),-Integer(10),-Integer(7),-Integer(4),Integer(5),˓→Integer(7),...
-Integer(10),-Integer(7),Integer(6),-Integer(5),˓→Integer(7),-Integer(10),-Integer(7),Integer(5),-Integer(6),Integer(7)],␣
˓→Integer(1))>>> G.degree()[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]>>> G.diameter()3>>> G.show()# long time#␣˓→needs sage.plot

PLOTTING: LCF Graphs are plotted as an 𝑛-cycle with edges in the middle, as described above.
sage.graphs.generators.families.LollipopGraph(n1, n2)
Returns a lollipop graph with 𝑛1 + 𝑛2 nodes.
A lollipop graph is a path graph (order 𝑛2 ) connected to a complete graph (order 𝑛1 ). (A barbell graph minus oneof 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 𝑛1 -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
˓→needs sage.plot>>> from sage.all import *>>> g = graphs.LollipopGraph(Integer(13),Integer(4)); g
Lollipop graph: Graph on 17 vertices>>> g.show()# long time
˓→needs sage.plot

2.8. Various families of graphs

#␣

#␣

1195

Graph Theory, Release 10.4

sage.graphs.generators.families.MathonPseudocyclicMergingGraph(M, t)
Mathon’s merging of classes in a pseudo-cyclic 3-class association scheme
Construct strongly regular graphs from p.97 of [BL1984].
INPUT:• M – the list of matrices in a pseudo-cyclic 3-class association scheme. The identity matrix must be the firstentry.
• t (integer) – the number of the graph, from 0 to 2.
See also:• is_muzychuk_S6()
sage.graphs.generators.families.MathonPseudocyclicStronglyRegularGraph(t,G=None,
L=None)Return a strongly regular graph on (4𝑡 + 1)(4𝑡 − 1)2 vertices from [Mat1978].
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 [Mat1978]. With this input, Mathon[Mat1978] 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 [ST1981].
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.
See also:• is_mathon_PC_srg()
EXAMPLES:
Using default G and L.
sage: from sage.graphs.generators.families import␣
˓→MathonPseudocyclicStronglyRegularGraphsage: G = MathonPseudocyclicStronglyRegularGraph(1); G˓→needs sage.modules sage.rings.finite_rings
Mathon s PC SRG on 45 vertices: Graph on 45 vertices
sage: G.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(45, 22, 10, 11)#␣#␣>>> from sage.all import *>>> from sage.graphs.generators.families import␣
˓→MathonPseudocyclicStronglyRegularGraph(continues on next page)

1196

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G = MathonPseudocyclicStronglyRegularGraph(Integer(1)); G˓→# needs sage.modules sage.rings.finite_rings
Mathon s PC SRG on 45 vertices: Graph on 45 vertices>>> G.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(45, 22, 10, 11)␣#␣

Supplying G and L (constructed from the automorphism group of G). The entries of L can’t be tested directly
because there’s some unpredictability in the way that GAP chooses a representative in NormalSubgroups(),the function that underlies our own normal_subgroups() method:
sage: # needs sage.groups sage.libs.gap sage.rings.finite_rings
sage: G = graphs.PaleyGraph(9)sage: a = G.automorphism_group(partition=[sorted(G)])
sage: it = (x for x in a.normal_subgroups() if x.order() == 9)sage: subg = next(iter(it))
sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage())....:
for z in subg]
sage: ff = list(map(lambda y: (y[0]-1,y[1]-1),....:
Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_tuples()[1:]))
sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff))
sage: G.relabel(range(9))
sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L)
sage: G3x3.is_strongly_regular(parameters=True)(441, 220, 109, 110)
sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27
sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2)sage: G9.is_strongly_regular(parameters=True)(441, 220, 109, 110)
sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss
9>>> from sage.all import *>>> # needs sage.groups sage.libs.gap sage.rings.finite_rings>>> G = graphs.PaleyGraph(Integer(9))>>> a = G.automorphism_group(partition=[sorted(G)])>>> it = (x for x in a.normal_subgroups() if x.order() == Integer(9))>>> subg = next(iter(it))>>> r = [matrix(libgap.PermutationMat(libgap(z), Integer(9)).sage())...
for z in subg]>>> ff = list(map(lambda y: (y[Integer(0)]-Integer(1),y[Integer(1)]-Integer(1)),...
Permutation(map(lambda x: Integer(1)+r.index(x**-Integer(1)), r)).
˓→cycle_tuples()[Integer(1):]))>>> L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(Integer(1),len(ff)+Integer(1)),
˓→ ff))>>> G.relabel(range(Integer(9)))>>> G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(Integer(2), G=G, L=L)>>> G3x3.is_strongly_regular(parameters=True)(441, 220, 109, 110)>>> G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss
27>>> G9 = graphs.MathonPseudocyclicStronglyRegularGraph(Integer(2))>>> G9.is_strongly_regular(parameters=True)(441, 220, 109, 110)>>> G9.automorphism_group(algorithm="bliss").order() # optional - bliss(continues on next page)2.8. Various families of graphs

1197Graph Theory, Release 10.4

(continued from previous page)9

sage.graphs.generators.families.MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed',
verbose=False)
Return a strongly regular graph of S6 type from [Muz2007] on 𝑛𝑑 ((𝑛𝑑 − 1)/(𝑛 − 1) + 1) vertices.
The construction depends upon a number of parameters, two of them, 𝑛 and 𝑑, mandatory, and Φ and Σ mappings𝑑−1
defined in [Muz2007]. These graphs have parameters (𝑚𝑛𝑑 , 𝑛𝑑−1 (𝑚−1)−1, 𝜇−2, 𝜇), where 𝜇 = 𝑛 𝑛−1−1 𝑛𝑑−1𝑑−1
and 𝑚 := 𝑛𝑛−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 [Muz2007].
INPUT:• n (integer) – a prime power• d (integer) – must be odd if 𝑛 is odd• Phi is an optional parameter of the construction; it must be either–

fixed – this will generate fixed default Φ𝑖 , for 𝑖 ∈ 𝑀 , or–random – Φ𝑖 are generated at random, or– A dictionary describing the functions Φ𝑖 ; for 𝑖 ∈ 𝑀 , Phi[(i, T)] in 𝑀 , for each edge T of 𝐿 on 𝑖. Also,
each Φ𝑖 must be injective.
• Sigma is an optional parameter of the construction; it must be either–

fixed – this will generate a fixed default Σ, or–random – Σ is generated at random.

• verbose (Boolean) – default is False. If True, print progress information
See also:• is_muzychuk_S6()

Todo: Implement the possibility to explicitly supply the parameter Σ of the construction.
EXAMPLES:
sage: # needs sage.combinat sage.modules sage.rings.finite_rings
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)

1198

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.combinat sage.modules sage.rings.finite_rings>>> graphs.MuzychukS6Graph(Integer(3), Integer(3)).is_strongly_
˓→regular(parameters=True)(378, 116, 34, 36)>>> phi = {(Integer(2),(Integer(0),Integer(2))):Integer(0), (Integer(1),˓→(Integer(1),Integer(3))):Integer(1), (Integer(0),(Integer(0),˓→Integer(3))):Integer(1), (Integer(2),(Integer(1),Integer(2))):Integer(1),...
(Integer(1),(Integer(1),Integer(2))):Integer(0), (Integer(0),˓→(Integer(0),Integer(2))):Integer(0), (Integer(3),(Integer(0),˓→Integer(3))):Integer(0), (Integer(3),(Integer(1),Integer(3))):Integer(1)}>>> graphs.MuzychukS6Graph(Integer(2), Integer(2), Phi=phi).is_strongly_
˓→regular(parameters=True)(16, 5, 0, 2)

sage.graphs.generators.families.MycielskiGraph(k=1, relabel=True)
Returns the 𝑘-th Mycielski Graph.
The graph 𝑀𝑘 is triangle-free and has chromatic number equal to 𝑘. These graphs show, constructively, that there
are triangle-free graphs with arbitrarily high chromatic number.
The Mycielski graphs are built recursively starting with 𝑀0 , an empty graph; 𝑀1 , a single vertex graph; and 𝑀2 isthe 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 𝑣𝑗 .
For more details, see the Wikipedia article Mycielskian.
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>>> from sage.all import *>>> g = graphs.MycielskiGraph(Integer(5))>>> g.is_triangle_free()True>>> 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

2.8. Various families of graphs

1199Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.MycielskiGraph(Integer(4))>>> g.is_isomorphic(graphs.GrotzschGraph())
True

sage.graphs.generators.families.MycielskiStep(g)Perform one iteration of the Mycielski construction.
See the documentation for MycielskiGraph which uses this method. We expose it to all users in case they
may find it useful.
EXAMPLE. One iteration of the Mycielski step applied to the 5-cycle yields a graph isomorphic to the Grotzsch
graph
sage: g = graphs.CycleGraph(5)sage: h = graphs.MycielskiStep(g)sage: h.is_isomorphic(graphs.GrotzschGraph())
True>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> h = graphs.MycielskiStep(g)>>> h.is_isomorphic(graphs.GrotzschGraph())
True

sage.graphs.generators.families.NKStarGraph(n, k)
Returns the (𝑛, 𝑘)-star graph.
The vertices of the (𝑛, 𝑘)-star graph are the set of all arrangements of 𝑛 symbols into labels of length 𝑘. There are
two adjacency rules for the (𝑛, 𝑘)-star graph. First, two vertices are adjacent if one can be obtained from the otherby swapping the first symbol with another symbol. Second, two vertices are adjacent if one can be obtained fromthe other by swapping the first symbol with an external symbol (a symbol not used in the original label).
INPUT:• n – integer; number of symbols• k – integer; length of the labels of the vertices
EXAMPLES:
sage: g = graphs.NKStarGraph(4,2)
sage: g.plot()# long time
˓→needs sage.plot
Graphics object consisting of 31 graphics primitives>>> from sage.all import *>>> g = graphs.NKStarGraph(Integer(4),Integer(2))>>> g.plot()# long time
˓→needs sage.plot
Graphics object consisting of 31 graphics primitives#␣#␣

REFERENCES:[CC1995]
AUTHORS:• Michael Yurko (2009-09-01)

1200

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage.graphs.generators.families.NStarGraph(n)Returns the 𝑛-star graph.
The vertices of the 𝑛-star graph are the set of permutations on 𝑛 symbols. There is an edge between two vertices
if their labels differ only in the first and one other position.
INPUT:• n – integer; number of symbols
EXAMPLES:
sage: g = graphs.NStarGraph(4)sage: g.plot()# long time
˓→needs sage.plot
Graphics object consisting of 61 graphics primitives>>> from sage.all import *>>> g = graphs.NStarGraph(Integer(4))>>> g.plot()# long time
˓→needs sage.plot
Graphics object consisting of 61 graphics primitives#␣#␣

REFERENCES:[AHK1994]
AUTHORS:• Michael Yurko (2009-09-01)
sage.graphs.generators.families.OddGraph(n)Returns the Odd Graph with parameter 𝑛.
The Odd Graph with parameter 𝑛 is defined as the Kneser Graph with parameters 2𝑛 − 1, 𝑛 − 1. Equivalently, the
Odd Graph is the graph whose vertices are the 𝑛 − 1-subsets of [0, 1, . . . , 2(𝑛 − 1)], and such that two vertices are
adjacent if their corresponding sets are disjoint.
For example, the Petersen Graph can be defined as the Odd Graph with parameter 3.
EXAMPLES:
sage: OG = graphs.OddGraph(3)sage: sorted(OG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]
sage: P = graphs.PetersenGraph()
sage: P.is_isomorphic(OG)True>>> from sage.all import *>>> OG = graphs.OddGraph(Integer(3))>>> sorted(OG.vertex_iterator(), key=str)[{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5},{3, 4}, {3, 5}, {4, 5}]>>> P = graphs.PetersenGraph()>>> P.is_isomorphic(OG)True

2.8. Various families of graphs

1201

Graph Theory, Release 10.4

sage.graphs.generators.families.PaleyGraph(q)Paley graph with 𝑞 vertices
Parameter 𝑞 must be the power of a prime number and congruent to 1 mod 4.
EXAMPLES:
sage: G = graphs.PaleyGraph(9); G˓→needs sage.rings.finite_rings
Paley graph with parameter 9: Graph on 9 vertices
sage: G.is_regular()˓→needs sage.rings.finite_rings
True

#␣

#␣

>>> from sage.all import *>>> G = graphs.PaleyGraph(Integer(9)); G˓→# needs sage.rings.finite_rings
Paley graph with parameter 9: Graph on 9 vertices>>> G.is_regular()˓→needs sage.rings.finite_rings
True

␣

#␣

A Paley graph is always self-complementary:sage: G.is_self_complementary()
˓→needs sage.rings.finite_rings
True

#␣

>>> from sage.all import *>>> G.is_self_complementary()
˓→needs sage.rings.finite_rings
True

#␣

sage.graphs.generators.families.PasechnikGraph(n)Pasechnik strongly regular graph on (4𝑛 − 1)2 vertices
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(),also known as pseudo Latin squares graph 𝐿2𝑛−1 (4𝑛 − 1), constructed from a skew Hadamard matrix of order 4𝑛following [Pas1992].
See also:• is_orthogonal_array_block_graph()
EXAMPLES:
sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True)
˓→needs sage.combinat sage.modules(225, 98, 43, 42)
sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True)
˓→time, needs sage.combinat sage.modules(361, 162, 73, 72)
sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True)(1225, 578, 273, 272)#␣# long␣# not tested>>> from sage.all import *>>> graphs.PasechnikGraph(Integer(4)).is_strongly_regular(parameters=True)␣(continues on next page)

1202

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)# needs sage.combinat sage.modules(225, 98, 43, 42)>>> graphs.PasechnikGraph(Integer(5)).is_strongly_regular(parameters=True)
˓→long time, needs sage.combinat sage.modules(361, 162, 73, 72)>>> graphs.PasechnikGraph(Integer(9)).is_strongly_regular(parameters=True)
˓→tested(1225, 578, 273, 272)
˓→#␣# not␣

sage.graphs.generators.families.RingedTree(k, vertex_labels=True)
Return the ringed tree on k-levels.
A ringed tree of level 𝑘 is a binary tree with 𝑘 levels (counting the root as a level), in which all vertices at the samelevel 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 [CFHM2013].
INPUT:• k – the number of levels of the ringed tree.
• vertex_labels (boolean) – whether to label vertices as binary words (default) or as integers.
EXAMPLES:
sage: # needs networkx
sage: G = graphs.RingedTree(5)sage: P = G.plot(vertex_labels=False, vertex_size=10)
˓→needs sage.plot
sage: P.show()# long time
˓→needs sage.plot
sage: G.vertices(sort=True)[ , 0 , 00 , 000 , 0000 , 0001 , 001 , 0010 , 0011 , 01 ,
010 , 0100 , 0101 , 011 , 0110 , 0111 , 1 , 10 , 100 ,1000 , 1001 , 101 , 1010 , 1011 , 11 , 110 , 1100 , 1101 ,
111 , 1110 , 1111 ]>>> from sage.all import *>>> # needs networkx>>> G = graphs.RingedTree(Integer(5))>>> P = G.plot(vertex_labels=False, vertex_size=Integer(10))˓→# needs sage.plot>>> P.show()# long time
˓→needs sage.plot>>> G.vertices(sort=True)[ , 0 , 00 , 000 , 0000 , 0001 , 001 , 0010 , 0011 , 01 ,
010 , 0100 , 0101 , 011 , 0110 , 0111 , 1 , 10 , 100 ,1000 , 1001 , 101 , 1010 , 1011 , 11 , 110 , 1100 , 1101 ,
111 , 1110 , 1111 ]

#␣
#␣

␣
#␣

sage.graphs.generators.families.RoseWindowGraph(n, a, r)
Return a rose window graph with 2𝑛 nodes.
The rose window graphs is a family of tetravalant graphs introduced in [Wilson2008]. The parameters 𝑛, 𝑎 and 𝑟
are integers such that 𝑛 > 2, 1 ≤ 𝑎, 𝑟 < 𝑛, and 𝑟 ̸= 𝑛/2.

2.8. Various families of graphs1203

Graph Theory, Release 10.4

INPUT:• n – the number of nodes is 2 * 𝑛• a – integer such that 1 ≤ 𝑎 < 𝑛 determining a-spoke edges• r – integer such that 1 ≤ 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first 𝑛 nodes drawn on theouter circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that. The
inner circle is drawn with the (𝑛)th node at the top, then counterclockwise as well. Vertices in the outer circle
are connected in the circular manner, vertices in the inner circle are connected when their label have difference 𝑟(mod 𝑛). Vertices on the outer rim are connected with the vertices on the inner rim when they are at the same
position and when they are 𝑎 apart.
EXAMPLES:
The vertices of a rose window graph have all degree 4:
sage: G = graphs.RoseWindowGraph(5, 1, 2)
sage: all(G.degree(u) == 4 for u in G)
True>>> from sage.all import *>>> G = graphs.RoseWindowGraph(Integer(5), Integer(1), Integer(2))>>> all(G.degree(u) == Integer(4) for u in G)
True

The smallest rose window graph as parameters (3, 2, 1):
sage: G = graphs.RoseWindowGraph(3, 2, 1)
sage: all(G.degree(u) == 4 for u in G)
True>>> from sage.all import *>>> G = graphs.RoseWindowGraph(Integer(3), Integer(2), Integer(1))>>> all(G.degree(u) == Integer(4) for u in G)
True

sage.graphs.generators.families.SierpinskiGasketGraph(n)Return the Sierpinski Gasket graph of generation 𝑛.
All vertices but 3 have valence 4.
INPUT:• 𝑛 – an integer
OUTPUT:a graph 𝑆𝑛 with 3(3𝑛−1 + 1)/2 vertices and 3𝑛 edges, closely related to the famous Sierpinski triangle fractal.
All these graphs have a triangular shape, and three special vertices at top, bottom left and bottom right. These are
the only vertices of valence 2, all the other ones having valence 4.
The graph 𝑆1 (generation 1) is a triangle.
The graph 𝑆𝑛+1 is obtained from the disjoint union of three copies A,B,C of 𝑆𝑛 by identifying pairs of vertices:
the top vertex of A with the bottom left vertex of B, the bottom right vertex of B with the top vertex of C, and thebottom left vertex of C with the bottom right vertex of A.

1204

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

2.8. Various families of graphs

1205

Graph Theory, Release 10.4

See also:• HanoiTowerGraph(). There is another family of graphs called Sierpinski graphs, where all vertices but
3 have valence 3. They are available using graphs.HanoiTowerGraph(3, n).
• GeneralizedSierpinskiGraph()
EXAMPLES:
sage: # needs sage.modules
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>>> from sage.all import *>>> # needs sage.modules>>> s4 = graphs.SierpinskiGasketGraph(Integer(4)); s4
Graph on 42 vertices>>> s4.size()81>>> s4.degree_histogram()[0, 0, 3, 0, 39]>>> s4.is_hamiltonian()
True

REFERENCES:[LLWC2011]sage.graphs.generators.families.SquaredSkewHadamardMatrixGraph(n)Pseudo-𝑂𝐴(2𝑛, 4𝑛 − 1)-graph from a skew Hadamard matrix of order 4𝑛
A strongly regular graph with parameters of the orthogonal array graph OrthogonalArrayBlockGraph(),also known as pseudo Latin squares graph 𝐿2𝑛 (4𝑛 − 1), constructed from a skew Hadamard matrix of order 4𝑛,
due to Goethals and Seidel, see [BL1984].
See also:• is_orthogonal_array_block_graph()
EXAMPLES:
sage: # needs sage.combinat sage.modules
sage: G = graphs.SquaredSkewHadamardMatrixGraph(4)sage: G.is_strongly_regular(parameters=True)(225, 112, 55, 56)
sage: G = graphs.SquaredSkewHadamardMatrixGraph(5)sage: G.is_strongly_regular(parameters=True)# long time(361, 180, 89, 90)
sage: G = graphs.SquaredSkewHadamardMatrixGraph(9)sage: G.is_strongly_regular(parameters=True)# not tested(1225, 612, 305, 306)

1206

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> G = graphs.SquaredSkewHadamardMatrixGraph(Integer(4))>>> G.is_strongly_regular(parameters=True)(225, 112, 55, 56)>>> G = graphs.SquaredSkewHadamardMatrixGraph(Integer(5))>>> G.is_strongly_regular(parameters=True)# long time(361, 180, 89, 90)>>> G = graphs.SquaredSkewHadamardMatrixGraph(Integer(9))>>> G.is_strongly_regular(parameters=True)# not tested(1225, 612, 305, 306)

sage.graphs.generators.families.SwitchedSquaredSkewHadamardMatrixGraph(n)A strongly regular graph in Seidel switching class of SquaredSkewHadamardMatrixGraph().
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 lattergraph (see [BH2012]) coincides with the set of parameters of the complement of the graph returned by this function.
See also:• is_switch_skewhad()
EXAMPLES:
sage: # needs sage.combinat sage.modules
sage: g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(4)sage: g.is_strongly_regular(parameters=True)(226, 105, 48, 49)
sage: from sage.combinat.designs.twographs import twograph_descendantsage: twograph_descendant(g, 0).is_strongly_regular(parameters=True)(225, 112, 55, 56)
sage: gc = g.complement()
sage: twograph_descendant(gc, 0).is_strongly_regular(parameters=True)(225, 112, 55, 56)>>> from sage.all import *>>> # needs sage.combinat sage.modules>>> g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(Integer(4))>>> g.is_strongly_regular(parameters=True)(226, 105, 48, 49)>>> from sage.combinat.designs.twographs import twograph_descendant>>> twograph_descendant(g, Integer(0)).is_strongly_regular(parameters=True)(225, 112, 55, 56)>>> gc = g.complement()>>> twograph_descendant(gc, Integer(0)).is_strongly_regular(parameters=True)(225, 112, 55, 56)

sage.graphs.generators.families.TabacjnGraph(n, a, b, r)
Return a Tabačjn graph with 2𝑛 nodes.
The Tabačjn graphs is a family of pentavalent bicirculants graphs proposed in [AHKOS2014] as a generalizationof generalized Petersen graphs. The parameters 𝑛, 𝑎, 𝑏, 𝑟 are integers such that 𝑛 ≥ 3, 1 ≤ 𝑎, 𝑏, 𝑟 ≤ 𝑛 − 1, with𝑎 ̸= 𝑏 and 𝑟 ̸= 𝑛/2.
INPUT:
2.8. Various families of graphs

1207

Graph Theory, Release 10.4

• n – the number of nodes is 2 * 𝑛• a – integer such that 0 < 𝑎 < 𝑛 and 𝑎 ̸= 𝑏, that determines a-spoke edges• b – integer such that 0 < 𝑏 < 𝑛 and 𝑏 ̸= 𝑎, that determines b-spoke edges• r – integer such that 0 < 𝑟 < 𝑛 and 𝑟 ̸= 𝑛/2 determining how inner vertices are connected
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the rose window graphs are displayed as an inner and outer cycle pair, with the first 𝑛 nodes drawn on theouter circle. The first (0) node is drawn at the top of the outer-circle, moving counterclockwise after that. The
inner circle is drawn with the (𝑛)th node at the top, then counterclockwise as well. Vertices in the outer circle
are connected in the circular manner, vertices in the inner circle are connected when their label have difference 𝑟(mod 𝑛). Vertices on the outer rim are connected with the vertices on the inner rim when they are at the same
position and when they are 𝑎 and 𝑏 apart.
EXAMPLES:
sage: G = graphs.TabacjnGraph(3, 1, 2, 1)
sage: G.degree()[5, 5, 5, 5, 5, 5]
sage: G.is_isomorphic(graphs.CompleteGraph(6))
Truesage: G = graphs.TabacjnGraph(6, 1, 5, 2)
sage: I = graphs.IcosahedralGraph()
sage: G.is_isomorphic(I)
True>>> from sage.all import *>>> G = graphs.TabacjnGraph(Integer(3), Integer(1), Integer(2), Integer(1))>>> G.degree()[5, 5, 5, 5, 5, 5]>>> G.is_isomorphic(graphs.CompleteGraph(Integer(6)))
True>>> G = graphs.TabacjnGraph(Integer(6), Integer(1), Integer(5), Integer(2))>>> I = graphs.IcosahedralGraph()>>> G.is_isomorphic(I)Truesage.graphs.generators.families.TadpoleGraph(n1, n2)
Return a tadpole graph with 𝑛1 + 𝑛2 nodes.
A tadpole graph is a path graph (order 𝑛2 ) connected to a cycle graph (order 𝑛1 ).
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 𝑛1 -th node at a 45 degree angle above theright 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
˓→needs sage.plot#␣>>> from sage.all import *>>> g = graphs.TadpoleGraph(Integer(13), Integer(4)); g(continues on next page)

1208

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

Tadpole graph: Graph on 17 vertices>>> g.show()˓→needs sage.plot# long time#␣

sage.graphs.generators.families.TuranGraph(n, r)
Returns the Turan graph with parameters 𝑛, 𝑟.
Turan graphs are complete multipartite graphs with 𝑛 vertices and 𝑟 subsets, denoted 𝑇 (𝑛, 𝑟), with the property
that the sizes of the subsets are as close to equal as possible. The graph 𝑇 (𝑛, 𝑟) will have 𝑛 (mod 𝑟) subsets of size⌊𝑛/𝑟⌋ and 𝑟 − (𝑛 (mod 𝑟)) subsets of size ⌈𝑛/𝑟⌉. See the Wikipedia article Turan_graph for more information.
INPUT:• n – integer; the number of vertices in the graph• r – integer; the number of partitions of the graph
EXAMPLES:The Turan graph is a complete multipartite graph:
sage: g = graphs.TuranGraph(13, 4)
sage: k = graphs.CompleteMultipartiteGraph([3,3,3,4])
sage: g.is_isomorphic(k)True>>> from sage.all import *>>> g = graphs.TuranGraph(Integer(13), Integer(4))>>> k = graphs.CompleteMultipartiteGraph([Integer(3),Integer(3),Integer(3),˓→Integer(4)])>>> g.is_isomorphic(k)
True
2

2

−𝑠 )
The Turan graph 𝑇 (𝑛, 𝑟) has (𝑟−1)(𝑛+ 𝑠(𝑠−1)edges, where 𝑠 = 𝑛 mod 𝑟 (Issue #34249):2𝑟
2

sage: n = 12
sage: r = 8
sage: g = graphs.TuranGraph(n, r)
sage: def count(n, r):....:s = n % r....:
return (r - 1) * (n**2 - s**2) / (2*r) + s*(s - 1)/2
sage: g.size() == count(n, r)
True
sage: n = randint(3, 100)
sage: r = randint(2, n - 1)sage: g = graphs.TuranGraph(n, r)
sage: g.size() == count(n, r)
True>>> from sage.all import *>>> n = Integer(12)>>> r = Integer(8)>>> g = graphs.TuranGraph(n, r)>>> def count(n, r):...
s = n % r...
return (r - Integer(1)) * (n**Integer(2) - s**Integer(2)) /␣˓→(Integer(2)*r) + s*(s - Integer(1))/Integer(2)(continues on next page)2.8. Various families of graphs1209

Graph Theory, Release 10.4

(continued from previous page)>>> g.size() == count(n, r)
True>>> n = randint(Integer(3), Integer(100))>>> r = randint(Integer(2), n - Integer(1))>>> g = graphs.TuranGraph(n, r)>>> g.size() == count(n, r)
True

sage.graphs.generators.families.WheelGraph(n)Returns a Wheel graph with n nodes.
A Wheel graph is a basic structure where one node is connected to all other nodes and those (outer) nodes areconnected 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 therest following in a counterclockwise manner.
With the wheel graph, we see that it doesn’t take a very large 𝑛 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: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....: k = graphs.WheelGraph(i+3)....: g.append(k)...
sage: for i in range(3):....: n = []....: for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....: j.append(n)...
sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):... k = graphs.WheelGraph(i+Integer(3))... g.append(k)...
>>> for i in range(Integer(3)):... n = []... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)...
(continues on next page)

1210

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphics_array(j)>>> G.show()# long time

Next, using the spring-layout algorithm:
sage: # needs networkx sage.plot
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 = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> import networkx>>> g = []>>> j = []>>> for i in range(Integer(9)):... spr = networkx.wheel_graph(i+Integer(3))... k = Graph(spr)... g.append(k)...
>>> for i in range(Integer(3)):... n = []... for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))... j.append(n)...
>>> G = graphics_array(j)>>> G.show()# long time

Compare the plotting:sage: # needs networkx sage.plot
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>>> from sage.all import *>>> # needs networkx sage.plot>>> n = networkx.wheel_graph(Integer(23))>>> spring23 = Graph(n)(continues on next page)2.8. Various families of graphs

1211

Graph Theory, Release 10.4

(continued from previous page)>>> posdict23 = graphs.WheelGraph(Integer(23))>>> spring23.show()# long time>>> posdict23.show() # long time

sage.graphs.generators.families.WindmillGraph(k, n)
Return the Windmill graph 𝑊 𝑑(𝑘, 𝑛).
The windmill graph 𝑊 𝑑(𝑘, 𝑛) is an undirected graph constructed for 𝑘 ≥ 2 and 𝑛 ≥ 2 by joining 𝑛 copies of thecomplete 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>>> from sage.all import *>>> n = Integer(5)>>> W = graphs.WindmillGraph(Integer(2), n)>>> 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>>> from sage.all import *>>> n = Integer(5)>>> W = graphs.WindmillGraph(Integer(3), n)>>> 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

1212

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> W = graphs.WindmillGraph(Integer(3), Integer(2))>>> 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() == kTrue>>> from sage.all import *>>> n,k = Integer(5),Integer(6)>>> W = graphs.WindmillGraph(k, n)>>> W.chromatic_number() == kTruesage.graphs.generators.families.chang_graphs()
Return the three Chang graphs.
Three of the four strongly regular graphs of parameters (28, 12, 6, 4) are called the Chang graphs. The fourth isthe 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)>>> from sage.all import *>>> chang_graphs = graphs.chang_graphs()>>> K8 = graphs.CompleteGraph(Integer(8))>>> T8 = K8.line_graph()>>> four_srg = chang_graphs + [T8]>>> 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)>>> from itertools import combinations>>> for g1,g2 in combinations(four_srg,Integer(2)):...
assert not g1.is_isomorphic(g2)Construct the Chang graphs by Seidel switching:

2.8. Various families of graphs1213

Graph Theory, Release 10.4

sage: c3c5 = graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5))
sage: c8 = graphs.CycleGraph(8)sage: s = [K8.subgraph_search(c8).edges(sort=False),
˓→needs sage.modules....:[(0,1,None),(2,3,None),(4,5,None),(6,7,None)],....:K8.subgraph_search(c3c5).edges(sort=False)]
sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G)˓→needs sage.modules....: for x, G in zip(s, chang_graphs)][True, True, True]#␣#␣>>> from sage.all import *>>> c3c5 = graphs.CycleGraph(Integer(3)).disjoint_union(graphs.
˓→CycleGraph(Integer(5)))>>> c8 = graphs.CycleGraph(Integer(8))>>> s = [K8.subgraph_search(c8).edges(sort=False),#␣˓→needs sage.modules...
[(Integer(0),Integer(1),None),(Integer(2),Integer(3),None),(Integer(4),˓→Integer(5),None),(Integer(6),Integer(7),None)],...
K8.subgraph_search(c3c5).edges(sort=False)]>>> [T8.seidel_switching(x, inplace=False).is_isomorphic(G)#␣˓→needs sage.modules... for x, G in zip(s, chang_graphs)][True, True, True]sage.graphs.generators.families.line_graph_forbidden_subgraphs()
Returns the 9 forbidden subgraphs of a line graph.
See the Wikipedia article Line_graph for more information.
The graphs are returned in the ordering given by the Wikipedia drawing, read from left to right and from top tobottom.
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]>>> from sage.all import *>>> 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]

1214

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage.graphs.generators.families.nauty_gentreeg(options='', debug=False)
Return a generator which creates non-isomorphic trees from nauty’s gentreeg program.
INPUT:• options – string (default: ""); a string passed to gentreeg as if it was run at a system command line.
At a minimum, you must pass the number of vertices you desire. Sage expects the graphs to be in nauty’s“sparse6” format, do not set an option to change this default or results will be unpredictable.
• debug – boolean (default: False); if True the first line of gentreeg’s output to standard error iscaptured and the first call to the generator’s next() function will return this line as a string. A line leadingwith “>A” indicates a successful initiation of the program with some information on the arguments, while aline beginning with “>E” indicates an error with the input.
The possible options, obtained as output of gentreeg -help:n: the number of vertices. Must be in range 1..128
res/mod: only generate subset res out of subsets 0..mod-1-D<int>: an upper bound for the maximum degree-Z<int>:<int> : bounds on the diameter-q: suppress auxiliary output

Options which cause gentreeg to use an output format different than the sparse6 format are not listed above (-p,-l, -u) as they will confuse the creation of a Sage graph. The res/mod option can be useful when using the output
in a routine run several times in parallel.
OUTPUT:
A generator which will produce the graphs as Sage graphs. These will be simple graphs: no loops, no multiple
edges, no directed edges.
See also:
trees() – another generator of trees
EXAMPLES:
The generator can be used to construct trees for testing, one at a time (usually inside a loop). Or it can be used tocreate an entire list all at once if there is sufficient memory to contain it:
sage: gen = graphs.nauty_gentreeg("4")
sage: next(gen)Graph on 4 vertices
sage: next(gen)Graph on 4 vertices
sage: next(gen)Traceback (most recent call last):...
StopIteration>>> from sage.all import *>>> gen = graphs.nauty_gentreeg("4")>>> next(gen)Graph on 4 vertices>>> next(gen)Graph on 4 vertices>>> next(gen)Traceback (most recent call last):...
StopIteration

2.8. Various families of graphs

1215Graph Theory, Release 10.4

The number of trees on the first few vertex counts. This agrees with OEIS sequence A000055:
sage: [len(list(graphs.nauty_gentreeg(str(i)))) for i in range(1, 15)]
[1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]>>> from sage.all import *>>> [len(list(graphs.nauty_gentreeg(str(i)))) for i in range(Integer(1),␣
˓→Integer(15))][1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]

The debug switch can be used to examine gentreeg’s reaction to the input in the options string. We illustrate
success. (A failure will be a string beginning with “>E”.) Passing the “-q” switch to gentreeg will suppress theindicator of a successful initiation, and so the first returned value might be an empty string if debug is True:
sage: gen = graphs.nauty_gentreeg("4", debug=True)
sage: print(next(gen))>A ...gentreeg ...
sage: gen = graphs.nauty_gentreeg("4 -q", debug=True)
sage: next(gen)>>> from sage.all import *>>> gen = graphs.nauty_gentreeg("4", debug=True)>>> print(next(gen))>A ...gentreeg ...
>>> gen = graphs.nauty_gentreeg("4 -q", debug=True)>>> next(gen)sage.graphs.generators.families.petersen_family(generate=False)
Returns the Petersen family
The Petersen family is a collection of 7 graphs which are the forbidden minors of the linklessly embeddable graphs.
For more information see the Wikipedia article Petersen_family.
INPUT:• generate (boolean) – whether to generate the family from the Δ−𝑌 transformations. When set to False(default) a hardcoded version of the graphs (with a prettier layout) is returned.
EXAMPLES:
sage: graphs.petersen_family()[Petersen graph: Graph on 10 vertices,
Complete graph: Graph on 6 vertices,
Multipartite Graph with set sizes [3, 3, 1]: Graph on 7 vertices,
Graph on 8 vertices,
Graph on 9 vertices,
Graph on 7 vertices,
Graph on 8 vertices]>>> from sage.all import *>>> 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,(continues on next page)

1216

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

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)
˓→needs sage.modules
sage: F1 = [g.canonical_label().graph6_string() for g in F1]
sage: F2 = [g.canonical_label().graph6_string() for g in F2]
˓→needs sage.modules
sage: set(F1) == set(F2)˓→needs sage.modules
True>>> from sage.all import *>>> F1 = graphs.petersen_family(generate=False)>>> F2 = graphs.petersen_family(generate=True)
˓→needs sage.modules>>> F1 = [g.canonical_label().graph6_string() for g in F1]>>> F2 = [g.canonical_label().graph6_string() for g in F2]
˓→needs sage.modules>>> set(F1) == set(F2)˓→needs sage.modules
True

#␣

#␣
#␣

#␣

#␣
#␣

sage.graphs.generators.families.trees(vertices)
Returns a generator of the distinct trees on a fixed number of vertices.
INPUT:• vertices – the size of the trees created.
OUTPUT:
A generator which creates an exhaustive, duplicate-free listing of the connected free (unlabeled) trees with vertices number of vertices. A tree is a graph with no cycles.
ALGORITHM:
Uses an algorithm that generates each new tree in constant time. See the documentation for, and implementationof, 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](continues on next page)2.8. Various families of graphs

1217Graph Theory, Release 10.4

(continued from previous page)[4, 2, 2, 1, 1, 1, 1][5, 2, 1, 1, 1, 1, 1][6, 1, 1, 1, 1, 1, 1]>>> from sage.all import *>>> tree_iterator = graphs.trees(Integer(7))>>> 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]>>> from sage.all import *>>> [len(list(graphs.trees(i))) for i in range(Integer(0), Integer(15))][1, 1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]

2.9 Basic graphs
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.basic.BullGraph()
Return a bull graph with 5 nodes.
A bull graph is named for its shape. It’s a triangle with horns. See the Wikipedia article Bull_graph for more
information.
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the bullgraph 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()˓→needs sage.plot

1218# long time#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.BullGraph(); g
Bull graph: Graph on 5 vertices>>> g.show()˓→needs sage.plot# 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 planarwith chromatic number 3 and chromatic index also 3:
sage: g.order(); g.size()55
sage: g.radius(); g.diameter(); g.girth()2
3
3
sage: g.chromatic_number()3>>> from sage.all import *>>> g.order(); g.size()55>>> g.radius(); g.diameter(); g.girth()2
3
3>>> 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 forgraphs, i.e. det(𝑥𝐼 − 𝐴), where 𝑥 is a variable, 𝐴 the adjacency matrix of the graph, and 𝐼 the identity matrix ofthe same dimensions as 𝐴:
sage: # needs sage.libs.flint
sage: chrompoly = g.chromatic_polynomial()
sage: x = chrompoly.parent()( x )sage: x * (x - 2) * (x - 1)^3 == chrompoly
True
sage: # needs sage.libs.flint sage.modules
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]
[0 1 0 0 0]
[0 0 1 0 0]
sage: Id = identity_matrix(ZZ, M.nrows())
sage: D = x*Id - M
sage: D.determinant() == charpoly
˓→needs sage.symbolicTruesage: x * (x^2 - x - 3) * (x^2 + x - 1) == charpoly
True

2.9. Basic graphs

#␣

1219

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.libs.flint>>> chrompoly = g.chromatic_polynomial()>>> x = chrompoly.parent()( x )>>> x * (x - Integer(2)) * (x - Integer(1))**Integer(3) == chrompoly
True>>> # needs sage.libs.flint sage.modules>>> charpoly = g.characteristic_polynomial()>>> M = g.adjacency_matrix(); M[0 1 1 0 0]
[1 0 1 1 0]
[1 1 0 0 1]
[0 1 0 0 0]
[0 0 1 0 0]>>> Id = identity_matrix(ZZ, M.nrows())>>> D = x*Id - M>>> D.determinant() == charpoly#␣˓→needs sage.symbolicTrue>>> x * (x**Integer(2) - x - Integer(3)) * (x**Integer(2) + x - Integer(1)) ==␣
˓→charpoly
Truesage.graphs.generators.basic.ButterflyGraph()
Return the butterfly graph.
Let 𝐶3 be the cycle graph on 3 vertices. The butterfly or bowtie graph is obtained by joining two copies of 𝐶3
at a common vertex, resulting in a graph that is isomorphic to the friendship graph 𝐹2 . See the Wikipedia article
Butterfly_graph for more information.
See also:• 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()˓→needs sage.plot
sage: G.is_planar()True
sage: G.order()5sage: G.size()
6>>> from sage.all import *>>> G = graphs.ButterflyGraph(); G
Butterfly graph: Graph on 5 vertices>>> G.show()˓→needs sage.plot>>> G.is_planar()True# long time

# long time#␣#␣(continues on next page)1220

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G.order()5>>> G.size()6

It has diameter 2, girth 3, and radius 1:
sage: G.diameter()2
sage: G.girth()3
sage: G.radius()
1>>> from sage.all import *>>> G.diameter()2>>> G.girth()3>>> G.radius()
1

The butterfly graph is Eulerian, with chromatic number 3:
sage: G.is_eulerian()True
sage: G.chromatic_number()3>>> from sage.all import *>>> G.is_eulerian()
True>>> G.chromatic_number()3

sage.graphs.generators.basic.CircularLadderGraph(n)Return a circular ladder graph with 2 * 𝑛 nodes.
A Circular ladder graph is a ladder graph that is connected at the ends, i.e.: a ladder bent around so that top meets
bottom. Thus it can be described as two parallel cycle graphs connected at each corresponding node pair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the circular ladder graph is displayed as an inner and outer cycle pair, with the first 𝑛 nodes drawn on the
inner circle. The first (0) node is drawn at the top of the inner-circle, moving clockwise after that. The outer circle
is drawn with the (𝑛 + 1)-th node at the top, then counterclockwise as well. When 𝑛 == 2, we rotate the outercircle by an angle of 𝜋/8 to ensure that all edges are visible (otherwise the 4 vertices of the graph would be placedon a single line).
EXAMPLES:
Construct and show a circular ladder graph with 26 nodes:
sage: g = graphs.CircularLadderGraph(13)sage: g.show()# long time
˓→needs sage.plot

2.9. Basic graphs

#␣

1221

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CircularLadderGraph(Integer(13))>>> g.show()# long time
˓→needs sage.plot#␣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):˓→needs sage.plot....:
n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)˓→needs sage.plot
sage: G.show()# long time
˓→needs sage.plot

#␣

#␣
#␣

>>> from sage.all import *>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CircularLadderGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):␣˓→# needs sage.plot...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)#␣˓→needs sage.plot>>> G.show()# long time#␣˓→needs sage.plot

sage.graphs.generators.basic.ClawGraph()
Return a claw graph.
A claw graph is named for its shape. It is actually a complete bipartite graph with (n1, n2) = (1, 3).
PLOTTING: See CompleteBipartiteGraph().
EXAMPLES:Show a Claw graph:
sage: (graphs.ClawGraph()).show()˓→needs sage.plot>>> from sage.all import *>>> (graphs.ClawGraph()).show()˓→needs sage.plot

1222# long time

# long time#␣#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

Inspect a Claw graph:
sage: G = graphs.ClawGraph()
sage: G
Claw graph: Graph on 4 vertices>>> from sage.all import *>>> G = graphs.ClawGraph()>>> G
Claw graph: Graph on 4 vertices

sage.graphs.generators.basic.CompleteBipartiteGraph(p, q, set_position=True)
Return a Complete Bipartite Graph on 𝑝 + 𝑞 vertices.
A Complete Bipartite Graph is a graph with its vertices partitioned into two groups, 𝑉1 = {0, ..., 𝑝 − 1} and𝑉2 = {𝑝, ..., 𝑝 + 𝑞 − 1}. Each 𝑢 ∈ 𝑉1 is connected to every 𝑣 ∈ 𝑉2 .
INPUT:• p, q – number of vertices in each side
• set_position – boolean (default True); if set to True, we assign positions to the vertices so that theset of cardinality 𝑝 is on the line 𝑦 = 1 and the set of cardinality 𝑞 is on the line 𝑦 = 0.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each complete bipartite graph will be displayed with the first 𝑝 nodes on the top row (at 𝑦 = 1) from left toright. The remaining 𝑞 nodes appear at 𝑦 = 0, also from left to right. The shorter row (partition with fewer nodes)
is stretched to the same length as the longer row, unless the shorter row has 1 node; in which case it is centered.
The 𝑥 values in the plot are in domain [0, max(𝑝, 𝑞)].
In the Complete Bipartite graph, there is a visual difference in using the spring-layout algorithm vs. the position
dictionary used in this constructor. The position dictionary flattens the graph and separates the partitioned nodes,
making it clear which nodes an edge is connected to. The Complete Bipartite graph plotted with the spring-layout
algorithm tends to center the nodes in 𝑝 (see spring_med in examples below), thus overlapping its nodes andedges, making it typically hard to decipher.
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor. Feel free to race the constructors below inthe 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: # needs networkx
sage: import networkx
sage: n = networkx.complete_bipartite_graph(389, 157)
# long time
sage: spring_big = Graph(n)# long time
sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157)
# long time>>> from sage.all import *>>> # needs networkx>>> import networkx>>> n = networkx.complete_bipartite_graph(Integer(389), Integer(157))# long␣˓→time>>> spring_big = Graph(n)# long time>>> posdict_big = graphs.CompleteBipartiteGraph(Integer(389), Integer(157))
˓→ # long time

2.9. Basic graphs

␣

1223

Graph Theory, Release 10.4

Compare the plotting:sage: n = networkx.complete_bipartite_graph(11, 17)
˓→needs networkx
sage: spring_med = Graph(n)˓→needs networkx
sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)#␣#␣>>> from sage.all import *>>> n = networkx.complete_bipartite_graph(Integer(11), Integer(17))˓→# needs networkx>>> spring_med = Graph(n)˓→needs networkx>>> posdict_med = graphs.CompleteBipartiteGraph(Integer(11), Integer(17))␣#␣

Notice here how the spring-layout tends to center the nodes of 𝑛1:
sage: spring_med.show()˓→needs networkx
sage: posdict_med.show()˓→needs sage.plot>>> from sage.all import *>>> spring_med.show()˓→needs networkx>>> posdict_med.show()˓→needs sage.plot# long time#␣# long time#␣# long time#␣# 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):˓→needs sage.plot....:
n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)˓→needs sage.plot
sage: G.show()# long time
˓→needs sage.plot>>> from sage.all import *>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CompleteBipartiteGraph(i+Integer(1),Integer(4))...
g.append(k)>>> for i in range(Integer(3)):˓→# needs sage.plot...
n = []...
for m in range(Integer(3)):

#␣

#␣
#␣

␣

(continues on next page)1224

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)#␣˓→needs sage.plot>>> G.show()# long time#␣˓→needs sage.plot

We compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.complete_bipartite_graph(i+1,4)....:
k = Graph(spr)....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.complete_bipartite_graph(i+Integer(1),Integer(4))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long timeIssue #12155:
sage: graphs.CompleteBipartiteGraph(5,6).complement()
complement(Complete bipartite graph of order 5+6): Graph on 11 vertices>>> from sage.all import *>>> graphs.CompleteBipartiteGraph(Integer(5),Integer(6)).complement()
complement(Complete bipartite graph of order 5+6): Graph on 11 vertices

sage.graphs.generators.basic.CompleteGraph(n)Return a complete graph on 𝑛 nodes.
A Complete Graph is a graph in which all nodes are connected to all other nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By con2.9. Basic graphs

1225Graph Theory, Release 10.4

vention, each complete graph will be displayed with the first (0) node at the top, with the rest following in acounterclockwise 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 pushoutward (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: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.CompleteGraph(i+3)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CompleteGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

We compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
sage: import networkx
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.complete_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))(continues on next page)

1226

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)....:j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> import networkx>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.complete_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

Compare the constructors (results will vary):
sage: # needs networkx
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>>> from sage.all import *>>> # needs networkx>>> import networkx>>> t = cputime()>>> n = networkx.complete_graph(Integer(389)); spring389 = Graph(n)>>> cputime(t) # random
0.59203700000000126>>> t = cputime()>>> posdict389 = graphs.CompleteGraph(Integer(389))>>> cputime(t) # random
0.6680419999999998

We compare plotting:sage: # needs networkx
sage: import networkx
sage: n = networkx.complete_graph(23)sage: spring23 = Graph(n)sage: posdict23 = graphs.CompleteGraph(23)sage: spring23.show()# long time
˓→needs sage.plot#␣(continues on next page)2.9. Basic graphs

1227Graph Theory, Release 10.4

(continued from previous page)

sage: posdict23.show()˓→needs sage.plot# long time>>> from sage.all import *>>> # needs networkx>>> import networkx>>> n = networkx.complete_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.CompleteGraph(Integer(23))>>> spring23.show()# long time
˓→needs sage.plot>>> posdict23.show()# long time
˓→needs sage.plot

#␣

#␣
#␣

sage.graphs.generators.basic.CompleteMultipartiteGraph(L)Return a complete multipartite graph.
INPUT:• L – a list of integers; the respective sizes of the components
PLOTTING: Produce a layout of the vertices so that vertices in the same vertex set are adjacent and clearly separated
from vertices in other vertex sets.
This is done by calculating the vertices of an 𝑟-gon then calculating the slope between adjacent vertices. We then‘walk’ around the 𝑟-gon placing graph vertices in regular intervals between adjacent vertices of the 𝑟-gon.
Makes a nicely organized graph like in this picture: https://commons.wikimedia.org/wiki/File:Turan_13-4.svg
EXAMPLES:
A complete tripartite graph with sets of sizes 5, 6, 8:
sage: g = graphs.CompleteMultipartiteGraph([5, 6, 8]); g
Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices>>> from sage.all import *>>> g = graphs.CompleteMultipartiteGraph([Integer(5), Integer(6), Integer(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>>> from sage.all import *>>> g.chromatic_number()3

sage.graphs.generators.basic.CorrelationGraph(seqs, alpha, include_anticorrelation)
Return a correlation graph with a node per sequence in seqs.
Edges are added between nodes where the corresponding sequences have a correlation coeffecient greater thanalpha.
If include_anticorrelation is True, then edges are also added between nodes with correlation coefficientless than -alpha.
INPUT:
1228

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• seqs – list of sequences, taht is a list of lists• alpha – float; threshold on the correlation coefficient between two sequences for adding an edge
• include_anticorrelation – boolean; whether to add edges between nodes with correlation coefficient less than -alpha or not
EXAMPLES:
sage: # needs numpy
sage: from sage.graphs.generators.basic import CorrelationGraphsage: data = [[1,2,3], [4,5,6], [7,8,9999]]
sage: CG1 = CorrelationGraph(data, 0.9, False)
sage: CG2 = CorrelationGraph(data, 0.9, True)
sage: CG3 = CorrelationGraph(data, 0.1, True)
sage: CG1.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]sage: CG2.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]sage: CG3.edges(sort=False)[(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2,␣
˓→None)]>>> from sage.all import *>>> # needs numpy>>> from sage.graphs.generators.basic import CorrelationGraph>>> data = [[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),˓→Integer(6)], [Integer(7),Integer(8),Integer(9999)]]>>> CG1 = CorrelationGraph(data, RealNumber( 0.9 ), False)>>> CG2 = CorrelationGraph(data, RealNumber( 0.9 ), True)>>> CG3 = CorrelationGraph(data, RealNumber( 0.1 ), True)>>> CG1.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]>>> CG2.edges(sort=False)[(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]>>> CG3.edges(sort=False)[(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2,␣
˓→None)]sage.graphs.generators.basic.CycleGraph(n)Return a cycle graph with 𝑛 nodes.
A cycle graph is a basic structure which is also typically called an 𝑛-gon.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each cycle graph will be displayed with the first (0) node at the top, with the rest following in a counterclockwise manner.
The cycle graph is a good opportunity to compare efficiency of filling a position dictionary vs. using the spring-layout
algorithm for plotting. Because the cycle graph is very symmetric, the resulting plots should be similar (in cases ofsmall 𝑛).
Filling the position dictionary in advance adds 𝑂(𝑛) to the constructor.
EXAMPLES:
Compare plotting using the predefined layout and networkx:
sage: # needs networkx sage.plot
sage: import networkx(continues on next page)2.9. Basic graphs

1229

Graph Theory, Release 10.4

(continued from previous page)

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>>> from sage.all import *>>> # needs networkx sage.plot>>> import networkx>>> n = networkx.cycle_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.CycleGraph(Integer(23))>>> spring23.show()# long time>>> 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: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.CycleGraph(i+3)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.CycleGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

Compare to plotting with the spring-layout algorithm:
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.cycle_graph(i+3)....:
k = Graph(spr)(continues on next page)

1230

Chapter 2. Constructors and databases

Graph Theory, Release 10.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 = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.cycle_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.basic.DartGraph()
Return a dart graph with 5 nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the dart graph is drawn as a dart, with the sharp part on the bottom.
EXAMPLES:
Construct and show a dart graph:
sage: g = graphs.DartGraph()
sage: g.show()˓→needs sage.plot>>> from sage.all import *>>> g = graphs.DartGraph()>>> g.show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.basic.DiamondGraph()
Return a diamond graph with 4 nodes.
A diamond graph is a square with one pair of diagonal nodes connected.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the diamond graph is drawn as a diamond, with the first node on top, second on the left, third on the right,
and fourth on the bottom; with the second and third node connected.
EXAMPLES:
Construct and show a diamond graph:2.9. Basic graphs1231

Graph Theory, Release 10.4

sage: g = graphs.DiamondGraph()
sage: g.show()˓→needs sage.plot>>> from sage.all import *>>> g = graphs.DiamondGraph()>>> g.show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.basic.EmptyGraph()
Return an empty graph (0 nodes and 0 edges).
This is useful for constructing graphs by adding edges and vertices individually or in a loop.
PLOTTING: When plotting, this graph will use the default spring-layout algorithm, unless a position dictionary is
specified.
EXAMPLES:
Add one vertex to an empty graph and then show:
sage: empty1 = graphs.EmptyGraph()
sage: empty1.add_vertex()0sage: empty1.show()˓→needs sage.plot>>> from sage.all import *>>> empty1 = graphs.EmptyGraph()>>> empty1.add_vertex()0>>> empty1.show()˓→needs sage.plot# long time

# 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
˓→needs sage.plot#␣>>> from sage.all import *>>> empty2 = graphs.EmptyGraph()>>> for i in range(Integer(5)):...
empty2.add_vertex() # add 5 nodes, labeled 0-401(continues on next page)1232

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)2
3
4>>> for i in range(Integer(3)):...
empty2.add_edge(i,i+Integer(1)) # add edges {[0:1],[1:2],[2:3]}>>> for i in range(Integer(1), Integer(4)):...
empty2.add_edge(Integer(4),i) # add edges {[1:4],[2:4],[3:4]}>>> empty2.show()# long time
˓→needs sage.plot#␣

sage.graphs.generators.basic.ForkGraph()
Return a fork graph with 5 nodes.
A fork graph, sometimes also called chair graph, is 5 vertex tree.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the fork graph is drawn as a fork, with the sharp part on the bottom.
EXAMPLES:
Construct and show a fork graph:
sage: g = graphs.ForkGraph()
sage: g.show()˓→needs sage.plot>>> from sage.all import *>>> g = graphs.ForkGraph()>>> g.show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.basic.GemGraph()
Return a gem graph with 5 nodes.
A gem graph is a fan graph (4,1).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the gem graph is drawn as a gem, with the sharp part on the bottom.
EXAMPLES:
Construct and show a gem graph:
sage: g = graphs.GemGraph()
sage: g.show()˓→needs sage.plot>>> from sage.all import *>>> g = graphs.GemGraph()>>> g.show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.basic.Grid2dGraph(p, q, set_positions=True)
Return a 2-dimensional grid graph with 𝑝 × 𝑞 nodes (𝑝 rows and 𝑞 columns).
A 2d grid graph resembles a 2 dimensional grid. All inner nodes are connected to their 4 neighbors. Outer(non-corner) nodes are connected to their 3 neighbors. Corner nodes are connected to their 2 neighbors.
INPUT:
2.9. Basic graphs1233

Graph Theory, Release 10.4

• p and q – two positive integers• set_positions – boolean (default: True); whether to set the position of the nodes
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, nodes are labelled in (row, column) pairs with (0, 0) in the top left corner. Edges will always be horizontal
and vertical - another advantage of filling the position dictionary.
EXAMPLES:
Construct and show a grid 2d graph Rows = 5, Columns = 7:
sage: g = graphs.Grid2dGraph(5,7)
sage: g.show()˓→needs sage.plot# long time>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5),Integer(7))>>> g.show()# long time
˓→needs sage.plot#␣#␣

sage.graphs.generators.basic.GridGraph(dim_list)
Return an 𝑛-dimensional grid graph.
INPUT:• dim_list – a list of integers representing the number of nodes toextend 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()˓→needs sage.plot# long time>>> from sage.all import *>>> G = graphs.GridGraph([Integer(2),Integer(3),Integer(4)])>>> G.show()# long time
˓→needs sage.plot
sage: C = graphs.CubeGraph(4)sage: G = graphs.GridGraph([2,2,2,2])
sage: C.show()˓→needs sage.plot
sage: G.show()˓→needs sage.plot#␣# long time#␣# long time#␣>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(4))>>> G = graphs.GridGraph([Integer(2),Integer(2),Integer(2),Integer(2)])>>> C.show()# long time
˓→needs sage.plot>>> G.show()# long time
˓→needs sage.plot

1234

#␣

#␣
#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage.graphs.generators.basic.HouseGraph()
Return a house graph with 5 nodes.
A house graph is named for its shape. It is a triangle (roof) over a square (walls).
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the house graph is drawn with the first node in the lower-left corner of the house, the second in thelower-right corner of the house. The third node is in the upper-left corner connecting the roof to the wall, and thefourth is in the upper-right corner connecting the roof to the wall. The fifth node is the top of the roof, connected
only to the third and fourth.
EXAMPLES:
Construct and show a house graph:
sage: g = graphs.HouseGraph()
sage: g.show()˓→needs sage.plot>>> from sage.all import *>>> g = graphs.HouseGraph()>>> g.show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.basic.HouseXGraph()
Return a house X graph with 5 nodes.
A house X graph is a house graph with two additional edges. The upper-right corner is connected to the lower-left.
And the upper-left corner is connected to the lower-right.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the house X graph is drawn with the first node in the lower-left corner of the house, the second in thelower-right corner of the house. The third node is in the upper-left corner connecting the roof to the wall, and thefourth 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()˓→needs sage.plot>>> from sage.all import *>>> g = graphs.HouseXGraph()>>> g.show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.basic.LadderGraph(n)Return a ladder graph with 2 * 𝑛 nodes.
A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected ateach corresponding node pair.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on the top
horizontal line.
EXAMPLES:
2.9. Basic graphs

1235Graph Theory, Release 10.4

Construct and show a ladder graph with 14 nodes:
sage: g = graphs.LadderGraph(7)sage: g.show()˓→needs sage.plot# long time>>> from sage.all import *>>> g = graphs.LadderGraph(Integer(7))>>> g.show()# long time
˓→needs sage.plot#␣#␣Create several ladder graphs in a Sage graphics array:sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.LadderGraph(i+2)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.LadderGraph(i+Integer(2))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.basic.MoebiusLadderGraph(n)Return a Möbius ladder graph with 2𝑛 nodes
A Möbius ladder graph of order 2𝑛 is a ladder graph of the same order that is connected at the ends with a single
twist, i.e., a ladder graph bent around so that top meets bottom with a single twist. Alternatively, it can be described
as a single cycle graph (of order 2𝑛) with the addition of edges (called 𝑟𝑢𝑛𝑔𝑠) joining the antipodal pairs of nodes.
Also, note that the Möbius ladder graph graphs.MoebiusLadderGraph(n) is precisely the same graph as
the circulant graph graphs.CirculantGraph(2 * n, [1, n]).
PLOTTING:
Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each
Möbius ladder graph will be displayed with the first (0) node at the top, with the rest following in a counterclockwisemanner.
INPUT:
1236

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• n – a non negative integer; number of nodes is 2𝑛
OUTPUT:• G – a Möbius ladder graph of order 2𝑛; note that a ValueError is returned if 𝑛 < 0
EXAMPLES:
Construct and show a Möbius ladder graph with 26 nodes:
sage: g = graphs.MoebiusLadderGraph(13)sage: g.show()# long time
˓→needs sage.plot>>> from sage.all import *>>> g = graphs.MoebiusLadderGraph(Integer(13))>>> g.show()# long time
˓→needs sage.plot#␣#␣Create several Möbius ladder graphs in a Sage graphics array:sage: # needs sage.plots
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.MoebiusLadderGraph(i+3)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plots>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.MoebiusLadderGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

REFERENCES:• Wikipedia article Möbius_ladder
See also:
LadderGraph(), CircularLadderGraph(), CirculantGraph()
AUTHORS:2.9. Basic graphs

1237Graph Theory, Release 10.4

• Janmenjaya Panda (2024-05-26)
sage.graphs.generators.basic.PathGraph(n, pos=None)
Return a path graph with 𝑛 nodes.
A path graph is a graph where all inner nodes are connected to their two neighbors and the two end-nodes areconnected to their one inner neighbors (i.e.: a cycle graph without the first and last node connected).
INPUT:• n – number of nodes of the path graph• pos – string (default: None); indicates the embedding to use between ‘circle’, ‘line’ or the default algorithm.
See the plotting section below for more detail.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the graph may be drawn in one of two ways: The ‘line’ argument will draw the graph in a horizontal line
(left to right) if there are less than 11 nodes. Otherwise the ‘line’ argument will append horizontal lines of length
10 nodes below, alternating left to right and right to left. The ‘circle’ argument will cause the graph to be drawn ina cycle-shape, with the first node at the top and then about the circle in a clockwise manner. By default (without anappropriate 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()˓→needs sage.plot# long time>>> from sage.all import *>>> p = graphs.PathGraph(Integer(10))>>> p.show()# long time
˓→needs sage.plot#␣#␣‘circle’: 10 < 𝑛 < 41sage: q = graphs.PathGraph(25)sage: q.show()˓→needs sage.plot# long time>>> from sage.all import *>>> q = graphs.PathGraph(Integer(25))>>> q.show()# long time
˓→needs sage.plot#␣#␣‘line’: 𝑛 ≥ 41
sage: r = graphs.PathGraph(55)sage: r.show()˓→needs sage.plot# long time>>> from sage.all import *>>> r = graphs.PathGraph(Integer(55))>>> r.show()# long time
˓→needs sage.plot#␣#␣Override the default drawing:

1238

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: s = graphs.PathGraph(5, circle )sage: s.show()˓→needs sage.plot# long time>>> from sage.all import *>>> s = graphs.PathGraph(Integer(5), circle )>>> s.show()# long time
˓→needs sage.plot#␣#␣

sage.graphs.generators.basic.StarGraph(n)Return a star graph with 𝑛 + 1 nodes.
A Star graph is a basic structure where one node is connected to all other nodes.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each star graph will be displayed with the first (0) node in the center, the second node (1) at the top, withthe 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, andthus look very similar to this constructor’s positioning.
EXAMPLES:
sage: import networkx
˓→needs networkx#␣>>> from sage.all import *>>> import networkx
˓→needs networkx#␣Compare the plots:
sage: # needs networkx sage.plot
sage: n = networkx.star_graph(23)sage: spring23 = Graph(n)sage: posdict23 = graphs.StarGraph(23)sage: spring23.show()
sage: posdict23.show() # long time

# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> n = networkx.star_graph(Integer(23))>>> spring23 = Graph(n)>>> posdict23 = graphs.StarGraph(Integer(23))>>> spring23.show()# long time>>> posdict23.show() # long time

View many star graphs as a Sage Graphics Array
With this constructor (i.e., the position dictionary filled)
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.StarGraph(i+3)(continues on next page)2.9. Basic graphs1239Graph Theory, Release 10.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 = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.StarGraph(i+Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

Compared to plotting with the spring-layout algorithm
sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:spr = networkx.star_graph(i+3)....:
k = Graph(spr)....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
spr = networkx.star_graph(i+Integer(3))...
k = Graph(spr)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)(continues on next page)

1240

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.basic.Toroidal6RegularGrid2dGraph(p, q)
Return a toroidal 6-regular grid.
The toroidal 6-regular grid is a 6-regular graph on 𝑝 × 𝑞 vertices and its elements have coordinates (𝑖, 𝑗) for𝑖 ∈ {0...𝑝 − 1} and 𝑗 ∈ {0...𝑞 − 1}.
Its edges are those of the ToroidalGrid2dGraph(), to which are added the edges between (𝑖, 𝑗) and ((𝑖 +1)%𝑝, (𝑗 + 1)%𝑞).
INPUT:• p, q – integers
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()
˓→needs sage.groupsTrue
sage: g.line_graph().is_vertex_transitive()
˓→needs sage.groupsTrue
sage: g.automorphism_group().cardinality()
˓→needs sage.groups
300
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.Toroidal6RegularGrid2dGraph(Integer(5),Integer(5))>>> g.is_regular(k=Integer(6))
True>>> g.is_vertex_transitive()
˓→needs sage.groupsTrue>>> g.line_graph().is_vertex_transitive()
˓→needs sage.groupsTrue>>> g.automorphism_group().cardinality()
˓→needs sage.groups
300>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

#␣

#␣

#␣

#␣

#␣

#␣

#␣

sage.graphs.generators.basic.ToroidalGrid2dGraph(p, q)
Return a toroidal 2-dimensional grid graph with 𝑝 × 𝑞 nodes (𝑝 rows and 𝑞 columns).
The toroidal 2-dimensional grid with parameters 𝑝, 𝑞 is the 2-dimensional grid graph with identical parameters towhich are added the edges ((𝑖, 0), (𝑖, 𝑞 − 1)) and ((0, 𝑖), (𝑝 − 1, 𝑖)).

2.9. Basic graphs1241

Graph Theory, Release 10.4

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>>> from sage.all import *>>> tgrid = graphs.ToroidalGrid2dGraph(Integer(8),Integer(9))>>> print(tgrid)
Toroidal 2D Grid Graph with parameters 8,9>>> grid = graphs.Grid2dGraph(Integer(8),Integer(9))>>> grid.is_regular()False>>> tgrid.is_regular()True

2.10 Chessboard graphs
The methods defined here appear in sage.graphs.graph_generators.
• BishopGraph• KingGraph• KnightGraph• QueenGraph• RookGraphAUTHORS:• David Coudert (2012)sage.graphs.generators.chessboard.BishopGraph(dim_list, radius=None, relabel=False)
Return the 𝑑-dimensional Bishop Graph with prescribed dimensions.
The 2-dimensional Bishop Graph of parameters 𝑛 and 𝑚 is a graph with 𝑛𝑚 vertices in which each vertex represents
a square in an 𝑛 × 𝑚 chessboard, and each edge corresponds to a legal move by a bishop.
The 𝑑-dimensional Bishop Graph with 𝑑 >= 2 has for vertex set the cells of a 𝑑-dimensional grid with prescribed
dimensions, and each edge corresponds to a legal move by a bishop in any pairs of dimensions.
The Bishop Graph is not connected.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard• radius – integer (default: None); by setting the radius to a positive integer, one may decrease the powerof the bishop to at most radius steps.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers

1242

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
The (n,m)-Bishop Graph is not connected:
sage: G = graphs.BishopGraph( [3, 4] )sage: G.is_connected()
False>>> from sage.all import *>>> G = graphs.BishopGraph( [Integer(3), Integer(4)] )>>> 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(sort=False) )....:if not B.is_isomorphic(H):....:print("that s not good!")>>> from sage.all import *>>> for d in range(Integer(3),Integer(12)):# long time...
H = Graph()...
for r in range(Integer(1),d+Integer(1)):...
B = graphs.BishopGraph([d,d],radius=r)...
H.add_edges( graphs.KnightGraph([d,d],one=r,two=r).edges(sort=False) )...
if not B.is_isomorphic(H):...
print("that s not good!")

sage.graphs.generators.chessboard.ChessboardGraphGenerator(dim_list, rook=True,
rook_radius=None,bishop=True,bishop_radius=None,knight=True, knight_x=1,
knight_y=2, relabel=False)
Return a Graph built on a 𝑑-dimensional chessboard with prescribed dimensions and interconnections.
This function allows to generate many kinds of graphs corresponding to legal movements on a 𝑑-dimensional chessboard: Queen Graph, King Graph, Knight Graphs, Bishop Graph, and many generalizations. It also allows to avoid
redundant code.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard• rook – boolean (default: True); indicates whether the chess piece is able to move as a rook, that is at any
distance along a dimension• rook_radius – integer (default: None); restriction on the rook-like movements to distance at mostrook_radius• bishop – boolean (default: True); indicates whether the chess piece is able to move like a bishop, that isalong diagonals• bishop_radius – integer (default: None); restriction on the bishop-like movements to distance at most
bishop_radius
2.10. Chessboard graphs1243

Graph Theory, Release 10.4

• knight – boolean (default: True); indicating whether the chess piece is able to move like a knight• knight_x – integer (default: 1); indicates the number on steps the chess piece moves in one dimension
when moving like a knight• knight_y – integer (default: 2); indicates the number on steps the chess piece moves in the second dimension when moving like a knight• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
OUTPUT:• A Graph build on a 𝑑-dimensional chessboard with prescribed dimensions, and with edges according given
parameters.
• A string encoding the dimensions. This is mainly useful for providing names to graphs.
EXAMPLES:
A (2, 2)-King Graph is isomorphic to the complete graph on 4 vertices:sage: G, _ = graphs.ChessboardGraphGenerator( [2,2] )sage: G.is_isomorphic( graphs.CompleteGraph(4) )True>>> from sage.all import *>>> G, _ = graphs.ChessboardGraphGenerator( [Integer(2),Integer(2)] )>>> G.is_isomorphic( graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> G, _ = graphs.ChessboardGraphGenerator([Integer(3),Integer(4)], rook=True,␣
˓→rook_radius=None, bishop=False, knight=False)>>> H = (graphs.CompleteGraph(Integer(3))).cartesian_product(graphs.
˓→CompleteGraph(Integer(4)))>>> G.is_isomorphic(H)Truesage.graphs.generators.chessboard.KingGraph(dim_list, radius=None, relabel=False)
Return 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 prescribed
dimensions, and each edge corresponds to a legal move by a king in either one or two dimensions.
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 – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard

1244

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• radius – integer (default: None); by setting the radius to a positive integer, one may increase the powerof 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 – boolean (default: False); indicates whether the 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>>> from sage.all import *>>> G = graphs.QueenGraph( [Integer(2), Integer(2)] )>>> G.is_isomorphic( graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> G = graphs.KingGraph( [Integer(5), Integer(4)], radius=Integer(5) )>>> H = graphs.QueenGraph( [Integer(4), Integer(5)] )>>> 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>>> from sage.all import *>>> G = graphs.KingGraph( [Integer(2), Integer(5), Integer(4)], radius=Integer(5)␣
˓→)>>> H = graphs.QueenGraph( [Integer(4), Integer(5), Integer(2)] )>>> G.is_isomorphic( H )Truesage.graphs.generators.chessboard.KnightGraph(dim_list, one=1, two=2, relabel=False)
Return 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.
The (𝑛, 𝑛)-Knight Graph is Hamiltonian for even 𝑛 > 4.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard
2.10. Chessboard graphs

1245Graph Theory, Release 10.4

• one – integer (default: 1); indicates the number of steps in the first dimension• two – integer (default: 2); indicates the number of steps in the second dimension• relabel – boolean (default: False); indicates whether the 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>>> from sage.all import *>>> G = graphs.KnightGraph( [Integer(3), Integer(3)] )>>> G.degree( (Integer(1),Integer(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>>> from sage.all import *>>> G = graphs.KnightGraph( [Integer(3), Integer(3)] )>>> G.delete_vertex( (Integer(1),Integer(1)) )>>> G.is_isomorphic( graphs.CycleGraph(Integer(8)) )True

The (6, 6)-Knight Graph is Hamiltonian:sage: G = graphs.KnightGraph( [6, 6] )sage: G.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> G = graphs.KnightGraph( [Integer(6), Integer(6)] )>>> G.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

sage.graphs.generators.chessboard.QueenGraph(dim_list, radius=None, relabel=False)
Return the 𝑑-dimensional Queen Graph with prescribed dimensions.
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 dimensions.
All 2-dimensional Queen Graphs are Hamiltonian and biconnected. The chromatic number of a (𝑛, 𝑛)-Queen
Graph is at least 𝑛, and it is exactly 𝑛 when 𝑛 ≡ 1, 5 mod 6.
INPUT:• dim_list – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard
1246

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• radius – integer (default: None); by setting the radius to a positive integer, one may reduce the visibilityof the queen to at most radius steps. When radius is 1, the resulting graph is a King Graph.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (2, 2)-Queen Graph is isomorphic to the complete graph on 4 vertices:sage: G = graphs.QueenGraph([2, 2])
sage: G.is_isomorphic(graphs.CompleteGraph(4))
True>>> from sage.all import *>>> G = graphs.QueenGraph([Integer(2), Integer(2)])>>> G.is_isomorphic(graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> G = graphs.QueenGraph([Integer(4), Integer(5)], radius=Integer(1))>>> H = graphs.KingGraph([Integer(5), Integer(4)])>>> 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>>> from sage.all import *>>> G = graphs.QueenGraph([Integer(3), Integer(4), Integer(5)], radius=Integer(1))>>> H = graphs.KingGraph([Integer(5), Integer(3), Integer(4)])>>> 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(sort=False))....:
if not G.is_isomorphic(H):....:print("that s not good!")>>> from sage.all import *>>> for d in range(Integer(3),Integer(12)):# long time(continues on next page)2.10. Chessboard graphs

1247

Graph Theory, Release 10.4

(continued from previous page)

...
...
...
...
...
...
...

for r in range(Integer(1),d+Integer(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(sort=False))
if not G.is_isomorphic(H):print("that s not good!")

sage.graphs.generators.chessboard.RookGraph(dim_list, radius=None, relabel=False)
Return 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 – iterable (list, set, dict); provides the dimensions 𝑛1 , 𝑛2 , . . . , 𝑛𝑑 , with 𝑛𝑖 ≥ 1, of the chessboard• radius – integer (default: None); by setting the radius to a positive integer, one may decrease the powerof the rook to at most radius steps. When the radius is 1, the resulting graph is a 𝑑-dimensional grid.
• relabel – boolean (default: False); indicates whether the vertices must be relabeled as integers
EXAMPLES:
The (𝑛, 𝑚)-Rook’s Graph is isomorphic to the Cartesian product of two complete graphs:
sage: G = graphs.RookGraph( [3, 4] )sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.CompleteGraph(4) )sage: G.is_isomorphic( H )True>>> from sage.all import *>>> G = graphs.RookGraph( [Integer(3), Integer(4)] )>>> H = ( graphs.CompleteGraph(Integer(3)) ).cartesian_product( graphs.
˓→CompleteGraph(Integer(4)) )>>> 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>>> from sage.all import *>>> G = graphs.RookGraph( [Integer(3), Integer(3), Integer(4)], radius=Integer(1)␣
˓→)>>> H = graphs.GridGraph( [Integer(3), Integer(4), Integer(3)] )>>> G.is_isomorphic( H )
True

1248

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

2.11 Intersection graphs
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.intersection.IntersectionGraph(S)Return the intersection graph of the family 𝑆
The intersection graph of a family 𝑆 is a graph 𝐺 with 𝑉 (𝐺) = 𝑆 such that two elements 𝑠1 , 𝑠2 ∈ 𝑆 are adjacentin 𝐺 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>>> from sage.all import *>>> graphs.IntersectionGraph([(Integer(1),Integer(2),Integer(3)),(Integer(3),˓→Integer(4),Integer(5)),(Integer(5),Integer(6),Integer(7))])
Intersection Graph: Graph on 3 vertices

sage.graphs.generators.intersection.IntervalGraph(intervals, points_ordered=False)
Return the graph corresponding to the given intervals.
An interval graph is built from a list (𝑎𝑖 , 𝑏𝑖 )1≤𝑖≤𝑛 of intervals : to each interval of the list is associated one vertex,
two vertices being adjacent if the two corresponding (closed) intervals intersect.
INPUT:• intervals – the list of pairs (𝑎𝑖 , 𝑏𝑖 ) defining the graph.
• points_ordered – states whether every interval (𝑎𝑖 , 𝑏𝑖 ) of 𝑖𝑛𝑡𝑒𝑟𝑣𝑎𝑙𝑠 satisfies 𝑎𝑖 < 𝑏𝑖 . If satisfied thensetting 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 andcan be recovered using get_vertex() or get_vertices().
EXAMPLES:
The following line creates the sequence of intervals (𝑖, 𝑖 + 2) for i in [0, ..., 8]:
sage: intervals = [(i,i+2) for i in range(9)]>>> from sage.all import *>>> intervals = [(i,i+Integer(2)) for i in range(Integer(9))]

In the corresponding graph2.11. Intersection graphs1249

Graph Theory, Release 10.4

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)>>> from sage.all import *>>> g = graphs.IntervalGraph(intervals)>>> g.get_vertex(Integer(3))(3, 5)>>> neigh = g.neighbors(Integer(3))>>> 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>>> from sage.all import *>>> 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)}>>> from sage.all import *>>> intervals = [ (Integer(1),Integer(2)), (Integer(1),Integer(2)), (Integer(1),˓→Integer(2)), (Integer(2),Integer(3)), (Integer(3),Integer(4)) ]>>> g = graphs.IntervalGraph(intervals,True)>>> g.clique_maximum()[0, 1, 2, 3]>>> 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(sort=True) == h.edges(sort=True)
True

1250

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> rev_intervals = [ (Integer(2),Integer(1)), (Integer(2),Integer(1)),␣
˓→(Integer(2),Integer(1)), (Integer(3),Integer(2)), (Integer(4),Integer(3)) ]>>> h = graphs.IntervalGraph(rev_intervals,False)>>> h.get_vertices(){0: (2, 1), 1: (2, 1), 2: (2, 1), 3: (3, 2), 4: (4, 3)}>>> g.edges(sort=True) == h.edges(sort=True)
True

sage.graphs.generators.intersection.OrthogonalArrayBlockGraph(k, n, OA=None)
Return the graph of an 𝑂𝐴(𝑘, 𝑛).
The intersection graph of the blocks of a transversal design with parameters (𝑘, 𝑛), or 𝑇 𝐷(𝑘, 𝑛) for short, is astrongly 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 fromthe blocks of an 𝑂𝐴(𝑘, 𝑛), two of them being adjacent if one of their coordinates match.
For more information on these graphs, see Andries Brouwer’s page on Orthogonal Array graphs.
Warning:• Brouwer’s website uses the notation 𝑂𝐴(𝑛, 𝑘) instead of 𝑂𝐴(𝑘, 𝑛)• For given parameters 𝑘 and 𝑛 there can be many 𝑂𝐴(𝑘, 𝑛) : the graphs returned are not uniquely definedby 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 versionsof Sage, or even worse : some could not be available anymore.
See also:
sage.combinat.designs.orthogonal_arrays
INPUT:• k, n – integers• OA – An orthogonal array. If set to None (default) then orthogonal_array() is called to compute an
𝑂𝐴(𝑘, 𝑛).
EXAMPLES:
sage: # needs sage.modules
sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G˓→needs sage.schemes
OA(5,5): Graph on 25 vertices
sage: G.is_strongly_regular(parameters=True)
˓→needs sage.schemes(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)2.11. Intersection graphs

#␣

#␣

1251

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.modules>>> G = graphs.OrthogonalArrayBlockGraph(Integer(5),Integer(5)); G˓→# needs sage.schemes
OA(5,5): Graph on 25 vertices>>> G.is_strongly_regular(parameters=True)
˓→needs sage.schemes(25, 20, 15, 20)>>> G = graphs.OrthogonalArrayBlockGraph(Integer(4),Integer(10)); G
OA(4,10): Graph on 100 vertices>>> G.is_strongly_regular(parameters=True)(100, 36, 14, 12)␣#␣

Two graphs built from different orthogonal arrays are also different:
sage: # needs sage.modules
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>>> from sage.all import *>>> # needs sage.modules>>> k = Integer(4); n = Integer(10)>>> OAa = designs.orthogonal_arrays.build(k,n)>>> OAb = [[(x+Integer(1))%n for x in R] for R in OAa]>>> set(map(tuple,OAa)) == set(map(tuple,OAb))
False>>> Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa)>>> Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb)>>> Ga == GbFalse

As OAb was obtained from OAa by a relabelling the two graphs are isomorphic:
sage: Ga.is_isomorphic(Gb)˓→needs sage.modules
True

#␣

>>> from sage.all import *>>> Ga.is_isomorphic(Gb)˓→needs sage.modules
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],(continues on next page)1252

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)....:[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)
˓→needs sage.modules
sage: g1 = graphs.OrthogonalArrayBlockGraph(3, 4, oa1)
˓→needs sage.modules
sage: g0.is_isomorphic(g1)˓→needs sage.modules
False

#␣
#␣
#␣

>>> from sage.all import *>>> oa0 = [[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1),␣
˓→Integer(3)], [Integer(0), Integer(2), Integer(0)], [Integer(0), Integer(3),␣
˓→Integer(2)],...
[Integer(1), Integer(0), Integer(3)], [Integer(1), Integer(1),␣
˓→Integer(1)], [Integer(1), Integer(2), Integer(2)], [Integer(1), Integer(3),␣
˓→Integer(0)],...
[Integer(2), Integer(0), Integer(0)], [Integer(2), Integer(1),␣
˓→Integer(2)], [Integer(2), Integer(2), Integer(1)], [Integer(2), Integer(3),␣
˓→Integer(3)],...
[Integer(3), Integer(0), Integer(2)], [Integer(3), Integer(1),␣
˓→Integer(0)], [Integer(3), Integer(2), Integer(3)], [Integer(3), Integer(3),␣
˓→Integer(1)]]>>> oa1 = [[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1),␣
˓→Integer(0)], [Integer(0), Integer(2), Integer(3)], [Integer(0), Integer(3),␣
˓→Integer(2)],...
[Integer(1), Integer(0), Integer(3)], [Integer(1), Integer(1),␣
˓→Integer(2)], [Integer(1), Integer(2), Integer(0)], [Integer(1), Integer(3),␣
˓→Integer(1)],...
[Integer(2), Integer(0), Integer(0)], [Integer(2), Integer(1),␣
˓→Integer(1)], [Integer(2), Integer(2), Integer(2)], [Integer(2), Integer(3),␣
˓→Integer(3)],...
[Integer(3), Integer(0), Integer(2)], [Integer(3), Integer(1),␣
˓→Integer(3)], [Integer(3), Integer(2), Integer(1)], [Integer(3), Integer(3),␣
˓→Integer(0)]]>>> g0 = graphs.OrthogonalArrayBlockGraph(Integer(3), Integer(4), oa0)␣˓→# needs sage.modules>>> g1 = graphs.OrthogonalArrayBlockGraph(Integer(3), Integer(4), oa1)␣˓→# needs sage.modules>>> g0.is_isomorphic(g1)#␣˓→needs sage.modules
False

But nevertheless isospectral:sage: g0.spectrum()˓→needs sage.modules sage.rings.number_field[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
sage: g1.spectrum()˓→needs sage.modules sage.rings.number_field[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]>>> from sage.all import *>>> g0.spectrum()˓→needs sage.modules sage.rings.number_field[9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]

#␣

#␣

#␣

(continues on next page)

2.11. Intersection graphs1253

Graph Theory, Release 10.4

(continued from previous page)>>> g1.spectrum()˓→needs sage.modules sage.rings.number_field[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)˓→needs sage.libs.gap sage.modules
True

#␣

>>> from sage.all import *>>> graphs.AffineOrthogonalPolarGraph(Integer(4),Integer(2), + ).is_˓→isomorphic(g0)# needs sage.libs.gap sage.modules
Truesage.graphs.generators.intersection.PermutationGraph(second_permutation,
first_permutation=None)
Build a permutation graph from one permutation or from two lists.
Definition:
If 𝜎 is a permutation of {1, 2, . . . , 𝑛}, then the permutation graph of 𝜎 is the graph on vertex set {1, 2, . . . , 𝑛} inwhich 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 firstof them. On the second one, still from left to right, mark 𝑛 points 𝜎(1), 𝜎(2), . . . , 𝜎(𝑛). Now, link bya 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 graphfor 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 thegiven 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, thenthe permutation graph defined by these two lists is the graph on the vertex set 𝑆 in which two vertices 𝑖 and 𝑗
are connected by an edge if and only if the order in which these vertices appear in the list (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 ) is the
opposite of the order in which they appear in the list (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ). When (𝑎1 , 𝑎2 , . . . , 𝑎𝑛 ) = (1, 2, . . . , 𝑛), thisgraph is the permutation graph of the permutation (𝑏1 , 𝑏2 , . . . , 𝑏𝑛 ) ∈ 𝑆𝑛 . Notice that 𝑆 does not have to be a setof 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 firsthorizontal 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 thegraph is to be built from two permutations/lists).
• first_permutation (optional) – the first of the two permutations/lists from which the graph should bebuilt, 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.

1254

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• Drawings of permutation graphs as intersection graphs of segments is possible through the show() methodof 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(sort=True, labels=False)
sage: set(edges) == set(p.inverse().inversions())
Truesage: PG = graphs.PermutationGraph([3,4,5,1,2])
sage: sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 4, None),(2, 5, None)]sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3])
sage: sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]sage: PG = graphs.PermutationGraph([1,4,2,5,3], [3,4,5,1,2])
sage: sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]sage: PG = graphs.PermutationGraph(Permutation([1,3,2]), Permutation([1,2,3]))
sage: sorted(PG.edges(sort=True))[(2, 3, None)]sage: graphs.PermutationGraph([]).edges(sort=True)[]
sage: graphs.PermutationGraph([], []).edges(sort=True)[]
sage: PG = graphs.PermutationGraph("graph", "phrag")sage: sorted(PG.edges(sort=True))[( a , g , None),( a , h , None),( a , p , None),( g , h , None),( g , p , None),(continues on next page)

2.11. Intersection graphs

1255

Graph Theory, Release 10.4

(continued from previous page)

( g ,
( h ,
( p ,

r , None),r , None),r , None)]>>> from sage.all import *>>> p = Permutations(Integer(5)).random_element()>>> PG = graphs.PermutationGraph(p)>>> edges = PG.edges(sort=True, labels=False)>>> set(edges) == set(p.inverse().inversions())
True>>> PG = graphs.PermutationGraph([Integer(3),Integer(4),Integer(5),Integer(1),˓→Integer(2)])>>> sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 4, None),(2, 5, None)]>>> PG = graphs.PermutationGraph([Integer(3),Integer(4),Integer(5),Integer(1),˓→Integer(2)], [Integer(1),Integer(4),Integer(2),Integer(5),Integer(3)])>>> sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]>>> PG = graphs.PermutationGraph([Integer(1),Integer(4),Integer(2),Integer(5),˓→Integer(3)], [Integer(3),Integer(4),Integer(5),Integer(1),Integer(2)])>>> sorted(PG.edges(sort=True))[(1, 3, None),(1, 4, None),(1, 5, None),(2, 3, None),(2, 5, None),(3, 4, None),(3, 5, None)]>>> PG = graphs.PermutationGraph(Permutation([Integer(1),Integer(3),Integer(2)]),␣
˓→Permutation([Integer(1),Integer(2),Integer(3)]))>>> sorted(PG.edges(sort=True))[(2, 3, None)]>>> graphs.PermutationGraph([]).edges(sort=True)[]>>> graphs.PermutationGraph([], []).edges(sort=True)[]>>> PG = graphs.PermutationGraph("graph", "phrag")>>> sorted(PG.edges(sort=True))[( a , g , None),( a , h , None),( a , p , None),(continues on next page)

1256

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

( g ,
( g ,
( g ,
( h ,
( p ,

h , None),p , None),r , None),r , None),r , None)]sage.graphs.generators.intersection.ToleranceGraph(tolrep)
Return the graph generated by the tolerance representation tolrep.
The tolerance representation tolrep is described by the list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), . . . , (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where 𝐼𝑖 =(𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line with 𝑙𝑖 < 𝑟𝑖 and 𝑡𝑖 a strictly positive value, called tolerance. This
representation generates the tolerance graph with the vertex set {0, 1, . . . , 𝑘} and the edge set {(𝑖, 𝑗) : |𝐼𝑖 ∩ 𝐼𝑗 | ≥min{𝑡𝑖 , 𝑡𝑗 }} where |𝐼𝑖 ∩ 𝐼𝑗 | denotes the length of the intersection of 𝐼𝑖 and 𝐼𝑗 .
INPUT:• tolrep – list of triples (𝑙𝑖 , 𝑟𝑖 , 𝑡𝑖 ) where (𝑙𝑖 , 𝑟𝑖 ) denotes a closed interval on the real line and 𝑡𝑖 a positive
value.
Note: The vertices are named 0, 1, . . . , 𝑘. The tolerance representation used to create the graph is saved with thegraph 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 somechecks: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>>> from sage.all import *>>> tolrep = [(Integer(1),Integer(4),Integer(3)),(Integer(1),Integer(2),˓→Integer(1)),(Integer(2),Integer(3),Integer(1)),(Integer(0),Integer(3),˓→Integer(3))]>>> g = graphs.ToleranceGraph(tolrep)>>> g.get_vertex(Integer(3))(0, 3, 3)>>> neigh = g.neighbors(Integer(3))>>> for v in neigh: print(g.get_vertex(v))(1, 2, 1)(2, 3, 1)>>> g.is_interval()
False>>> g.is_weakly_chordal()True

2.11. Intersection graphs

1257

Graph Theory, Release 10.4

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>>> from sage.all import *>>> tolrep2 = [(Integer(0),Integer(4),Integer(5)),(Integer(1),Integer(2),˓→Integer(1)),(Integer(2),Integer(3),Integer(1)),(Integer(0),Integer(4),˓→Integer(5))]>>> g2 = graphs.ToleranceGraph(tolrep2)>>> g2.get_vertices(){0: (0, 4, 5), 1: (1, 2, 1), 2: (2, 3, 1), 3: (0, 4, 5)}>>> g2.is_isomorphic(g)TrueReal 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>>> from sage.all import *>>> tolrep = [(RealNumber( 0.1 ),RealNumber( 3.3 ),RealNumber( 4.4 )),(RealNumber(
˓→ 1.1 ),RealNumber( 2.5 ),RealNumber( 1.1 )),(RealNumber( 1.4 ),RealNumber( 4.4
˓→ ),RealNumber( 3.3 ))]>>> g = graphs.ToleranceGraph(tolrep)>>> g.is_isomorphic(graphs.PathGraph(Integer(3)))
True

2.12 1-skeletons of Platonic solids
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.platonic_solids.DodecahedralGraph()
Return a Dodecahedral graph (with 20 nodes)
The dodecahedral graph is cubic symmetric, so the spring-layout algorithm will be very effective for display. It isdual to the icosahedral graph.
PLOTTING: The Dodecahedral graph should be viewed in 3 dimensions. We choose to use a planar embeddingof the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be
added to select the desired layout.
EXAMPLES:
Construct and show a Dodecahedral graph:
sage: g = graphs.DodecahedralGraph()
sage: g.show()˓→needs sage.plot

1258# long time#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.DodecahedralGraph()>>> g.show()˓→needs sage.plot# long time#␣Create several dodecahedral graphs in a Sage graphics array They will be drawn differently due to the use of thespring-layout algorithm:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.DodecahedralGraph()....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.DodecahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.platonic_solids.HexahedralGraph()
Return a hexahedral graph (with 8 nodes).
A regular hexahedron is a 6-sided cube. The hexahedral graph corresponds to the connectivity of the vertices of
the hexahedron. This graph is equivalent to a 3-cube.
PLOTTING: The Hexahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding of
the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be added
to select the desired layout.
EXAMPLES:
Construct and show a Hexahedral graph:
sage: g = graphs.HexahedralGraph()
sage: g.show()˓→needs sage.plot

2.12. 1-skeletons of Platonic solids# long time

#␣

1259

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.HexahedralGraph()>>> g.show()˓→needs sage.plot# long time#␣Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of thespring-layout algorithm:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.HexahedralGraph()....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.HexahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.platonic_solids.IcosahedralGraph()
Return an Icosahedral graph (with 12 nodes).
The regular icosahedron is a 20-sided triangular polyhedron. The icosahedral graph corresponds to the connectivityof the vertices of the icosahedron. It is dual to the dodecahedral graph. The icosahedron is symmetric, so thespring-layout algorithm will be very effective for display.
PLOTTING: The Icosahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding of
the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be added
to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.IcosahedralGraph()
sage: g.show()˓→needs sage.plot

1260# long time#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.IcosahedralGraph()>>> g.show()˓→needs sage.plot# long time#␣Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use of thespring-layout algorithm:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.IcosahedralGraph()....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.IcosahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.platonic_solids.OctahedralGraph()
Return an Octahedral graph (with 6 nodes).
The regular octahedron is an 8-sided polyhedron with triangular faces. The octahedral graph corresponds to theconnectivity of the vertices of the octahedron. It is the line graph of the tetrahedral graph. The octahedral issymmetric, so the spring-layout algorithm will be very effective for display.
PLOTTING: The Octahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding of
the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be added
to select the desired layout.
EXAMPLES:
Construct and show an Octahedral graph:
sage: g = graphs.OctahedralGraph()
sage: g.show()˓→needs sage.plot

2.12. 1-skeletons of Platonic solids# long time

#␣

1261

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.OctahedralGraph()>>> g.show()˓→needs sage.plot# long time#␣Create several octahedral graphs in a Sage graphics array They will be drawn differently due to the use of thespring-layout algorithm:
sage: # needs sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.OctahedralGraph()....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.OctahedralGraph()...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.platonic_solids.TetrahedralGraph()
Return a tetrahedral graph (with 4 nodes).
A tetrahedron is a 4-sided triangular pyramid. The tetrahedral graph corresponds to the connectivity of the verticesof the tetrahedron. This graph is equivalent to a wheel graph with 4 nodes and also a complete graph on four nodes.
(See examples below).
PLOTTING: The Tetrahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding of
the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be added
to select the desired layout.
EXAMPLES:
Construct and show a Tetrahedral graph:
sage: g = graphs.TetrahedralGraph()
sage: g.show()˓→needs sage.plot

1262# long time#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.TetrahedralGraph()>>> g.show()˓→needs sage.plot# long time#␣The following example requires networkx:
sage: import networkx as NX
˓→needs networkx>>> from sage.all import *>>> import networkx as NX
˓→needs networkx#␣#␣Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm
below in a Sage graphics array:sage: # needs networkx sage.plot
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 = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> tetra_pos = graphs.TetrahedralGraph()>>> tetra_spring = Graph(NX.tetrahedral_graph())>>> wheel = graphs.WheelGraph(Integer(4))>>> complete = graphs.CompleteGraph(Integer(4))>>> g = [tetra_pos, tetra_spring, wheel, complete]>>> j = []>>> for i in range(Integer(2)):...
n = []...
for m in range(Integer(2)):...
n.append(g[i + m].plot(vertex_size=Integer(50), vertex_labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

2.12. 1-skeletons of Platonic solids

1263

Graph Theory, Release 10.4

2.13 Random graphs
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.random.RandomBarabasiAlbert(n, m, seed=None)
Return a random graph created using the Barabasi-Albert preferential attachment model.
A graph with 𝑚 vertices and no edges is initialized, and a graph of 𝑛 vertices is grown by attaching new vertices
each with 𝑚 edges that are attached to existing vertices, preferentially with high degree.
INPUT:• n – number of vertices in the graph• m – number of edges to attach from each new node
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We show the edge list of a random graph on 6 nodes with 𝑚 = 2:
sage: G = graphs.RandomBarabasiAlbert(6,2)˓→needs networkx
sage: G.order(), G.size()
˓→needs networkx(6, 8)
sage: G.degree_sequence() # random
˓→needs networkx[4, 3, 3, 2, 2, 2]

#␣
#␣

#␣

>>> from sage.all import *>>> G = graphs.RandomBarabasiAlbert(Integer(6),Integer(2))˓→# needs networkx>>> G.order(), G.size()
˓→needs networkx(6, 8)>>> G.degree_sequence() # random
˓→needs networkx[4, 3, 3, 2, 2, 2]

␣
#␣

#␣

We plot a random graph on 12 nodes with 𝑚 = 3:
sage: ba = graphs.RandomBarabasiAlbert(12,3)
˓→needs networkx
sage: ba.show()# long time
˓→needs networkx sage.plot>>> from sage.all import *>>> ba = graphs.RandomBarabasiAlbert(Integer(12),Integer(3))˓→# needs networkx>>> ba.show()# long time
˓→needs networkx sage.plot

#␣
#␣

␣
#␣

We view many random graphs using a graphics array:sage: # needs networkx sage.plot
sage: g = []sage: j = [](continues on next page)

1264

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: for i in range(1,10):....:k = graphs.RandomBarabasiAlbert(i+3, 3)....:g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(1),Integer(10)):...
k = graphs.RandomBarabasiAlbert(i+Integer(3), Integer(3))...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

When 𝑚 = 1, the generated graph is a tree:
sage: graphs.RandomBarabasiAlbert(6, 1).is_tree()
˓→needs networkx
True

#␣

>>> from sage.all import *>>> graphs.RandomBarabasiAlbert(Integer(6), Integer(1)).is_tree()˓→# needs networkx
True␣

sage.graphs.generators.random.RandomBicubicPlanar(n, seed=None)
Return the graph of a random bipartite cubic map with 3𝑛 edges.
INPUT:
𝑛 – an integer (at least 1)• seed – a random.Random seed or a Python int for the random number generator (default: None)OUTPUT:a graph with multiple edges (no embedding is provided)
The algorithm used is described in [Sch1999]. This samples a random rooted bipartite cubic map, chosen uniformly
at random.
First one creates a random binary tree with 𝑛 vertices. Next one turns this into a blossoming tree (at random) andreads 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).
2.13. Random graphs

1265

Graph Theory, Release 10.4

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: # needs sage.combinat
sage: n = randint(200, 300)
sage: G = graphs.RandomBicubicPlanar(n)sage: G.order() == 2*nTrue
sage: G.size() == 3*nTrue
sage: G.is_bipartite() and G.is_planar() and G.is_regular(3)True
sage: dic = { red : [v for v in G.vertices(sort=False) if v[0] == n ],....:blue : [v for v in G.vertices(sort=False) if v[0] != n ]}sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic)
˓→needs sage.plot
Graphics object consisting of ... graphics primitives>>> from sage.all import *>>> # needs sage.combinat>>> n = randint(Integer(200), Integer(300))>>> G = graphs.RandomBicubicPlanar(n)>>> G.order() == Integer(2)*nTrue>>> G.size() == Integer(3)*nTrue>>> G.is_bipartite() and G.is_planar() and G.is_regular(Integer(3))
True>>> dic = { red : [v for v in G.vertices(sort=False) if v[Integer(0)] == n ],...
blue : [v for v in G.vertices(sort=False) if v[Integer(0)] != n ]}>>> G.plot(vertex_labels=False, vertex_size=Integer(20), vertex_colors=dic)˓→# needs sage.plot
Graphics object consisting of ... graphics primitives#␣␣

sage.graphs.generators.random.RandomBipartite(n1, n2, p, set_position=False, seed=None)
Returns a bipartite graph with 𝑛1 + 𝑛2 vertices such that any edge from [𝑛1] to [𝑛2] exists with probability 𝑝.
INPUT:
1266

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• 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 theset of cardinality 𝑛1 is on the line 𝑦 = 1 and the set of cardinality 𝑛2 is on the line 𝑦 = 0.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: g = graphs.RandomBipartite(5, 2, 0.5)
˓→needs numpy
sage: g.vertices(sort=True)
˓→needs numpy[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]>>> from sage.all import *>>> g = graphs.RandomBipartite(Integer(5), Integer(2), RealNumber( 0.5 ))˓→# needs numpy>>> g.vertices(sort=True)
˓→needs numpy[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]

#␣
#␣

␣
#␣

sage.graphs.generators.random.RandomBlockGraph(m, k, kmax=None, incidence_structure=False,
seed=None)
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• 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 thegraphs is returned instead of the graph itself, that is the list of the lists of vertices in each block. This is usefulfor the creation of some hypergraphs.
• seed – a random.Random seed or a Python int for the random number generator (default: None)OUTPUT:
A Graph when incidence_structure==False (default), and otherwise an incidence structure.
EXAMPLES:
A block graph with a single block is a clique:2.13. Random graphs

1267

Graph Theory, Release 10.4

sage: B = graphs.RandomBlockGraph(1, 4)
sage: B.is_clique()True>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(1), Integer(4))>>> 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>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(10), Integer(2))>>> 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>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(5), Integer(3), kmax=Integer(6))>>> blocks,cuts = B.blocks_and_cut_vertices()>>> 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>>> from sage.all import *>>> m, k = Integer(6), Integer(4)>>> B = graphs.RandomBlockGraph(m, k)>>> B.order() == m*(k-Integer(1))+Integer(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

1268

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> B = graphs.RandomBlockGraph(Integer(6), Integer(2), kmax=Integer(6))>>> B.is_block_graph()
True>>> B in graph_classes.Block
True

Asking for the incidence structure: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)#␣˓→needs sage.modules
Incidence structure with 19 points and 6 blocks
sage: m*(k-1)+1
19>>> from sage.all import *>>> m, k = Integer(6), Integer(4)>>> IS = graphs.RandomBlockGraph(m, k, incidence_structure=True)>>> from sage.combinat.designs.incidence_structures import IncidenceStructure>>> IncidenceStructure(IS)#␣˓→needs sage.modules
Incidence structure with 19 points and 6 blocks>>> m*(k-Integer(1))+Integer(1)19sage.graphs.generators.random.RandomBoundedToleranceGraph(n, seed=None)
Return a random bounded tolerance graph.
The random tolerance graph is built from a random bounded tolerance representation by using the function
𝑇 𝑜𝑙𝑒𝑟𝑎𝑛𝑐𝑒𝐺𝑟𝑎𝑝ℎ. This representation is a list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), ..., (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where 𝑘 = 𝑛 − 1 and𝐼𝑖 = (𝑙𝑖 , 𝑟𝑖 ) denotes a random interval and 𝑡𝑖 a random positive value less than or equal to the length of the interval
𝐼𝑖 . The width of the representation is limited to 𝑛2 * 2𝑛 .
Note: The tolerance representation used to create the graph can be recovered using get_vertex() or
get_vertices().
INPUT:• n – number of vertices of the random graph.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
Every (bounded) tolerance graph is perfect. Hence, the chromatic number is equal to the clique number
sage: g = graphs.RandomBoundedToleranceGraph(8)sage: g.clique_number() == g.chromatic_number()True>>> from sage.all import *>>> g = graphs.RandomBoundedToleranceGraph(Integer(8))>>> g.clique_number() == g.chromatic_number()True

2.13. Random graphs1269

Graph Theory, Release 10.4

sage.graphs.generators.random.RandomChordalGraph(n, algorithm='growing', k=None, l=None,
f=None, s=None, seed=None)
Return a random chordal graph of order n.
A Graph 𝐺 is said to be chordal if it contains no induced hole (a cycle of length at least 4). Equivalently, 𝐺 ischordal if it has a perfect elimination orderings, if each minimal separator is a clique, or if it is the intersection
graphs of subtrees of a tree. See the Wikipedia article Chordal_graph.
This generator implements the algorithms proposed in [SHET2018] for generating random chordal graphs as theintersection graph of 𝑛 subtrees of a tree of order 𝑛.
The returned graph is not necessarily connected.
INPUT:• n – integer; the number of nodes of the graph• algorithm – string (default: "growing"); the choice of the algorithm for randomly selecting 𝑛 subtreesof a random tree of order 𝑛. Possible choices are:– "growing" – for each subtree 𝑇𝑖 , the algorithm picks a size 𝑘𝑖 randomly from [1, 𝑘]. Then a random
node of 𝑇 is chosen as the first node of 𝑇𝑖 . In each of the subsequent 𝑘𝑖 − 1 iterations, it picks a random
node in the neighborhood of 𝑇𝑖 and adds it to 𝑇𝑖 .
– "connecting" – for each subtree 𝑇𝑖 , it first selects 𝑘𝑖 nodes of 𝑇 , where 𝑘𝑖 is a random integer froma Poisson distribution with mean 𝑙. 𝑇𝑖 is then generated to be the minimal subtree containing the selected
𝑘𝑖 nodes. This implies that a subtree will most likely have many more nodes than those selected initially,
and this must be taken into consideration when choosing 𝑙.
– "pruned" – for each subtree 𝑇𝑖 , it randomly selects a fraction 𝑓 of the edges on the tree and removes
them. The number of edges to delete, say 𝑙, is calculated as ⌊(𝑛 − 1)𝑓 ⌋, which will leave 𝑙 + 1 subtrees
in total. Then, it determines the sizes of the 𝑙 + 1 subtrees and stores the distinct values. Finally, it picks
a random size 𝑘𝑖 from the set of largest 100(1 − 𝑠)% of distinct values, and randomly chooses a subtreewith size 𝑘𝑖 .
• k –√integer (default: None); maximum size of a subtree. If not specified (None), the maximum size is set
to 𝑛. This parameter is used only when algorithm="growing". See growing_subtrees() for
more details.
• l – a strictly positive real number (default: None); mean of a Poisson distribution. If not specified, themean in set to log2 𝑛. This parameter is used only when algorithm="connecting". See connecting_nodes() for more details.
• f – a rational number (default: None); the edge deletion fraction. This value must be chosen in [0..1]. If not
1
specified, this parameter is set to 𝑛−1. This parameter is used only when algorithm="pruned". See
pruned_tree() for more details.
• s – a real number between 0 and 1 (default: None); selection barrier for the size of trees. If not specified, this parameter is set to 0.5. This parameter is used only when algorithm="pruned". See
pruned_tree() for more details.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: from sage.graphs.generators.random import RandomChordalGraphsage: T = RandomChordalGraph(20, algorithm="growing", k=5)
sage: T.is_chordal()Truesage: T = RandomChordalGraph(20, algorithm="connecting", l=3)
˓→needs numpy#␣(continues on next page)

1270

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: T.is_chordal()˓→needs numpy
True
sage: T = RandomChordalGraph(20, algorithm="pruned", f=1/3, s=.5)
sage: T.is_chordal()
True

#␣

>>> from sage.all import *>>> from sage.graphs.generators.random import RandomChordalGraph>>> T = RandomChordalGraph(Integer(20), algorithm="growing", k=Integer(5))>>> T.is_chordal()True>>> T = RandomChordalGraph(Integer(20), algorithm="connecting", l=Integer(3))␣˓→# needs numpy>>> T.is_chordal()#␣˓→needs numpy
True>>> T = RandomChordalGraph(Integer(20), algorithm="pruned", f=Integer(1)/˓→Integer(3), s=RealNumber( .5 ))>>> T.is_chordal()True

See also:• growing_subtrees()• connecting_nodes()• pruned_tree()• Wikipedia article Chordal_graph• is_chordal()• IntersectionGraph()
sage.graphs.generators.random.RandomGNM(n, m, dense=False, seed=None)
Return a graph randomly picked out of all graphs on 𝑛 vertices with 𝑚 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 – a random.Random seed or a Python int for the 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(sort=True, labels=False)#␣˓→needs networkx[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]>>> from sage.all import *>>> graphs.RandomGNM(Integer(5), Integer(10)).edges(sort=True, labels=False)␣(continues on next page)

2.13. Random graphs

1271

Graph Theory, Release 10.4

(continued from previous page)# needs networkx[(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 and 12 edges:
sage: gnm = graphs.RandomGNM(12, 12)
˓→needs networkx
sage: gnm.show()˓→needs networkx sage.plot#␣# long time>>> from sage.all import *>>> gnm = graphs.RandomGNM(Integer(12), Integer(12))˓→# needs networkx>>> gnm.show()# long time
˓→needs networkx sage.plot

#␣

␣
#␣

We view many random graphs using a graphics array:sage: # needs networkx sage.plot
sage: g = []sage: j = []sage: for i in range(9):....:k = graphs.RandomGNM(i+3, i^2-i)....:
g.append(k)sage: for i in range(3):....:n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)sage: G.show()# long time>>> from sage.all import *>>> # needs networkx sage.plot>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.RandomGNM(i+Integer(3), i**Integer(2)-i)...
g.append(k)>>> for i in range(Integer(3)):...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)>>> G.show()# long time

sage.graphs.generators.random.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 – a random.Random seed or a Python int for the random number generator (default: None)
1272

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• fast – boolean set to True (default) to use the algorithm with time complexity in 𝑂(𝑛 + 𝑚) proposed in[BB2005a]. 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 insage.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:• [ER1959]• [Gil1959]
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(sort=true, labels=False)[(0, 3), (1, 2), (2, 3), (2, 4)]>>> from sage.all import *>>> set_random_seed(Integer(0))>>> graphs.RandomGNP(Integer(6), RealNumber( .4 )).edges(sort=true, labels=False)[(0, 3), (1, 2), (2, 3), (2, 4)]

We plot a random graph on 12 nodes with probability 𝑝 = .71:
sage: gnp = graphs.RandomGNP(12,.71)
sage: gnp.show()˓→needs sage.plot# long time#␣>>> from sage.all import *>>> gnp = graphs.RandomGNP(Integer(12),RealNumber( .71 ))>>> gnp.show()# long time
˓→needs sage.plot#␣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):˓→needs sage.plot....:
n = []....:
for m in range(3):....:n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))....:
j.append(n)sage: G = graphics_array(j)˓→needs sage.plot
sage: G.show()# long time
˓→needs sage.plot

#␣

#␣
#␣

(continues on next page)

2.13. Random graphs1273

Graph Theory, Release 10.4

(continued from previous page)

sage: graphs.RandomGNP(4,1)
Complete graph: Graph on 4 vertices>>> from sage.all import *>>> g = []>>> j = []>>> for i in range(Integer(9)):...
k = graphs.RandomGNP(i+Integer(3),RealNumber( .43 ))...
g.append(k)>>> for i in range(Integer(3)):␣˓→# needs sage.plot...
n = []...
for m in range(Integer(3)):...
n.append(g[Integer(3)*i + m].plot(vertex_size=Integer(50), vertex_
˓→labels=False))...
j.append(n)>>> G = graphics_array(j)#␣˓→needs sage.plot>>> G.show()# long time#␣˓→needs sage.plot>>> graphs.RandomGNP(Integer(4),Integer(1))
Complete graph: Graph on 4 vertices

sage.graphs.generators.random.RandomHolmeKim(n, m, p, seed=None)
Return a random graph generated by the Holme and Kim algorithm for graphs with power law degree distribution
and approximate average clustering.
INPUT:• n – number of vertices• m – number of random edges to add for each new node
• p – probability of adding a triangle after adding a random edge
• seed – a random.Random seed or a Python int for the random number generator (default: None)
From the NetworkX documentation: the average clustering has a hard time getting above a certain cutoff that
depends on 𝑚. This cutoff is often quite low. Note that the transitivity (fraction of triangles to possible triangles)
seems to go down with network size. It is essentially the Barabasi-Albert growth model with an extra step thateach random edge is followed by a chance of making an edge to one of its neighbors too (and thus a triangle). Thisalgorithm improves on B-A in the sense that it enables a higher average clustering to be attained if desired. It seems
possible to have a disconnected graph with this algorithm since the initial 𝑚 nodes may not be all linked to a newnode on the first iteration like the BA model.
EXAMPLES:
sage: G = graphs.RandomHolmeKim(12, 3, .3)
˓→needs networkx
sage: G.show()# long time
˓→needs networkx sage.plot>>> from sage.all import *>>> G = graphs.RandomHolmeKim(Integer(12), Integer(3), RealNumber( .3 ))˓→# needs networkx>>> G.show()# long time
˓→needs networkx sage.plot

1274

#␣
#␣

␣
#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

REFERENCE:[HK2002a]sage.graphs.generators.random.RandomIntervalGraph(n, seed=None)
Returns a random interval graph.
An interval graph is built from a list (𝑎𝑖 , 𝑏𝑖 )1≤𝑖≤𝑛 of intervals : to each interval of the list is associated one vertex,
two vertices being adjacent if the two corresponding intervals intersect.
A random interval graph of order 𝑛 is generated by picking random values for the (𝑎𝑖 , 𝑏𝑗 ), each of the two coordinates being generated from the uniform distribution on the interval [0, 1].
This definitions follows [BF2001].
Note: The vertices are named 0, 1, 2, and so on. The intervals used to create the graph are saved with the graphand can be recovered using get_vertex() or get_vertices().
INPUT:• n – integer; the number of vertices in the random graph• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
As for any interval graph, the chromatic number is equal to the clique number
sage: g = graphs.RandomIntervalGraph(8)sage: g.clique_number() == g.chromatic_number()True>>> from sage.all import *>>> g = graphs.RandomIntervalGraph(Integer(8))>>> g.clique_number() == g.chromatic_number()Truesage.graphs.generators.random.RandomKTree(n, k, seed=None)
Return a random 𝑘-tree on 𝑛 nodes numbered 0 through 𝑛 − 1.
ALGORITHM:
The algorithm first generates a complete graph on 𝑘 + 1 vertices. Vertices are subsequently generated by randomly
choosing one of the existing cliques in the graph, and creating a new clique by replacing one of the vertices in theselected clique with a newly created one.
INPUT:• n – number of vertices in the 𝑘-tree• k – within a clique each vertex is connected to 𝑘 vertices. 𝑘 also corresponds to the treewidth of the 𝑘-tree• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomKTree(50, 5)
sage: G.treewidth()5
sage: G.show() # not tested

2.13. Random graphs

1275Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.RandomKTree(Integer(50), Integer(5))>>> G.treewidth()5>>> G.show() # not tested

sage.graphs.generators.random.RandomLobster(n, p, q, seed=None)
Return 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 toa path when pruning all leaf vertices (𝑞 = 0).
INPUT:• n – expected number of vertices in the backbone• p – probability of adding an edge to the backbone• q – probability of adding an edge (claw) to the arms
• seed – a random.Random seed or a Python int for the random number generator (default: None).
EXAMPLES:
We check a random graph with 12 backbone nodes and probabilities 𝑝 = 0.7 and 𝑞 = 0.3:
sage: # needs networkx
sage: G = graphs.RandomLobster(12, 0.7, 0.3)
sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1]
sage: G.delete_vertices(leaves)# caterpillar
sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1]
sage: G.delete_vertices(leaves)# pathsage: s = G.degree_sequence()
sage: if G:....:
if G.num_verts() == 1:....:
assert s == [0]
....:
else:
....:
assert s[-2:] == [1, 1]....:
assert all(d == 2 for d in s[:-2])>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomLobster(Integer(12), RealNumber( 0.7 ), RealNumber( 0.3 ))>>> leaves = [v for v in G.vertices(sort=False) if G.degree(v) == Integer(1)]>>> G.delete_vertices(leaves)# caterpillar>>> leaves = [v for v in G.vertices(sort=False) if G.degree(v) == Integer(1)]>>> G.delete_vertices(leaves)# path>>> s = G.degree_sequence()>>> if G:...
if G.num_verts() == Integer(1):...
assert s == [Integer(0)]
...
else:
...
assert s[-Integer(2):] == [Integer(1), Integer(1)]...
assert all(d == Integer(2) for d in s[:-Integer(2)])
sage: G = graphs.RandomLobster(9, .6, .3)
˓→needs networkx
sage: G.show()# long time
˓→needs networkx sage.plot

1276

#␣
#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.RandomLobster(Integer(9), RealNumber( .6 ), RealNumber( .3 ))˓→# needs networkx>>> G.show()# long time
˓→needs networkx sage.plot

␣#␣

sage.graphs.generators.random.RandomNewmanWattsStrogatz(n, k, p, seed=None)
Return a Newman-Watts-Strogatz small world random graph on 𝑛 vertices.
From the NetworkX documentation: first create a ring over 𝑛 nodes. Then each node in the ring is connectedwith its 𝑘 nearest neighbors. Then shortcuts are created by adding new edges as follows: for each edge 𝑢 − 𝑣 in
the underlying “𝑛-ring with 𝑘 nearest neighbors”; with probability 𝑝 add a new edge 𝑢 − 𝑤 with randomly-chosen
existing node 𝑤. In contrast with networkx.watts_strogatz_graph(), no edges are removed.
INPUT:• n – number of vertices• k – each vertex is connected to its 𝑘 nearest neighbors• p – the probability of adding a new edge for each edge
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that the generated graph contains a cycle of order 𝑛:sage: # needs networkx
sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2)
sage: G.order()7
sage: C7 = graphs.CycleGraph(7)sage: G.subgraph_search(C7)Subgraph of (): Graph on 7 vertices
sage: G.diameter() <= C7.diameter()True>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomNewmanWattsStrogatz(Integer(7), Integer(2), RealNumber( 0.2
˓→ ))>>> G.order()7>>> C7 = graphs.CycleGraph(Integer(7))>>> G.subgraph_search(C7)Subgraph of (): Graph on 7 vertices>>> G.diameter() <= C7.diameter()Truesage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3)
˓→needs networkx
sage: G.show()# long time
˓→needs networkx sage.plot#␣#␣>>> from sage.all import *>>> G = graphs.RandomNewmanWattsStrogatz(Integer(12), Integer(2), RealNumber( .3˓→ ))# needs networkx(continues on next page)

2.13. Random graphs

1277Graph Theory, Release 10.4

(continued from previous page)>>> G.show()˓→needs networkx sage.plot# long time#␣

REFERENCE:[NWS2002]
sage.graphs.generators.random.RandomPartialKTree(n, k, x, seed=None)
Return a random partial 𝑘-tree on 𝑛 nodes.
A partial 𝑘-tree is defined as a subgraph of a 𝑘-tree. This can also be described as a graph with treewidth at most𝑘.
INPUT:• n – number of vertices in the 𝑘-tree• k – within a clique each vertex is connected to 𝑘 vertices. 𝑘 also corresponds to the treewidth of the 𝑘-tree• x – how many edges are deleted from the 𝑘-tree• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomPartialKTree(50,5,2)
sage: G.treewidth()5
sage: G.show() # not tested>>> from sage.all import *>>> G = graphs.RandomPartialKTree(Integer(50),Integer(5),Integer(2))>>> G.treewidth()5>>> G.show() # not tested

sage.graphs.generators.random.RandomRegular(d, n, seed=None)
Return a random 𝑑-regular graph on 𝑛 vertices, or False on failure.
Since every edge is incident to two vertices, 𝑛 × 𝑑 must be even.
INPUT:• d – degree• n – number of vertices• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that a random graph with 8 nodes each of degree 3 is 3-regular:
sage: G = graphs.RandomRegular(3, 8)
˓→needs networkx
sage: G.is_regular(k=3)˓→needs networkx
True
sage: G.degree_histogram()
˓→needs networkx[0, 0, 0, 8]

1278

#␣
#␣

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.RandomRegular(Integer(3), Integer(8))˓→# needs networkx>>> G.is_regular(k=Integer(3))˓→# needs networkx
True>>> G.degree_histogram()
˓→needs networkx[0, 0, 0, 8]
sage: G = graphs.RandomRegular(3, 20)
˓→needs networkx
sage: if G:
˓→needs networkx sage.plot....:
G.show()

␣
␣

#␣

#␣
# random output>>> from sage.all import *>>> G = graphs.RandomRegular(Integer(3), Integer(20))˓→# needs networkx>>> if G:# random output
˓→networkx sage.plot...
G.show()# long time,␣␣# long time, needs␣

REFERENCES:• [KV2003]• [SW1999]
sage.graphs.generators.random.RandomRegularBipartite(n1, n2, d1, set_position=False,
seed=None)
Return a random regular bipartite graph on 𝑛1 + 𝑛2 vertices.
The bipartite graph has 𝑛1 * 𝑑1 edges. Hence, 𝑛2 must divide 𝑛1 * 𝑑1. Each vertex of the set of cardinality 𝑛1 hasdegree 𝑑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, therunning time can be huge. Note that the currently implemented algorithm does not generate uniformly randomgraphs.
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 theset of cardinality 𝑛1 is on the line 𝑦 = 1 and the set of cardinality 𝑛2 is on the line 𝑦 = 0.
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: g = graphs.RandomRegularBipartite(4, 6, 3)
sage: g.order(), g.size()(10, 12)sage: set(g.degree())(continues on next page)

2.13. Random graphs1279

Graph Theory, Release 10.4

(continued from previous page){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()>>> from sage.all import *>>> g = graphs.RandomRegularBipartite(Integer(4), Integer(6), Integer(3))>>> g.order(), g.size()(10, 12)>>> set(g.degree()){2, 3}>>> graphs.RandomRegularBipartite(Integer(1), Integer(2), Integer(2), set_
˓→position=True).get_pos(){0: (1, 1.0), 1: (0, 0), 2: (2.0, 0.0)}>>> graphs.RandomRegularBipartite(Integer(2), Integer(1), Integer(1), set_
˓→position=True).get_pos(){0: (0, 1), 1: (2.0, 1.0), 2: (1, 0.0)}>>> graphs.RandomRegularBipartite(Integer(2), Integer(3), Integer(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)}>>> graphs.RandomRegularBipartite(Integer(2), Integer(3), Integer(3), set_
˓→position=False).get_pos()sage.graphs.generators.random.RandomShell(constructor, seed=None)
Return a random shell graph for the constructor given.
INPUT:• constructor – a list of 3-tuples (𝑛, 𝑚, 𝑑), each representing a shell, where:– n – the number of vertices in the shell– m – the number of edges in the shell– d – the ratio of inter (next) shell edges to intra shell edges• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)])
˓→needs networkx
sage: G.order(), G.size()
˓→needs networkx(30, 52)
sage: G.show()# long time
˓→needs networkx sage.plot

#␣
#␣

#␣

>>> from sage.all import *>>> G = graphs.RandomShell([(Integer(10),Integer(20),RealNumber( 0.8 )),˓→(Integer(20),Integer(40),RealNumber( 0.8 ))])
# needs␣
˓→networkx(continues on next page)

1280

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G.order(), G.size()
˓→needs networkx(30, 52)>>> G.show()˓→needs networkx sage.plot#␣# long time#␣

sage.graphs.generators.random.RandomToleranceGraph(n, seed=None)
Return a random tolerance graph.
The random tolerance graph is built from a random tolerance representation by using the function ToleranceGraph(). This representation is a list ((𝑙0 , 𝑟0 , 𝑡0 ), (𝑙1 , 𝑟1 , 𝑡1 ), ..., (𝑙𝑘 , 𝑟𝑘 , 𝑡𝑘 )) where 𝑘 = 𝑛 − 1 and 𝐼𝑖 = (𝑙𝑖 , 𝑟𝑖 )denotes a random interval and 𝑡𝑖 a random positive value. The width of the representation is limited to 𝑛2 * 2𝑛 .
Note: The vertices are named 0, 1, · · · , 𝑛 − 1. The tolerance representation used to create the graph is saved withthe graph and can be recovered using get_vertex() or get_vertices().
INPUT:• n – number of vertices of the random graph• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
Every tolerance graph is perfect. Hence, the chromatic number is equal to the clique number
sage: g = graphs.RandomToleranceGraph(8)sage: g.clique_number() == g.chromatic_number()True>>> from sage.all import *>>> g = graphs.RandomToleranceGraph(Integer(8))>>> g.clique_number() == g.chromatic_number()Truesage.graphs.generators.random.RandomTree(n, seed=None)
Returns a random tree on 𝑛 nodes numbered 0 through 𝑛 − 1.
By Cayley’s theorem, there are 𝑛𝑛−2 trees with vertex set {0, 1, . . . , 𝑛 − 1}. This constructor chooses one of these
uniformly at random.
ALGORITHM:
The algorithm works by generating an (𝑛 − 2)-long random sequence of numbers chosen independently and uniformly from {0, 1, . . . , 𝑛 − 1} and then applies an inverse Prufer transformation.
INPUT:• n – number of vertices in the tree
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
sage: G = graphs.RandomTree(10)sage: G.is_tree()True(continues on next page)

2.13. Random graphs

1281

Graph Theory, Release 10.4

(continued from previous page)

sage: G.show()˓→needs sage.plot# long time#␣>>> from sage.all import *>>> G = graphs.RandomTree(Integer(10))>>> G.is_tree()True>>> G.show()# long time
˓→needs sage.plot#␣

sage.graphs.generators.random.RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None)
Return a tree with a power law degree distribution, or False on failure.
From the NetworkX documentation: a trial power law degree sequence is chosen and then elements are swappedwith 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 distribution• tries – number of attempts to adjust sequence to make a tree
• seed – a random.Random seed or a Python int for the random number generator (default: None)
EXAMPLES:
We check that the generated graph is a tree:
sage: G = graphs.RandomTreePowerlaw(10, 3)
˓→needs networkx
sage: G.is_tree()
˓→needs networkx
True
sage: G.order(), G.size()
˓→needs networkx(10, 9)#␣#␣#␣>>> from sage.all import *>>> G = graphs.RandomTreePowerlaw(Integer(10), Integer(3))˓→# needs networkx>>> G.is_tree()
˓→needs networkx
True>>> G.order(), G.size()
˓→needs networkx(10, 9)sage: G = graphs.RandomTreePowerlaw(15, 2)
˓→needs networkx
sage: if G:# random output
˓→needs networkx sage.plot....:
G.show()>>> from sage.all import *>>> G = graphs.RandomTreePowerlaw(Integer(15), Integer(2))

␣
#␣

#␣

#␣
# long time,␣␣(continues on next page)

1282

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)# needs networkx˓→>>> if G:
˓→networkx sage.plot...
G.show()# random output# long time, needs␣

sage.graphs.generators.random.RandomTriangulation(n, set_position=False, k=3, seed=None)
Return a random inner triangulation of an outer face of degree k with n vertices in total.
An inner triangulation is a plane graph all of whose faces (except the outer/unbounded face) are triangles (3-cycles).
INPUT:• n – the number of vertices of the graph• k – the size of the outer face
• set_position – boolean (default False); if set to True, this will compute coordinates for a planardrawing of the graph.
• seed – a random.Random seed or a Python int for the random number generator (default: None)OUTPUT:
A random graph chosen uniformly among the inner triangulations of a rooted 𝑘-gon with 𝑛 vertices (including the𝑘 vertices from the outer face). This is a planar graph and comes with a combinatorial embedding. The vertices of
the root edge are labelled -1 and -2 and the outer face is the face returned by Graph.faces() in which -1
and -2 are consecutive vertices in this order.
Because some triangulations have nontrivial automorphism groups, this may not be equal to the uniform distribution
among inner triangulations of unrooted 𝑘-gons.
ALGORITHM:
The algorithm is taken from [PS2006], Section 5.
Starting from a planar 𝑘-gonal forest (represented by its contour as a sequence of vertices), one performs local
closures, until no one is possible. A local closure amounts to replace in the cyclic contour word a sequence in1,
in2, in3, lf, in3 by in1, in3.
At every step of the algorithm, newly created edges are recorded in a graph, which will be returned at the end. The
combinatorial embedding is also computed and recorded in the output graph.
See also:
triangulations(), RandomTwoSphere().
EXAMPLES:
sage: 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)
˓→needs sage.plot
Graphics object consisting of 13 graphics primitives#␣sage: H = graphs.RandomTriangulation(7, k=5)
sage: sorted(len(f) for f in H.faces())[3, 3, 3, 3, 3, 3, 3, 5]

2.13. Random graphs1283

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.RandomTriangulation(Integer(6), True); G
Graph on 6 vertices>>> G.is_planar()
True>>> G.girth()3>>> G.plot(vertex_size=Integer(0), vertex_labels=False)˓→# needs sage.plot
Graphics object consisting of 13 graphics primitives

␣>>> H = graphs.RandomTriangulation(Integer(7), k=Integer(5))>>> sorted(len(f) for f in H.faces())[3, 3, 3, 3, 3, 3, 3, 5]

sage.graphs.generators.random.RandomUnitDiskGraph(n, radius=0.1, side=1, seed=None)
Return a random unit disk graph of order 𝑛.
A unit disk graph is the intersection graph of a family of unit disks in the Euclidean plane. That is a graph with
one vertex per disk of the family and an edge between two vertices whenever they lie within a unit distance of eachother. See the Wikipedia article Unit_disk_graph for more details.
INPUT:• n – number of nodes• radius – float (default: 0.1); two vertices at distance less than radius are connected by an edge
• side – float (default: 1); indicate the side of the area in which the points are drawn• seed – seed of the random number generator
EXAMPLES:
When using twice the same seed, the vertices get the same positions:sage: # needs scipy
sage: from sage.misc.randstate import current_randstate
sage: seed = current_randstate().seed()sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed)sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed)sage: H.is_subgraph(G, induced=False)
True
sage: H.size() <= G.size()
True
sage: Gpos = G.get_pos()sage: Hpos = H.get_pos()sage: all(Gpos[u] == Hpos[u] for u in G)
True>>> from sage.all import *>>> # needs scipy>>> from sage.misc.randstate import current_randstate>>> seed = current_randstate().seed()>>> G = graphs.RandomUnitDiskGraph(Integer(20), radius=RealNumber( .5 ),␣
˓→side=Integer(1), seed=seed)>>> H = graphs.RandomUnitDiskGraph(Integer(20), radius=RealNumber( .2 ),␣
˓→side=Integer(1), seed=seed)>>> H.is_subgraph(G, induced=False)(continues on next page)

1284

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

True>>> H.size() <= G.size()
True>>> Gpos = G.get_pos()>>> Hpos = H.get_pos()>>> all(Gpos[u] == Hpos[u] for u in G)
True

When the radius is more than√

2side, the graph is a clique:sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1)
˓→needs scipy
sage: G.is_clique()
˓→needs scipy
True>>> from sage.all import *>>> G = graphs.RandomUnitDiskGraph(Integer(10), radius=Integer(2),␣
˓→side=Integer(1))# needs scipy>>> G.is_clique()
˓→needs scipy
True

#␣
#␣

#␣

sage.graphs.generators.random.blossoming_contour(t, shift=0, seed=None)
Return a random blossoming of a binary tree 𝑡, as a contour word.
This is doing several things simultaneously:• complete the binary tree, by adding leaves labelled xb,• add a vertex labelled n at the middle of every inner edge, with a leaf labelled x either on the left or on theright (at random),• number all vertices (but not leaves) by integers starting from 𝑠ℎ𝑖𝑓 𝑡,• compute the counter-clockwise contour word of the result.
Initial vertices receive the label i.
This is an auxiliary function, used for the generation of random planar bicubic maps.
INPUT:• 𝑡 – a binary tree (non-empty)• shift – an integer (default 0), used as a starting index
OUTPUT:
contour word of a random blossoming of 𝑡
EXAMPLES:
sage: from sage.graphs.generators.random import blossoming_contour
sage: print(blossoming_contour(BinaryTrees(1).an_element()))[( i , 0), ( xb ,), ( i , 0), ( xb ,), ( i , 0)]
sage: t = BinaryTrees(2).random_element()
˓→needs sage.combinat
sage: print(blossoming_contour(t)) # random#␣#␣(continues on next page)

2.13. Random graphs

1285Graph Theory, Release 10.4

(continued from previous page)needs sage.combinat[( i , 0), ( xb ,), ( i , 0), ( n , 2), ( i , 1), ( xb ,), ( i , 1),( xb ,), ( i , 1), ( n , 2), ( x ,), ( n , 2), ( i , 0)]˓→

sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w)˓→needs sage.combinat
21
sage: w.count(( xb ,))˓→needs sage.combinat
4
sage: w.count(( x ,))˓→needs sage.combinat
2

#␣

#␣

#␣

>>> from sage.all import *>>> from sage.graphs.generators.random import blossoming_contour>>> print(blossoming_contour(BinaryTrees(Integer(1)).an_element()))[( i , 0), ( xb ,), ( i , 0), ( xb ,), ( i , 0)]>>> t = BinaryTrees(Integer(2)).random_element()˓→# needs sage.combinat>>> print(blossoming_contour(t)) # random
˓→needs sage.combinat[( i , 0), ( xb ,), ( i , 0), ( n , 2), ( i , 1), ( xb ,), ( i , 1),( xb ,), ( i , 1), ( n , 2), ( x ,), ( n , 2), ( i , 0)]>>> w = blossoming_contour(BinaryTrees(Integer(3)).random_element()); len(w)˓→# needs sage.combinat
21>>> w.count(( xb ,))˓→needs sage.combinat
4>>> w.count(( x ,))˓→needs sage.combinat
2

␣
#␣

␣

#␣

#␣

sage.graphs.generators.random.connecting_nodes(T, l)
Return a list of the vertex sets of n randomly chosen subtrees of T.
This method is part of RandomChordalGraph().
ALGORITHM:
For each subtree 𝑇𝑖 , we first select 𝑘𝑖 nodes of 𝑇 , where 𝑘𝑖 is a random integer from a Poisson distribution withmean 𝑙. 𝑇𝑖 is then generated to be the minimal subtree that contains the selected 𝑘𝑖 nodes. This implies that a subtree
will most likely have many more nodes than those selected initially, and this must be taken into consideration whenchoosing 𝑙.
See [SHET2018] for more details.
INPUT:• T – a tree
• l – a strictly positive real number; mean of a Poisson distribution
EXAMPLES:

1286

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: from sage.graphs.generators.random import connecting_nodes
sage: T = graphs.RandomTree(10)sage: S = connecting_nodes(T, 5)
˓→needs numpy
sage: len(S)˓→needs numpy
10>>> from sage.all import *>>> from sage.graphs.generators.random import connecting_nodes>>> T = graphs.RandomTree(Integer(10))>>> S = connecting_nodes(T, Integer(5))˓→# needs numpy>>> len(S)˓→needs numpy
10

#␣
#␣

␣
#␣

sage.graphs.generators.random.growing_subtrees(T, k)
Return a list of the vertex sets of n randomly chosen subtrees of T.
For a tree of order 𝑛, the collection contains 𝑛 subtrees with maximum order 𝑘 and average order 𝑘+1
2 .
This method is part of RandomChordalGraph().
ALGORITHM:
For each subtree 𝑇𝑖 , the algorithm picks a size 𝑘𝑖 randomly from [1, 𝑘]. Then a random node of 𝑇 is chosen as thefirst node of 𝑇𝑖 . In each of the subsequent 𝑘𝑖 − 1 iterations, it picks a random node in the neighborhood of 𝑇𝑖 andadds it to 𝑇𝑖 .
See [SHET2018] for more details.
INPUT:• T – a tree
• k – a strictly positive integer; maximum size of a subtree
EXAMPLES:
sage: from sage.graphs.generators.random import growing_subtrees
sage: T = graphs.RandomTree(10)sage: S = growing_subtrees(T, 5)
sage: len(S)10>>> from sage.all import *>>> from sage.graphs.generators.random import growing_subtrees>>> T = graphs.RandomTree(Integer(10))>>> S = growing_subtrees(T, Integer(5))>>> len(S)10sage.graphs.generators.random.pruned_tree(T, f, s)
Return a list of the vertex sets of n randomly chosen subtrees of T.
This method is part of RandomChordalGraph().
ALGORITHM:

2.13. Random graphs

1287

Graph Theory, Release 10.4

For each subtree 𝑇𝑖 , it randomly selects a fraction 𝑓 of the edges on the tree and removes them. The number ofedges to delete, say 𝑙, is calculated as ⌊((𝑛 − 1)𝑓 ⌋, which will leave 𝑙 + 1 subtrees in total. Then, it determines thesizes of the 𝑙 + 1 subtrees and stores the distinct values. Finally, it picks a random size 𝑘𝑖 from the set of largest
100(1 − 𝑠)% of distinct values, and randomly chooses a subtree with size 𝑘𝑖 .
See [SHET2018] for more details.
INPUT:• T – a tree
• f – a rational number; the edge deletion fraction. This value must be chosen in [0..1].
• s – a real number between 0 and 1; selection barrier for the size of trees
EXAMPLES:
sage: from sage.graphs.generators.random import pruned_tree
sage: T = graphs.RandomTree(11)sage: S = pruned_tree(T, 1/10, 0.5)
sage: len(S)11>>> from sage.all import *>>> from sage.graphs.generators.random import pruned_tree>>> T = graphs.RandomTree(Integer(11))>>> S = pruned_tree(T, Integer(1)/Integer(10), RealNumber( 0.5 ))>>> len(S)11

2.14 Various small graphs
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.smallgraphs.Balaban10Cage(embedding=1)
Return the Balaban 10-cage.
The Balaban 10-cage is a 3-regular graph with 70 vertices and 105 edges. See the Wikipedia article Balaban_10-cage.
The default embedding gives a deeper understanding of the graph’s automorphism group. It is divided into 4 layers(each layer being a set of points at equal distance from the drawing’s center). From outside to inside:• L1: The outer layer (vertices which are the furthest from the origin) is actually the disjoint union of two cyclesof 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 oflength 10.
This graph is not vertex-transitive, and its vertices are partitioned into 3 orbits: L2, L3, and the union of L1 of L4
whose elements are equivalent.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to be either 1 or 2

1288

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
sage: # needs networkx
sage: g = graphs.Balaban10Cage()sage: g.girth()10
sage: g.chromatic_number()2
sage: g.diameter()6
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
True
sage: g.show(figsize=[10,10])
˓→needs sage.plot#␣# long time>>> from sage.all import *>>> # needs networkx>>> g = graphs.Balaban10Cage()>>> g.girth()
10>>> g.chromatic_number()2>>> g.diameter()6>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> g.show(figsize=[Integer(10),Integer(10)])˓→# needs sage.plot#␣#␣# long time␣

sage.graphs.generators.smallgraphs.Balaban11Cage(embedding=1)
Return the Balaban 11-cage.
For more information, see the Wikipedia article Balaban_11-cage.
INPUT:• embedding – integer (default: 1); three embeddings are available, and can be selected by setting embedding to be 1, 2, or 3
– The first embedding is the one appearing on page 9 of the Fifth Annual Graph Drawing Contest report[EMMN1998]. It separates vertices based on their eccentricity (see eccentricity()).
– The second embedding has been produced just for Sage and is meant to emphasize the automorphismgroup’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:
sage: g = graphs.Balaban11Cage()sage: g.order()112(continues on next page)

2.14. Various small graphs1289Graph Theory, Release 10.4

(continued from previous page)

sage: g.size()
168
sage: g.girth()11
sage: g.diameter()8
sage: g.automorphism_group().cardinality()
˓→needs sage.groups64#␣>>> from sage.all import *>>> g = graphs.Balaban11Cage()>>> g.order()112>>> g.size()168>>> g.girth()11>>> g.diameter()8>>> g.automorphism_group().cardinality()
˓→needs sage.groups64#␣

Our many embeddings:
sage: g1 = graphs.Balaban11Cage(embedding=1)
sage: g2 = graphs.Balaban11Cage(embedding=2)
˓→needs networkx
sage: g3 = graphs.Balaban11Cage(embedding=3)
˓→needs networkx
sage: g1.show(figsize=[10,10])# long time
˓→needs sage.plot
sage: g2.show(figsize=[10,10])# long time
˓→needs networkx sage.plot
sage: g3.show(figsize=[10,10])# long time
˓→needs networkx sage.plot>>> from sage.all import *>>> g1 = graphs.Balaban11Cage(embedding=Integer(1))>>> g2 = graphs.Balaban11Cage(embedding=Integer(2))˓→# needs networkx>>> g3 = graphs.Balaban11Cage(embedding=Integer(3))˓→# needs networkx>>> g1.show(figsize=[Integer(10),Integer(10)])˓→# needs sage.plot>>> g2.show(figsize=[Integer(10),Integer(10)])˓→# needs networkx sage.plot>>> g3.show(figsize=[Integer(10),Integer(10)])˓→# needs networkx sage.plot

#␣
#␣
#␣
#␣
#␣

␣
␣
# long time␣# long time␣# long time␣Proof that the embeddings are the same graph:
sage: g1.is_isomorphic(g2)˓→needs networkx
True

1290

# g2 and g3 are obviously isomorphic#␣Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic
˓→needs networkx
True

#␣

sage.graphs.generators.smallgraphs.BidiakisCube()
Return the Bidiakis cube.
For more information, see the Wikipedia article Bidiakis_cube.
EXAMPLES:
The Bidiakis cube is a 3-regular graph having 12 vertices and 18 edges. This means that each vertex has a degreeof 3:
sage: g = graphs.BidiakisCube(); gBidiakis cube: Graph on 12 vertices
sage: g.show()˓→needs sage.plot
sage: g.order()12sage: g.size()18
sage: g.is_regular(3)True>>> from sage.all import *>>> g = graphs.BidiakisCube(); gBidiakis cube: Graph on 12 vertices>>> g.show()˓→needs sage.plot>>> g.order()12>>> g.size()18>>> g.is_regular(Integer(3))
True# long time

# long time#␣#␣

It is a Hamiltonian graph with diameter 3 and girth 4:
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
True
sage: g.diameter()3
sage: g.girth()4>>> from sage.all import *>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> g.diameter()3>>> g.girth()
4

2.14. Various small graphs

#␣

#␣

1291

Graph Theory, Release 10.4

It is a planar graph with characteristic polynomial (𝑥 − 3)(𝑥 − 2)(𝑥4 )(𝑥 + 1)(𝑥 + 2)(𝑥2 + 𝑥 − 4)2 and chromatic
number 3:
sage: g.is_planar()True
sage: char_poly = g.characteristic_polynomial()#␣˓→needs sage.modules
sage: x = char_poly.parent()( x )#␣˓→needs sage.modules
sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^
˓→2# needs sage.modules
True
sage: g.chromatic_number()#␣˓→needs sage.modules
3>>> from sage.all import *>>> g.is_planar()True>>> char_poly = g.characteristic_polynomial()#␣˓→needs sage.modules>>> x = char_poly.parent()( x )#␣˓→needs sage.modules>>> char_poly == (x - Integer(3)) * (x - Integer(2)) * (x**Integer(4)) * (x +␣˓→Integer(1)) * (x + Integer(2)) * (x**Integer(2) + x - Integer(4))**Integer(2)␣˓→# needs sage.modules
True>>> g.chromatic_number()#␣˓→needs sage.modules
3sage.graphs.generators.smallgraphs.BiggsSmithGraph(embedding=1)
Return the Biggs-Smith graph.
For more information, see the Wikipedia article Biggs-Smith_graph.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to be 1 or 2
EXAMPLES:
Basic properties:
sage: # needs networkx
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
˓→needs sage.plot

1292

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs networkx>>> g = graphs.BiggsSmithGraph()>>> g.order()102>>> g.size()153>>> g.girth()9>>> g.diameter()7>>> g.automorphism_group().cardinality()# long time2448>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot␣The other embedding:sage: graphs.BiggsSmithGraph(embedding=2).show()˓→needs networkx# long time>>> from sage.all import *>>> graphs.BiggsSmithGraph(embedding=Integer(2)).show()˓→# needs networkx#␣# long time␣

sage.graphs.generators.smallgraphs.BlanusaFirstSnarkGraph()
Return the first Blanusa Snark Graph.
The Blanusa graphs are two snarks on 18 vertices and 27 edges. For more information on them, see the Wikipedia
article Blanusa_snarks.
See also:• BlanusaSecondSnarkGraph().
EXAMPLES:
sage: g = graphs.BlanusaFirstSnarkGraph()
sage: g.order()18
sage: g.size()27
sage: g.diameter()4
sage: g.girth()5
sage: g.automorphism_group().cardinality()
˓→needs sage.groups8#␣>>> from sage.all import *>>> g = graphs.BlanusaFirstSnarkGraph()>>> g.order()18>>> g.size()
27(continues on next page)

2.14. Various small graphs1293

Graph Theory, Release 10.4

(continued from previous page)>>> g.diameter()4>>> g.girth()5>>> g.automorphism_group().cardinality()
˓→needs sage.groups8#␣

sage.graphs.generators.smallgraphs.BlanusaSecondSnarkGraph()
Return the second Blanusa Snark Graph.
The Blanusa graphs are two snarks on 18 vertices and 27 edges. For more information on them, see the Wikipedia
article Blanusa_snarks.
See also:• BlanusaFirstSnarkGraph().
EXAMPLES:
sage: g = graphs.BlanusaSecondSnarkGraph()
sage: g.order()18
sage: g.size()27
sage: g.diameter()4
sage: g.girth()5
sage: g.automorphism_group().cardinality()
˓→needs sage.groups4#␣>>> from sage.all import *>>> g = graphs.BlanusaSecondSnarkGraph()>>> g.order()18>>> g.size()27>>> g.diameter()4>>> g.girth()5>>> g.automorphism_group().cardinality()
˓→needs sage.groups4#␣

sage.graphs.generators.smallgraphs.BrinkmannGraph()
Return the Brinkmann graph.
For more information, see the Wikipedia article Brinkmann_graph.
EXAMPLES:
The Brinkmann graph is a 4-regular graph having 21 vertices and 42 edges. This means that each vertex has degree
4:

1294

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.BrinkmannGraph(); G
Brinkmann graph: Graph on 21 vertices
sage: G.show()˓→needs sage.plot
sage: G.order()21
sage: G.size()42
sage: G.is_regular(4)True# long time>>> from sage.all import *>>> G = graphs.BrinkmannGraph(); G
Brinkmann graph: Graph on 21 vertices>>> G.show()# long time
˓→needs sage.plot>>> G.order()21>>> G.size()42>>> G.is_regular(Integer(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>>> from sage.all import *>>> G.is_eulerian()
True>>> G.radius()
3>>> G.diameter()3>>> G.girth()
5

The Brinkmann graph is also Hamiltonian with chromatic number 4:
sage: G.is_hamiltonian()
˓→needs sage.numerical.mip
True
sage: G.chromatic_number()4>>> from sage.all import *>>> G.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

#␣

(continues on next page)

2.14. Various small graphs

1295Graph Theory, Release 10.4

(continued from previous page)>>> G.chromatic_number()4

Its automorphism group is isomorphic to 𝐷7 :sage: ag = G.automorphism_group()
˓→needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(7))˓→needs sage.groups
True

#␣
#␣

>>> from sage.all import *>>> ag = G.automorphism_group()
˓→needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(7)))˓→# needs sage.groups
True

#␣
␣

sage.graphs.generators.smallgraphs.BrouwerHaemersGraph()
Return the Brouwer-Haemers Graph.
The Brouwer-Haemers is the only strongly regular graph of parameters (81, 20, 1, 6). It is build in Sage as theAffine Orthogonal graph 𝑉 𝑂− (6, 3). For more information on this graph, see its corresponding page on Andries
Brouwer’s website.
EXAMPLES:
sage: g = graphs.BrouwerHaemersGraph(); g˓→needs sage.modules
Brouwer-Haemers: Graph on 81 vertices#␣>>> from sage.all import *>>> g = graphs.BrouwerHaemersGraph(); g˓→needs sage.modules
Brouwer-Haemers: Graph on 81 vertices#␣

It is indeed strongly regular with parameters (81, 20, 1, 6):
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(81, 20, 1, 6)>>> from sage.all import *>>> g.is_strongly_regular(parameters=True)
˓→needs sage.modules sage.rings.finite_rings(81, 20, 1, 6)# long time

# long time#␣#␣

Its has as eigenvalues 20, 2 and −7:sage: set(g.spectrum()) == {20,2,-7}
˓→needs sage.modules sage.rings.finite_rings
True

#␣

>>> from sage.all import *>>> set(g.spectrum()) == {Integer(20),Integer(2),-Integer(7)}␣(continues on next page)

1296

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)˓→# needs sage.modules sage.rings.finite_rings

True

sage.graphs.generators.smallgraphs.BuckyBall()Return the Bucky Ball graph.
This graph is a 3-regular 60-vertex planar graph. Its vertices and edges correspond precisely to the carbon atoms andbonds 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>>> from sage.all import *>>> g = graphs.BuckyBall()>>> g.is_planar()
True

The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky Ball polyhedron, but this is muchslower:sage: # needs sage.geometry.polyhedron sage.groups sage.rings.number_fieldsage: g = polytopes.buckyball().vertex_graph()
sage: g.remove_loops()
sage: h = graphs.BuckyBall()sage: g.is_isomorphic(h)True>>> from sage.all import *>>> # needs sage.geometry.polyhedron sage.groups sage.rings.number_field>>> g = polytopes.buckyball().vertex_graph()>>> g.remove_loops()>>> h = graphs.BuckyBall()>>> g.is_isomorphic(h)True

The graph is returned along with an attractive embedding:sage: g = graphs.BuckyBall() # long time
sage: g.plot(vertex_labels=False, vertex_size=10).show()˓→needs sage.plot# long time,␣

>>> from sage.all import *>>> g = graphs.BuckyBall() # long time>>> g.plot(vertex_labels=False, vertex_size=Integer(10)).show()
˓→time, needs sage.plot# long␣sage.graphs.generators.smallgraphs.CameronGraph()
Return the Cameron graph.
The Cameron graph is strongly regular with parameters 𝑣 = 231, 𝑘 = 30, 𝜆 = 9, 𝜇 = 3.

2.14. Various small graphs

1297Graph Theory, Release 10.4

For more information on the Cameron graph, see https://www.win.tue.nl/ aeb/graphs/Cameron.html.
EXAMPLES:
sage: # needs sage.groups
sage: g = graphs.CameronGraph()
sage: g.order()231
sage: g.size()
3465
sage: g.is_strongly_regular(parameters=True)(231, 30, 9, 3)>>> from sage.all import *>>> # needs sage.groups>>> g = graphs.CameronGraph()>>> g.order()231>>> g.size()3465>>> g.is_strongly_regular(parameters=True)(231, 30, 9, 3)# long time

# long time

sage.graphs.generators.smallgraphs.Cell120()
Return the 120-Cell graph.
This is the adjacency graph of the 120-cell. It has 600 vertices and 1200 edges. For more information, see the
Wikipedia article 120-cell.
EXAMPLES:
sage: # long time, needs sage.rings.number_fieldsage: g = graphs.Cell120()sage: g.size()
1200
sage: g.is_regular(4)True
sage: g.is_vertex_transitive()
True>>> from sage.all import *>>> # long time, needs sage.rings.number_field>>> g = graphs.Cell120()>>> g.size()
1200>>> g.is_regular(Integer(4))
True>>> g.is_vertex_transitive()
True

sage.graphs.generators.smallgraphs.Cell600(embedding=1)
Return the 600-Cell graph.
This is the adjacency graph of the 600-cell. It has 120 vertices and 720 edges. For more information, see the
Wikipedia article 600-cell.
INPUT:• embedding – integer (default: 1); two different embeddings for a plot
1298

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

EXAMPLES:
sage: # long time, needs sage.rings.number_fieldsage: g = graphs.Cell600()
sage: g.size()
720
sage: g.is_regular(12)Truesage: g.is_vertex_transitive()
True>>> from sage.all import *>>> # long time, needs sage.rings.number_field>>> g = graphs.Cell600()>>> g.size()
720>>> g.is_regular(Integer(12))
True>>> g.is_vertex_transitive()
True

sage.graphs.generators.smallgraphs.ChvatalGraph()
Return the Chvatal graph.
Chvatal graph is one of the few known graphs to satisfy Grunbaum’s conjecture that for every 𝑚, 𝑛, there
is an 𝑚-regular, 𝑚-chromatic graph of girth at least 𝑛. For more information, see the Wikipedia article
Chv%C3%A1tal_graph.
EXAMPLES:The Chvatal graph has 12 vertices and 24 edges. It is a 4-regular, 4-chromatic graph with radius 2, diameter 2, andgirth 4:sage: G = graphs.ChvatalGraph(); G
Chvatal graph: Graph on 12 vertices
sage: G.order(); G.size()
1224
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>>> from sage.all import *>>> G = graphs.ChvatalGraph(); G
Chvatal graph: Graph on 12 vertices>>> G.order(); G.size()1224>>> G.degree()[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]>>> G.chromatic_number()4>>> G.radius(); G.diameter(); G.girth()(continues on next page)

2.14. Various small graphs

1299

Graph Theory, Release 10.4

(continued from previous page)2
2
4

sage.graphs.generators.smallgraphs.ClebschGraph()
Return the Clebsch graph.
See the Wikipedia article Clebsch_graph for more information.
EXAMPLES:
sage: g = graphs.ClebschGraph()
sage: g.automorphism_group().cardinality()
˓→needs sage.groups
1920
sage: g.girth()4
sage: g.chromatic_number()4
sage: g.diameter()2
sage: g.show(figsize=[10, 10])# long time
˓→needs sage.plot>>> from sage.all import *>>> g = graphs.ClebschGraph()>>> g.automorphism_group().cardinality()
˓→needs sage.groups
1920>>> g.girth()4>>> g.chromatic_number()4>>> g.diameter()2>>> g.show(figsize=[Integer(10), Integer(10)])˓→# needs sage.plot

#␣

#␣

#␣

# long time␣

sage.graphs.generators.smallgraphs.CoxeterGraph()
Return the Coxeter graph.
See the Wikipedia article Coxeter_graph.
EXAMPLES:
sage: g = graphs.CoxeterGraph()
sage: g.automorphism_group().cardinality()
˓→needs sage.groups336
sage: g.girth()7
sage: g.chromatic_number()3
sage: g.diameter()4
sage: g.show(figsize=[10, 10])# long time
˓→needs sage.plot

1300

#␣

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CoxeterGraph()>>> g.automorphism_group().cardinality()
˓→needs sage.groups336>>> g.girth()7>>> g.chromatic_number()3>>> g.diameter()4>>> g.show(figsize=[Integer(10), Integer(10)])˓→# needs sage.plot#␣# long time␣

sage.graphs.generators.smallgraphs.DejterGraph()
Return the Dejter graph.
The Dejter graph is obtained from the binary 7-cube by deleting a copy of the Hamming code of length 7. It is
6-regular, with 112 vertices and 336 edges. For more information, see the Wikipedia article Dejter_graph.
EXAMPLES:
sage: g = graphs.DejterGraph(); g˓→needs sage.rings.finite_rings
Dejter Graph: Graph on 112 vertices
sage: g.is_regular(k=6)˓→needs sage.rings.finite_rings
True
sage: g.girth()˓→needs sage.rings.finite_rings
4>>> from sage.all import *>>> g = graphs.DejterGraph(); g˓→needs sage.rings.finite_rings
Dejter Graph: Graph on 112 vertices>>> g.is_regular(k=Integer(6))˓→# needs sage.rings.finite_rings
True>>> g.girth()˓→needs sage.rings.finite_rings
4

#␣

#␣

#␣

#␣

␣

#␣

sage.graphs.generators.smallgraphs.DesarguesGraph()
Return the Desargues graph.
PLOTTING: The layout chosen is the same as on the cover of [Har1994].
EXAMPLES:
sage: D = graphs.DesarguesGraph()
sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5)
˓→needs networkx
sage: D.is_isomorphic(L)˓→needs networkx
True
sage: D.show()# long time
˓→needs sage.plot

2.14. Various small graphs

#␣
#␣

#␣

1301

Graph Theory, Release 10.4>>> from sage.all import *>>> D = graphs.DesarguesGraph()>>> L = graphs.LCFGraph(Integer(20),[Integer(5),-Integer(5),Integer(9),˓→Integer(9)],Integer(5))# needs networkx>>> D.is_isomorphic(L)#␣˓→needs networkx
True>>> D.show()# long time#␣˓→needs sage.plot

sage.graphs.generators.smallgraphs.DoubleStarSnark()
Return the double star snark.
The double star snark is a 3-regular graph on 30 vertices. See the Wikipedia article Double-star_snark.
EXAMPLES:
sage: g = graphs.DoubleStarSnark()
sage: g.order()30
sage: g.size()
45
sage: g.chromatic_number()3
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
False
sage: g.automorphism_group().cardinality()
˓→needs sage.groups
80
sage: g.show()˓→needs sage.plot

#␣

#␣

#␣

>>> from sage.all import *>>> g = graphs.DoubleStarSnark()>>> g.order()30>>> g.size()45>>> g.chromatic_number()3>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
False>>> g.automorphism_group().cardinality()
˓→needs sage.groups
80>>> g.show()˓→needs sage.plot

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.DurerGraph()
Return the Dürer graph.
For more information, see the Wikipedia article D%C3%BCrer_graph.
EXAMPLES:The Dürer graph is named after Albrecht Dürer. It is a planar graph with 12 vertices and 18 edges:

1302

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.DurerGraph(); G
Durer graph: Graph on 12 vertices
sage: G.is_planar()True
sage: G.order()12sage: G.size()18>>> from sage.all import *>>> G = graphs.DurerGraph(); G
Durer graph: Graph on 12 vertices>>> G.is_planar()
True>>> G.order()12>>> 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>>> from sage.all import *>>> G.chromatic_number()3>>> G.diameter()
4>>> G.girth()3

Its automorphism group is isomorphic to 𝐷6 :sage: ag = G.automorphism_group()
˓→needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(6))˓→needs sage.groups
True>>> from sage.all import *>>> ag = G.automorphism_group()
˓→needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(6)))˓→# needs sage.groups
True

#␣
#␣

#␣
␣

sage.graphs.generators.smallgraphs.DyckGraph()
Return the Dyck graph.
For more information, see the MathWorld article on the Dyck graph or the Wikipedia article Dyck_graph.
EXAMPLES:
2.14. Various small graphs1303

Graph Theory, Release 10.4

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>>> from sage.all import *>>> G = graphs.DyckGraph(); G
Dyck graph: Graph on 32 vertices>>> G.order()32>>> G.size()48>>> G.is_regular()
True>>> G.is_regular(Integer(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()
˓→needs sage.numerical.mip
True
sage: G.is_bipartite()True>>> from sage.all import *>>> G.is_planar()
False>>> G.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> G.is_bipartite()
True

#␣

#␣

It has radius 5, diameter 5, and girth 6:
sage: G.radius()
5
sage: G.diameter()5
sage: G.girth()6>>> from sage.all import *>>> G.radius()
5(continues on next page)

1304

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> G.diameter()5>>> 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()
˓→needs sage.groups
192>>> from sage.all import *>>> G.chromatic_number()2>>> G.automorphism_group().cardinality()
˓→needs sage.groups
192

#␣

#␣

It is a non-integral graph as it has irrational eigenvalues:
sage: G.characteristic_polynomial().factor()˓→needs sage.libs.pari sage.modules(x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6>>> from sage.all import *>>> G.characteristic_polynomial().factor()˓→needs sage.libs.pari sage.modules(x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6#␣#␣

It is a toroidal graph, and its embedding on a torus is dual to an embedding of the Shrikhande graph(ShrikhandeGraph).
sage.graphs.generators.smallgraphs.EllinghamHorton54Graph()
Return the Ellingham-Horton 54-graph.
For more information, see the Wikipedia article Ellingham-Horton_graph.
EXAMPLES:This graph is 3-regular:
sage: g = graphs.EllinghamHorton54Graph()
sage: g.is_regular(k=3)
True>>> from sage.all import *>>> g = graphs.EllinghamHorton54Graph()>>> g.is_regular(k=Integer(3))
True

It is 3-connected and bipartite:sage: g.vertex_connectivity()3# not tested - too long(continues on next page)

2.14. Various small graphs

1305

Graph Theory, Release 10.4

(continued from previous page)

sage: g.is_bipartite()True>>> from sage.all import *>>> g.vertex_connectivity()3>>> g.is_bipartite()True# not tested - too long

It is not Hamiltonian:sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
False# not tested>>> from sage.all import *>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
False

#␣

# not tested#␣… and it has a nice drawing
sage: g.show(figsize=[10, 10])# not tested - too long>>> from sage.all import *>>> g.show(figsize=[Integer(10), Integer(10)])# not tested - too longsage.graphs.generators.smallgraphs.EllinghamHorton78Graph()
Return the Ellingham-Horton 78-graph.
For more information, see the Wikipedia article Ellingham%E2%80%93Horton_graph
EXAMPLES:This graph is 3-regular:
sage: g = graphs.EllinghamHorton78Graph()
sage: g.is_regular(k=3)
True>>> from sage.all import *>>> g = graphs.EllinghamHorton78Graph()>>> g.is_regular(k=Integer(3))
True

It is 3-connected and bipartite:sage: g.vertex_connectivity()3
sage: g.is_bipartite()True>>> from sage.all import *>>> g.vertex_connectivity()3# not tested (too long)# not tested (too long)(continues on next page)

1306

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_bipartite()
True

It is not Hamiltonian:sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
False# not tested>>> from sage.all import *>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
False

#␣

# not tested#␣… and it has a nice drawing
sage: g.show(figsize=[10,10])# not tested (too long)>>> from sage.all import *>>> g.show(figsize=[Integer(10),Integer(10)])# not tested (too long)sage.graphs.generators.smallgraphs.ErreraGraph()
Return the Errera graph.
For more information, see the Wikipedia article Errera_graph.
EXAMPLES:
The Errera graph is named after Alfred Errera. It is a planar graph on 17 vertices and having 45 edges:
sage: G = graphs.ErreraGraph(); G
Errera graph: Graph on 17 vertices
sage: G.is_planar()True
sage: G.order()17sage: G.size()45>>> from sage.all import *>>> G = graphs.ErreraGraph(); G
Errera graph: Graph on 17 vertices>>> G.is_planar()
True>>> G.order()17>>> G.size()45

The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and chromatic number 4:
sage: G.is_hamiltonian()
˓→needs sage.numerical.mip
True
sage: G.radius()3#␣(continues on next page)

2.14. Various small graphs

1307

Graph Theory, Release 10.4

(continued from previous page)

sage: G.diameter()4
sage: G.girth()3
sage: G.chromatic_number()4>>> from sage.all import *>>> G.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> G.radius()
3>>> G.diameter()
4>>> G.girth()3>>> 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 numberof vertices of degree 6, then 𝑓 + 𝑠 is equal to the order of the Errera graph:
sage: D = G.degree_sequence()
sage: D.count(5) + D.count(6) == G.order()True>>> from sage.all import *>>> D = G.degree_sequence()>>> D.count(Integer(5)) + D.count(Integer(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()
˓→needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(10))˓→needs sage.groups
True

#␣
#␣

>>> from sage.all import *>>> ag = G.automorphism_group()
˓→needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(10)))˓→# needs sage.groups
True

#␣
␣

sage.graphs.generators.smallgraphs.F26AGraph()
Return the F26A graph.
The F26A graph is a symmetric bipartite cubic graph with 26 vertices and 39 edges. For more information, see the
Wikipedia article F26A_graph.
EXAMPLES:

1308

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs networkx
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>>> from sage.all import *>>> # needs networkx>>> g = graphs.F26AGraph(); g
F26A Graph: Graph on 26 vertices>>> g.order(), g.size()(26, 39)>>> g.automorphism_group().cardinality()78>>> g.girth()6>>> g.is_bipartite()True>>> g.characteristic_polynomial().factor()(x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6

sage.graphs.generators.smallgraphs.FlowerSnark()
Return a Flower Snark.
A flower snark has 20 vertices. It is part of the class of biconnected cubic graphs with edge chromatic number = 4,
known as snarks. (i.e.: the Petersen graph). All snarks are not Hamiltonian, non-planar and have Petersen graph
graph minors. See the Wikipedia article Flower_snark.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the nodes are drawn 0-14 on the outer circle, and 15-19 in an inner pentagon.
EXAMPLES: Inspect a flower snark:
sage: F = graphs.FlowerSnark()
sage: F
Flower Snark: Graph on 20 vertices
sage: F.graph6_string()
ShCGHC@?GGg@?@?Gp?K??C?CA?G?_G?Cc>>> from sage.all import *>>> F = graphs.FlowerSnark()>>> F
Flower Snark: Graph on 20 vertices>>> F.graph6_string()
ShCGHC@?GGg@?@?Gp?K??C?CA?G?_G?Cc

Now show it:

2.14. Various small graphs1309

Graph Theory, Release 10.4

sage: F.show()˓→needs sage.plot>>> from sage.all import *>>> F.show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.smallgraphs.FolkmanGraph()
Return the Folkman graph.
See the Wikipedia article Folkman_graph.
EXAMPLES:
sage: # needs networkx
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()
˓→needs sage.numerical_mip
True
sage: g.is_vertex_transitive()
False
sage: g.is_bipartite()True>>> from sage.all import *>>> # needs networkx>>> g = graphs.FolkmanGraph()>>> g.order()20>>> g.size()40>>> g.diameter()4>>> g.girth()4>>> g.charpoly().factor()(x - 4) * (x + 4) * x^10 * (x^2 - 6)^4>>> g.chromatic_number()2>>> g.is_eulerian()True>>> g.is_hamiltonian()
˓→needs sage.numerical_mip#␣#␣(continues on next page)

1310

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)True>>> g.is_vertex_transitive()
False>>> g.is_bipartite()True

sage.graphs.generators.smallgraphs.FosterGraph()
Return the Foster graph.
See the Wikipedia article Foster_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.FosterGraph()
sage: g.order()90sage: g.size()
135
sage: g.diameter()8
sage: g.girth()10
sage: g.automorphism_group().cardinality()
4320
sage: g.is_hamiltonian()
˓→needs sage.numerical_mip
True>>> from sage.all import *>>> # needs networkx>>> g = graphs.FosterGraph()>>> g.order()90>>> g.size()135>>> g.diameter()8>>> g.girth()
10>>> g.automorphism_group().cardinality()
4320>>> g.is_hamiltonian()
˓→needs sage.numerical_mip
True

#␣

#␣

sage.graphs.generators.smallgraphs.FranklinGraph()
Return the Franklin graph.
For more information, see the Wikipedia article Franklin_graph.
EXAMPLES:
The Franklin graph is named after Philip Franklin. It is a 3-regular graph on 12 vertices and having 18 edges:
sage: G = graphs.FranklinGraph(); GFranklin graph: Graph on 12 vertices(continues on next page)

2.14. Various small graphs1311

Graph Theory, Release 10.4

(continued from previous page)

sage: G.is_regular(3)True
sage: G.order()12sage: G.size()18>>> from sage.all import *>>> G = graphs.FranklinGraph(); GFranklin graph: Graph on 12 vertices>>> G.is_regular(Integer(3))
True>>> G.order()12>>> G.size()18

The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4:
sage: G.is_hamiltonian()
˓→needs sage.numerical_mip
True
sage: G.is_bipartite()True
sage: G.radius()
3
sage: G.diameter()3
sage: G.girth()4>>> from sage.all import *>>> G.is_hamiltonian()
˓→needs sage.numerical_mip
True>>> G.is_bipartite()
True>>> G.radius()
3>>> G.diameter()3>>> 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>>> from sage.all import *>>> G.is_perfect()(continues on next page)1312

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

True>>> G.is_triangle_free()True>>> G.chromatic_number()2

sage.graphs.generators.smallgraphs.FruchtGraph()
Return a Frucht Graph.
A Frucht graph has 12 nodes and 18 edges. It is the smallest cubic identity graph. It is planar and Hamiltonian.
See the Wikipedia article Frucht_graph.
PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the first seven nodes are on the outer circle, with the next four on an inner circle and the last in the center.
EXAMPLES:
sage: FRUCHT = graphs.FruchtGraph()
sage: FRUCHT
Frucht graph: Graph on 12 vertices
sage: FRUCHT.graph6_string()
KhCKM?_EGK?L
sage: (graphs.FruchtGraph()).show()˓→needs networkx>>> from sage.all import *>>> FRUCHT = graphs.FruchtGraph()>>> FRUCHT
Frucht graph: Graph on 12 vertices>>> FRUCHT.graph6_string()
KhCKM?_EGK?L>>> (graphs.FruchtGraph()).show()˓→needs networkx# long time

# long time#␣#␣

sage.graphs.generators.smallgraphs.GoldnerHararyGraph()
Return the Goldner-Harary graph.
For more information, see the Wikipedia article Goldner%E2%80%93Harary_graph.
EXAMPLES:The Goldner-Harary graph is named after A. Goldner and Frank Harary. It is a planar graph having 11 vertices
and 27 edges:
sage: G = graphs.GoldnerHararyGraph(); G
Goldner-Harary graph: Graph on 11 vertices
sage: G.is_planar()True
sage: G.order()11sage: G.size()27>>> from sage.all import *>>> G = graphs.GoldnerHararyGraph(); G
Goldner-Harary graph: Graph on 11 vertices>>> G.is_planar()(continues on next page)

2.14. Various small graphs1313

Graph Theory, Release 10.4

(continued from previous page)

True>>> G.order()11>>> G.size()
27

The Goldner-Harary graph is chordal with radius 2, diameter 2, and girth 3:
sage: G.is_chordal()Truesage: G.radius()
2
sage: G.diameter()2
sage: G.girth()3>>> from sage.all import *>>> G.is_chordal()
True>>> G.radius()
2>>> G.diameter()2>>> 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()
˓→needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(6))˓→needs sage.groups
True

#␣
#␣

>>> from sage.all import *>>> G.chromatic_number()4>>> ag = G.automorphism_group()
˓→needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(6)))˓→# needs sage.groups
True

#␣
␣

sage.graphs.generators.smallgraphs.GolombGraph()
Return the Golomb graph.
See the Wikipedia article Golomb_graph for more information.
EXAMPLES:The Golomb graph is a planar and Hamiltonian graph with 10 vertices and 18 edges. It has chromatic number 4,
diameter 3, radius 2 and girth 3. It can be drawn in the plane as a unit distance graph:

1314

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G = graphs.GolombGraph(); G˓→needs sage.symbolic
Golomb graph: Graph on 10 vertices
sage: pos = G.get_pos()
˓→needs sage.symbolic
sage: def dist2(u, v):....:
return (u[0]-v[0])**2 + (u[1]-v[1])**2
sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None))˓→needs sage.symbolicTrue>>> from sage.all import *>>> G = graphs.GolombGraph(); G˓→needs sage.symbolic
Golomb graph: Graph on 10 vertices>>> pos = G.get_pos()
˓→needs sage.symbolic>>> def dist2(u, v):...
return (u[Integer(0)]-v[Integer(0)])**Integer(2) + (u[Integer(1)]˓→v[Integer(1)])**Integer(2)>>> all(dist2(pos[u], pos[v]) == Integer(1) for u, v in G.edge_
˓→iterator(labels=None))# needs sage.symbolic
True

#␣

#␣

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.GossetGraph()
Return the Gosset graph.
The Gosset graph is the skeleton of the Gosset_3_21() polytope. It has with 56 vertices and degree 27. For
more information, see the Wikipedia article Gosset_graph.
EXAMPLES:
sage: g = graphs.GossetGraph(); gGosset Graph: Graph on 56 vertices
sage: g.order(), g.size()(56, 756)>>> from sage.all import *>>> g = graphs.GossetGraph(); gGosset Graph: Graph on 56 vertices>>> g.order(), g.size()(56, 756)

sage.graphs.generators.smallgraphs.GrayGraph(embedding=1)
Return the Gray graph.
See the Wikipedia article Gray_graph.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.GrayGraph()
sage: g.order()(continues on next page)

2.14. Various small graphs

1315Graph Theory, Release 10.4

(continued from previous page)54
sage: g.size()81
sage: g.girth()8
sage: g.diameter()6
sage: g.show(figsize=[10, 10])# long time
˓→needs sage.plot
sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10])˓→needs sage.plot#␣# long time,␣

>>> from sage.all import *>>> # needs networkx>>> g = graphs.GrayGraph()>>> g.order()54>>> g.size()81>>> g.girth()8>>> g.diameter()6>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot>>> graphs.GrayGraph(embedding=Integer(2)).show(figsize=[Integer(10),␣
˓→Integer(10)])# long time, needs sage.plot

␣

sage.graphs.generators.smallgraphs.GritsenkoGraph()
Return SRG(65, 32, 15, 16) constructed by Gritsenko.
We took the adjacency matrix from O. Gritsenko’s [Gri2021] and extracted orbits of the automorphism group on
the edges.
EXAMPLES:
sage: H = graphs.GritsenkoGraph(); H
˓→needs sage.groups
Gritsenko strongly regular graph: Graph on 65 vertices
sage: H.is_strongly_regular(parameters=True)
˓→needs sage.groups(65, 32, 15, 16)>>> from sage.all import *>>> H = graphs.GritsenkoGraph(); H
˓→needs sage.groups
Gritsenko strongly regular graph: Graph on 65 vertices>>> H.is_strongly_regular(parameters=True)
˓→needs sage.groups(65, 32, 15, 16)

#␣

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.GrotzschGraph()
Return the Grötzsch graph.
The Grötzsch graph is an example of a triangle-free graph with chromatic number equal to 4. For more information,
see the Wikipedia article Gr%C3%B6tzsch_graph.

1316

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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()
˓→needs sage.numerical.mip
True
sage: G.order()11sage: G.size()
20>>> from sage.all import *>>> G = graphs.GrotzschGraph(); G
Grotzsch graph: Graph on 11 vertices>>> G.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> G.order()11>>> 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>>> from sage.all import *>>> G.is_triangle_free()True>>> G.radius()
2>>> G.diameter()2>>> 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()
˓→needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(5))˓→needs sage.groupsTrue

2.14. Various small graphs

#␣
#␣

1317

Graph Theory, Release 10.4>>> from sage.all import *>>> G.chromatic_number()4>>> ag = G.automorphism_group()
˓→needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(5)))˓→# needs sage.groups
True

#␣
␣

sage.graphs.generators.smallgraphs.HallJankoGraph(from_string=True)
Return the Hall-Janko graph.
For more information on the Hall-Janko graph, see the Wikipedia article Hall-Janko_graph.
The construction used to generate this graph in Sage is by a 100-point permutation representation of the Janko group
𝐽2 , as described in version 3 of the ATLAS of Finite Group representations, in particular on the page ATLAS: J2– Permutation representation on 100 points.
INPUT:• from_string – boolean (default: True); whether to build the graph from its sparse6 string or through
GAP. The two methods return the same graph though doing it through GAP takes more time.
EXAMPLES:
sage: g = graphs.HallJankoGraph()
sage: g.is_regular(36)True
sage: g.is_vertex_transitive()
˓→needs sage.groups
True

#␣

>>> from sage.all import *>>> g = graphs.HallJankoGraph()>>> g.is_regular(Integer(36))
True>>> g.is_vertex_transitive()
˓→needs sage.groups
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
>>> from sage.all import *>>> nu = set(g.neighbors(Integer(0)))>>> for v in range(Integer(1), Integer(100)):...
if v in nu:(continues on next page)

1318

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

...
...
...
...
...
...
...
...

expected = Integer(14)else:
expected = Integer(12)nv = set(g.neighbors(v))
nv.discard(Integer(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())˓→needs sage.libs.pari sage.modules(x - 36) * (x - 6)^36 * (x + 4)^63>>> from sage.all import *>>> g.diameter()2>>> g.girth()3>>> factor(g.characteristic_polynomial())˓→needs sage.libs.pari sage.modules(x - 36) * (x - 6)^36 * (x + 4)^63#␣#␣

sage.graphs.generators.smallgraphs.HarborthGraph()
Return the Harborth Graph.
The Harborth graph has 104 edges and 52 vertices, and is the smallest known example of a 4-regular matchstickgraph. For more information, see the Wikipedia article Harborth_graph.
EXAMPLES:
sage: g = graphs.HarborthGraph(); gHarborth Graph: Graph on 52 vertices
sage: g.is_regular(4)True>>> from sage.all import *>>> g = graphs.HarborthGraph(); gHarborth Graph: Graph on 52 vertices>>> g.is_regular(Integer(4))
Truesage.graphs.generators.smallgraphs.HarriesGraph(embedding=1)
Return the Harries Graph.
The Harries graph is a Hamiltonian 3-regular graph on 70 vertices. See the Wikipedia article Harries_graph.
The default embedding here is to emphasize the graph’s 4 orbits. This graph actually has a funny construction. The
following procedure gives an idea of it, though not all the adjacencies are being properly defined.
1. Take two disjoint copies of a Petersen graph. Their vertices will form an orbit of the final graph.
2. Subdivide all the edges once, to create 15+15=30 new vertices, which together form another orbit.
2.14. Various small graphs1319

Graph Theory, Release 10.4

3. Create 15 vertices, each of them linked to 2 corresponding vertices of the previous orbit, one in each of thetwo subdivided Petersen graphs. At the end of this step all vertices from the previous orbit have degree 3, andthe only vertices of degree 2 in the graph are those that were just created.
4. Create 5 vertices connected only to the ones from the previous orbit so that the graph becomes 3-regular.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.HarriesGraph()
sage: g.order()70sage: g.size()105
sage: g.girth()10
sage: g.diameter()6
sage: g.show(figsize=[10, 10])# long time
˓→needs sage.plot
sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10])˓→needs sage.plot#␣# long time,␣

>>> from sage.all import *>>> # needs networkx>>> g = graphs.HarriesGraph()>>> g.order()70>>> g.size()105>>> g.girth()
10>>> g.diameter()6>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot>>> graphs.HarriesGraph(embedding=Integer(2)).show(figsize=[Integer(10),␣
˓→Integer(10)])# long time, needs sage.plot

␣

sage.graphs.generators.smallgraphs.HarriesWongGraph(embedding=1)
Return the Harries-Wong Graph.
See the Wikipedia article Harries-Wong_graph.
About the default embedding:
The default embedding is an attempt to emphasize the graph’s 8 (!!!) different orbits. In order to understand thisbetter, 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.

1320

Chapter 2. Constructors and databases

Graph Theory, Release 10.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 treeon 1 + 3 + 6 + 12 vertices. The leaves of this new tree are made adjacent to the 12 vertices of the third orbit,
and the graph is now 3-regular. This binary tree contributes 4 new orbits to the Harries-Wong graph.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.HarriesWongGraph()
sage: g.order()70sage: g.size()105
sage: g.girth()10
sage: g.diameter()6
sage: orbits = g.automorphism_group(orbits=True)[-1]˓→needs sage.groups
sage: g.show(figsize=[15, 15], partition=orbits)
˓→needs sage.groups sage.plot# long time#␣# long time#␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.HarriesWongGraph()>>> g.order()70>>> g.size()105>>> g.girth()
10>>> g.diameter()6>>> orbits = g.automorphism_group(orbits=True)[-Integer(1)]# long time˓→# needs sage.groups>>> g.show(figsize=[Integer(15), Integer(15)], partition=orbits)# long␣˓→time# needs sage.groups sage.plot

␣Alternative embedding:sage: graphs.HarriesWongGraph(embedding=2).show()˓→needs networkx sage.plot# long time>>> from sage.all import *>>> graphs.HarriesWongGraph(embedding=Integer(2)).show()˓→# needs networkx sage.plot# long time#␣␣

sage.graphs.generators.smallgraphs.HeawoodGraph()
Return a Heawood graph.
The Heawood graph is a cage graph that has 14 nodes. It is a cubic symmetric graph. (See also the Möbius-Kantor
graph, MobiusKantorGraph()). It is nonplanar and Hamiltonian. It has diameter 3, radius 3, girth 6, and2.14. Various small graphs1321

Graph Theory, Release 10.4

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 continuingcounterclockwise.
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()˓→needs sage.plot>>> from sage.all import *>>> H = graphs.HeawoodGraph()>>> H
Heawood graph: Graph on 14 vertices>>> H.graph6_string()
MhEGHC@AI?_PC@_G_>>> (graphs.HeawoodGraph()).show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.smallgraphs.HerschelGraph()
Return the Herschel graph.
For more information, see the Wikipedia article Herschel_graph.
EXAMPLES:
The Herschel graph is named after Alexander Stewart Herschel. It is a planar, bipartite graph with 11 vertices and
18 edges:sage: G = graphs.HerschelGraph(); G
Herschel graph: Graph on 11 vertices
sage: G.is_planar()True
sage: G.is_bipartite()True
sage: G.order()11sage: G.size()18>>> from sage.all import *>>> G = graphs.HerschelGraph(); G
Herschel graph: Graph on 11 vertices>>> G.is_planar()
True>>> G.is_bipartite()
True>>> G.order()11>>> G.size()
18

The Herschel graph is a perfect graph with radius 3, diameter 4, and girth 4:
1322

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: G.is_perfect()True
sage: G.radius()
3
sage: G.diameter()4
sage: G.girth()4>>> from sage.all import *>>> G.is_perfect()True>>> G.radius()
3>>> G.diameter()
4>>> 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()
˓→needs sage.groups
sage: ag.is_isomorphic(DihedralGroup(6))˓→needs sage.groups
True>>> from sage.all import *>>> G.chromatic_number()2>>> ag = G.automorphism_group()
˓→needs sage.groups>>> ag.is_isomorphic(DihedralGroup(Integer(6)))˓→# needs sage.groups
True

#␣
#␣

#␣
␣

sage.graphs.generators.smallgraphs.HigmanSimsGraph(relabel=True)
Return the Higman-Sims graph.
The Higman-Sims graph is a remarkable strongly regular graph of degree 22 on 100 vertices. For example, it canbe split into two sets of 50 vertices each, so that each half induces a subgraph isomorphic to the Hoffman-Singletongraph (HoffmanSingletonGraph()). This can be done in 352 ways (see Higman-Sims graph by Andries E.
Brouwer, accessed 24 October 2009.)
Its most famous property is that the automorphism group has an index 2 subgroup which is one of the 26 sporadic
groups [HS1968].
The construction used here follows [Haf2004].
See also the Wikipedia article Higman–Sims_graph.
INPUT:• relabel – boolean (default: True); whether to relabel the vertices with consecutive integers. If False thelabels are strings that are three digits long. “xyz” means the vertex is in group 𝑥 (zero through three), pentagon
or pentagram 𝑦 (zero through four), and is vertex 𝑧 (zero through four) of that pentagon or pentagram. See[Haf2004] for more.
2.14. Various small graphs1323

Graph Theory, Release 10.4

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)Truesage: 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>>> from sage.all import *>>> H = graphs.HigmanSimsGraph()>>> A = H.subgraph(range(Integer(0),Integer(50)))>>> B = H.subgraph(range(Integer(50),Integer(100)))>>> K = graphs.HoffmanSingletonGraph()>>> K.is_isomorphic(A) and K.is_isomorphic(B)
True>>> C = H.subgraph(range(Integer(25),Integer(75)))>>> D = H.subgraph(list(range(Integer(0),Integer(25)))+list(range(Integer(75),
˓→Integer(100))))>>> 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()
˓→needs sage.groups
sage: g = G.order(); g˓→needs sage.groups
88704000
sage: K = G.normal_subgroups()[1]˓→needs sage.groups
sage: K.is_simple()
˓→needs sage.groupsTrue
sage: g//K.order()˓→needs sage.groups2>>> from sage.all import *>>> H = graphs.HigmanSimsGraph()>>> G = H.automorphism_group()
˓→needs sage.groups>>> g = G.order(); g˓→needs sage.groups
88704000

#␣
#␣

#␣
#␣

#␣

#␣
#␣

(continues on next page)1324

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> K = G.normal_subgroups()[Integer(1)]˓→# needs sage.groups>>> K.is_simple()
˓→needs sage.groupsTrue>>> g//K.order()˓→needs sage.groups
2

␣
#␣

#␣

AUTHOR:• Rob Beezer (2009-10-24)
sage.graphs.generators.smallgraphs.HoffmanGraph()
Return the Hoffman Graph.
See the Wikipedia article Hoffman_graph.
EXAMPLES:
sage: g = graphs.HoffmanGraph()
sage: g.is_bipartite()True
sage: g.is_hamiltonian()# long time
˓→needs sage.numerical.mip
True
sage: g.radius()
3
sage: g.diameter()4
sage: g.automorphism_group().cardinality()
˓→needs sage.groups48>>> from sage.all import *>>> g = graphs.HoffmanGraph()>>> g.is_bipartite()True>>> g.is_hamiltonian()# long time
˓→needs sage.numerical.mip
True>>> g.radius()
3>>> g.diameter()4>>> g.automorphism_group().cardinality()
˓→needs sage.groups
48

#␣

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.HoffmanSingletonGraph()
Return the Hoffman-Singleton graph.
The Hoffman-Singleton graph is the Moore graph of degree 7, diameter 2 and girth 5. The Hoffman-Singleton
theorem states that any Moore graph with girth 5 must have degree 2, 3, 7 or 57. The first three respectively are
the pentagon, the Petersen graph, and the Hoffman-Singleton graph. The existence of a Moore graph with girth 5
and degree 57 is still open.

2.14. Various small graphs1325Graph Theory, Release 10.4

A Moore graph is a graph with diameter 𝑑 and girth 2𝑑 + 1. This implies that the graph is regular, and distanceregular.
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>>> from sage.all import *>>> HS = graphs.HoffmanSingletonGraph()>>> Set(HS.degree()){7}>>> HS.girth()5>>> HS.diameter()2>>> HS.num_verts()
50

Note that you get a different layout each time you create the graph.
sage: HS.layout()[1] # random(-0.844..., 0.535...)sage: HS = graphs.HoffmanSingletonGraph()
sage: HS.layout()[1] # random(-0.904..., 0.425...)>>> from sage.all import *>>> HS.layout()[Integer(1)] # random(-0.844..., 0.535...)>>> HS = graphs.HoffmanSingletonGraph()>>> HS.layout()[Integer(1)] # random(-0.904..., 0.425...)sage.graphs.generators.smallgraphs.HoltGraph()
Return the Holt graph (also called the Doyle graph).
See the Wikipedia article Holt_graph.
EXAMPLES:
sage: g = graphs.HoltGraph();gHolt graph: Graph on 27 vertices
sage: g.is_regular()True
sage: g.is_vertex_transitive()#␣(continues on next page)

1326

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)needs sage.groupsTrue
sage: g.chromatic_number()3
sage: g.is_hamiltonian()# long time
˓→needs sage.numerical.mip
True
sage: g.radius()
3
sage: g.diameter()3
sage: g.girth()5
sage: g.automorphism_group().cardinality()
˓→needs sage.groups54˓→>>> from sage.all import *>>> g = graphs.HoltGraph();gHolt graph: Graph on 27 vertices>>> g.is_regular()True>>> g.is_vertex_transitive()
˓→needs sage.groupsTrue>>> g.chromatic_number()3>>> g.is_hamiltonian()# long time
˓→needs sage.numerical.mip
True>>> g.radius()
3>>> g.diameter()3>>> g.girth()5>>> g.automorphism_group().cardinality()
˓→needs sage.groups
54

#␣

#␣

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.HortonGraph()
Return the Horton Graph.
The Horton graph is a cubic 3-connected non-hamiltonian graph. For more information, see the Wikipedia article
Horton_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.HortonGraph()
sage: g.order()96
sage: g.size()
144
sage: g.radius()
10
sage: g.diameter()(continues on next page)

2.14. Various small graphs1327

Graph Theory, Release 10.4

(continued from previous page)10
sage: g.girth()6
sage: g.automorphism_group().cardinality()96
sage: g.chromatic_number()2
sage: g.is_hamiltonian()# not tested (veeeery long)
˓→needs sage.numerical.mip
False>>> from sage.all import *>>> # needs networkx>>> g = graphs.HortonGraph()>>> g.order()96>>> g.size()144>>> g.radius()
10>>> g.diameter()
10>>> g.girth()6>>> g.automorphism_group().cardinality()96>>> g.chromatic_number()2>>> g.is_hamiltonian()# not tested (veeeery long)
˓→needs sage.numerical.mip
False

#␣

#␣

sage.graphs.generators.smallgraphs.IoninKharaghani765Graph()
Return a (765, 192, 48, 48)-strongly regular graph.
Existence of a strongly regular graph with these parameters was claimed in [IK2003]. Implementing the 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 setof all 12 lines 𝐿𝑖,𝑗 , plus the empty set. Let 𝜋 be the permutation defined on ℳ by 𝜋(𝐿𝑖,𝑗 ) = 𝐿𝑖,𝑗+1
and 𝜋(∅) = ∅, so that 𝜋 has three orbits of cardinality 3 and one of cardinality 1.
Let 𝐴 = (𝑝1 , ..., 𝑝9 ) with 𝑝1 = (−1, 1), 𝑝2 = (−1, 0), 𝑝3 = (−1, 1), 𝑝4 = (0, −1), 𝑝5 = (0, 0),
𝑝6 = (0, 1), 𝑝7 = (1, −1), 𝑝8 = (1, 0), 𝑝9 = (1, 1). Note that 𝑝𝑖 + 𝑝10−𝑖 = (0, 0). For any
subset 𝑋 of 𝐴, let 𝑀 (𝑋) be the (0, 1)-matrix of order 9 whose (𝑖, 𝑗)-entry equals 1 if and only if
𝑝10−𝑖 − 𝑝𝑗 ∈ 𝑋. Note that 𝑀 is a symmetric matrix.
An 𝑀 𝐹 -tuple is an ordered quintuple (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) of subsets of 𝐴, of which one is the empty
set and the other four are pairwise non-parallel lines. Such a quintuple generates the following block
1328

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

matrix:⎛𝑀 (𝑋1 )⎜ 𝑀 (𝑋2 )⎜𝑁 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 ) = ⎜⎜ 𝑀 (𝑋3 )⎝ 𝑀 (𝑋4 )𝑀 (𝑋5 )𝑀 (𝑋2 )𝑀 (𝑋3 )𝑀 (𝑋4 )𝑀 (𝑋5 )𝑀 (𝑋1 )𝑀 (𝑋3 )𝑀 (𝑋4 )𝑀 (𝑋5 )𝑀 (𝑋1 )𝑀 (𝑋2 )𝑀 (𝑋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 symmetricincidence 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 thematrix 𝑁 (𝜎 𝑘 (𝑋1 , 𝑋2 , 𝑋3 , 𝑋4 , 𝑋5 )) (through the association of 𝜔 𝑘 with an element of 𝐺). Then 𝑆 isa 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˓→needs sage.modules sage.rings.finite_rings
Ionin-Kharaghani: Graph on 765 vertices>>> from sage.all import *>>> g = graphs.IoninKharaghani765Graph(); g˓→needs sage.modules sage.rings.finite_rings
Ionin-Kharaghani: Graph on 765 vertices#␣#␣

Todo: An update to [IK2003] meant to fix the problem encountered became available 2016/02/24, see http://www.cs.uleth.ca/ hadi/research/IoninKharaghani.pdf
sage.graphs.generators.smallgraphs.JankoKharaghaniGraph(v)Return a (936, 375, 150, 150)-srg or a (1800, 1029, 588, 588)-srg.
This functions returns a strongly regular graph for the two sets of parameters shown to be realizable in [JK2002].
The paper also uses a construction from [GM1987].
INPUT:• v – integer; one of 936 or 1800
2.14. Various small graphs1329

Graph Theory, Release 10.4

EXAMPLES:
sage: g = graphs.JankoKharaghaniGraph(936)˓→needs sage.libs.pari
sage: g.is_strongly_regular(parameters=True)
˓→needs sage.libs.pari(936, 375, 150, 150)

# long time#␣# long time#␣sage: g = graphs.JankoKharaghaniGraph(1800)
sage: g.is_strongly_regular(parameters=True)(1800, 1029, 588, 588)

# not tested (30s)# not tested (30s)>>> from sage.all import *>>> g = graphs.JankoKharaghaniGraph(Integer(936))# long time˓→# needs sage.libs.pari>>> g.is_strongly_regular(parameters=True)# long time
˓→needs sage.libs.pari(936, 375, 150, 150)

␣#␣>>> g = graphs.JankoKharaghaniGraph(Integer(1800))# not tested (30s)>>> g.is_strongly_regular(parameters=True)# not tested (30s)(1800, 1029, 588, 588)

sage.graphs.generators.smallgraphs.JankoKharaghaniTonchevGraph()
Return a (324, 153, 72, 72)-strongly regular graph from [JKT2001].
Build the graph using the description given in [JKT2001], taking sets B1 and B163 in the text as adjacencies ofvertices 1 and 163, respectively, and taking the edge orbits of the group 𝐺 provided.
EXAMPLES:
sage: Gamma = graphs.JankoKharaghaniTonchevGraph()˓→needs sage.libs.gap
sage: Gamma.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(324, 153, 72, 72)>>> from sage.all import *>>> Gamma = graphs.JankoKharaghaniTonchevGraph()˓→needs sage.libs.gap>>> Gamma.is_strongly_regular(parameters=True)
˓→needs sage.libs.gap(324, 153, 72, 72)# long time#␣# long time#␣# long time#␣# long time#␣

sage.graphs.generators.smallgraphs.KittellGraph()
Return the Kittell Graph.
For more information, see the Wolfram page about the Kittel Graph.
EXAMPLES:
sage: g = graphs.KittellGraph()
sage: g.order()23
sage: g.size()63
sage: g.radius()
3(continues on next page)

1330

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: g.diameter()4
sage: g.girth()3
sage: g.chromatic_number()4>>> from sage.all import *>>> g = graphs.KittellGraph()>>> g.order()23>>> g.size()63>>> g.radius()
3>>> g.diameter()4>>> g.girth()3>>> g.chromatic_number()4

sage.graphs.generators.smallgraphs.Klein3RegularGraph()
Return the Klein 3-regular graph.
The cubic Klein graph has 56 vertices and can be embedded on a surface of genus 3. It is the dual of Klein7RegularGraph(). For more information, see the Wikipedia article Klein_graphs.
EXAMPLES:
sage: g = graphs.Klein3RegularGraph(); gKlein 3-regular Graph: Graph on 56 vertices
sage: g.order(), g.size()(56, 84)
sage: g.girth()7
sage: g.automorphism_group().cardinality()
˓→needs sage.groups336
sage: g.chromatic_number()3>>> from sage.all import *>>> g = graphs.Klein3RegularGraph(); gKlein 3-regular Graph: Graph on 56 vertices>>> g.order(), g.size()(56, 84)>>> g.girth()7>>> g.automorphism_group().cardinality()
˓→needs sage.groups336>>> g.chromatic_number()
3

#␣

#␣

sage.graphs.generators.smallgraphs.Klein7RegularGraph()
Return the Klein 7-regular graph.
2.14. Various small graphs

1331

Graph Theory, Release 10.4

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(); gKlein 7-regular Graph: Graph on 24 vertices
sage: g.order(), g.size()(24, 84)
sage: g.girth()3
sage: g.automorphism_group().cardinality()
˓→needs sage.groups336
sage: g.chromatic_number()4#␣>>> from sage.all import *>>> g = graphs.Klein7RegularGraph(); gKlein 7-regular Graph: Graph on 24 vertices>>> g.order(), g.size()(24, 84)>>> g.girth()3>>> g.automorphism_group().cardinality()
˓→needs sage.groups336>>> g.chromatic_number()4#␣sage.graphs.generators.smallgraphs.KrackhardtKiteGraph()
Return a Krackhardt kite graph with 10 nodes.
The Krackhardt kite graph was originally developed by David Krackhardt for the purpose of studying social networks (see [Kre2002] and the Wikipedia article Krackhardt_kite_graph). It is used to show the distinction between
degree centrality, betweenness centrality, and closeness centrality. For more information read the 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 graphsage: g = graphs.KrackhardtKiteGraph()
sage: g.show()˓→needs sage.plot# long time#␣>>> from sage.all import *>>> g = graphs.KrackhardtKiteGraph()(continues on next page)

1332

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> g.show()˓→needs sage.plot# long time#␣

sage.graphs.generators.smallgraphs.LivingstoneGraph()
Return the Livingstone Graph.
The Livingstone graph is a distance-transitive graph on 266 vertices whose automorphism group is the J1 group.
For more information, see the Wikipedia article Livingstone_graph.
EXAMPLES:
sage: # optional - internet
sage: g = graphs.LivingstoneGraph()
sage: g.order()266
sage: g.size()
1463
sage: g.girth()5
sage: g.is_vertex_transitive()
True
sage: g.is_distance_regular()True>>> from sage.all import *>>> # optional - internet>>> g = graphs.LivingstoneGraph()>>> g.order()266>>> g.size()1463>>> g.girth()5>>> g.is_vertex_transitive()
True>>> g.is_distance_regular()Truesage.graphs.generators.smallgraphs.LjubljanaGraph(embedding=1)
Return the Ljubljana Graph.
The Ljubljana graph is a bipartite 3-regular graph on 112 vertices and 168 edges. It is not vertex-transitive as it has
two orbits which are also independent sets of size 56. See the Wikipedia article Ljubljana_graph.
The default embedding is obtained from the Heawood graph.
INPUT:• embedding – integer (default: 1); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.LjubljanaGraph()
sage: g.order()112
sage: g.size()(continues on next page)

2.14. Various small graphs1333

Graph Theory, Release 10.4

(continued from previous page)168
sage: g.girth()10
sage: g.diameter()8
sage: g.show(figsize=[10, 10])# long time
˓→needs sage.plot
sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10])
˓→time, needs sage.plot#␣# long␣

>>> from sage.all import *>>> # needs networkx>>> g = graphs.LjubljanaGraph()>>> g.order()112>>> g.size()168>>> g.girth()
10>>> g.diameter()8>>> g.show(figsize=[Integer(10), Integer(10)])# long time˓→# needs sage.plot>>> graphs.LjubljanaGraph(embedding=Integer(2)).show(figsize=[Integer(10),␣
˓→Integer(10)])# long time, needs sage.plot

␣

sage.graphs.generators.smallgraphs.LocalMcLaughlinGraph()
Return the local McLaughlin graph.
The local McLaughlin graph is a strongly regular graph with parameters (162, 56, 10, 24). It can be obtained from
McLaughlinGraph() by considering the stabilizer of a point: one of its orbits has cardinality 162.
EXAMPLES:
sage: g = graphs.LocalMcLaughlinGraph(); g˓→package_design
Local McLaughlin Graph: Graph on 162 vertices
sage: g.is_strongly_regular(parameters=True)
˓→package_design(162, 56, 10, 24)# long time, optional - gap_

# long time, optional - gap_>>> from sage.all import *>>> g = graphs.LocalMcLaughlinGraph(); g# long time, optional - gap_package_
˓→design
Local McLaughlin Graph: Graph on 162 vertices>>> g.is_strongly_regular(parameters=True)# long time, optional - gap_package_
˓→design(162, 56, 10, 24)

sage.graphs.generators.smallgraphs.M22Graph()
Return the M22 graph.
The 𝑀22 graph is the unique strongly regular graph with parameters 𝑣 = 77, 𝑘 = 16, 𝜆 = 0, 𝜇 = 4.
For more information on the 𝑀22 graph, see https://www.win.tue.nl/ aeb/graphs/M22.html.
EXAMPLES:

1334

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: # needs sage.groups
sage: g = graphs.M22Graph()
sage: g.order()77sage: g.size()616
sage: g.is_strongly_regular(parameters=True)(77, 16, 0, 4)>>> from sage.all import *>>> # needs sage.groups>>> g = graphs.M22Graph()>>> g.order()77>>> g.size()616>>> g.is_strongly_regular(parameters=True)(77, 16, 0, 4)

sage.graphs.generators.smallgraphs.MarkstroemGraph()
Return the Markström Graph.
The Markström Graph is a cubic planar graph with no cycles of length 4 nor 8, but containing cycles of length 16.
For more information, see the Wolfram page about the Markström Graph.
EXAMPLES:
sage: g = graphs.MarkstroemGraph()
sage: g.order()24
sage: g.size()36
sage: g.is_planar()True
sage: g.is_regular(3)True
sage: g.subgraph_search(graphs.CycleGraph(4)) is None˓→needs sage.modules
True
sage: g.subgraph_search(graphs.CycleGraph(8)) is None˓→needs sage.modules
True
sage: g.subgraph_search(graphs.CycleGraph(16))˓→needs sage.modules
Subgraph of (Markstroem Graph): Graph on 16 vertices>>> from sage.all import *>>> g = graphs.MarkstroemGraph()>>> g.order()24>>> g.size()36>>> g.is_planar()True>>> g.is_regular(Integer(3))
True>>> g.subgraph_search(graphs.CycleGraph(Integer(4))) is None

#␣

#␣

#␣

␣
(continues on next page)

2.14. Various small graphs

1335

Graph Theory, Release 10.4

(continued from previous page)# needs sage.modules

˓→

True
>>> g.subgraph_search(graphs.CycleGraph(Integer(8))) is None˓→# needs sage.modules
True>>> g.subgraph_search(graphs.CycleGraph(Integer(16)))˓→# needs sage.modules
Subgraph of (Markstroem Graph): Graph on 16 vertices␣␣

sage.graphs.generators.smallgraphs.MathonStronglyRegularGraph(t)Return one of Mathon’s graphs on 784 vertices.
INPUT:• t – integer; the number of the graph, from 0 to 2
EXAMPLES:
sage: # long time, needs sage.libs.gap
sage: from sage.graphs.generators.smallgraphs import MathonStronglyRegularGraphsage: G = MathonStronglyRegularGraph(0)sage: G.is_strongly_regular(parameters=True)(784, 243, 82, 72)>>> from sage.all import *>>> # long time, needs sage.libs.gap>>> from sage.graphs.generators.smallgraphs import MathonStronglyRegularGraph>>> G = MathonStronglyRegularGraph(Integer(0))>>> G.is_strongly_regular(parameters=True)(784, 243, 82, 72)

sage.graphs.generators.smallgraphs.McGeeGraph(embedding=2)
Return the McGee Graph.
See the Wikipedia article McGee_graph.
INPUT:• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.McGeeGraph()
sage: g.order()24
sage: g.size()36
sage: g.girth()7
sage: g.diameter()4
sage: g.show()˓→needs sage.plot
sage: graphs.McGeeGraph(embedding=1).show()˓→needs sage.plot

1336

#␣
# long time#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs networkx>>> g = graphs.McGeeGraph()>>> g.order()24>>> g.size()36>>> g.girth()7>>> g.diameter()4>>> g.show()˓→needs sage.plot>>> graphs.McGeeGraph(embedding=Integer(1)).show()˓→# needs sage.plot#␣# long time␣

sage.graphs.generators.smallgraphs.McLaughlinGraph()
Return the McLaughlin Graph.
The McLaughlin Graph is the unique strongly regular graph of parameters (275, 112, 30, 56).
For more information on the McLaughlin Graph, see its web page on Andries Brouwer’s website which gives thedefinition that this method implements.
Note: To create this graph you must have the gap_packages spkg installed.
EXAMPLES:
sage: g = graphs.McLaughlinGraph()
sage: g.is_strongly_regular(parameters=True)(275, 112, 30, 56)
sage: set(g.spectrum()) == {112, 2, -28}
True

# optional - gap_package_design# optional - gap_package_design# optional - gap_package_design>>> from sage.all import *>>> g = graphs.McLaughlinGraph()# optional - gap_package_design>>> g.is_strongly_regular(parameters=True)# optional - gap_package_design(275, 112, 30, 56)>>> set(g.spectrum()) == {Integer(112), Integer(2), -Integer(28)}#␣˓→optional - gap_package_design
Truesage.graphs.generators.smallgraphs.MeredithGraph()
Return the Meredith Graph.
The Meredith Graph is a 4-regular 4-connected non-hamiltonian graph. For more information on the Meredith
Graph, see the Wikipedia article Meredith_graph.
EXAMPLES:
sage: g = graphs.MeredithGraph()
sage: g.is_regular(4)True
sage: g.order()70sage: g.size()(continues on next page)

2.14. Various small graphs

1337

Graph Theory, Release 10.4

(continued from previous page)140
sage: g.radius()
7
sage: g.diameter()8
sage: g.girth()4
sage: g.chromatic_number()3
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
False>>> from sage.all import *>>> g = graphs.MeredithGraph()>>> g.is_regular(Integer(4))
True>>> g.order()70>>> g.size()140>>> g.radius()
7>>> g.diameter()8>>> g.girth()4>>> g.chromatic_number()3>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
False# long time

# long time#␣#␣

sage.graphs.generators.smallgraphs.MoebiusKantorGraph()
Return a Möbius-Kantor Graph.
A Möbius-Kantor graph is a cubic symmetric graph. (See also the Heawood graph). It has 16 nodes and 24 edges. It
is nonplanar and Hamiltonian. It has diameter 4, girth 6, and chromatic number 2. It is identical to the GeneralizedPetersen 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()˓→needs sage.plot# long time#␣>>> from sage.all import *>>> MK = graphs.MoebiusKantorGraph()>>> MK(continues on next page)

1338

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

Moebius-Kantor Graph: Graph on 16 vertices>>> MK.graph6_string()
OhCGKE?O@?ACAC@I?Q_AS>>> (graphs.MoebiusKantorGraph()).show()˓→needs sage.plot# long time#␣

sage.graphs.generators.smallgraphs.MoserSpindle()
Return the Moser spindle.
For more information, see the Wikipedia article Moser_spindle.
EXAMPLES:
The Moser spindle is a planar graph having 7 vertices and 11 edges:
sage: # needs sage.symbolic
sage: G = graphs.MoserSpindle(); G
Moser spindle: Graph on 7 vertices
sage: G.is_planar()True
sage: G.order()7
sage: G.size()
11>>> from sage.all import *>>> # needs sage.symbolic>>> G = graphs.MoserSpindle(); G
Moser spindle: Graph on 7 vertices>>> G.is_planar()
True>>> G.order()7>>> G.size()11

It is a Hamiltonian graph with radius 2, diameter 2, and girth 3:
sage: # needs sage.symbolic
sage: G.is_hamiltonian()
˓→needs sage.numerical.mip
True
sage: G.radius()
2
sage: G.diameter()2
sage: G.girth()3>>> from sage.all import *>>> # needs sage.symbolic>>> G.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> G.radius()
2>>> G.diameter()#␣#␣(continues on next page)

2.14. Various small graphs1339

Graph Theory, Release 10.4

(continued from previous page)2>>> G.girth()
3

The Moser spindle can be drawn in the plane as a unit distance graph, has chromatic number 4, and its automorphismgroup is isomorphic to the dihedral group 𝐷4 :sage: # needs sage.symbolic
sage: pos = G.get_pos()sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1....:
for u, v in G.edge_iterator(labels=None))True
sage: G.chromatic_number()4
sage: ag = G.automorphism_group()
sage: ag.is_isomorphic(DihedralGroup(4))
True>>> from sage.all import *>>> # needs sage.symbolic>>> pos = G.get_pos()>>> all(sum((ui-vi)**Integer(2) for ui, vi in zip(pos[u], pos[v])) == Integer(1)...
for u, v in G.edge_iterator(labels=None))
True>>> G.chromatic_number()4>>> ag = G.automorphism_group()>>> ag.is_isomorphic(DihedralGroup(Integer(4)))
Truesage.graphs.generators.smallgraphs.NauruGraph(embedding=2)
Return the Nauru Graph.
See the Wikipedia article Nauru_graph.
INPUT:• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: g = graphs.NauruGraph()
sage: g.order()24
sage: g.size()36
sage: g.girth()6
sage: g.diameter()4
sage: g.show()˓→needs sage.plot
sage: graphs.NauruGraph(embedding=1).show()˓→needs sage.plot

1340

#␣
# long time#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.NauruGraph()>>> g.order()24>>> g.size()36>>> g.girth()6>>> g.diameter()4>>> g.show()˓→needs sage.plot>>> graphs.NauruGraph(embedding=Integer(1)).show()˓→# needs sage.plot#␣# long time␣

sage.graphs.generators.smallgraphs.PappusGraph()
Return the Pappus graph, a graph on 18 vertices.
The Pappus graph is cubic, symmetric, and distance-regular.
EXAMPLES:
sage: G = graphs.PappusGraph()
sage: G.show()# long time
˓→needs sage.plot
sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3)
˓→needs networkx
sage: L.show()# long time
˓→needs networkx sage.plot
sage: G.is_isomorphic(L)˓→needs networkx
True

#␣
#␣
#␣
#␣

>>> from sage.all import *>>> G = graphs.PappusGraph()>>> G.show()# long time
˓→needs sage.plot>>> L = graphs.LCFGraph(Integer(18), [Integer(5),Integer(7),-Integer(7),˓→Integer(7),-Integer(7),-Integer(5)], Integer(3))˓→needs networkx>>> L.show()# long time
˓→needs networkx sage.plot>>> G.is_isomorphic(L)˓→needs networkx
True

#␣

#␣
#␣
#␣

sage.graphs.generators.smallgraphs.PerkelGraph()
Return the Perkel Graph.
The Perkel Graph is a 6-regular graph with 57 vertices and 171 edges. It is the unique distance-regular graphwith 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(continues on next page)

2.14. Various small graphs1341

Graph Theory, Release 10.4

(continued from previous page)

sage: g.is_distance_regular(parameters=True)([6, 5, 2, None], [None, 1, 1, 3])>>> from sage.all import *>>> g = graphs.PerkelGraph(); g
Perkel Graph: Graph on 57 vertices>>> g.is_distance_regular(parameters=True)([6, 5, 2, None], [None, 1, 1, 3])

sage.graphs.generators.smallgraphs.PetersenGraph()
Return the Petersen Graph.
The Petersen Graph is a named graph that consists of 10 vertices and 15 edges, usually drawn as a five-point starembedded in a pentagon.
The Petersen Graph is a common counterexample. For example, it is not Hamiltonian.
PLOTTING: See the plotting section for the generalized Petersen graphs.
EXAMPLES: We compare below the Petersen graph with the default spring-layout versus a planned position dictionary of (𝑥, 𝑦) tuples:sage: 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
˓→needs sage.plot
sage: petersen_database = graphs.PetersenGraph()
sage: petersen_database.show()# long time
˓→needs sage.plot>>> from sage.all import *>>> petersen_spring = Graph({Integer(0):[Integer(1),Integer(4),Integer(5)],␣
˓→Integer(1):[Integer(0),Integer(2),Integer(6)], Integer(2):[Integer(1),˓→Integer(3),Integer(7)],...
Integer(3):[Integer(2),Integer(4),Integer(8)],␣
˓→Integer(4):[Integer(0),Integer(3),Integer(9)], Integer(5):[Integer(0),˓→Integer(7),Integer(8)],...
Integer(6):[Integer(1),Integer(8),Integer(9)],␣
˓→Integer(7):[Integer(2),Integer(5),Integer(9)], Integer(8):[Integer(3),˓→Integer(5),Integer(6)],...
Integer(9):[Integer(4),Integer(6),Integer(7)]})>>> petersen_spring.show()# long time
˓→needs sage.plot>>> petersen_database = graphs.PetersenGraph()>>> petersen_database.show()# long time
˓→needs sage.plot

#␣

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.PoussinGraph()
Return the Poussin Graph.
For more information on the Poussin Graph, see its corresponding Wolfram page.
EXAMPLES:

1342

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: g = graphs.PoussinGraph()
sage: g.order()15
sage: g.is_planar()True>>> from sage.all import *>>> g = graphs.PoussinGraph()>>> g.order()15>>> g.is_planar()True

sage.graphs.generators.smallgraphs.RobertsonGraph()
Return the Robertson graph.
See the Wikipedia article Robertson_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.RobertsonGraph()
sage: g.order()19sage: 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()
˓→needs sage.numerical.mip
True
sage: g.is_vertex_transitive()
False

#␣

>>> from sage.all import *>>> # needs networkx>>> g = graphs.RobertsonGraph()>>> g.order()19>>> g.size()38>>> g.diameter()3>>> g.girth()5>>> 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>>> g.chromatic_number()
3(continues on next page)

2.14. Various small graphs1343

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True>>> g.is_vertex_transitive()
False

#␣

sage.graphs.generators.smallgraphs.SchlaefliGraph()
Return the Schläfli graph.
The Schläfli graph is the only strongly regular graphs of parameters (27, 16, 10, 8) (see [GR2001]).
For more information, see the Wikipedia article Schläfli_graph.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
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)>>> from sage.all import *>>> S = graphs.SchlaefliGraph()>>> S.is_strongly_regular(parameters=True)(27, 16, 10, 8)

The graph is vertex-transitive:
sage: S.is_vertex_transitive()
˓→needs sage.groups
True

#␣

>>> from sage.all import *>>> S.is_vertex_transitive()
˓→needs sage.groups
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>>> from sage.all import *>>> neighborhood = S.subgraph(vertices=S.neighbors(Integer(0)))>>> graphs.ClebschGraph().complement().is_isomorphic(neighborhood)
True

1344

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage.graphs.generators.smallgraphs.ShrikhandeGraph()
Return the Shrikhande graph.
For more information, see the MathWorld article on the Shrikhande graph or the Wikipedia article
Shrikhande_graph.
See also:
Graph.is_strongly_regular() – tests whether a graph is strongly regular and/or returns its parameters.
EXAMPLES:The Shrikhande graph was defined by S. S. Shrikhande in 1959. It has 16 vertices and 48 edges, and is strongly
regular of degree 6 with parameters (2, 2):
sage: G = graphs.ShrikhandeGraph(); G
Shrikhande graph: Graph on 16 vertices
sage: G.order()16
sage: G.size()48
sage: G.is_regular(6)Truesage: set([ len([x for x in G.neighbors(i) if x in G.neighbors(j)])....:
for i in range(G.order())....:
for j in range(i) ]){2}>>> from sage.all import *>>> G = graphs.ShrikhandeGraph(); G
Shrikhande graph: Graph on 16 vertices>>> G.order()16>>> G.size()48>>> G.is_regular(Integer(6))
True>>> set([ len([x for x in G.neighbors(i) if x in G.neighbors(j)])...
for i in range(G.order())...
for j in range(i) ]){2}

It is non-planar, and both Hamiltonian and Eulerian:sage: G.is_planar()False
sage: G.is_hamiltonian()
˓→needs sage.numerical.mip
True
sage: G.is_eulerian()True>>> from sage.all import *>>> G.is_planar()
False>>> G.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

#␣

(continues on next page)

2.14. Various small graphs

1345

Graph Theory, Release 10.4

(continued from previous page)>>> 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>>> from sage.all import *>>> G.radius()
2>>> G.diameter()2>>> 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()
˓→needs sage.groups192#␣>>> from sage.all import *>>> G.chromatic_number()4>>> G.automorphism_group().cardinality()
˓→needs sage.groups
192#␣

It is an integral graph since it has only integral eigenvalues:
sage: G.characteristic_polynomial().factor()˓→needs sage.libs.pari sage.modules(x - 6) * (x - 2)^6 * (x + 2)^9#␣>>> from sage.all import *>>> G.characteristic_polynomial().factor()˓→needs sage.libs.pari sage.modules(x - 6) * (x - 2)^6 * (x + 2)^9#␣

It is a toroidal graph, and its embedding on a torus is dual to an embedding of the Dyck graph (DyckGraph).
sage.graphs.generators.smallgraphs.SimsGewirtzGraph()
Return the Sims-Gewirtz Graph.
This graph is obtained from the Higman Sims graph by considering the graph induced by the vertices at distance
two from the vertices of an (any) edge. It is the only strongly regular graph with parameters 𝑣 = 56, 𝑘 = 10,
𝜆 = 0, 𝜇 = 2
For more information on the Sylvester graph, see https://www.win.tue.nl/ aeb/graphs/Sims-Gewirtz.html or its
Wikipedia article Gewirtz_graph.
1346

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

See also:• HigmanSimsGraph().
EXAMPLES:
sage: g = graphs.SimsGewirtzGraph(); gSims-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)>>> from sage.all import *>>> g = graphs.SimsGewirtzGraph(); gSims-Gewirtz Graph: Graph on 56 vertices>>> g.order()56>>> g.size()
280>>> g.is_strongly_regular(parameters = True)(56, 10, 0, 2)

sage.graphs.generators.smallgraphs.SousselierGraph()
Return the Sousselier Graph.
The Sousselier graph is a hypohamiltonian graph on 16 vertices and 27 edges. For more information, see Wikipedia
article Sousselier_graph or the corresponding French Wikipedia page.
EXAMPLES:
sage: g = graphs.SousselierGraph()
sage: g.order()16
sage: g.size()27
sage: g.radius()
2
sage: g.diameter()3
sage: g.automorphism_group().cardinality()
˓→needs sage.groups2
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

#␣

#␣

>>> from sage.all import *>>> g = graphs.SousselierGraph()>>> g.order()16(continues on next page)

2.14. Various small graphs

1347

Graph Theory, Release 10.4

(continued from previous page)>>> g.size()27>>> g.radius()
2>>> g.diameter()3>>> g.automorphism_group().cardinality()
˓→needs sage.groups2>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
False>>> g.delete_vertex(g.random_vertex())>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.SuzukiGraph()
Return the Suzuki Graph.
The Suzuki graph has 1782 vertices, and is strongly regular with parameters (1782, 416, 100, 96). Known as S.15
in [Hub1975].
Note: It takes approximately 50 seconds to build this graph. Do not be too impatient.
EXAMPLES:
sage: g = graphs.SuzukiGraph(); g # optional internet # not tested
Suzuki graph: Graph on 1782 vertices
sage: g.is_strongly_regular(parameters=True) # optional internet # not tested(1782, 416, 100, 96)>>> from sage.all import *>>> g = graphs.SuzukiGraph(); g # optional internet # not tested
Suzuki graph: Graph on 1782 vertices>>> g.is_strongly_regular(parameters=True) # optional internet # not tested(1782, 416, 100, 96)

sage.graphs.generators.smallgraphs.SylvesterGraph()
Return the Sylvester Graph.
This graph is obtained from the Hoffman Singleton graph by considering the graph induced by the vertices at
distance two from the vertices of an (any) edge.
For more information on the Sylvester graph, see https://www.win.tue.nl/ aeb/graphs/Sylvester.html.
See also:• HoffmanSingletonGraph().
EXAMPLES:
sage: g = graphs.SylvesterGraph(); gSylvester Graph: Graph on 36 vertices
sage: g.order()(continues on next page)

1348

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)36
sage: g.size()90
sage: g.is_regular(k=5)
True>>> from sage.all import *>>> g = graphs.SylvesterGraph(); gSylvester Graph: Graph on 36 vertices>>> g.order()36>>> g.size()90>>> g.is_regular(k=Integer(5))
Truesage.graphs.generators.smallgraphs.SzekeresSnarkGraph()
Return the Szekeres Snark Graph.
The Szekeres graph is a snark with 50 vertices and 75 edges. For more information on this graph, see the Wikipedia
article Szekeres_snark.
EXAMPLES:
sage: g = graphs.SzekeresSnarkGraph()
sage: g.order()50sage: g.size()75
sage: g.chromatic_number()3>>> from sage.all import *>>> g = graphs.SzekeresSnarkGraph()>>> g.order()50>>> g.size()75>>> g.chromatic_number()3

sage.graphs.generators.smallgraphs.ThomsenGraph()
Return the Thomsen Graph.
The Thomsen Graph is actually a complete bipartite graph with (𝑛1, 𝑛2) = (3, 3). It is also called the Utility
graph.
PLOTTING: See CompleteBipartiteGraph.
EXAMPLES:
sage: T = graphs.ThomsenGraph()
sage: T
Thomsen graph: Graph on 6 vertices
sage: T.graph6_string()EFz_(continues on next page)

2.14. Various small graphs1349

Graph Theory, Release 10.4

(continued from previous page)

sage: (graphs.ThomsenGraph()).show()˓→needs sage.plot>>> from sage.all import *>>> T = graphs.ThomsenGraph()>>> T
Thomsen graph: Graph on 6 vertices>>> T.graph6_string()EFz_>>> (graphs.ThomsenGraph()).show()˓→needs sage.plot# long time

# long time#␣#␣

sage.graphs.generators.smallgraphs.TietzeGraph()
Return the Tietze Graph.
For more information on the Tietze Graph, see the Wikipedia article Tietze%27s_graph.
EXAMPLES:
sage: g = graphs.TietzeGraph()
sage: g.order()12sage: g.size()18
sage: g.diameter()3
sage: g.girth()3
sage: g.automorphism_group().cardinality()
˓→needs sage.groups
12
sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6))˓→needs sage.groups
True

#␣

#␣

>>> from sage.all import *>>> g = graphs.TietzeGraph()>>> g.order()12>>> g.size()18>>> g.diameter()3>>> g.girth()3>>> g.automorphism_group().cardinality()#␣˓→needs sage.groups
12>>> g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(Integer(6)))␣
˓→# needs sage.groups
Truesage.graphs.generators.smallgraphs.TruncatedIcosidodecahedralGraph()
Return the truncated icosidodecahedron.
The truncated icosidodecahedron is an Archimedean solid with 30 square faces, 20 regular hexagonal faces, 12 regular decagonal faces, 120 vertices and 180 edges. For more information, see the Wikipedia article Truncated_icosi1350

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

dodecahedron.
EXAMPLES:
Unfortunately, this graph can not be constructed currently, due to numerical issues:
sage: g = graphs.TruncatedIcosidodecahedralGraph(); g˓→needs sage.geometry.polyhedron sage.groups sage.rings.number_field
Traceback (most recent call last):...
ValueError: *Error: Numerical inconsistency is found. Use the GMP exact␣˓→arithmetic.
sage: g.order(), g.size()# not tested
˓→needs sage.geometry.polyhedron sage.groups sage.rings.number_field(120, 180)>>> from sage.all import *>>> g = graphs.TruncatedIcosidodecahedralGraph(); g˓→needs sage.geometry.polyhedron sage.groups sage.rings.number_field
Traceback (most recent call last):...
ValueError: *Error: Numerical inconsistency is found. Use the GMP exact␣˓→arithmetic.
>>> g.order(), g.size()# not tested
˓→needs sage.geometry.polyhedron sage.groups sage.rings.number_field(120, 180)

#␣

#␣

#␣

#␣

sage.graphs.generators.smallgraphs.TruncatedTetrahedralGraph()
Return the truncated tetrahedron.
The truncated tetrahedron is an Archimedean solid with 12 vertices and 18 edges. For more information, see the
Wikipedia article Truncated_tetrahedron.
EXAMPLES:
sage: g = graphs.TruncatedTetrahedralGraph(); g
Truncated Tetrahedron: Graph on 12 vertices
sage: g.order(), g.size()(12, 18)
sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph())˓→needs sage.geometry.polyhedron
True>>> from sage.all import *>>> g = graphs.TruncatedTetrahedralGraph(); g
Truncated Tetrahedron: Graph on 12 vertices>>> g.order(), g.size()(12, 18)>>> g.is_isomorphic(polytopes.simplex(Integer(3)).truncation().graph())˓→# needs sage.geometry.polyhedron
True

#␣

␣

sage.graphs.generators.smallgraphs.Tutte12Cage()
Return the Tutte 12-Cage.
See the Wikipedia article Tutte_12-cage.
EXAMPLES:

2.14. Various small graphs

1351

Graph Theory, Release 10.4

sage: # needs networkx
sage: g = graphs.Tutte12Cage()sage: g.order()126
sage: g.size()
189
sage: g.girth()12
sage: g.diameter()6
sage: g.show()˓→needs sage.plot#␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.Tutte12Cage()>>> g.order()126>>> g.size()
189>>> g.girth()
12>>> g.diameter()6>>> g.show()˓→needs sage.plot#␣

sage.graphs.generators.smallgraphs.TutteCoxeterGraph(embedding=2)
Return the Tutte-Coxeter graph.
See the Wikipedia article Tutte-Coxeter_graph.
INPUT:• embedding – integer (default: 2); two embeddings are available, and can be selected by setting embedding to 1 or 2
EXAMPLES:
sage: # needs networkx
sage: g = graphs.TutteCoxeterGraph()
sage: g.order()30
sage: g.size()
45
sage: g.girth()8
sage: g.diameter()4
sage: g.show()˓→needs sage.plot
sage: graphs.TutteCoxeterGraph(embedding=1).show()˓→needs sage.plot#␣# long time#␣>>> from sage.all import *>>> # needs networkx>>> g = graphs.TutteCoxeterGraph()>>> g.order()(continues on next page)1352

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)30>>> g.size()45>>> g.girth()8>>> g.diameter()4>>> g.show()˓→needs sage.plot>>> graphs.TutteCoxeterGraph(embedding=Integer(1)).show()˓→# needs sage.plot#␣# long time␣

sage.graphs.generators.smallgraphs.TutteGraph()
Return the Tutte Graph.
The Tutte graph is a 3-regular, 3-connected, and planar non-hamiltonian graph. For more information on the Tutte
Graph, see the Wikipedia article Tutte_graph.
EXAMPLES:
sage: g = graphs.TutteGraph()
sage: g.order()46
sage: g.size()69
sage: g.is_planar()True
sage: g.vertex_connectivity()# long time
˓→needs sage.numerical.mip
3
sage: g.girth()4
sage: g.automorphism_group().cardinality()
˓→needs sage.groups3
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
False>>> from sage.all import *>>> g = graphs.TutteGraph()>>> g.order()46>>> g.size()69>>> g.is_planar()True>>> g.vertex_connectivity()# long time
˓→needs sage.numerical.mip
3>>> g.girth()4>>> g.automorphism_group().cardinality()
˓→needs sage.groups3>>> g.is_hamiltonian()

#␣

#␣

#␣

#␣

#␣

#␣
(continues on next page)

2.14. Various small graphs1353

Graph Theory, Release 10.4

(continued from previous page)needs sage.numerical.mip
False
˓→

sage.graphs.generators.smallgraphs.U42Graph216()
Return a (216,40,4,8)-strongly regular graph from [CRS2016].
Build the graph, interpreting the 𝑈4 (2)-action considered in [CRS2016] as the one on the hyperbolic lines of thecorresponding unitary polar space, and then doing the unique merging of the orbitals leading to a graph with theparameters in question.
EXAMPLES:
sage: G=graphs.U42Graph216()
sage: G.is_strongly_regular(parameters=True)(216, 40, 4, 8)>>> from sage.all import *>>> G=graphs.U42Graph216()>>> G.is_strongly_regular(parameters=True)(216, 40, 4, 8)# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grape

sage.graphs.generators.smallgraphs.U42Graph540()
Return a (540,187,58,68)-strongly regular graph from [CRS2016].
Build the graph, interpreting the 𝑈4 (2)-action considered in [CRS2016] as the action of 𝑈4 (2) = 𝑆𝑝4 (3) < 𝑈4 (3)on the nonsingular, w.r.t. to the Hermitean form stabilised by 𝑈4 (3), points of the 3-dimensional projective spaceover 𝐺𝐹 (9). There are several possible mergings of orbitals, some leading to non-isomorphic graphs with the same
parameters. We found the merging here using [FK1991].
EXAMPLES:
sage: G = graphs.U42Graph540()
sage: G.is_strongly_regular(parameters=True)(540, 187, 58, 68)>>> from sage.all import *>>> G = graphs.U42Graph540()>>> G.is_strongly_regular(parameters=True)(540, 187, 58, 68)# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grape# optional - gap_package_grape

sage.graphs.generators.smallgraphs.WagnerGraph()
Return the Wagner Graph.
See the Wikipedia article Wagner_graph.
EXAMPLES:
sage: # needs networkx
sage: g = graphs.WagnerGraph()
sage: g.order()8sage: g.size()12
sage: g.girth()4
sage: g.diameter()(continues on next page)

1354

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)2
sage: g.show()˓→needs sage.plot>>> from sage.all import *>>> # needs networkx>>> g = graphs.WagnerGraph()>>> g.order()8>>> g.size()12>>> g.girth()4>>> g.diameter()2>>> g.show()˓→needs sage.plot#␣#␣

sage.graphs.generators.smallgraphs.WatkinsSnarkGraph()
Return the Watkins Snark Graph.
The Watkins Graph is a snark with 50 vertices and 75 edges. For more information, see the Wikipedia article
Watkins_snark.
EXAMPLES:
sage: g = graphs.WatkinsSnarkGraph()
sage: g.order()50sage: g.size()75
sage: g.chromatic_number()3>>> from sage.all import *>>> g = graphs.WatkinsSnarkGraph()>>> g.order()50>>> g.size()75>>> g.chromatic_number()3

sage.graphs.generators.smallgraphs.WellsGraph()
Return the Wells graph.
For more information on the Wells graph (also called Armanios-Wells graph), see this page.
The implementation follows the construction given on page 266 of [BCN1989]. This requires to create intermediategraphs 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 mosttime-consuming operation in any sensible algorithm, and …. “preserves knowledge”, which is what open-source
software is meant to do.
EXAMPLES:

2.14. Various small graphs

1355

Graph Theory, Release 10.4

sage: g = graphs.WellsGraph(); gWells 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>>> from sage.all import *>>> g = graphs.WellsGraph(); gWells graph: Graph on 32 vertices>>> g.order()32>>> g.size()
80>>> g.girth()5>>> g.diameter()4>>> g.chromatic_number()4>>> g.is_regular(k=Integer(5))
Truesage.graphs.generators.smallgraphs.WienerArayaGraph()
Return the Wiener-Araya Graph.
The Wiener-Araya Graph is a planar hypohamiltonian graph on 42 vertices and 67 edges. For more information,
see the Wolfram Page on the Wiener-Araya Graph or Wikipedia article Wiener-Araya_graph.
EXAMPLES:
sage: g = graphs.WienerArayaGraph()
sage: g.order()42sage: g.size()
67
sage: g.girth()4
sage: g.is_planar()True
sage: g.is_hamiltonian()# not tested (30s)˓→needs sage.numerical.mip
False
sage: g.delete_vertex(g.random_vertex())
sage: g.is_hamiltonian()
˓→needs sage.numerical.mip
True

1356

#␣

#␣

Chapter 2. Constructors and databases

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.WienerArayaGraph()>>> g.order()42>>> g.size()67>>> g.girth()4>>> g.is_planar()True>>> g.is_hamiltonian()# not tested (30s)˓→needs sage.numerical.mip
False>>> g.delete_vertex(g.random_vertex())>>> g.is_hamiltonian()
˓→needs sage.numerical.mip
True

#␣

#␣

2.15 Graphs from the World Map
The methods defined here appear in sage.graphs.graph_generators.
sage.graphs.generators.world_map.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 – boolean (default: False); whether to only return states in the continental Africa or all
African states• year – integer (default: 2018); 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
sage: Madagaskar in cont_Africa
False>>> from sage.all import *>>> Africa = graphs.AfricaMap(); Africa
Africa Map: Graph on 54 vertices>>> sorted(Africa.neighbors( Libya ))[ Algeria , Chad , Egypt , Niger , Sudan ,Tunisia ]>>> cont_Africa = graphs.AfricaMap(continental=True)>>> cont_Africa.order()(continues on next page)

2.15. Graphs from the World Map

1357

Graph Theory, Release 10.4

(continued from previous page)48>>> Madagaskar
False

in cont_Africa

sage.graphs.generators.world_map.EuropeMap(continental=False, year=2018)
Return European states as a graph of common border.
“European state” here is defined as an independent state having the capital city in Europe. The graph has an edge
between those countries that have common land border.
INPUT:• continental – boolean (default: False); whether to only return states in the continental Europe or all
European states• year – integer (default: 2018); 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>>> from sage.all import *>>> Europe = graphs.EuropeMap(); Europe
Europe Map: Graph on 44 vertices>>> Europe.neighbors( Ireland )[ United Kingdom ]>>> cont_Europe = graphs.EuropeMap(continental=True)>>> cont_Europe.order()40>>> Iceland in cont_Europe
False

sage.graphs.generators.world_map.USAMap(continental=False)
Return states of USA as a graph of common border.
The graph has an edge between those states that have common land border line or point. Hence for example
Colorado and Arizona are marked as neighbors, but Michigan and Minnesota are not.
INPUT:• continental – boolean (default: False); whether to exclude Alaska and Hawaii
EXAMPLES:
How many states are neighbor’s neighbor for Pennsylvania:
sage: USA = graphs.USAMap()sage: distance = USA.shortest_path_lengths( Pennsylvania )(continues on next page)

1358

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

sage: len([n2 for n2, d in distance.items() if d == 2])7>>> from sage.all import *>>> USA = graphs.USAMap()>>> distance = USA.shortest_path_lengths( Pennsylvania )>>> len([n2 for n2, d in distance.items() if d == Integer(2)])
7

Diameter for continental USA:sage: USAcont = graphs.USAMap(continental=True)
sage: USAcont.diameter()11>>> from sage.all import *>>> USAcont = graphs.USAMap(continental=True)>>> USAcont.diameter()11

sage.graphs.generators.world_map.WorldMap()
Return the Graph of all the countries, in which two countries are adjacent in the graph if they have a common
boundary.
This graph has been built from the data available in The CIA World Factbook [CIA] (2009-08-21).
The returned graph G has a member G.gps_coordinates equal to a dictionary containing the GPS coordinatesof each country’s capital city.
EXAMPLES:
sage: g = graphs.WorldMap()sage: g.has_edge("France", "Italy")Truesage: g.gps_coordinates["Bolivia"][[17, S ], [65, W ]]sage: g.connected_component_containing_vertex( Ireland , sort=True)[ Ireland , United Kingdom ]>>> from sage.all import *>>> g = graphs.WorldMap()>>> g.has_edge("France", "Italy")True>>> g.gps_coordinates["Bolivia"][[17, S ], [65, W ]]>>> g.connected_component_containing_vertex( Ireland , sort=True)[ Ireland , United Kingdom ]2.15. Graphs from the World Map

1359

Graph Theory, Release 10.4

2.16 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 thecomplexity of several computational problems.
It is available on the GraphClasses.org website maintained by H.N. de Ridder et al.

2.16.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>>> from sage.all import *>>> Trees = graph_classes.Tree>>> Chordal = graph_classes.Chordal

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>>> from sage.all import *>>> 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 thedocumentation 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>>> from sage.all import *>>> graph_classes.Chordal <= graph_classes.Tree
Unknown

1360

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

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
name...
Problems :----------3-Colourability
CliqueClique cover...
>>> from sage.all import *>>> Chordal.description()
Class of graphs : Chordal------------------------id
name...
Problems :----------3-Colourability
CliqueClique cover
...

:
:

gc_32
chordal:::LinearPolynomial
Polynomial

:
:

gc_32
chordal:::LinearPolynomial
Polynomial

It is possible to obtain the complete list of the classes stored in ISGCI by calling the show_all() method (beware –long output):sage: graph_classes.show_all()id| name| type|␣˓→smallgraph-------------------------------------------------------------------------------------˓→-------------------------------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|...
>>> from sage.all import *>>> graph_classes.show_all()id| name| type|␣˓→smallgraph-------------------------------------------------------------------------------------˓→-------------------------------gc_309| $K_4$--minor--free| base|gc_541| $N^*$| base|gc_215| $N^*$--perfect| base|(continues on next page)2.16. ISGCI: Information System on Graph Classes and their Inclusions

1361

Graph Theory, Release 10.4

(continued from previous page)

gc_5
gc_3
gc_6
gc_7
...

| $P_4$--bipartite| $P_4$--brittle| $P_4$--comparability| $P_4$--extendible| base| base| base| 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>>> from sage.all import *>>> GC = graph_classes.get_class("gc_5")>>> 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>>> from sage.all import *>>> graphs.PathGraph(Integer(5)) in graph_classes.Tree
True

or:
sage: graphs.PathGraph(5).is_tree()True>>> from sage.all import *>>> graphs.PathGraph(Integer(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 instancesage: g = graphs.PetersenGraph()
sage: g in graph_classes.ClawFree
False
sage: g.line_graph() in graph_classes.ClawFree
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g in graph_classes.ClawFree
False(continues on next page)

1362

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)>>> 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>>> from sage.all import *>>> gc = graph_classes.get_class("gc_441")>>> gcdiamond--free graphs>>> graphs.PetersenGraph() in gc
True

2.16.2 Predefined classes
graph_classes currently predefines the following graph classes
Class

Related methods

Apex
AT_freeBiconnected

is_apex(), apex_vertices()
is_asteroidal_triple_free()is_biconnected(),blocks_and_cut_vertices(),
blocks_and_cuts_tree()
BalancedTree(), is_tree()
BalancedTree(), is_bipartite()is_block_graph(),blocks_and_cut_vertices(),
RandomBlockGraph()
is_chordal()
ClawGraph()

BinaryTrees
Bipartite
Block
ChordalClaw-Free
Comparability
Gallai
Grid
IntervalLine
ModularOuterplanar
Perfect
PlanarPolyhedral
Split
Tree
UnitDisk
UnitInterval

is_gallai_tree()Grid2dGraph(), GridGraph()
RandomIntervalGraph(), IntervalGraph(), is_interval()
line_graph_forbidden_subgraphs(),
is_line_graph()
modular_decomposition()
is_circular_planar()
is_perfect()is_planar()
is_polyhedral()is_split()
trees(), is_tree()IntervalGraph()
is_interval()

2.16. ISGCI: Information System on Graph Classes and their Inclusions

1363

Graph Theory, Release 10.4

2.16.3 Sage’s view of ISGCIThe 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 }>>> from sage.all import *>>> 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 }The class inclusion digraph: Sage remembers the class inclusions through the inclusion digraph (see inclusion_digraph()). Its nodes are ID of ISGCI classes:
sage: d = graph_classes.inclusion_digraph()
sage: d.vertices(sort=True)[-10:][ gc_990 , gc_991 , gc_992 , gc_993 , gc_994 ,˓→998 ,
gc_999 ]>>> from sage.all import *>>> d = graph_classes.inclusion_digraph()>>> d.vertices(sort=True)[-Integer(10):][ gc_990 , gc_991 , gc_992 , gc_993 , gc_994 ,˓→998 ,
gc_999 ]1364

gc_995 ,gc_996 ,gc_997 ,gc_

gc_995 ,gc_996 ,gc_997 ,gc_

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

An arc from gc1 to gc2 means that gc1 is a superclass of gc2. This being said, not all edges are stored ! To ensurethat 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>>> from sage.all import *>>> bip_id = graph_classes.Bipartite._gc_id>>> perfect_id = graph_classes.Perfect._gc_id>>> d.has_edge(perfect_id, bip_id)
False>>> 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>>> from sage.all import *>>> p = d.shortest_path(perfect_id, bip_id)>>> len(p) - Integer(1)2>>> print(p)# random[ gc_56 , gc_76 , gc_69 ]>>> 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"); Perfectperfect graphs(continues on next page)2.16. ISGCI: Information System on Graph Classes and their Inclusions

1365

Graph Theory, Release 10.4

(continued from previous page)

sage: Berge <= PerfectTrue
sage: Perfect <= Berge
True
sage: Perfect == Berge
True>>> from sage.all import *>>> graph_classes.inclusion_digraph().is_directed_acyclic()
False>>> Berge = graph_classes.get_class("gc_274"); Berge
Berge graphs>>> Perfect = graph_classes.get_class("gc_56"); Perfectperfect graphs>>> Berge <= Perfect
True>>> Perfect <= Berge
True>>> Perfect == Berge
True

2.16.4 Information for developers• The database is loaded not so large, but it is still preferable to only load it on demand. This is achieved through thecached methods classes() and inclusion_digraph().
• Upon the first access to the database, the information is extracted from the XML file and stored in the cache ofthree 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 inclusions.
• 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 inSage. 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

1366

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

• 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 inSage).
• 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 aplanar graph, and use a specialized algorithm for finding an independent set.

2.16.5 AUTHORS:• H.N. de Ridder et al. (ISGCI database)• Nathann Cohen (Sage implementation)

2.16.6 Methods
class sage.graphs.isgci.GraphClass(name, gc_id, recognition_function=None)
Bases: SageObject, CachedRepresentation
An instance of this class represents a Graph Class, matching some entry in the ISGCI database.
EXAMPLES:
Testing the inclusion of two classes:
sage: Chordal = graph_classes.Chordal
sage: Trees = graph_classes.Tree
sage: Trees <= Chordal
Truesage: Chordal <= Trees
Unknown>>> from sage.all import *>>> Chordal = graph_classes.Chordal>>> Trees = graph_classes.Tree>>> Trees <= Chordal
True>>> Chordal <= Trees
Unknown

description()
Print the information of ISGCI about the current class.
EXAMPLES:
sage: graph_classes.Chordal.description()
Class of graphs : Chordal------------------------id: gc_32
name: chordal...
Problems :----------3-Colourability: Linear
Clique: Polynomial(continues on next page)2.16. ISGCI: Information System on Graph Classes and their Inclusions

1367

Graph Theory, Release 10.4

(continued from previous page)

Clique cover...
Recognition...

:

Polynomial:

Linear>>> from sage.all import *>>> graph_classes.Chordal.description()
Class of graphs : Chordal------------------------id: gc_32
name: chordal...
Problems :----------3-Colourability: Linear
Clique: Polynomial
Clique cover: Polynomial...
Recognition: Linear...

forbidden_subgraphs()
Return the list of forbidden induced subgraphs defining the class.
If the graph class is not defined by a finite list of forbidden induced subgraphs, None is returned instead.
EXAMPLES:
sage: graph_classes.Perfect.forbidden_subgraphs()sage: gc = graph_classes.get_class( gc_62 )sage: gc
claw--free graphs
sage: gc.forbidden_subgraphs()[Graph on 4 vertices]sage: gc.forbidden_subgraphs()[0].is_isomorphic(graphs.ClawGraph())
True>>> from sage.all import *>>> graph_classes.Perfect.forbidden_subgraphs()>>> gc = graph_classes.get_class( gc_62 )>>> gcclaw--free graphs>>> gc.forbidden_subgraphs()[Graph on 4 vertices]>>> gc.forbidden_subgraphs()[Integer(0)].is_isomorphic(graphs.ClawGraph())
Trueclass sage.graphs.isgci.GraphClasses
Bases: UniqueRepresentation
classes()
Return the graph classes, as a dictionary.
Upon the first call, this loads the database from the local XML file. Subsequent calls are cached.
EXAMPLES:

1368

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

sage: t = graph_classes.classes()sage: type(t)<... dict >sage: sorted(t["gc_151"].keys())[ id , name ,... problem ,... type ]sage: t["gc_151"][ name ]cographsage: t["gc_151"][ problem ][ Clique ]{ complexity : Linear }>>> from sage.all import *>>> t = graph_classes.classes()>>> type(t)<... dict >>>> sorted(t["gc_151"].keys())[ id , name ,... problem ,... type ]>>> t["gc_151"][ name ]cograph>>> t["gc_151"][ problem ][ Clique ]{ complexity : Linear }get_class(id)Return the class corresponding to the given id in the ISGCI database.
INPUT:• id (string) – the desired class’ ID
See also:
show_all()
EXAMPLES:
With an existing id:
sage: Cographs = graph_classes.get_class("gc_151")
sage: Cographs
cograph graphs>>> from sage.all import *>>> Cographs = graph_classes.get_class("gc_151")>>> 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().
>>> from sage.all import *>>> graph_classes.get_class(-Integer(1))
Traceback (most recent call last):...
(continues on next page)2.16. ISGCI: Information System on Graph Classes and their Inclusions

1369

Graph Theory, Release 10.4

(continued from previous page)

ValueError: The given class id does not exist in the ISGCI database. Is the␣˓→db too old ? You can update it with graph_classes.update_db().

inclusion_digraph()
Return the class inclusion digraph.
Upon the first call, this loads the database from the local XML file. Subsequent calls are cached.
EXAMPLES:
sage: g = graph_classes.inclusion_digraph(); gDigraph on ... vertices>>> from sage.all import *>>> g = graph_classes.inclusion_digraph(); gDigraph on ... vertices

inclusions()
Return the graph class inclusions.
OUTPUT:a list of dictionaries
Upon the first call, this loads the database from the local XML file. Subsequent calls are cached.
EXAMPLES:
sage: t = graph_classes.inclusions()
sage: type(t)<... list >sage: t[0]{ sub : gc_1 , super : gc_2 }>>> from sage.all import *>>> t = graph_classes.inclusions()>>> type(t)<... list >>>> t[Integer(0)]{ sub : gc_1 , super : gc_2 }show_all()Prints all graph classes stored in ISGCIEXAMPLES:
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|(continues on next page)

1370

Chapter 2. Constructors and databases

Graph Theory, Release 10.4

(continued from previous page)

gc_7
...

| $P_4$--extendible| base|>>> from sage.all import *>>> 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()
Return a dictionary associating a graph to a graph description string.
Upon the first call, this loads the database from the local XML files. Subsequent calls are cached.
EXAMPLES:
sage: t = graph_classes.smallgraphs()sage: t[ 2C_4 ]Graph on 8 vertices
sage: t[ 2K_3 + e ]Graph on 6 vertices
sage: t[ fish ]Graph on 6 vertices
sage: t[ bull ]Graph on 5 vertices>>> from sage.all import *>>> t = graph_classes.smallgraphs()>>> t[ 2C_4 ]Graph on 8 vertices>>> t[ 2K_3 + e ]Graph on 6 vertices>>> t[ fish ]Graph on 6 vertices>>> t[ bull ]Graph on 5 vertices

update_db()
Updates the ISGCI database by downloading the latest version from internet.
This method downloads the ISGCI database from the website GraphClasses.org. It then extracts the zip fileand parses its XML content.
Depending on the credentials of the user running Sage when this command is run, one attempt is made atsaving the result in Sage’s directory so that all users can benefit from it. If the credentials are not sufficient,
the XML file are saved instead in the user’s directory (in the SAGE_DB folder).
EXAMPLES:

2.16. ISGCI: Information System on Graph Classes and their Inclusions

1371

Graph Theory, Release 10.4

sage: graph_classes.update_db()
Database downloaded>>> from sage.all import *>>> graph_classes.update_db()
Database downloaded

1372# optional - internet# optional - internet

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 thansparse_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 awrapper 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.

1373

Graph Theory, Release 10.4

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 ...>>>> from sage.all import *>>> Graph()._backend<sage.graphs.base.sparse_graph.SparseGraphBackend object at ...>A (di)graph backend is a simpler (di)graph class having only the most elementary methods (e.g.: add/remove vertices/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 extendedby:• 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.

1374

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

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 consideredto actually be in the graph. The variables num_verts and num_arcs are self-explanatory. Note that num_vertsis the number of bits set in active_vertices, not the full length of the bitset. The arrays in_degrees andout_degrees are of the same length as the bitset.
For more information about active vertices, see the documentation for the method realloc.
class sage.graphs.base.c_graph.CGraph
Bases: object
Compiled sparse and dense graphs.
add_arc(u, v)
Add arc (u, v) to the graph.
INPUT:• u, v – non-negative integers, must be in self
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:sage: from sage.graphs.base.c_graph import CGraphsage: G = CGraph()
sage: G.add_arc(0, 1)
Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph>>> from sage.all import *>>> from sage.graphs.base.c_graph import CGraph>>> G = CGraph()>>> G.add_arc(Integer(0), Integer(1))
Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph

It works, once there are vertices and add_arc_unsafe() is implemented:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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(continues on next page)3.2. Fast compiled graphs

1375Graph Theory, Release 10.4

(continued from previous page)

sage: G.has_arc(1, 0)
False
sage: G.has_arc(0, 1)
True
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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 graphsage: G.has_arc(1,0)
False
sage: G.has_arc(0,1)
True>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(5))>>> G.add_arc(Integer(0), Integer(1))>>> G.add_arc(Integer(4), Integer(7))
Traceback (most recent call last):...
LookupError: vertex (7) is not a vertex of the graph>>> G.has_arc(Integer(1), Integer(0))
False>>> G.has_arc(Integer(0), Integer(1))
True>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc(Integer(0),Integer(1))>>> G.add_arc(Integer(4),Integer(7))
Traceback (most recent call last):...
LookupError: vertex (7) is not a vertex of the graph>>> G.has_arc(Integer(1),Integer(0))
False>>> G.has_arc(Integer(0),Integer(1))
True

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 isreturned. That is, for 𝑘 = −1, this function will find the first available vertex that is not in self andadd that vertex to this graph.
OUTPUT:• -1 – indicates that no vertex was added because the current allocation is already full or the vertex is outof range.
• nonnegative integer – this vertex is now guaranteed to be in the graph.
See also:
1376

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• 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:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: G = SparseGraph(3, extra_vertices=3)
sage: G.add_vertex(3)3sage: G.add_arc(2, 5)
Traceback (most recent call last):...
LookupError: vertex (5) is not a vertex of the graphsage: G.add_arc(1, 3)
sage: G.has_arc(1, 3)
True
sage: G.has_arc(2, 3)
False>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(3), extra_vertices=Integer(3))>>> G.add_vertex(Integer(3))
3>>> G.add_arc(Integer(2), Integer(5))
Traceback (most recent call last):...
LookupError: vertex (5) is not a vertex of the graph>>> G.add_arc(Integer(1), Integer(3))>>> G.has_arc(Integer(1), Integer(3))
True>>> G.has_arc(Integer(2), Integer(3))
False

Adding vertices to a dense graph:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: G = DenseGraph(3, extra_vertices=3)
sage: G.add_vertex(3)3sage: G.add_arc(2,5)
Traceback (most recent call last):...
LookupError: vertex (5) is not a vertex of the graphsage: G.add_arc(1, 3)
sage: G.has_arc(1, 3)
True
sage: G.has_arc(2, 3)
False>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(3), extra_vertices=Integer(3))>>> G.add_vertex(Integer(3))(continues on next page)3.2. Fast compiled graphs

1377

Graph Theory, Release 10.4

(continued from previous page)3>>> G.add_arc(Integer(2),Integer(5))
Traceback (most recent call last):...
LookupError: vertex (5) is not a vertex of the graph>>> G.add_arc(Integer(1), Integer(3))>>> G.has_arc(Integer(1), Integer(3))
True>>> G.has_arc(Integer(2), Integer(3))
False

Repeatedly adding a vertex using 𝑘 = −1 will allocate more memory as required:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(3), extra_vertices=Integer(0))>>> G.verts()[0, 1, 2]>>> for i in range(Integer(10)):...
_ = G.add_vertex(-Integer(1));...
>>> G.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(3), extra_vertices=Integer(0))>>> G.verts()[0, 1, 2]>>> for i in range(Integer(12)):...
_ = G.add_vertex(-Integer(1));...
>>> G.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

add_vertices(verts)
1378

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

Add vertices from the iterable verts.
INPUT:• verts – an iterable of vertices; value -1 has a special meaning – for each such value an unused vertex
name is found, used to create a new vertex and returned.
OUTPUT:
List of generated labels if there is any -1 in verts. None otherwise.
See also:• add_vertex() – add a vertex to a graph
EXAMPLES:
Adding vertices for sparse graphs:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> S = SparseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> S.verts()[0, 1, 2, 3]>>> S.add_vertices([Integer(3), -Integer(1), Integer(4), Integer(9)])[5]>>> S.verts()[0, 1, 2, 3, 4, 5, 9]>>> S.realloc(Integer(20))>>> S.verts()[0, 1, 2, 3, 4, 5, 9]

Adding vertices for dense graphs:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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]

3.2. Fast compiled graphs1379

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> D = DenseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> D.verts()[0, 1, 2, 3]>>> D.add_vertices([Integer(3), -Integer(1), Integer(4), Integer(9)])[5]>>> D.verts()[0, 1, 2, 3, 4, 5, 9]>>> D.realloc(Integer(20))>>> D.verts()[0, 1, 2, 3, 4, 5, 9]

all_arcs(u, v)
Gives the labels of all arcs (u, v). An unlabeled arc is interpreted as having label 0.
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc_label(Integer(1),Integer(2),Integer(1))>>> G.add_arc_label(Integer(1),Integer(2),Integer(2))>>> G.add_arc_label(Integer(1),Integer(2),Integer(2))>>> G.add_arc_label(Integer(1),Integer(2),Integer(2))>>> G.add_arc_label(Integer(1),Integer(2),Integer(3))>>> G.add_arc_label(Integer(1),Integer(2),Integer(3))>>> G.add_arc_label(Integer(1),Integer(2),Integer(4))>>> G.all_arcs(Integer(1),Integer(2))[4, 3, 3, 2, 2, 2, 1]

arc_label(u, v)
Retrieves the first label found associated with (u, v).
INPUT:• u, v – non-negative integers, must be in self
OUTPUT: one of• positive integer – indicates that there is a label on (u, v).
• 0 – either the arc (u, v) is unlabeled, or there is no arc at all.
EXAMPLES:

1380

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

sage: from sage.graphs.base.sparse_graph import SparseGraphsage: G = SparseGraph(5)sage: G.add_arc_label(3,4,7)
sage: G.arc_label(3,4)
7>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc_label(Integer(3),Integer(4),Integer(7))>>> G.arc_label(Integer(3),Integer(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)
0sage: G.arc_label(1,1)
0>>> from sage.all import *>>> G.add_arc_label(Integer(1),Integer(0))>>> G.arc_label(Integer(1),Integer(0))
0>>> G.arc_label(Integer(1),Integer(1))
0This 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>>> from sage.all import *>>> G.add_arc_label(Integer(1),Integer(2),Integer(1))>>> G.add_arc_label(Integer(1),Integer(2),Integer(2))>>> G.arc_label(Integer(1),Integer(2))
2check_vertex(n)Check that n is a vertex of self.
This method is different from has_vertex(). The current method raises an error if n is not a vertex ofthis graph. On the other hand, has_vertex() returns a boolean to signify whether or not n is a vertex ofthis graph.
INPUT:• n – a nonnegative integer representing a vertex
OUTPUT:• Raise an error if n is not a vertex of this graphSee also:

3.2. Fast compiled graphs1381

Graph Theory, Release 10.4

• has_vertex() – determine whether this graph has a specific vertex
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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 graphsage: S.check_vertex(24)Traceback (most recent call last):...
LookupError: vertex (24) is not a vertex of the graphsage: S.check_vertex(-19)
Traceback (most recent call last):...
LookupError: vertex (-19) is not a vertex of the graph>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> S = SparseGraph(nverts=Integer(10), expected_degree=Integer(3), extra_
˓→vertices=Integer(10))>>> S.check_vertex(Integer(4))>>> S.check_vertex(Integer(12))
Traceback (most recent call last):...
LookupError: vertex (12) is not a vertex of the graph>>> S.check_vertex(Integer(24))
Traceback (most recent call last):...
LookupError: vertex (24) is not a vertex of the graph>>> S.check_vertex(-Integer(19))
Traceback (most recent call last):...
LookupError: vertex (-19) is not a vertex of the graphsage: from sage.graphs.base.dense_graph import DenseGraphsage: D = DenseGraph(nverts=10, extra_vertices=10)
sage: D.check_vertex(4)sage: D.check_vertex(12)Traceback (most recent call last):...
LookupError: vertex (12) is not a vertex of the graphsage: D.check_vertex(24)Traceback (most recent call last):...
LookupError: vertex (24) is not a vertex of the graphsage: D.check_vertex(-19)
Traceback (most recent call last):...
LookupError: vertex (-19) is not a vertex of the graph>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> D = DenseGraph(nverts=Integer(10), extra_vertices=Integer(10))(continues on next page)1382

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> D.check_vertex(Integer(4))>>> D.check_vertex(Integer(12))
Traceback (most recent call last):...
LookupError: vertex (12) is not a vertex of the graph>>> D.check_vertex(Integer(24))
Traceback (most recent call last):...
LookupError: vertex (24) is not a vertex of the graph>>> D.check_vertex(-Integer(19))
Traceback (most recent call last):...
LookupError: vertex (-19) is not a vertex of the graphcurrent_allocation()
Report the number of vertices allocated.
OUTPUT:• The number of vertices allocated. This number is usually different from the order of a graph. We may
have allocated enough memory for a graph to hold 𝑛 > 0 vertices, but the order (actual number ofvertices) of the graph could be less than 𝑛.
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.current_allocation()8
sage: S.add_vertex(6)6sage: S.current_allocation()8
sage: S.add_vertex(10)10sage: 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)40sage: S.current_allocation()50
sage: S.realloc(30)-1sage: S.current_allocation()50
sage: S.del_vertex(40)sage: S.realloc(30)sage: S.current_allocation()30>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph(continues on next page)3.2. Fast compiled graphs1383

Graph Theory, Release 10.4

(continued from previous page)>>> S = SparseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> S.current_allocation()
8>>> S.add_vertex(Integer(6))
6>>> S.current_allocation()
8>>> S.add_vertex(Integer(10))
10>>> S.current_allocation()
16>>> S.add_vertex(Integer(40))
Traceback (most recent call last):...
RuntimeError: requested vertex is past twice the allocated range: use realloc>>> S.realloc(Integer(50))>>> S.add_vertex(Integer(40))
40>>> S.current_allocation()50>>> S.realloc(Integer(30))-1>>> S.current_allocation()50>>> S.del_vertex(Integer(40))>>> S.realloc(Integer(30))>>> S.current_allocation()30

The actual number of vertices in a graph might be less than the number of vertices allocated for the graph:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: G = DenseGraph(nverts=3, extra_vertices=2)
sage: order = len(G.verts())
sage: order3
sage: G.current_allocation()5
sage: order < G.current_allocation()
True>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(nverts=Integer(3), extra_vertices=Integer(2))>>> order = len(G.verts())>>> order
3>>> G.current_allocation()5>>> order < G.current_allocation()
Truedel_all_arcs(u, v)
Delete all arcs from u to v.
INPUT:

1384

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• u – integer; the tail of an arc.
• v – integer; the head of an arc.
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:sage: from sage.graphs.base.c_graph import CGraphsage: G = CGraph()
sage: G.del_all_arcs(0,1)
Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph>>> from sage.all import *>>> from sage.graphs.base.c_graph import CGraph>>> G = CGraph()>>> G.del_all_arcs(Integer(0),Integer(1))
Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph

It works, once there are vertices and del_arc_unsafe() is implemented:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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)
0sage: G.del_all_arcs(0,1)
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc_label(Integer(0),Integer(1),Integer(0))>>> G.add_arc_label(Integer(0),Integer(1),Integer(1))>>> G.add_arc_label(Integer(0),Integer(1),Integer(2))>>> G.add_arc_label(Integer(0),Integer(1),Integer(3))>>> G.del_all_arcs(Integer(0),Integer(1))>>> G.has_arc(Integer(0),Integer(1))
False>>> G.arc_label(Integer(0),Integer(1))(continues on next page)3.2. Fast compiled graphs1385

Graph Theory, Release 10.4

(continued from previous page)0>>> G.del_all_arcs(Integer(0),Integer(1))>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(5))>>> G.add_arc(Integer(0), Integer(1))>>> G.has_arc(Integer(0), Integer(1))
True>>> G.del_all_arcs(Integer(0), Integer(1))>>> G.has_arc(Integer(0), Integer(1))
False

del_arc_label(u, v, l)Delete an arc (u, v) with label l.
INPUT:• u, v – non-negative integers, must be in self
• l – a positive integer label, or zero for no label
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc_label(Integer(0),Integer(1),Integer(0))>>> G.add_arc_label(Integer(0),Integer(1),Integer(1))>>> G.add_arc_label(Integer(0),Integer(1),Integer(2))>>> G.add_arc_label(Integer(0),Integer(1),Integer(2))>>> G.add_arc_label(Integer(0),Integer(1),Integer(3))>>> G.del_arc_label(Integer(0),Integer(1),Integer(2))>>> G.all_arcs(Integer(0),Integer(1))[0, 3, 2, 1]>>> G.del_arc_label(Integer(0),Integer(1),Integer(0))>>> G.all_arcs(Integer(0),Integer(1))[3, 2, 1]

del_vertex(v)Delete the vertex v, along with all edges incident to it.
If v is not in self, fails silently.
INPUT:

1386

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• v – a nonnegative integer representing a vertex
See also:• del_vertex_unsafe – delete a vertex from a graph. This method is potentially unsafe. Use
del_vertex() instead.
EXAMPLES:
Deleting vertices of sparse graphs:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(3))>>> G.add_arc(Integer(0), Integer(1))>>> G.add_arc(Integer(0), Integer(2))>>> G.add_arc(Integer(1), Integer(2))>>> G.add_arc(Integer(2), Integer(0))>>> G.del_vertex(Integer(2))>>> for i in range(Integer(2)):...
for j in range(Integer(2)):...
if G.has_arc(i, j):...
print("{} {}".format(i,j))
0 1>>> G = SparseGraph(Integer(3))>>> G.add_arc(Integer(0), Integer(1))>>> G.add_arc(Integer(0), Integer(2))>>> G.add_arc(Integer(1), Integer(2))>>> G.add_arc(Integer(2), Integer(0))>>> G.del_vertex(Integer(1))>>> for i in range(Integer(3)):...
for j in range(Integer(3)):...
if G.has_arc(i, j):(continues on next page)3.2. Fast compiled graphs

1387

Graph Theory, Release 10.4

(continued from previous page)

...
0 2
2 0

print("{} {}".format(i,j))

Deleting vertices of dense graphs:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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
>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(4))>>> G.add_arc(Integer(0), Integer(1)); G.add_arc(Integer(0), Integer(2))>>> G.add_arc(Integer(3), Integer(1)); G.add_arc(Integer(3), Integer(2))>>> G.add_arc(Integer(1), Integer(2))>>> G.verts()[0, 1, 2, 3]>>> G.del_vertex(Integer(3)); G.verts()[0, 1, 2]>>> for i in range(Integer(3)):...
for j in range(Integer(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 SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(3))(continues on next page)

1388

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> G.verts()[0, 1, 2]>>> G.has_vertex(Integer(3))
False>>> G.del_vertex(Integer(3))>>> G.verts()[0, 1, 2]
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(5))>>> G.verts()[0, 1, 2, 3, 4]>>> G.has_vertex(Integer(6))
False>>> G.del_vertex(Integer(6))>>> G.verts()[0, 1, 2, 3, 4]

has_arc(u, v)
Check if the arc (u, v) is in this graph.
INPUT:• u – integer; the tail of an arc• v – integer; the head of an arc
OUTPUT:• Print a Not Implemented! message. This method is not implemented at the CGraph level. A childclass should provide a suitable implementation.
EXAMPLES:
On the CGraph this always returns False:
sage: from sage.graphs.base.c_graph import CGraphsage: G = CGraph()
sage: G.has_arc(0, 1)
False>>> from sage.all import *>>> from sage.graphs.base.c_graph import CGraph>>> G = CGraph()>>> G.has_arc(Integer(0), Integer(1))
False

3.2. Fast compiled graphs1389

Graph Theory, Release 10.4

It works once has_arc_unsafe is implemented:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: G = DenseGraph(5)sage: G.add_arc(0, 1)
sage: G.has_arc(1, 0)
False
sage: G.has_arc(0, 1)
True
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: G = SparseGraph(5)sage: G.add_arc_label(0,1)
sage: G.has_arc(1,0)
False
sage: G.has_arc(0,1)
True>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(5))>>> G.add_arc(Integer(0), Integer(1))>>> G.has_arc(Integer(1), Integer(0))
False>>> G.has_arc(Integer(0), Integer(1))
True>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc_label(Integer(0),Integer(1))>>> G.has_arc(Integer(1),Integer(0))
False>>> G.has_arc(Integer(0),Integer(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 SparseGraphsage: 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

1390

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc_label(Integer(0),Integer(1),Integer(0))>>> G.add_arc_label(Integer(0),Integer(1),Integer(1))>>> G.add_arc_label(Integer(0),Integer(1),Integer(2))>>> G.add_arc_label(Integer(0),Integer(1),Integer(2))>>> G.has_arc_label(Integer(0),Integer(1),Integer(1))
True>>> G.has_arc_label(Integer(0),Integer(1),Integer(2))
True>>> G.has_arc_label(Integer(0),Integer(1),Integer(3))
False

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 vertexof 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:sage: from sage.graphs.base.sparse_graph import SparseGraphsage: S = SparseGraph(nverts=10, expected_degree=3, extra_vertices=10)
sage: S.has_vertex(6)Truesage: S.has_vertex(12)False
sage: S.has_vertex(24)False
sage: S.has_vertex(-19)
False>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> S = SparseGraph(nverts=Integer(10), expected_degree=Integer(3), extra_
˓→vertices=Integer(10))>>> S.has_vertex(Integer(6))
True>>> S.has_vertex(Integer(12))
False>>> S.has_vertex(Integer(24))
False(continues on next page)3.2. Fast compiled graphs1391

Graph Theory, Release 10.4

(continued from previous page)>>> S.has_vertex(-Integer(19))
False
sage: from sage.graphs.base.dense_graph import DenseGraphsage: D = DenseGraph(nverts=10, extra_vertices=10)
sage: D.has_vertex(6)Truesage: D.has_vertex(12)False
sage: D.has_vertex(24)False
sage: D.has_vertex(-19)
False>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> D = DenseGraph(nverts=Integer(10), extra_vertices=Integer(10))>>> D.has_vertex(Integer(6))
True>>> D.has_vertex(Integer(12))
False>>> D.has_vertex(Integer(24))
False>>> D.has_vertex(-Integer(19))
False

in_neighbors(v)Return the list of in-neighbors of the vertex v.
INPUT:• v – integer representing a vertex of this graph
OUTPUT:• Raise NotImplementedError. This method is not implemented at the CGraph level. A child classshould provide a suitable implementation.
Note: Due to the implementation of SparseGraph, this method is much more expensive than out_neighbors_unsafe for SparseGraph’s.
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:sage: from sage.graphs.base.c_graph import CGraphsage: G = CGraph()
sage: G.in_neighbors(0)Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph>>> from sage.all import *>>> from sage.graphs.base.c_graph import CGraph>>> G = CGraph()(continues on next page)1392

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> G.in_neighbors(Integer(0))
Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph

It works, once there are vertices and out_neighbors_unsafe() is implemented:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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]sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(5))>>> G.add_arc(Integer(0), Integer(1))>>> G.add_arc(Integer(3), Integer(1))>>> G.add_arc(Integer(1), Integer(3))>>> G.in_neighbors(Integer(1))[0, 3]>>> G.in_neighbors(Integer(3))[1]>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc(Integer(0),Integer(1))>>> G.add_arc(Integer(3),Integer(1))>>> G.add_arc(Integer(1),Integer(3))>>> G.in_neighbors(Integer(1))[0, 3]>>> G.in_neighbors(Integer(3))[1]out_neighbors(u)Return the list of out-neighbors of the vertex u.
INPUT:• u – integer representing a vertex of this graph
EXAMPLES:
On the CGraph level, this always produces an error, as there are no vertices:
3.2. Fast compiled graphs1393

Graph Theory, Release 10.4

sage: from sage.graphs.base.c_graph import CGraphsage: G = CGraph()
sage: G.out_neighbors(0)Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph>>> from sage.all import *>>> from sage.graphs.base.c_graph import CGraph>>> G = CGraph()>>> G.out_neighbors(Integer(0))
Traceback (most recent call last):...
LookupError: vertex (0) is not a vertex of the graph

It works, once there are vertices and out_neighbors_unsafe() is implemented:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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]
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(5))>>> G.add_arc(Integer(0), Integer(1))>>> G.add_arc(Integer(1), Integer(2))>>> G.add_arc(Integer(1), Integer(3))>>> G.out_neighbors(Integer(0))[1]>>> G.out_neighbors(Integer(1))[2, 3]>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc(Integer(0),Integer(1))>>> G.add_arc(Integer(1),Integer(2))>>> G.add_arc(Integer(1),Integer(3))>>> G.out_neighbors(Integer(0))[1]>>> G.out_neighbors(Integer(1))[2, 3]

1394

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

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 classshould 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 CGraphsage: G = CGraph()
sage: G.realloc(20)Traceback (most recent call last):...
NotImplementedError>>> from sage.all import *>>> from sage.graphs.base.c_graph import CGraph>>> G = CGraph()>>> G.realloc(Integer(20))
Traceback (most recent call last):...
NotImplementedError

The realloc implementation for sparse graphs:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.current_allocation()8
sage: S.add_vertex(6)6sage: S.current_allocation()8
sage: S.add_vertex(10)10sage: 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(continues on next page)3.2. Fast compiled graphs1395

Graph Theory, Release 10.4

(continued from previous page)

sage: S.current_allocation()50
sage: S.realloc(30)-1sage: S.current_allocation()50
sage: S.del_vertex(40)sage: S.realloc(30)sage: S.current_allocation()30>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> S = SparseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> S.current_allocation()
8>>> S.add_vertex(Integer(6))
6>>> S.current_allocation()
8>>> S.add_vertex(Integer(10))
10>>> S.current_allocation()
16>>> S.add_vertex(Integer(40))
Traceback (most recent call last):...
RuntimeError: requested vertex is past twice the allocated range: use realloc>>> S.realloc(Integer(50))>>> S.add_vertex(Integer(40))
40>>> S.current_allocation()50>>> S.realloc(Integer(30))-1>>> S.current_allocation()50>>> S.del_vertex(Integer(40))>>> S.realloc(Integer(30))>>> S.current_allocation()30

The realloc implementation for dense graphs:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: D = DenseGraph(nverts=4, extra_vertices=4)
sage: D.current_allocation()8
sage: D.add_vertex(6)6sage: D.current_allocation()8
sage: D.add_vertex(10)10sage: D.current_allocation()
16(continues on next page)1396

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

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)40sage: D.current_allocation()50
sage: D.realloc(30)-1sage: D.current_allocation()50
sage: D.del_vertex(40)sage: D.realloc(30)sage: D.current_allocation()30>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> D = DenseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> D.current_allocation()8>>> D.add_vertex(Integer(6))
6>>> D.current_allocation()8>>> D.add_vertex(Integer(10))
10>>> D.current_allocation()
16>>> D.add_vertex(Integer(40))
Traceback (most recent call last):...
RuntimeError: requested vertex is past twice the allocated range: use realloc>>> D.realloc(Integer(50))>>> D.add_vertex(Integer(40))
40>>> D.current_allocation()50>>> D.realloc(Integer(30))-1>>> D.current_allocation()50>>> D.del_vertex(Integer(40))>>> D.realloc(Integer(30))>>> D.current_allocation()30

verts()
Return a list of the vertices in self.
OUTPUT:• A list of all vertices in this graph
EXAMPLES:

3.2. Fast compiled graphs1397

Graph Theory, Release 10.4

sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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]>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> S = SparseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> S.verts()[0, 1, 2, 3]>>> S.add_vertices([Integer(3),Integer(5),Integer(7),Integer(9)])>>> S.verts()[0, 1, 2, 3, 5, 7, 9]>>> S.realloc(Integer(20))>>> S.verts()[0, 1, 2, 3, 5, 7, 9]
sage: from sage.graphs.base.dense_graph import DenseGraphsage: G = DenseGraph(3, extra_vertices=2)
sage: G.verts()[0, 1, 2]
sage: G.del_vertex(0)sage: G.verts()[1, 2]>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(3), extra_vertices=Integer(2))>>> G.verts()[0, 1, 2]>>> G.del_vertex(Integer(0))>>> G.verts()[1, 2]

class sage.graphs.base.c_graph.CGraphBackend
Bases: GenericGraphBackend
Base class for sparse and dense graph backends.
sage: from sage.graphs.base.c_graph import CGraphBackend>>> from sage.all import *>>> 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()(continues on next page)1398

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

sage: CGB.degree(0, True)
Traceback (most recent call last):...
NotImplementedError: a derived class must returnself._cg>>> from sage.all import *>>> from sage.graphs.base.c_graph import CGraphBackend>>> CGB = CGraphBackend()>>> CGB.degree(Integer(0), True)
Traceback (most recent call last):...
NotImplementedError: a derived class must returnself._cg

The appropriate way to use these backends is via Sage graphs:
sage: G = Graph(30)sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
sage: G.edges(sort=True, labels=False)[(0, 1), (0, 3), (4, 5), (9, 23)]>>> from sage.all import *>>> G = Graph(Integer(30))>>> G.add_edges([(Integer(0),Integer(1)), (Integer(0),Integer(3)), (Integer(4),˓→Integer(5)), (Integer(9), Integer(23))])>>> G.edges(sort=True, labels=False)[(0, 1), (0, 3), (4, 5), (9, 23)]

This class handles the labels of vertices and edges. For vertices it uses two dictionaries vertex_labels andvertex_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.
add_edge(u, v, l, directed)
Add the edge (u,v) to self.
INPUT:• u, v – the vertices of the edge
• l – the edge label• directed – if False, also add (v,u)
Note: The input l is ignored if the backend does not support labels.
EXAMPLES:

3.2. Fast compiled graphs1399

Graph Theory, Release 10.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)]>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.add_edge(Integer(0),Integer(1),None,False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, None)]sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)sage: D.add_edge(0, 1, None, False)
sage: list(D.iterator_edges(range(9), True))[(0, 1, None)]>>> from sage.all import *>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.add_edge(Integer(0), Integer(1), None, False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, None)]

add_edges(edges, directed, remove_loops=False)
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)• remove_loops – if True, remove loops
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)]>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0),Integer(1)), (Integer(2),Integer(3)),␣
˓→(Integer(4),Integer(5)), (Integer(5),Integer(6))], False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, None),(2, 3, None),(4, 5, None),(5, 6, None)]

add_vertex(name)
Add a vertex to self.
INPUT:

1400

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• 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>>> from sage.all import *>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.add_vertex(Integer(10))>>> 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>>> from sage.all import *>>> S = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> S.add_vertex(Integer(10))>>> S.add_vertex([])
Traceback (most recent call last):...
TypeError: unhashable type: list

add_vertices(vertices)
Add vertices to self.
INPUT:• vertices – iterator of vertex labels; a new name is created, used and returned in the output list for all
None values in vertices
OUTPUT:
Generated names of new vertices if there is at least one None value present in vertices. None otherwise.
See also:• add_vertex() – add a vertex to this graph3.2. Fast compiled graphs1401

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(1))>>> D.add_vertices([Integer(1), Integer(2), Integer(3)])>>> D.add_vertices([None] * Integer(4))[4, 5, 6, 7]
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(0)sage: G.add_vertices([0, 1])
sage: list(G.iterator_verts(None))[0, 1]
sage: list(G.iterator_edges([0, 1], True))[]>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0))>>> G.add_vertices([Integer(0), Integer(1)])>>> list(G.iterator_verts(None))[0, 1]>>> list(G.iterator_edges([Integer(0), Integer(1)], True))[]sage: import sage.graphs.base.dense_graphsage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)sage: D.add_vertices([10, 11, 12])>>> from sage.all import *>>> import sage.graphs.base.dense_graph>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.add_vertices([Integer(10), Integer(11), Integer(12)])bidirectional_dijkstra(x, y, weight_function=None, distance_flag=False)
Return 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 – function (default: None); a function that inputs an edge (u, v, l) andoutputs its weight. If None, we use the edge label l as a weight, if l is not None, else 1 as a weight.
• distance_flag – boolean (default: False); when set to True, the shortest path distance from x
to y is returned instead of the path.
OUTPUT:• A list of vertices in the shortest path from x to y or distance from x to y is returned depending upon thevalue of parameter distance_flag
EXAMPLES:

1402

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

sage: G = Graph(graphs.PetersenGraph())
sage: for (u, v) in G.edges(sort=True, labels=None):....:G.set_edge_label(u, v, 1)
sage: G.shortest_path(0, 1, by_weight=True)[0, 1]
sage: G.shortest_path_length(0, 1, by_weight=True)1
sage: G = DiGraph([(1, 2, { weight :1}), (1, 3, { weight :5}), (2, 3, { weight˓→ :1})])
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>>> from sage.all import *>>> G = Graph(graphs.PetersenGraph())>>> for (u, v) in G.edges(sort=True, labels=None):...
G.set_edge_label(u, v, Integer(1))>>> G.shortest_path(Integer(0), Integer(1), by_weight=True)[0, 1]>>> G.shortest_path_length(Integer(0), Integer(1), by_weight=True)
1>>> G = DiGraph([(Integer(1), Integer(2), { weight :Integer(1)}), (Integer(1),˓→ Integer(3), { weight :Integer(5)}), (Integer(2), Integer(3), { weight
˓→ :Integer(1)})])>>> G.shortest_path(Integer(1), Integer(3), weight_function=lambda␣
˓→e:e[Integer(2)][ weight ])[1, 2, 3]>>> G.shortest_path_length(Integer(1), Integer(3), weight_function=lambda␣
˓→e:e[Integer(2)][ weight ])2bidirectional_dijkstra_special(x, y, weight_function=None, exclude_vertices=None,
exclude_edges=None, include_vertices=None,distance_flag=False, reduced_weight=None)
Return the shortest path or distance from x to y using a bidirectional version of Dijkstra’s algorithm.
This method is an extension of bidirectional_dijkstra() method enabling to exclude vertices
and/or edges from the search for the shortest path between x and y.
This method also has include_vertices option enabling to include the vertices which will be used tosearch for the shortest path between x and 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
• exclude_vertices – iterable container (default: None); iterable of vertices to exclude from thegraph while calculating the shortest path from x to y
• exclude_edges – iterable container (default: None); iterable of edges to exclude from the graphwhile calculating the shortest path from x to y
• include_vertices – iterable container (default: None); iterable of vertices to consider in the graphwhile calculating the shortest path from x to y
• weight_function – function (default: None); a function that inputs an edge (u, v, l) andoutputs its weight. If None, we use the edge label l as a weight, if l is not None, else 1 as a weight.
3.2. Fast compiled graphs1403

Graph Theory, Release 10.4

• distance_flag – boolean (default: False); when set to True, the shortest path distance from x
to y is returned instead of the path.
• reduced_weight – dictionary (default: None); a dictionary that takes as input an edge (u, v)
and outputs its reduced weight.
OUTPUT:• A list of vertices in the shortest path from x to y or distance from x to y is returned depending upon thevalue of parameter distance_flag
EXAMPLES:
sage: G = Graph([(1, 2, 20), (2, 3, 10), (3, 4, 30), (1, 5, 20), (5, 6, 10),␣
˓→(6, 4, 50), (4, 7, 5)])sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2])[1, 2, 3, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2], exclude_vertices=[2], exclude_edges=[(3, 4)])
[1, 5, 6, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2], exclude_vertices=[2, 7])[1, 5, 6, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2],exclude_edges=[(5, 6)])[1, 2, 3, 4]
sage: G._backend.bidirectional_dijkstra_special(1, 4, weight_function=lambda␣
˓→e:e[2],include_vertices=[1, 5, 6, 4])[1, 5, 6, 4]>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2), Integer(20)), (Integer(2), Integer(3),˓→ Integer(10)), (Integer(3), Integer(4), Integer(30)), (Integer(1),␣
˓→Integer(5), Integer(20)), (Integer(5), Integer(6), Integer(10)),␣
˓→(Integer(6), Integer(4), Integer(50)), (Integer(4), Integer(7),␣
˓→Integer(5))])>>> G._backend.bidirectional_dijkstra_special(Integer(1), Integer(4), weight_
˓→function=lambda e:e[Integer(2)])[1, 2, 3, 4]>>> G._backend.bidirectional_dijkstra_special(Integer(1), Integer(4), weight_
˓→function=lambda e:e[Integer(2)], exclude_vertices=[Integer(2)], exclude_
˓→edges=[(Integer(3), Integer(4))])[1, 5, 6, 4]>>> G._backend.bidirectional_dijkstra_special(Integer(1), Integer(4), weight_
˓→function=lambda e:e[Integer(2)], exclude_vertices=[Integer(2), Integer(7)])[1, 5, 6, 4]>>> G._backend.bidirectional_dijkstra_special(Integer(1), Integer(4), weight_
˓→function=lambda e:e[Integer(2)],exclude_edges=[(Integer(5), Integer(6))])[1, 2, 3, 4]>>> G._backend.bidirectional_dijkstra_special(Integer(1), Integer(4), weight_
˓→function=lambda e:e[Integer(2)],include_vertices=[Integer(1), Integer(5),␣
˓→Integer(6), Integer(4)])[1, 5, 6, 4]

breadth_first_search(v, reverse=False, ignore_direction=False, report_distance=False, edges=False)
Return a breadth-first search from vertex v.
INPUT:

1404

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• 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.
• report_distance – boolean (default: False); if True, reports pairs (vertex, distance)
where distance is the distance from the start nodes. If False only the vertices are reported.
• edges – boolean (default: False); whether to return the edges of the BFS tree in the order of visit or
the vertices (default). Edges are directed in root to leaf orientation of the tree.
Note that parameters edges and report_distance cannot be True simultaneously.
ALGORITHM:
Below is a general template for breadth-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 queue of nodes to visit
2. 𝐷 ← [∞, ∞, . . . , ∞] # 𝑛 copies of ∞3. 𝐷[𝑠] ← 0
4. 𝑇 ← [ ]5. while length(𝑄) > 0 do
1. 𝑣 ← dequeue(𝑄)
2. for each 𝑤 ∈ adj(𝑣) do # for digraphs, use out-neighbor set oadj(𝑣)1. if 𝐷[𝑤] = ∞ then
1. 𝐷[𝑤] ← 𝐷[𝑣] + 1
2. enqueue(𝑄, 𝑤)
3. 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())
sage: list(G.breadth_first_search(0))[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]

3.2. Fast compiled graphs

1405

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph(graphs.PetersenGraph())>>> list(G.breadth_first_search(Integer(0)))[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]

Visiting European countries using breadth-first search:sage: G = graphs.EuropeMap(continental=True)
sage: list(G.breadth_first_search("Portugal"))[ Portugal , Spain , ..., Greece ]>>> from sage.all import *>>> G = graphs.EuropeMap(continental=True)>>> list(G.breadth_first_search("Portugal"))[ Portugal , Spain , ..., Greece ]c_graph()Return the ._cg and ._cg_rev attributes
Note: The ._cg_rev attribute has been removed and hence None is returned.
EXAMPLES:
sage: cg,cg_rev = graphs.PetersenGraph()._backend.c_graph()
sage: cg
<sage.graphs.base.sparse_graph.SparseGraph object at ...>>>> from sage.all import *>>> cg,cg_rev = graphs.PetersenGraph()._backend.c_graph()>>> cg<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 degreeof 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>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraphBackend>>> B = SparseGraphBackend(Integer(7))(continues on next page)

1406

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> B.degree(Integer(3), False)0

del_edge(u, v, l, directed)
Delete edge (u, v, l).
INPUT:• u, v – the vertices of the edge
• l – the edge label• directed – if False, also delete (v, u, l)Note: The input l is ignored if the backend does not support labels.
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: list(D.iterator_edges(range(9), True))[(0, 1, None),(2, 3, None),(4, 5, None),(5, 6, None)]sage: D.del_edge(0,1,None,True)
sage: list(D.iterator_out_edges(range(9), True))[(1, 0, None),(2, 3, None),(3, 2, None),(4, 5, None),(5, 4, None),(5, 6, None),(6, 5, None)]>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0),Integer(1)), (Integer(2),Integer(3)),␣
˓→(Integer(4),Integer(5)), (Integer(5),Integer(6))], False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, None),(2, 3, None),(4, 5, None),(5, 6, None)]>>> D.del_edge(Integer(0),Integer(1),None,True)>>> list(D.iterator_out_edges(range(Integer(9)), True))[(1, 0, None),(2, 3, None),(3, 2, None),(4, 5, None),(5, 4, None),(5, 6, None),(6, 5, None)]sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)sage: D.add_edges([(0, 1), (2, 3), (4, 5), (5, 6)], False)(continues on next page)3.2. Fast compiled graphs

1407

Graph Theory, Release 10.4

(continued from previous page)

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)]>>> from sage.all import *>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))], False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, None),(2, 3, None),(4, 5, None),(5, 6, None)]>>> D.del_edge(Integer(0), Integer(1), None, True)>>> list(D.iterator_out_edges(range(Integer(9)), True))[(1, 0, None),(2, 3, None),(3, 2, None),(4, 5, None),(5, 4, None),(5, 6, None),(6, 5, None)]del_edges(edges, directed)
Delete edges from a list.
INPUT:• edges – the edges to be added; can either be of the form (u,v) or (u,v,l)• directed – if False, remove``(v,u)`` as well as (u,v)
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: D.del_edges([(0,1), (2,3), (4,5), (5,6)], False)
sage: list(D.iterator_edges(range(9), True))[]>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0),Integer(1)), (Integer(2),Integer(3)),␣
˓→(Integer(4),Integer(5)), (Integer(5),Integer(6))], False)>>> D.del_edges([(Integer(0),Integer(1)), (Integer(2),Integer(3)),␣
˓→(Integer(4),Integer(5)), (Integer(5),Integer(6))], False)(continues on next page)

1408

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> list(D.iterator_edges(range(Integer(9)), True))[]del_vertex(v)Delete a vertex in self, failing silently if the vertex is not in the graph.
INPUT:• v – vertex to be deleted
See also:• 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>>> from sage.all import *>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.del_vertex(Integer(0))>>> D.has_vertex(Integer(0))
False
sage: S = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: S.del_vertex(0)sage: S.has_vertex(0)False>>> from sage.all import *>>> S = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> S.del_vertex(Integer(0))>>> S.has_vertex(Integer(0))
False

del_vertices(vertices)
Delete vertices from an iterable container.
INPUT:• vertices – iterator of vertex labels
OUTPUT:• Same as for del_vertex().
See also:• del_vertex() – delete a vertex of this graph
EXAMPLES:

3.2. Fast compiled graphs1409

Graph Theory, Release 10.4

sage: import sage.graphs.base.dense_graphsage: 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>>> from sage.all import *>>> import sage.graphs.base.dense_graph>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.del_vertices([Integer(7), Integer(8)])>>> D.has_vertex(Integer(7))
False>>> D.has_vertex(Integer(6))
Truesage: 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>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.del_vertices([Integer(1), Integer(2), Integer(3)])>>> D.has_vertex(Integer(1))
False>>> D.has_vertex(Integer(0))
Truedepth_first_search(v, reverse=False, ignore_direction=False)
Return 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. 𝐷[𝑠] ← 01410

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

4. 𝑇 ← [ ]5. while length(𝑆) > 0 do
1. 𝑣 ← pop(𝑆)
2. for each 𝑤 ∈ adj(𝑣) do # for digraphs, use out-neighbor set oadj(𝑣)1. if 𝐷[𝑤] = ∞ then
1. 𝐷[𝑤] ← 𝐷[𝑣] + 1
2. push(𝑆, 𝑤)
3. 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())
sage: list(G.depth_first_search(0))[0, 5, 8, 6, 9, 7, 2, 3, 4, 1]>>> from sage.all import *>>> G = Graph(graphs.PetersenGraph())>>> list(G.depth_first_search(Integer(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"]})sage: list(G.depth_first_search("Stuttgart"))[ Stuttgart , Nurnberg , ...]>>> from sage.all import *>>> 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"],(continues on next page)3.2. Fast compiled graphs1411

Graph Theory, Release 10.4

(continued from previous page)... "Nurnberg": ["Wurzburg","Stuttgart","Munchen"],... "Stuttgart": ["Nurnberg"], "Erfurt": ["Wurzburg"]})>>> list(G.depth_first_search("Stuttgart"))[ Stuttgart , Nurnberg , ...]

has_vertex(v)Check whether v is a vertex of self.
INPUT:• v – any object
OUTPUT:• True if v is a vertex of this graph; False otherwise
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
sage: B = SparseGraphBackend(7)sage: B.has_vertex(6)Truesage: B.has_vertex(7)False>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraphBackend>>> B = SparseGraphBackend(Integer(7))>>> B.has_vertex(Integer(6))
True>>> B.has_vertex(Integer(7))
False

in_degree(v)Return 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>>> from sage.all import *>>> D = DiGraph( { Integer(0): [Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1): [Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3):␣
˓→[Integer(4)], Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]␣
˓→} )>>> D.out_degree(Integer(1))
2is_connected()
Check whether the graph is connected.
EXAMPLES:
1412

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

Petersen’s graph is connected:
sage: DiGraph(graphs.PetersenGraph()).is_connected()True>>> from sage.all import *>>> DiGraph(graphs.PetersenGraph()).is_connected()
True

While the disjoint union of two of them is not:sage: DiGraph(2*graphs.PetersenGraph()).is_connected()
False>>> from sage.all import *>>> DiGraph(Integer(2)*graphs.PetersenGraph()).is_connected()False

A graph with non-integer vertex labels:
sage: Graph(graphs.CubeGraph(3)).is_connected()True>>> from sage.all import *>>> Graph(graphs.CubeGraph(Integer(3))).is_connected()
True

is_directed_acyclic(certificate=False)
Check whether the graph is both directed and acyclic (possibly with a certificate)
INPUT:• certificate – boolean (default: False); whether to return a certificate
OUTPUT:
When certificate=False, returns a boolean value. When certificate=True :• If the graph is acyclic, returns a pair (True, ordering) where ordering is a list of the vertices
such that u appears before v in ordering if u, v is an edge.
• Else, returns a pair (False, cycle) where cycle is a list of vertices representing a circuit in thegraph.
ALGORITHM:
We pick a vertex at random, think hard and find out that if we are to remove the vertex from the graph we must
remove all of its out-neighbors in the first place. So we put all of its out-neighbours in a stack, and repeat thesame 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 stackonce : if for some reason the previous algorithm leads us to do it twice, it means we have found a circuit.
We keep track of the vertices whose out-neighborhood has been added to the stack once with a variable named
tried.
There is no reason why the graph should be empty at the end of this procedure, so we run it again on theremaining 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.

3.2. Fast compiled graphs1413

Graph Theory, Release 10.4

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()#␣˓→needs sage.plot
sage: D.is_directed_acyclic()True>>> from sage.all import *>>> D = DiGraph({ Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(4):[Integer(2),Integer(5)], Integer(1):[Integer(8)],␣
˓→Integer(2):[Integer(7)], Integer(3):[Integer(7)], Integer(5):[Integer(6),˓→Integer(7)], Integer(7):[Integer(8)], Integer(6):[Integer(9)],␣
˓→Integer(8):[Integer(10)], Integer(9):[Integer(10)] })>>> D.plot(layout= circular ).show()#␣˓→needs sage.plot>>> 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>>> from sage.all import *>>> D.add_edge(Integer(9),Integer(7))>>> 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])>>> from sage.all import *>>> 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>>> from sage.all import *>>> D.add_edge(Integer(7),Integer(4))>>> D.is_directed_acyclic()
False

Indeed, it creates a circuit 7, 4, 5:
sage: D.is_directed_acyclic(certificate = True)(False, [7, 4, 5])1414

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> 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(sort=True) ])....: return h...
sage: all( random_acyclic(100, .2).is_directed_acyclic()# long time....:
for i in range(50))
True>>> from sage.all import *>>> 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(sort=True)␣
˓→])... return h...
>>> all( random_acyclic(Integer(100), RealNumber( .2 )).is_directed_acyclic()␣
˓→# long time...
for i in range(Integer(50)))
True

is_strongly_connected()
Check whether the graph is strongly connected.
EXAMPLES:
The circuit on 3 vertices is obviously strongly connected:
sage: g = DiGraph({0: [1], 1: [2], 2: [0]})sage: g.is_strongly_connected()True>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(0)]})>>> g.is_strongly_connected()
True

But a transitive triangle is not:sage: g = DiGraph({0: [1,2], 1: [2]})sage: g.is_strongly_connected()
False>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1),Integer(2)], Integer(1):␣
˓→[Integer(2)]})(continues on next page)3.2. Fast compiled graphs1415

Graph Theory, Release 10.4

(continued from previous page)>>> g.is_strongly_connected()False

is_subgraph(other, vertices, ignore_labels=False)
Return whether the subgraph of self induced by vertices is a subgraph of other.
If vertices are the vertices of self, return whether self is a subgraph of other.
INPUT:• other – a subclass of CGraphBackend• vertices – a iterable over the vertex labels• ignore_labels – boolean (default: False); whether to ignore the labels
EXAMPLES:
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(4, directed=True)
sage: H = sage.graphs.base.dense_graph.DenseGraphBackend(4, directed=True)
sage: G.add_edges([[0,1],[0,2],[0,3],[1,2]], True)
sage: H.add_edges([[0,1],[0,2],[0,3]], True)
sage: G.is_subgraph(H, range(4))
False
sage: H.is_subgraph(G, range(4))
True
sage: G.is_subgraph(H, [0,1,3])
True>>> from sage.all import *>>> G = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(4),␣
˓→directed=True)>>> H = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(4),␣
˓→directed=True)>>> G.add_edges([[Integer(0),Integer(1)],[Integer(0),Integer(2)],[Integer(0),˓→Integer(3)],[Integer(1),Integer(2)]], True)>>> H.add_edges([[Integer(0),Integer(1)],[Integer(0),Integer(2)],[Integer(0),˓→Integer(3)]], True)>>> G.is_subgraph(H, range(Integer(4)))
False>>> H.is_subgraph(G, range(Integer(4)))
True>>> G.is_subgraph(H, [Integer(0),Integer(1),Integer(3)])
True

Ignore the labels or not:sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(3, directed=True)
sage: G.multiple_edges(True)
sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(3, directed=True)
sage: H.multiple_edges(True)
sage: G.add_edges([[0,1, a ], [0,1, b ], [0,2, c ], [0,2, d ], [0,2, e ]],␣˓→True)sage: H.add_edges([[0,1, a ], [0,1, foo ], [0,2, c ], [0,2, d ], [0,2, e ],␣
˓→[0,2, e ]], True)
sage: G.is_subgraph(H, range(3))
False(continues on next page)1416

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

sage: G.is_subgraph(H, range(3), ignore_labels=True)
True>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(3),␣
˓→directed=True)>>> G.multiple_edges(True)>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(3),␣
˓→directed=True)>>> H.multiple_edges(True)>>> G.add_edges([[Integer(0),Integer(1), a ], [Integer(0),Integer(1), b ],␣˓→[Integer(0),Integer(2), c ], [Integer(0),Integer(2), d ], [Integer(0),˓→Integer(2), e ]], True)>>> H.add_edges([[Integer(0),Integer(1), a ], [Integer(0),Integer(1), foo ],␣˓→[Integer(0),Integer(2), c ], [Integer(0),Integer(2), d ], [Integer(0),˓→Integer(2), e ], [Integer(0),Integer(2), e ]], True)>>> G.is_subgraph(H, range(Integer(3)))
False>>> G.is_subgraph(H, range(Integer(3)), ignore_labels=True)
True

Multiplicities of edges are considered:
sage: G.is_subgraph(H, [0,2])
True
sage: H.is_subgraph(G, [0,2])
False>>> from sage.all import *>>> G.is_subgraph(H, [Integer(0),Integer(2)])
True>>> H.is_subgraph(G, [Integer(0),Integer(2)])
False

iterator_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices.
Edges are assumed to be undirected.
Warning: This will try to sort the two ends of every edge.
INPUT:• vertices – a list of vertex labels• labels – boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: G.add_edge(1,2,3,False)
sage: list(G.iterator_edges(range(9), False))[(1, 2)]sage: list(G.iterator_edges(range(9), True))[(1, 2, 3)]

3.2. Fast compiled graphs1417

Graph Theory, Release 10.4>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> G.add_edge(Integer(1),Integer(2),Integer(3),False)>>> list(G.iterator_edges(range(Integer(9)), False))[(1, 2)]>>> list(G.iterator_edges(range(Integer(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)]>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> G.add_edge(Integer(1),Integer(2),Integer(3),True)>>> list(G.iterator_in_edges([Integer(1)], False))[]>>> list(G.iterator_in_edges([Integer(2)], False))[(1, 2)]>>> list(G.iterator_in_edges([Integer(2)], True))[(1, 2, 3)]

iterator_in_nbrs(v)Iterate over the incoming neighbors of v.
INPUT:• v – a vertex of this graph
OUTPUT:• An iterator over the in-neighbors of the vertex v
See also:• 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())
sage: list(P._backend.iterator_in_nbrs(0))[1, 4, 5]1418

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> P = DiGraph(graphs.PetersenGraph().to_directed())>>> list(P._backend.iterator_in_nbrs(Integer(0)))[1, 4, 5]

iterator_nbrs(v)Iterate over the neighbors of v.
INPUT:• v – a vertex of this graph
OUTPUT:• An iterator over the neighbors the vertex v
See also:• 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())
sage: list(P._backend.iterator_nbrs(0))[1, 4, 5]
sage: Q = DiGraph(P)sage: list(Q._backend.iterator_nbrs(0))[1, 4, 5]>>> from sage.all import *>>> P = Graph(graphs.PetersenGraph())>>> list(P._backend.iterator_nbrs(Integer(0)))[1, 4, 5]>>> Q = DiGraph(P)>>> list(Q._backend.iterator_nbrs(Integer(0)))[1, 4, 5]

iterator_out_edges(vertices, labels)
Iterate over the outbound edges incident to a sequence of vertices.
INPUT:• vertices – a list of vertex labels• labels – boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: G.add_edge(1,2,3,True)
sage: list(G.iterator_out_edges([2], False))[]
sage: list(G.iterator_out_edges([1], False))[(1, 2)]sage: list(G.iterator_out_edges([1], True))[(1, 2, 3)]

3.2. Fast compiled graphs1419

Graph Theory, Release 10.4>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> G.add_edge(Integer(1),Integer(2),Integer(3),True)>>> list(G.iterator_out_edges([Integer(2)], False))[]>>> list(G.iterator_out_edges([Integer(1)], False))[(1, 2)]>>> list(G.iterator_out_edges([Integer(1)], True))[(1, 2, 3)]

iterator_out_nbrs(v)Iterate over the outgoing neighbors of v.
INPUT:• v – a vertex of this graph
OUTPUT:• An iterator over the out-neighbors of the vertex v
See also:• 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())
sage: list(P._backend.iterator_out_nbrs(0))[1, 4, 5]>>> from sage.all import *>>> P = DiGraph(graphs.PetersenGraph().to_directed())>>> list(P._backend.iterator_out_nbrs(Integer(0)))[1, 4, 5]

iterator_unsorted_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices.
Edges are assumed to be undirected.
This does not sort the ends of each edge.
INPUT:• vertices – a list of vertex labels• labels – boolean, whether to return labels as well
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: G.add_edge(1,2,3,False)
sage: list(G.iterator_unsorted_edges(range(9), False))[(2, 1)]
sage: list(G.iterator_unsorted_edges(range(9), True))[(2, 1, 3)]1420

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> G.add_edge(Integer(1),Integer(2),Integer(3),False)>>> list(G.iterator_unsorted_edges(range(Integer(9)), False))[(2, 1)]>>> list(G.iterator_unsorted_edges(range(Integer(9)), True))[(2, 1, 3)]

iterator_verts(verts=None)
Iterate over the vertices of self intersected with verts.
INPUT:• verts – an iterable container of objects (default: None)OUTPUT:• If verts=None, return an iterator over all vertices of this graph• If verts is a single vertex of the graph, treat it as the container [verts]• If verts is a iterable container of vertices, find the intersection of verts with the vertex set of thisgraph 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())
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]>>> from sage.all import *>>> P = Graph(graphs.PetersenGraph())>>> list(P._backend.iterator_verts(P))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> list(P._backend.iterator_verts())[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> list(P._backend.iterator_verts([Integer(1), Integer(2), Integer(3)]))[1, 2, 3]>>> list(P._backend.iterator_verts([Integer(1), Integer(2), Integer(10)]))[1, 2]

loops(new=None)
Check whether loops are allowed in this graph.
INPUT:• new – boolean (default: None); to set or None to get
OUTPUT:3.2. Fast compiled graphs1421

Graph Theory, Release 10.4

• If new=None, return True if this graph allows self-loops or False if self-loops are not allowed• If new is a boolean, set the self-loop permission of this graph according to the boolean value of new
EXAMPLES:
sage: G = Graph()
sage: G._backend.loops()
False
sage: G._backend.loops(True)
sage: G._backend.loops()
True>>> from sage.all import *>>> G = Graph()>>> G._backend.loops()
False>>> G._backend.loops(True)>>> G._backend.loops()
True

num_edges(directed)
Return the number of edges in self.
INPUT:• directed – boolean; whether to count (u, v) and (v, u) as one or two edges
OUTPUT:• If directed=True, counts the number of directed edges in this graph. Otherwise, return the size of
this graph.
See also:• num_verts() – return the order of this graph.
EXAMPLES:
sage: G = Graph(graphs.PetersenGraph())
sage: G._backend.num_edges(False)15>>> from sage.all import *>>> G = Graph(graphs.PetersenGraph())>>> G._backend.num_edges(False)15

num_verts()
Return the number of vertices in self.
OUTPUT:• The order of this graph.
See also:• num_edges() – return the number of (directed) edges in this graph.
EXAMPLES:
1422

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

sage: G = Graph(graphs.PetersenGraph())
sage: G._backend.num_verts()
10>>> from sage.all import *>>> G = Graph(graphs.PetersenGraph())>>> G._backend.num_verts()
10

out_degree(v)Return the out-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>>> from sage.all import *>>> D = DiGraph( { Integer(0): [Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1): [Integer(0),Integer(2)], Integer(2): [Integer(3)], Integer(3):␣
˓→[Integer(4)], Integer(4): [Integer(0),Integer(5)], Integer(5): [Integer(1)]␣
˓→} )>>> D.out_degree(Integer(1))
2relabel(perm, directed)
Relabel the graph according to perm.
INPUT:• perm – anything which represents a permutation as v --> perm[v], for example a dict or a list
• directed – ignored (this is here for compatibility with other backends)
EXAMPLES:
sage: G = Graph(graphs.PetersenGraph())
sage: G._backend.relabel(range(9,-1,-1), False)
sage: G.edges(sort=True)[(0, 2, None),(0, 3, None),(0, 5, None),(1, 3, None),(1, 4, None),(1, 6, None),(2, 4, None),(2, 7, None),(3, 8, None),(4, 9, None),(5, 6, None),(5, 9, None),(6, 7, None),(continues on next page)3.2. Fast compiled graphs1423

Graph Theory, Release 10.4

(continued from previous page)(7, 8, None),(8, 9, None)]>>> from sage.all import *>>> G = Graph(graphs.PetersenGraph())>>> G._backend.relabel(range(Integer(9),-Integer(1),-Integer(1)), False)>>> G.edges(sort=True)[(0, 2, None),(0, 3, None),(0, 5, None),(1, 3, None),(1, 4, None),(1, 6, None),(2, 4, None),(2, 7, None),(3, 8, None),(4, 9, None),(5, 6, None),(5, 9, None),(6, 7, None),(7, 8, None),(8, 9, None)]shortest_path(x, y, distance_flag=False)
Return the shortest path or distance from x to y.
INPUT:• x – the starting vertex in the shortest path from x to y
• y – the end vertex in the shortest path from x to y
• distance_flag – boolean (default: False); when set to True, the shortest path distance from x
to y is returned instead of the path
OUTPUT:• A list of vertices in the shortest path from x to y or distance from x to y is returned depending upon thevalue of parameter distance_flag
EXAMPLES:
sage: G = Graph(graphs.PetersenGraph())
sage: G.shortest_path(0, 1)[0, 1]
sage: G.shortest_path_length(0, 1)
1>>> from sage.all import *>>> G = Graph(graphs.PetersenGraph())>>> G.shortest_path(Integer(0), Integer(1))[0, 1]>>> G.shortest_path_length(Integer(0), Integer(1))
1shortest_path_all_vertices(v, cutoff=None, distance_flag=False)
Return for each reachable vertex u a shortest v-u path or distance from v to u.
INPUT:
1424

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• v – a starting vertex in the shortest path
• cutoff – integer (default: None); maximal distance of returned paths (longer paths will not be returned), ignored when set to None
• distance_flag – boolean (default: False); when set to True, each vertex u connected to v ismapped 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((not paths[v] or len(paths[v])-1 == g.distance(0,v)) for v in g)True
sage: g._backend.shortest_path_all_vertices(0, distance_flag=True){0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> paths = g._backend.shortest_path_all_vertices(Integer(0))>>> all((not paths[v] or len(paths[v])-Integer(1) == g.distance(Integer(0),˓→v)) for v in g)
True>>> g._backend.shortest_path_all_vertices(Integer(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>>> from sage.all import *>>> g = Integer(2) * graphs.RandomGNP(Integer(20), RealNumber( .3 ))>>> paths = g._backend.shortest_path_all_vertices(Integer(0))>>> all((v not in paths and g.distance(Integer(0), v) == +Infinity) or␣
˓→len(paths[v]) - Integer(1) == g.distance(Integer(0), v) for v in g)True

shortest_path_special(x, y, exclude_vertices=None, exclude_edges=None, distance_flag=False)
Return the shortest path or distance from x to y.
This method is an extension of shortest_path() method enabling to exclude vertices and/or edges fromthe search for the shortest path between x and y.
3.2. Fast compiled graphs

1425

Graph Theory, Release 10.4

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
• exclude_vertices – iterable container (default: None); iterable of vertices to exclude from thegraph while calculating the shortest path from x to y
• exclude_edges – iterable container (default: None); iterable of edges to exclude from the graphwhile calculating 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 thevalue of parameter distance_flag
EXAMPLES:
sage: G = Graph([(1, 2), (2, 3), (3, 4), (1, 5), (5, 6), (6, 7), (7, 4)])sage: G._backend.shortest_path_special(1, 4)[1, 2, 3, 4]
sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[5,7])[1, 2, 3, 4]
sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[2, 3])[1, 5, 6, 7, 4]
sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[2], exclude_
˓→edges=[(5, 6)])[]sage: G._backend.shortest_path_special(1, 4, exclude_vertices=[2], exclude_
˓→edges=[(2, 3)])
[1, 5, 6, 7, 4]>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2)), (Integer(2), Integer(3)),␣
˓→(Integer(3), Integer(4)), (Integer(1), Integer(5)), (Integer(5),␣
˓→Integer(6)), (Integer(6), Integer(7)), (Integer(7), Integer(4))])>>> G._backend.shortest_path_special(Integer(1), Integer(4))[1, 2, 3, 4]>>> G._backend.shortest_path_special(Integer(1), Integer(4), exclude_
˓→vertices=[Integer(5),Integer(7)])[1, 2, 3, 4]>>> G._backend.shortest_path_special(Integer(1), Integer(4), exclude_
˓→vertices=[Integer(2), Integer(3)])[1, 5, 6, 7, 4]>>> G._backend.shortest_path_special(Integer(1), Integer(4), exclude_
˓→vertices=[Integer(2)], exclude_edges=[(Integer(5), Integer(6))])[]>>> G._backend.shortest_path_special(Integer(1), Integer(4), exclude_
˓→vertices=[Integer(2)], exclude_edges=[(Integer(2), Integer(3))])[1, 5, 6, 7, 4]strongly_connected_component_containing_vertex(v)Return the strongly connected component containing the given vertex.
INPUT:• v – a vertex

1426

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> g = DiGraph(graphs.PetersenGraph())>>> g.strongly_connected_component_containing_vertex(Integer(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
>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(3))>>> all([v] == g.strongly_connected_component_containing_vertex(v) for v in g)
True

subgraph_given_vertices(other, vertices)
Initialize other to be the subgraph of self with given vertices.
INPUT:• other – a (mutable) subclass of CGraphBackend• vertices – a list of vertex labels
EXAMPLES:
Make a dense copy:
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9, directed=True)
sage: G.loops(True)
sage: G.add_edges([[0,1], [1,2], [2,3], [3,4], [4,5], [5,6], [7,8], [3,3]],␣
˓→True)sage: H = sage.graphs.base.dense_graph.DenseGraphBackend(0, directed=True)
sage: H.loops(True)
sage: G.subgraph_given_vertices(H, range(9))
sage: list(H.iterator_out_edges(list(range(9)), False)) == list(G.iterator_
˓→out_edges(list(range(9)), False))
True>>> from sage.all import *>>> G = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9),␣
˓→directed=True)>>> G.loops(True)>>> G.add_edges([[Integer(0),Integer(1)], [Integer(1),Integer(2)],␣
˓→[Integer(2),Integer(3)], [Integer(3),Integer(4)], [Integer(4),Integer(5)],␣
˓→[Integer(5),Integer(6)], [Integer(7),Integer(8)], [Integer(3),Integer(3)]],␣
˓→True)>>> H = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(0),␣
˓→directed=True)(continues on next page)3.2. Fast compiled graphs

1427

Graph Theory, Release 10.4

(continued from previous page)>>> H.loops(True)>>> G.subgraph_given_vertices(H, range(Integer(9)))>>> list(H.iterator_out_edges(list(range(Integer(9))), False)) == list(G.
˓→iterator_out_edges(list(range(Integer(9))), False))
True

Make a sparse copy:
sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(0, directed=True)
sage: H.loops(True)
sage: G.subgraph_given_vertices(H, range(9))
sage: sorted(list(H.iterator_out_edges(list(range(9)), False))) ==␣
˓→sorted(list(G.iterator_out_edges(list(range(9)), False)))True>>> from sage.all import *>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0),␣
˓→directed=True)>>> H.loops(True)>>> G.subgraph_given_vertices(H, range(Integer(9)))>>> sorted(list(H.iterator_out_edges(list(range(Integer(9))), False))) ==␣
˓→sorted(list(G.iterator_out_edges(list(range(Integer(9))), False)))
True

Initialize a proper subgraph:
sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(0, directed=True)
sage: H.loops(True)
sage: G.subgraph_given_vertices(H, [2,3,4,5])
sage: list(H.iterator_out_edges(list(range(9)), False))[(2, 3), (3, 3), (3, 4), (4, 5)]>>> from sage.all import *>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0),␣
˓→directed=True)>>> H.loops(True)>>> G.subgraph_given_vertices(H, [Integer(2),Integer(3),Integer(4),˓→Integer(5)])>>> list(H.iterator_out_edges(list(range(Integer(9))), False))[(2, 3), (3, 3), (3, 4), (4, 5)]Loops are removed, if the other graph does not allow loops:
sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(0, directed=True)
sage: H.loops(False)
sage: G.subgraph_given_vertices(H, [2,3,4,5])
sage: list(H.iterator_out_edges(list(range(9)), False))[(2, 3), (3, 4), (4, 5)]>>> from sage.all import *>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0),␣
˓→directed=True)>>> H.loops(False)>>> G.subgraph_given_vertices(H, [Integer(2),Integer(3),Integer(4),˓→Integer(5)])(continues on next page)

1428

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> list(H.iterator_out_edges(list(range(Integer(9))), False))[(2, 3), (3, 4), (4, 5)]Multiple edges and labels are copied:sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(4, directed=False)
sage: G.multiple_edges(True)
sage: G.add_edges([[0,1, a ], [1,2, b ], [2,3, c ], [0,1, d ]], False)
sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(0, directed=False)
sage: H.multiple_edges(True)
sage: G.subgraph_given_vertices(H, [0,1,2])
sage: list(H.iterator_edges(list(range(4)), True))[(0, 1, a ), (0, 1, d ), (1, 2, b )]>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(4),␣
˓→directed=False)>>> G.multiple_edges(True)>>> G.add_edges([[Integer(0),Integer(1), a ], [Integer(1),Integer(2), b ],␣˓→[Integer(2),Integer(3), c ], [Integer(0),Integer(1), d ]], False)>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0),␣
˓→directed=False)>>> H.multiple_edges(True)>>> G.subgraph_given_vertices(H, [Integer(0),Integer(1),Integer(2)])>>> list(H.iterator_edges(list(range(Integer(4))), True))[(0, 1, a ), (0, 1, d ), (1, 2, b )]Multiple edges are removed, if the other graph does not allow them:sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(0, directed=False)
sage: H.multiple_edges(False)
sage: G.subgraph_given_vertices(H, [0,1,2])
sage: list(H.iterator_edges(list(range(4)), True))[(0, 1, d ), (1, 2, b )]>>> from sage.all import *>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0),␣
˓→directed=False)>>> H.multiple_edges(False)>>> G.subgraph_given_vertices(H, [Integer(0),Integer(1),Integer(2)])>>> list(H.iterator_edges(list(range(Integer(4))), True))[(0, 1, d ), (1, 2, b )]Labels are removed, if the other graph does not allow them:sage: H = sage.graphs.base.dense_graph.DenseGraphBackend(0, directed=False)
sage: G.subgraph_given_vertices(H, [0,1,2])
sage: list(H.iterator_edges(list(range(4)), True))[(0, 1, None), (1, 2, None)]>>> from sage.all import *>>> H = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(0),␣
˓→directed=False)>>> G.subgraph_given_vertices(H, [Integer(0),Integer(1),Integer(2)])>>> list(H.iterator_edges(list(range(Integer(4))), True))[(0, 1, None), (1, 2, None)]

3.2. Fast compiled graphs1429

Graph Theory, Release 10.4

A directed subgraph of an undirected graph is taken by initializing with edges in both directions:sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(4, directed=True)
sage: G.loops(True)
sage: G.multiple_edges(True)
sage: G.add_edges([[0,1, a ], [1,2, b ], [2,3, c ], [0,1, d ], [2,2, e ]],␣˓→False)sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(0, directed=True)
sage: H.multiple_edges(True)
sage: H.loops(True)
sage: G.subgraph_given_vertices(H, [0,1,2])
sage: list(H.iterator_out_edges(list(range(4)), True))[(0, 1, a ),(0, 1, d ),(1, 0, a ),(1, 0, d ),(1, 2, b ),(2, 1, b ),(2, 2, e )]>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(4),␣
˓→directed=True)>>> G.loops(True)>>> G.multiple_edges(True)>>> G.add_edges([[Integer(0),Integer(1), a ], [Integer(1),Integer(2), b ],␣˓→[Integer(2),Integer(3), c ], [Integer(0),Integer(1), d ], [Integer(2),˓→Integer(2), e ]], False)>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0),␣
˓→directed=True)>>> H.multiple_edges(True)>>> H.loops(True)>>> G.subgraph_given_vertices(H, [Integer(0),Integer(1),Integer(2)])>>> list(H.iterator_out_edges(list(range(Integer(4))), True))[(0, 1, a ),(0, 1, d ),(1, 0, a ),(1, 0, d ),(1, 2, b ),(2, 1, b ),(2, 2, e )]An undirected subgraph of a directeed graph is not defined:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(4, directed=True)
sage: G.add_edges([[0,1, a ], [1,2, b ], [2,3, c ]], False)
sage: H = sage.graphs.base.sparse_graph.SparseGraphBackend(0, directed=False)
sage: G.subgraph_given_vertices(H, [0,1,2])
Traceback (most recent call last):...
ValueError: cannot obtain an undirected subgraph of a directed graph>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(4),␣
˓→directed=True)>>> G.add_edges([[Integer(0),Integer(1), a ], [Integer(1),Integer(2), b ],␣˓→[Integer(2),Integer(3), c ]], False)(continues on next page)1430

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> H = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(0),␣
˓→directed=False)>>> G.subgraph_given_vertices(H, [Integer(0),Integer(1),Integer(2)])
Traceback (most recent call last):...
ValueError: cannot obtain an undirected subgraph of a directed graphclass 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 inmemory 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 thelist. For breadth-first search (BFS), element removal follow a first-in first-out (FIFO) protocol, as signified
by the value direction=0. We use a queue to maintain the list of vertices to visit in this case. For
depth-first search (DFS), element removal follow a last-in first-out (LIFO) protocol, as signified by the value
direction=-1. In this case, we use a stack to maintain the list of vertices to visit.
• stack – a list of vertices to visit, used only when direction=-1• queue – a queue of vertices to visit, used only when direction=0• seen – a list of vertices that are already visited• test_out – boolean; whether we want to consider the out-neighbors of the graph to be traversed. For
undirected graphs, we consider both the in- and out-neighbors. However, for digraphs we only traverse along
out-neighbors.
• test_in – boolean; whether we want to consider the in-neighbors of the graph to be traversed. For 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]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> list(g.breadth_first_search(Integer(0)))[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]

3.3 Fast sparse graphs
For an overview of graph data structures in sage, see overview.

3.3. Fast sparse graphs

1431

Graph Theory, Release 10.4

3.3.1 Usage Introduction
sage: from sage.graphs.base.sparse_graph import SparseGraph>>> from sage.all import *>>> 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)>>> from sage.all import *>>> S = SparseGraph(nverts = Integer(10), expected_degree = Integer(3), extra_
˓→vertices = Integer(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)9sage: S.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> from sage.all import *>>> S.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> S.add_vertex(Integer(9))
9>>> 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)10sage: S.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]>>> from sage.all import *>>> S.add_vertex(Integer(10))
10>>> 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)(continues on next page)1432

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)[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>>> from sage.all import *>>> S.add_arc(Integer(0),Integer(1))>>> S.add_arc(Integer(1),Integer(2))>>> S.add_arc(Integer(1),Integer(0))>>> S.has_arc(Integer(7),Integer(3))
False>>> S.has_arc(Integer(0),Integer(1))
True>>> S.in_neighbors(Integer(1))[0]>>> S.out_neighbors(Integer(1))[0, 2]>>> S.del_all_arcs(Integer(0),Integer(1))>>> S.all_arcs(Integer(0),Integer(1))[]>>> S.all_arcs(Integer(1),Integer(2))[0]>>> S.del_vertex(Integer(7))>>> S.all_arcs(Integer(7),Integer(3))
Traceback (most recent call last):...
LookupError: vertex (7) is not a vertex of the graphSparse 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>>> from sage.all import *>>> S.add_arc_label(Integer(0),Integer(1),-Integer(1))
Traceback (most recent call last):...
ValueError: Label (-1) must be a nonnegative integer.
>>> S.add_arc(Integer(0),Integer(1))>>> S.arc_label(Integer(0),Integer(1))
03.3. Fast sparse graphs1433

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> S.add_arc_label(Integer(0),Integer(1),Integer(1))>>> S.arc_label(Integer(0),Integer(1))
1>>> S.all_arcs(Integer(0),Integer(1))[0, 1]

Zero specifies only that there is no labeled arc:sage: S.arc_label(1,2)
0>>> from sage.all import *>>> S.arc_label(Integer(1),Integer(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>>> from sage.all import *>>> S.all_arcs(Integer(1),Integer(2))[0]>>> S.add_arc(Integer(1),Integer(2))>>> S.arc_label(Integer(1),Integer(2))
0Instead, 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>>> from sage.all import *>>> T = SparseGraph(nverts = Integer(3), expected_degree = Integer(2))>>> T.add_arc(Integer(0),Integer(1))>>> T.add_arc(Integer(1),Integer(2))>>> T.add_arc(Integer(2),Integer(0))>>> T.has_arc(Integer(0),Integer(1))
True

1434

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

Sparse graphs are by their nature directed. As of this writing, you need to do operations in pairs to treat the undirectedcase (or use a backend or a Sage graph):
sage: T.has_arc(1,0)
False>>> from sage.all import *>>> T.has_arc(Integer(1),Integer(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]>>> from sage.all import *>>> for _ in range(Integer(10)): S.add_arc(Integer(5),Integer(4))>>> S.all_arcs(Integer(5),Integer(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 pureC.

3.3.2 Underlying Data Structure
The class SparseGraph contains the following variables which are inherited from CGraph (for explanation, refer tothe 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
cdef SparseGraphBTNode **vertices_rev
cdef bint _directed

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 fixedhash function which takes values in 0 <= hash < hash_length. Each address may represent different arcs, say(u, v1) and (u, v2) where hash(v1) == hash(v2). Thus, a binary tree structure is used at this step to speed
access to individual arcs, whose nodes (each of which represents a pair (u,v)) are instances of the following type:cdef struct SparseGraphBTNode:int vertex
int number
SparseGraphLLNode *labels
SparseGraphBTNode *left
SparseGraphBTNode *right3.3. Fast sparse graphs

1435

Graph Theory, Release 10.4

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 withmany 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_deactual degree
gree given, because this is the size of each hash table. Indeed, the expected size of the binary trees 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 theseuses.
class sage.graphs.base.sparse_graph.SparseGraph
Bases: CGraph
Compiled sparse graphs.
sage: from sage.graphs.base.sparse_graph import SparseGraph>>> from sage.all import *>>> 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)>>> from sage.all import *>>> S = SparseGraph(nverts = Integer(10), expected_degree = Integer(3), extra_
˓→vertices = Integer(10))

INPUT:• nverts – non-negative integer, the number of vertices.
• expected_degree – non-negative integer (default: 16), expected upperbound on degree of vertices.
• extra_vertices – non-negative integer (default: 0), how many extra
vertices to allocate.
• verts – optional list of vertices to add• arcs – optional list of arcs to add
The first nverts are created as vertices of the graph, and the next extra_vertices can be freely added
without reallocation. See top level documentation for more details. The input verts and arcs are mainly foruse in pickling.
add_arc_label(u, v, l=0)
Add arc (u, v) to the graph with label l.
INPUT:

1436

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• 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 SparseGraphsage: 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 graphsage: 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>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc_label(Integer(0),Integer(1))>>> G.add_arc_label(Integer(4),Integer(7))
Traceback (most recent call last):...
LookupError: vertex (7) is not a vertex of the graph>>> G.has_arc(Integer(1),Integer(0))
False>>> G.has_arc(Integer(0),Integer(1))
True>>> G.add_arc_label(Integer(1),Integer(2),Integer(2))>>> G.arc_label(Integer(1),Integer(2))
2in_degree(v)Returns the in-degree of v
INPUT:• v – integer
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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)0sage: G.in_degree(1)1>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))(continues on next page)3.3. Fast sparse graphs

1437

Graph Theory, Release 10.4

(continued from previous page)>>> G.add_arc(Integer(0),Integer(1))>>> G.add_arc(Integer(1),Integer(2))>>> G.add_arc(Integer(1),Integer(3))>>> G.in_degree(Integer(0))
0>>> G.in_degree(Integer(1))
1is_directed()
Return whether the graph is directed.
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: G = SparseGraph(5)sage: G.is_directed()Truesage: G = SparseGraph(5, directed=False)
sage: G.is_directed()
False>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.is_directed()
True>>> G = SparseGraph(Integer(5), directed=False)>>> G.is_directed()
False

out_degree(u)Returns the out-degree of v
INPUT:• u – integer
EXAMPLES:
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: 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)1sage: G.out_degree(1)2>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> G = SparseGraph(Integer(5))>>> G.add_arc(Integer(0),Integer(1))>>> G.add_arc(Integer(1),Integer(2))>>> G.add_arc(Integer(1),Integer(3))>>> G.out_degree(Integer(0))
1(continues on next page)

1438

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> G.out_degree(Integer(1))
2realloc(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 SparseGraphsage: S = SparseGraph(nverts=4, extra_vertices=4)
sage: S.current_allocation()8
sage: S.add_vertex(6)6sage: S.current_allocation()8
sage: S.add_vertex(10)10sage: 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)40sage: S.current_allocation()50
sage: S.realloc(30)-1sage: S.current_allocation()50
sage: S.del_vertex(40)sage: S.realloc(30)sage: S.current_allocation()30>>> from sage.all import *>>> from sage.graphs.base.sparse_graph import SparseGraph>>> S = SparseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> S.current_allocation()
8>>> S.add_vertex(Integer(6))
6>>> S.current_allocation()
8>>> S.add_vertex(Integer(10))
10>>> S.current_allocation()
16(continues on next page)3.3. Fast sparse graphs1439

Graph Theory, Release 10.4

(continued from previous page)>>> S.add_vertex(Integer(40))
Traceback (most recent call last):...
RuntimeError: requested vertex is past twice the allocated range: use realloc>>> S.realloc(Integer(50))>>> S.add_vertex(Integer(40))
40>>> S.current_allocation()50>>> S.realloc(Integer(30))-1>>> S.current_allocation()50>>> S.del_vertex(Integer(40))>>> S.realloc(Integer(30))>>> S.current_allocation()
30

class sage.graphs.base.sparse_graph.SparseGraphBackend
Bases: CGraphBackend
Backend for Sage graphs using SparseGraphs.
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend>>> from sage.all import *>>> 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, sparse=True)
sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
sage: G.edges(sort=True, labels=False)[(0, 1), (0, 3), (4, 5), (9, 23)]>>> from sage.all import *>>> G = Graph(Integer(30), sparse=True)>>> G.add_edges([(Integer(0),Integer(1)), (Integer(0),Integer(3)), (Integer(4),˓→Integer(5)), (Integer(9), Integer(23))])>>> G.edges(sort=True, 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(list(G),....:key=lambda x: (isinstance(x, tuple), x))
[0,
...
29,
(0, 1, 2)]
sage: from sage.graphs.base.sparse_graph import SparseGraphsage: SG = SparseGraph(30)(continues on next page)

1440

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

sage: SG.add_vertex((0,1,2))
Traceback (most recent call last):...
TypeError: an integer is required>>> from sage.all import *>>> G.add_vertex((Integer(0),Integer(1),Integer(2)))>>> sorted(list(G),...
key=lambda x: (isinstance(x, tuple), x))
[0,
...
29,
(0, 1, 2)]>>> from sage.graphs.base.sparse_graph import SparseGraph>>> SG = SparseGraph(Integer(30))>>> SG.add_vertex((Integer(0),Integer(1),Integer(2)))
Traceback (most recent call last):...
TypeError: an integer is required

get_edge_label(u, v)
Return the edge label for (u, v).
INPUT:• u, v – the vertices of the edge
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: D.add_edges([(0,1,1), (2,3,2), (4,5,3), (5,6,2)], False)
sage: list(D.iterator_edges(range(9), True))[(0, 1, 1), (2, 3, 2), (4, 5, 3), (5, 6, 2)]
sage: D.get_edge_label(3,2)
2>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0),Integer(1),Integer(1)), (Integer(2),Integer(3),˓→Integer(2)), (Integer(4),Integer(5),Integer(3)), (Integer(5),Integer(6),˓→Integer(2))], False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, 1), (2, 3, 2), (4, 5, 3), (5, 6, 2)]>>> D.get_edge_label(Integer(3),Integer(2))
2has_edge(u, v, l)Returns whether this graph has edge (u,v) with label l. If l is None, return whether this graph has anedge (u,v) with any label.
INPUT:• u, v – the vertices of the edge
• l – the edge label, or None
EXAMPLES:

3.3. Fast sparse graphs

1441

Graph Theory, Release 10.4

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>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0),Integer(1)), (Integer(2),Integer(3)),␣
˓→(Integer(4),Integer(5)), (Integer(5),Integer(6))], False)>>> D.has_edge(Integer(0),Integer(1),None)
True

multiple_edges(new)Get/set whether or not self allows multiple edges.
INPUT:• new – boolean (to set) or None (to get)
EXAMPLES:
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: G.multiple_edges(True)
sage: G.multiple_edges(None)
True
sage: G.multiple_edges(False)
sage: G.multiple_edges(None)
False
sage: G.add_edge(0,1,0,True)
sage: G.add_edge(0,1,0,True)
sage: list(G.iterator_out_edges(range(9), True))[(0, 1, 0)]>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> G.multiple_edges(True)>>> G.multiple_edges(None)
True>>> G.multiple_edges(False)>>> G.multiple_edges(None)
False>>> G.add_edge(Integer(0),Integer(1),Integer(0),True)>>> G.add_edge(Integer(0),Integer(1),Integer(0),True)>>> list(G.iterator_out_edges(range(Integer(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:

1442

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: G.add_edge(1,2,None,True)
sage: G.set_edge_label(1,2, a ,True)
sage: list(G.iterator_out_edges(range(9), True))[(1, 2, a )]>>> from sage.all import *>>> G = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> G.add_edge(Integer(1),Integer(2),None,True)>>> G.set_edge_label(Integer(1),Integer(2), a ,True)>>> list(G.iterator_out_edges(range(Integer(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_out_edges(range(9), True))[(1, 2, a )]>>> from sage.all import *>>> G.set_edge_label(Integer(2),Integer(1), b ,True)>>> list(G.iterator_out_edges(range(Integer(9)), True))[(1, 2, a )]3.4 Fast dense graphs
For an overview of graph data structures in sage, see overview.

3.4.1 Usage Introduction
sage: from sage.graphs.base.dense_graph import DenseGraph>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph

Dense graphs are initialized as follows:
sage: D = DenseGraph(nverts=10, extra_vertices=10)>>> from sage.all import *>>> D = DenseGraph(nverts=Integer(10), extra_vertices=Integer(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)9sage: D.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

3.4. Fast dense graphs

1443

Graph Theory, Release 10.4>>> from sage.all import *>>> D.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> D.add_vertex(Integer(9))
9>>> 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)10sage: D.verts()[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]>>> from sage.all import *>>> D.add_vertex(Integer(10))
10>>> 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>>> from sage.all import *>>> D.add_arc(Integer(0), Integer(1))>>> D.add_arc(Integer(1), Integer(2))>>> D.add_arc(Integer(1), Integer(0))>>> D.has_arc(Integer(7), Integer(3))
False>>> D.has_arc(Integer(0), Integer(1))
True>>> D.in_neighbors(Integer(1))[0]>>> D.out_neighbors(Integer(1))[0, 2]>>> D.del_all_arcs(Integer(0), Integer(1))>>> D.has_arc(Integer(0), Integer(1))(continues on next page)

1444

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

False>>> D.has_arc(Integer(1), Integer(2))
True>>> D.del_vertex(Integer(7))>>> D.has_arc(Integer(7), Integer(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>>> from sage.all import *>>> T = DenseGraph(nverts=Integer(3), extra_vertices=Integer(2))>>> T.add_arc(Integer(0), Integer(1))>>> T.add_arc(Integer(1), Integer(2))>>> T.add_arc(Integer(2), Integer(0))>>> T.has_arc(Integer(0), Integer(1))
True
sage: for _ in range(10): D.add_arc(5, 4)
sage: D.has_arc(5,4 )True>>> from sage.all import *>>> for _ in range(Integer(10)): D.add_arc(Integer(5), Integer(4))>>> D.has_arc(Integer(5),Integer(4) )True

Dense graphs are by their nature directed. As of this writing, you need to do operations in pairs to treat the undirectedcase (or use a backend or a Sage graph):
sage: T.has_arc(1, 0)
False>>> from sage.all import *>>> T.has_arc(Integer(1), Integer(0))
False

The curious developer is encouraged to check out the unsafe functions, which do not check input but which run in pureC.

3.4. Fast dense graphs

1445

Graph Theory, Release 10.4

3.4.2 Underlying Data Structure
The class DenseGraph contains the following variables which are inherited from CGraph (for explanation, refer tothe 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 binary_matrix_t edges

Note: As the edges are stored as the adjacency matrix of the graph, enumerating the edges of the graph has complexity
𝑂(𝑛2 ) and enumerating the neighbors of a vertex has complexity 𝑂(𝑛) (where 𝑛 in the size of the bitset active_vertices).
So, the class DenseGraph should be used for graphs such that the number of edges is close to the square of the numberof vertices.
class sage.graphs.base.dense_graph.DenseGraph
Bases: CGraph
Compiled dense graphs.
sage: from sage.graphs.base.dense_graph import DenseGraph>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph

Dense graphs are initialized as follows:
sage: D = DenseGraph(nverts=10, extra_vertices=10)>>> from sage.all import *>>> D = DenseGraph(nverts=Integer(10), extra_vertices=Integer(10))

INPUT:• nverts – non-negative integer; the number of vertices• extra_vertices – non-negative integer (default: 10); how many extra vertices to allocate• verts – list (default: None); optional list of vertices to add• arcs – list (default: None); optional list of arcs to add• directed – boolean (default: None); whether the graph is directed
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 foruse in pickling.
complement()
Replace the graph with its complement

1446

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

Note: Assumes that the graph has no loop.
EXAMPLES:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: 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>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> G = DenseGraph(Integer(5))>>> G.add_arc(Integer(0), Integer(1))>>> G.has_arc(Integer(0), Integer(1))
True>>> G.complement()>>> G.has_arc(Integer(0), Integer(1))
False

realloc(total_verts)
Reallocate the number of vertices to use, without actually adding any.
INPUT:• total – integer; the total size to make the array
Returns -1 and fails if reallocation would destroy any active vertices.
EXAMPLES:
sage: from sage.graphs.base.dense_graph import DenseGraphsage: D = DenseGraph(nverts=4, extra_vertices=4)
sage: D.current_allocation()8
sage: D.add_vertex(6)6sage: D.current_allocation()8
sage: D.add_vertex(10)10sage: 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)40sage: D.current_allocation()50
sage: D.realloc(30)-1(continues on next page)

3.4. Fast dense graphs

1447

Graph Theory, Release 10.4

(continued from previous page)

sage: D.current_allocation()50
sage: D.del_vertex(40)sage: D.realloc(30)sage: D.current_allocation()30>>> from sage.all import *>>> from sage.graphs.base.dense_graph import DenseGraph>>> D = DenseGraph(nverts=Integer(4), extra_vertices=Integer(4))>>> D.current_allocation()8>>> D.add_vertex(Integer(6))
6>>> D.current_allocation()8>>> D.add_vertex(Integer(10))
10>>> D.current_allocation()
16>>> D.add_vertex(Integer(40))
Traceback (most recent call last):...
RuntimeError: requested vertex is past twice the allocated range: use realloc>>> D.realloc(Integer(50))>>> D.add_vertex(Integer(40))
40>>> D.current_allocation()50>>> D.realloc(Integer(30))-1>>> D.current_allocation()50>>> D.del_vertex(Integer(40))>>> D.realloc(Integer(30))>>> D.current_allocation()
30

class sage.graphs.base.dense_graph.DenseGraphBackend
Bases: CGraphBackend
Backend for Sage graphs using DenseGraphs.
sage: from sage.graphs.base.dense_graph import DenseGraphBackend>>> from sage.all import *>>> 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, sparse=False)
sage: G.add_edges([(0, 1), (0, 3), (4, 5), (9, 23)])
sage: G.edges(sort=True, labels=False)[(0, 1), (0, 3), (4, 5), (9, 23)]

1448

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph(Integer(30), sparse=False)>>> G.add_edges([(Integer(0), Integer(1)), (Integer(0), Integer(3)), (Integer(4),␣
˓→Integer(5)), (Integer(9), Integer(23))])>>> G.edges(sort=True, 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: sorted(list(G),....:key=lambda x: (isinstance(x, tuple), x))
[0,
...
29,
(0, 1, 2)]
sage: from sage.graphs.base.dense_graph import DenseGraphsage: DG = DenseGraph(30)sage: DG.add_vertex((0, 1, 2))Traceback (most recent call last):...
TypeError: an integer is required>>> from sage.all import *>>> G.add_vertex((Integer(0), Integer(1), Integer(2)))>>> sorted(list(G),...
key=lambda x: (isinstance(x, tuple), x))
[0,
...
29,
(0, 1, 2)]>>> from sage.graphs.base.dense_graph import DenseGraph>>> DG = DenseGraph(Integer(30))>>> DG.add_vertex((Integer(0), Integer(1), Integer(2)))
Traceback (most recent call last):...
TypeError: an integer is required

add_edges(edges, directed, remove_loops=False)
Add edges from a list.
INPUT:• edges – an iterable of edges to be added; each edge can either beof the form (u, v) or (u, v, l)• directed – if False, adds (v, u) as well as (u, v)• remove_loops – if True, remove loops
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),(continues on next page)

3.4. Fast dense graphs

1449

Graph Theory, Release 10.4

(continued from previous page)(4, 5, None),(5, 6, None)]>>> from sage.all import *>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))], False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, None),(2, 3, None),(4, 5, None),(5, 6, None)]

get_edge_label(u, v)
Return the edge label for (u, v).
Always None, since dense graphs do not support edge labels.
INPUT:• u, v – the vertices of the edge
EXAMPLES:
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)sage: D.add_edges([(0, 1), (2, 3, 7), (4, 5), (5, 6)], False)
sage: list(D.iterator_edges(range(9), True))[(0, 1, None),(2, 3, None),(4, 5, None),(5, 6, None)]sage: D.del_edge(0, 1, None, True)
sage: list(D.iterator_out_edges(range(9), True))[(1, 0, None),(2, 3, None),(3, 2, None),(4, 5, None),(5, 4, None),(5, 6, None),(6, 5, None)]sage: D.get_edge_label(2, 3)
sage: D.get_edge_label(2, 4)
Traceback (most recent call last):...
LookupError: (2, 4) is not an edge of the graph>>> from sage.all import *>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3),␣
˓→Integer(7)), (Integer(4), Integer(5)), (Integer(5), Integer(6))], False)>>> list(D.iterator_edges(range(Integer(9)), True))[(0, 1, None),(2, 3, None),(4, 5, None),(5, 6, None)]>>> D.del_edge(Integer(0), Integer(1), None, True)>>> list(D.iterator_out_edges(range(Integer(9)), True))(continues on next page)

1450

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)[(1, 0, None),(2, 3, None),(3, 2, None),(4, 5, None),(5, 4, None),(5, 6, None),(6, 5, None)]>>> D.get_edge_label(Integer(2), Integer(3))>>> D.get_edge_label(Integer(2), Integer(4))
Traceback (most recent call last):...
LookupError: (2, 4) is not an edge of the graphhas_edge(u, v, l)
Check whether this graph has edge (u, v).
Note: The input l is for consistency with other backends.
INPUT:• u, v – the vertices of the edge
• l – the edge label (ignored)
EXAMPLES:
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)sage: D.add_edges([(0, 1), (2, 3), (4, 5), (5, 6)], False)
sage: D.has_edge(0, 1, None)
True>>> from sage.all import *>>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> D.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3)),␣
˓→(Integer(4), Integer(5)), (Integer(5), Integer(6))], False)>>> D.has_edge(Integer(0), Integer(1), None)
True

multiple_edges(new)Get/set whether or not self allows multiple edges.
INPUT:• new – boolean (to set) or None (to get)
EXAMPLES:
sage: import sage.graphs.base.dense_graphsage: 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

3.4. Fast dense graphs1451

Graph Theory, Release 10.4>>> from sage.all import *>>> import sage.graphs.base.dense_graph>>> G = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> G.multiple_edges(True)
Traceback (most recent call last):...
NotImplementedError: dense graphs do not support multiple edges>>> 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_graphsage: 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>>> from sage.all import *>>> import sage.graphs.base.dense_graph>>> G = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9))>>> G.set_edge_label(Integer(1), Integer(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 data_structures/binary_matrix.pxd, whichis almost a copy of the bitset data structure. The only difference is that it differentiates the rows (the vertices) instead ofstoring the whole data in a long bitset, and we can use that.
For an overview of graph data structures in sage, see overview.

1452

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

3.5.1 Index
Cython functions
dense_graph_init

Fill a binary matrix with the information from a Sage (di)graph.

Python functions
is_strongly_regular()is_triangle_free()triangles_count()connected_subgraph_iterator()

Check whether the graph is strongly regular
Check whether 𝐺 is triangle free
Return the number of triangles containing 𝑣, for every 𝑣
Iterator over the induced connected subgraphs of order at most 𝑘

3.5.2 Functions
sage.graphs.base.static_dense_graph.connected_full_subgraphs(G, edges_only=False,labels=False,
min_edges=None,
max_edges=None)
Return an iterator over the connected subgraphs of 𝐺 with same vertex set.
This method implements a iterator over the connected subgraphs of the input (di)graph with the same ground setof vertices. That is, it iterates over every subgraph 𝐻 = (𝑉𝐻 , 𝐸𝐻 ) of 𝐺 = (𝑉, 𝐸) such that 𝑉𝐻 = 𝑉 , 𝐸𝐻 ⊆ 𝐸
and 𝐻 is connected. Hence, this method may yield a huge number of graphs.
When the input (di)graph 𝐺 is not connected, this method returns nothing.
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 not allowed• edges_only – boolean (default: False); whether to return (Di)Graph or list of vertices• labels – boolean (default: False); whether to return labelled edges or not. This parameter is used only
when edges_only is True.
• min_edges – integer (default: None); minimum number of edges of reported subgraphs. By default(None), this lower bound will be set to 𝑛 − 1.
• max_edges – integer (default: None); maximum number of edges of reported subgraphs. By default(None), this lower bound will be set to the number of edges of the input (di)graph.
Note: Roughly, this method explores all possible subsets of neighbors of each vertex, which represents a huge
number of subsets. We have thus chosen to limit the degree of the vertices of the graphs that can be considered,even if the graph has a single connected subgraph (e.g., a tree). It is therefore recommended to call this method on
biconnected components, as done in connected_subgraph_iterator().
EXAMPLES:
The complete graph of order 3 has 4 connected subgraphs:

3.5. Static dense graphs1453

Graph Theory, Release 10.4

sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
sage: G = graphs.CompleteGraph(3)sage: len(list(connected_full_subgraphs(G)))
4>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import connected_full_subgraphs>>> G = graphs.CompleteGraph(Integer(3))>>> len(list(connected_full_subgraphs(G)))
4

A cycle of order 5 has 6 connected subgraphs:
sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
sage: G = graphs.CycleGraph(5)sage: len(list(connected_full_subgraphs(G)))
6>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import connected_full_subgraphs>>> G = graphs.CycleGraph(Integer(5))>>> len(list(connected_full_subgraphs(G)))
6

The House graph has 18 connected subgraphs of order 5:
sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
sage: G = graphs.HouseGraph()
sage: L = list(connected_full_subgraphs(G))
sage: len(L)18sage: all(g.order() == 5 for g in L)
True
sage: all(g.is_connected() for g in L)
True
sage: F = frozenset(frozenset(g.edges(sort=False, labels=False)) for g in L)
sage: len(F)18>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import connected_full_subgraphs>>> G = graphs.HouseGraph()>>> L = list(connected_full_subgraphs(G))>>> len(L)18>>> all(g.order() == Integer(5) for g in L)
True>>> all(g.is_connected() for g in L)
True>>> F = frozenset(frozenset(g.edges(sort=False, labels=False)) for g in L)>>> len(F)18Specifying bounds on the number of edges:

1454

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
sage: G = graphs.HouseGraph()
sage: [g.size() for g in connected_full_subgraphs(G)][6, 5, 5, 5, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4]
sage: [g.size() for g in connected_full_subgraphs(G, max_edges=4)][4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
sage: [g.size() for g in connected_full_subgraphs(G, min_edges=6)][6]
sage: [g.size() for g in connected_full_subgraphs(G, min_edges=5, max_edges=5)][5, 5, 5, 5, 5, 5]>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import connected_full_subgraphs>>> G = graphs.HouseGraph()>>> [g.size() for g in connected_full_subgraphs(G)][6, 5, 5, 5, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4]>>> [g.size() for g in connected_full_subgraphs(G, max_edges=Integer(4))][4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]>>> [g.size() for g in connected_full_subgraphs(G, min_edges=Integer(6))][6]>>> [g.size() for g in connected_full_subgraphs(G, min_edges=Integer(5), max_
˓→edges=Integer(5))][5, 5, 5, 5, 5, 5]

Asking for edges only:
sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
sage: G = Graph([(0, 1, "01"), (0, 2, "02"), (1, 2, "12")])sage: it = connected_full_subgraphs(G, edges_only=True)
sage: next(it)[(0, 1), (0, 2), (1, 2)]
sage: next(it)[(0, 1), (0, 2)]
sage: it = connected_full_subgraphs(G, edges_only=True, labels=True)
sage: next(it)[(0, 1, 01 ), (0, 2, 02 ), (1, 2, 12 )]sage: next(it)[(0, 1, 01 ), (0, 2, 02 )]>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import connected_full_subgraphs>>> G = Graph([(Integer(0), Integer(1), "01"), (Integer(0), Integer(2), "02"),␣
˓→(Integer(1), Integer(2), "12")])>>> it = connected_full_subgraphs(G, edges_only=True)>>> next(it)[(0, 1), (0, 2), (1, 2)]>>> next(it)[(0, 1), (0, 2)]>>> it = connected_full_subgraphs(G, edges_only=True, labels=True)>>> next(it)[(0, 1, 01 ), (0, 2, 02 ), (1, 2, 12 )]>>> next(it)[(0, 1, 01 ), (0, 2, 02 )]Subgraphs of a digraph:3.5. Static dense graphs

1455

Graph Theory, Release 10.4

sage: from sage.graphs.base.static_dense_graph import connected_full_subgraphs
sage: G = digraphs.Complete(2)sage: list(connected_full_subgraphs(G, edges_only=True))[[(0, 1)], [(1, 0)], [(0, 1), (1, 0)]]>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import connected_full_subgraphs>>> G = digraphs.Complete(Integer(2))>>> list(connected_full_subgraphs(G, edges_only=True))[[(0, 1)], [(1, 0)], [(0, 1), (1, 0)]]sage.graphs.base.static_dense_graph.connected_subgraph_iterator(G, k=None,vertices_only=False,
edges_only=False,labels=False,
induced=True,
exactly_k=False)
Return an terator over the induced connected subgraphs of order at most 𝑘.
This method implements a iterator over the induced connected subgraphs of the input (di)graph. An induced
subgraph of a graph is another graph, formed from a subset of the vertices of the graph and all of the edges
connecting pairs of vertices in that subset (Wikipedia article Induced_subgraph).
As for method sage.graphs.generic_graph.connected_components(), edge orientation is ignored. Hence, the directed graph with a single arc 0 → 1 is considered connected.
INPUT:• G – a Graph or a DiGraph; loops and multiple edges are allowed• k – (optional) integer; maximum order of the connected subgraphs to report; by default, the method iterates
over all connected subgraphs (equivalent to k == n)• vertices_only – boolean (default: False); whether to return (Di)Graph or list of vertices. This parameter is ignored when induced is True.
• edges_only – boolean (default: False); whether to return (Di)Graph or list of edges. When vertices_only is True, this parameter is ignored.
• labels – boolean (default: False); whether to return labelled edges or not. This parameter is used only
when vertices_only is False and edges_only is True.
• induced – boolean (default: True); whether to return induced connected sub(di)graph only or also
non-induced sub(di)graphs. This parameter can be set to False for simple (di)graphs only.
• exactly_k – boolean (default: False); True if we only return graphs of order 𝑘, False if we returngraphs of order at most 𝑘.
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,(continues on next page)

1456

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

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=3, vertices_only=True, exactly_k=True))[[1, 2, 3], [1, 2, 4], [2, 3, 4]]
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: G = graphs.CompleteGraph(3)sage: len(list(G.connected_subgraph_iterator()))
7
sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))7
sage: len(list(G.connected_subgraph_iterator(edges_only=True)))7
sage: len(list(G.connected_subgraph_iterator(induced=False)))10
sage: G = DiGraph([(0, 1), (1, 0), (1, 2), (2, 1)])
sage: len(list(G.connected_subgraph_iterator()))
6
sage: len(list(G.connected_subgraph_iterator(vertices_only=True)))6sage: len(list(G.connected_subgraph_iterator(edges_only=True)))6sage: len(list(G.connected_subgraph_iterator(induced=False)))18>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(3),␣
˓→Integer(4)), (Integer(4), Integer(2))])>>> list(G.connected_subgraph_iterator())[Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,(continues on next page)

3.5. Static dense graphs

1457

Graph Theory, Release 10.4

(continued from previous page)

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]>>> 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]]>>> list(G.connected_subgraph_iterator(k=Integer(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]>>> list(G.connected_subgraph_iterator(k=Integer(3), vertices_only=True, exactly_
˓→k=True))[[1, 2, 3], [1, 2, 4], [2, 3, 4]]>>> list(G.connected_subgraph_iterator(k=Integer(2), vertices_only=True))[[1], [1, 2], [2], [2, 3], [2, 4], [3], [3, 4], [4]]>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(1))])>>> list(G.connected_subgraph_iterator())[Subgraph of (): Digraph on 1 vertex,
Subgraph of (): Digraph on 2 vertices,
Subgraph of (): Digraph on 1 vertex]>>> list(G.connected_subgraph_iterator(vertices_only=True))[[1], [1, 2], [2]]>>> G = graphs.CompleteGraph(Integer(3))>>> len(list(G.connected_subgraph_iterator()))
7>>> len(list(G.connected_subgraph_iterator(vertices_only=True)))7>>> len(list(G.connected_subgraph_iterator(edges_only=True)))7>>> len(list(G.connected_subgraph_iterator(induced=False)))10>>> G = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(0)), (Integer(1),␣
˓→Integer(2)), (Integer(2), Integer(1))])>>> len(list(G.connected_subgraph_iterator()))
6>>> len(list(G.connected_subgraph_iterator(vertices_only=True)))
6>>> len(list(G.connected_subgraph_iterator(edges_only=True)))
6>>> len(list(G.connected_subgraph_iterator(induced=False)))18

sage.graphs.base.static_dense_graph.is_strongly_regular(g, parameters=False)
1458

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

Check whether the graph is strongly regular.
A simple graph 𝐺 is said to be strongly regular with parameters (𝑛, 𝑘, 𝜆, 𝜇) if and only if:• 𝐺 has 𝑛 vertices• 𝐺 is 𝑘-regular• Any two adjacent vertices of 𝐺 have 𝜆 common neighbors• Any two non-adjacent vertices of 𝐺 have 𝜇 common neighbors
By convention, the complete graphs, the graphs with no edges and the empty graph are not strongly regular.
See the Wikipedia article Strongly regular graph.
INPUT:• parameters – boolean (default: False); whether to return the quadruple (𝑛, 𝑘, 𝜆, 𝜇). If parameters= False (default), this method only returns True and False answers. If parameters = True, theTrue 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)>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_strongly_regular()True>>> 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)>>> from sage.all import *>>> g = graphs.ClebschGraph()>>> g.is_strongly_regular()True>>> 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 graphs1459

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.ChvatalGraph()>>> g.is_strongly_regular()
False

Complete graphs are not strongly regular. (Issue #14297)
sage: g = graphs.CompleteGraph(5)sage: g.is_strongly_regular()False>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> 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>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5)).complement()>>> g.is_strongly_regular()False

The empty graph is not strongly regular:
sage: g = graphs.EmptyGraph()
sage: g.is_strongly_regular()False>>> from sage.all import *>>> g = graphs.EmptyGraph()>>> g.is_strongly_regular()False

If the input graph has loops or multiedges an exception is raised:sage: Graph([(1,1),(2,2)],loops=True).is_strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withloops. Perhaps this method can be updated to handle them, but in themeantime if you want to use it please disallow loops using
allow_loops().
sage: Graph([(1,2),(1,2)],multiedges=True).is_strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withmultiedges. Perhaps this method can be updated to handle them, but inthe meantime if you want to use it please disallow multiedges using
allow_multiple_edges().

1460

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> Graph([(Integer(1),Integer(1)),(Integer(2),Integer(2))],loops=True).is_˓→strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withloops. Perhaps this method can be updated to handle them, but in themeantime if you want to use it please disallow loops using
allow_loops().
>>> Graph([(Integer(1),Integer(2)),(Integer(1),Integer(2))],multiedges=True).is_˓→strongly_regular()Traceback (most recent call last):...
ValueError: This method is not known to work on graphs withmultiedges. Perhaps this method can be updated to handle them, but inthe meantime if you want to use it please disallow multiedges using
allow_multiple_edges().

sage.graphs.base.static_dense_graph.is_triangle_free(G, certificate=False)
Check whether 𝐺 is triangle free.
INPUT:• G – a Sage graph• certificate – boolean (default: False); whether to return a triangle if one is found
EXAMPLES:
sage: from sage.graphs.base.static_dense_graph import is_triangle_free
sage: is_triangle_free(graphs.PetersenGraph())
True
sage: K4 = graphs.CompleteGraph(4)sage: is_triangle_free(K4)False
sage: b, certif = is_triangle_free(K4, certificate=True)
sage: K4.subgraph(certif).is_clique()True>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import is_triangle_free>>> is_triangle_free(graphs.PetersenGraph())
True>>> K4 = graphs.CompleteGraph(Integer(4))>>> is_triangle_free(K4)False>>> b, certif = is_triangle_free(K4, certificate=True)>>> K4.subgraph(certif).is_clique()True

sage.graphs.base.static_dense_graph.triangles_count(G)Return the number of triangles containing 𝑣, for every 𝑣.
INPUT:• G – a simple Sage graph
EXAMPLES:

3.5. Static dense graphs

1461

Graph Theory, Release 10.4

sage: from sage.graphs.base.static_dense_graph import triangles_countsage: 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)# needs sage.symbolicTrue>>> from sage.all import *>>> from sage.graphs.base.static_dense_graph import triangles_count>>> triangles_count(graphs.PetersenGraph()){0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}>>> sum(triangles_count(graphs.CompleteGraph(Integer(15))).values()) ==␣
˓→Integer(3) * binomial(Integer(15), Integer(3))# needs sage.symbolicTrue

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.
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 theflow-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 byneighbors[n]-1.

1462

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• edge_labels (list); this cython list associates a label to each edge of the graph. If a given edge is represented
by edges[i], this its associated label can be found at edge_labels[i]. This object is usually NULL, unlessthe 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 endof 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.3 Technical details• When creating a short_digraph from a Graph or DiGraph named G, the 𝑖th vertex corresponds by default
to list(G)[i]. Using optional parameter vertex_list, you can specify the order of the vertices. Then 𝑖thvertex will corresponds to vertex_list[i].
• Some methods return bitset_t objects when lists could be expected. There is a very useful bitset_list
function for this kind of problems :-)• When the edges are labelled, most of the space taken by this graph is taken by edge labels. If no edge is labelledthen 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, insteadof the expected two. Storing the number of edges is the only way to avoid an uselessly costly computation to obtainthe number of edges of an undirected, looped, AND labelled graph (think of several loops on the same vertex withdifferent labels).
• The codes of this module are well documented, and many answers can be found directly in the code.

3.6. Static sparse graphs1463

Graph Theory, Release 10.4

3.6.4 Cython functions
init_short_diInitialize short_digraph g from a Sage (Di)Graph.
graph(short_digraphg, G, edge_labelled,
vertex_list,
sort_neighbors)
int n_edges(short_di- Return the number of edges in g
graph g)int
out_de- Return the out-degree of vertex 𝑖 in ggree(short_digraphg, int i)
has_edge(short_diTest the existence of an edge.
graph g, int u, int v)
edge_label(short_diReturn the label associated with a given edgegraph g, int * edge)
init_empty_copy(short_diAllocate dst so that it can contain as many vertices and edges as src.
graph dst, short_digraph src)
init_reInitialize dst to a copy of src with all edges in the opposite direction.
verse(short_digraphdst,
short_digraphsrc)
free_short_diFree the resources used by ggraph(short_digraphg)Connectivity
can_be_reached_from(short_digraph g, int src, bitset_t reached)
Assuming bitset_t reached has size at least g.n, this method updates reached so that it represents
the set of vertices that can be reached from src in g.
strongly_connected_component_containing_vertex(short_digraph g, short_digraphg_reversed, int v, bitset_t scc)
Assuming bitset_t reached has size at least g.n, this method updates scc so that it represents thevertices of the strongly connected component containing v in g. The variable g_reversed is assumed torepresent 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 connectedcomponents 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.

1464

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

3.6.5 What is this module used for ?
It is for instance 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 (asthey cannot directly call methods with C arguments).
sage.graphs.base.static_sparse_graph.spectral_radius(G, prec=1e-10)
Return an interval of floating point number that encloses the spectral radius of this graph
The input graph G must be strongly connected.
INPUT:• prec – (default 1e-10) an upper bound for the relative precision of the interval
The algorithm is iterative and uses an inequality valid for non-negative matrices. Namely, if 𝐴 is a non-negativesquare 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
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>>> from sage.all import *>>> from sage.graphs.base.static_sparse_graph import spectral_radius>>> G = DiGraph([(Integer(0),Integer(0)),(Integer(0),Integer(1)),(Integer(1),˓→Integer(0))], loops=True)>>> phi = (RR(Integer(1)) + RR(Integer(5)).sqrt() ) / Integer(2)>>> phi # abs tol 1e-14
1.618033988749895>>> e_min, e_max = spectral_radius(G, RealNumber( 1e-14 ))>>> e_min, e_max# abs tol 1e-14(continues on next page)

3.6. Static sparse graphs

1465

Graph Theory, Release 10.4

(continued from previous page)(1.618033988749894, 1.618033988749896)>>> (e_max - e_min) # abs tol 1e-14
1e-14>>> e_min < phi < e_max
TrueThis 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))
˓→needs sage.modules sage.rings.number_fieldsage: e_min < e < e_max
˓→needs sage.modules sage.rings.number_field sage.symbolic
True

#␣
#␣

sage: G.spectral_radius() # abs tol 1e-9
(2.48119430408, 2.4811943041)>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),˓→Integer(2)),(Integer(1),Integer(3)),(Integer(2),Integer(4)),(Integer(3),˓→Integer(4))])>>> e_min, e_max = spectral_radius(G, RealNumber( 1e-14 ))>>> e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False))
˓→needs sage.modules sage.rings.number_field>>> e_min < e < e_max
˓→needs sage.modules sage.rings.number_field sage.symbolic
True

#␣
#␣

>>> G.spectral_radius() # abs tol 1e-9
(2.48119430408, 2.4811943041)

A larger example:
sage: # needs sage.modules
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: px^201 - x^199 - 1
sage: r = p.roots(AA, multiplicities=False)[0]˓→needs sage.rings.number_fieldsage: e_min < r < e_max
˓→needs sage.rings.number_field
True

#␣
#␣

>>> from sage.all import *>>> # needs sage.modules>>> G = DiGraph()>>> G.add_edges((i,i+Integer(1)) for i in range(Integer(200)))>>> G.add_edge(Integer(200),Integer(0))>>> G.add_edge(Integer(1),Integer(0))(continues on next page)

1466

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> e_min, e_max = spectral_radius(G, RealNumber( 0.00001 ))>>> p = G.adjacency_matrix(sparse=True).charpoly()>>> px^201 - x^199 - 1>>> r = p.roots(AA, multiplicities=False)[Integer(0)]˓→# needs sage.rings.number_field>>> e_min < r < e_max
˓→needs sage.rings.number_field
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)>>> from sage.all import *>>> G = DiGraph(Integer(100000))>>> r = list(range(Integer(100000)))>>> while not G.is_strongly_connected():...
shuffle(r)...
G.add_edges(enumerate(r), loops=False)>>> spectral_radius(G, RealNumber( 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))˓→needs sage.modules sage.rings.number_field
2.414213562373095?

#␣>>> from sage.all import *>>> G = DiGraph(Integer(2),loops=True,multiedges=True)>>> G.add_edges([(Integer(0),Integer(0)),(Integer(0),Integer(0)),(Integer(0),˓→Integer(1)),(Integer(1),Integer(0))])>>> spectral_radius(G, RealNumber( 1e-14 )) # abs tol 1e-14(2.414213562373094, 2.414213562373095)>>> max(G.adjacency_matrix().eigenvalues(AA))#␣˓→needs sage.modules sage.rings.number_field
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)])(continues on next page)

3.6. Static sparse graphs

1467

Graph Theory, Release 10.4

(continued from previous page)

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)>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(3)),(Integer(2),˓→Integer(3))])>>> G.spectral_radius() # abs tol 1e-10(1.6180339887253428, 1.6180339887592732)>>> G = DiGraph([(Integer(0),Integer(1)),(Integer(0),Integer(3)),(Integer(2),˓→Integer(3)),(Integer(3),Integer(0)),(Integer(1),Integer(0)),(Integer(1),˓→Integer(2))])>>> G.spectral_radius() # abs tol 1e-10(1.5537739740270458, 1.553773974033029)>>> G = graphs.CompleteBipartiteGraph(Integer(1),Integer(3))>>> G.spectral_radius() # abs tol 1e-10(1.7320508075688772, 1.7320508075688774)

sage.graphs.base.static_sparse_graph.strongly_connected_components_digraph(G)Return the digraph of the strongly connected components (SCCs).
This routine is used to test strongly_connected_components_digraph_C, but it is not used by theSage 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_digraphsage: 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})>>> from sage.all import *>>> from sage.graphs.base.static_sparse_graph import strongly_connected_
˓→components_digraph>>> strongly_connected_components_digraph(digraphs.Path(Integer(3)))(Digraph on 3 vertices, {0: 2, 1: 1, 2: 0})>>> strongly_connected_components_digraph(DiGraph(Integer(4)))(Digraph on 4 vertices, {0: 0, 1: 1, 2: 2, 3: 3})sage.graphs.base.static_sparse_graph.tarjan_strongly_connected_components(G)Return the lists of vertices in each strongly connected components (SCCs).
This method implements the Tarjan algorithm to compute the strongly connected components of the digraph. It
returns a list of lists of vertices, each list of vertices representing a strongly connected component.
The basic idea of the algorithm is this: a depth-first search (DFS) begins from an arbitrary start node (and subsequent
DFSes are conducted on any nodes that have not yet been found). As usual with DFSes, the search visits every
node of the graph exactly once, declining to revisit any node that has already been explored. Thus, the collection

1468

Chapter 3. Low-level implementation

Graph Theory, Release 10.4of search trees is a spanning forest of the graph. The strongly connected components correspond to the subtrees ofthis spanning forest that have no edge directed outside the subtree.
To recover these components, during the DFS, we keep the index of a node, that is, the position in the DFS tree,
and the lowlink: as soon as the subtree rooted at 𝑣 has been fully explored, the lowlink of 𝑣 is the smallest index
reachable from 𝑣 passing from descendants of 𝑣. If the subtree rooted at 𝑣 has been fully explored, and the index
of 𝑣 equals the lowlink of 𝑣, that whole subtree is a new SCC.
For more information, see the Wikipedia article Tarjan%27s_strongly_connected_components_algorithm.
EXAMPLES:
sage: 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(sort=True)[[0, 1, 2, 3], [4, 5, 6]]
sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )sage: D.strongly_connected_components()[[3], [2], [1], [0], [6], [5], [4]]sage: D.add_edge([2,0])
sage: D.strongly_connected_components()[[3], [0, 1, 2], [6], [5], [4]]sage: D = DiGraph([( a , b ), ( b , c ), ( c , d ), ( d , b ), ( c , e )])sage: [sorted(scc) for scc in D.strongly_connected_components()][[ e ], [ b , c , d ], [ a ]]>>> from sage.all import *>>> from sage.graphs.base.static_sparse_graph import tarjan_strongly_connected_
˓→components>>> tarjan_strongly_connected_components(digraphs.Path(Integer(3)))[[2], [1], [0]]>>> D = DiGraph( { Integer(0) : [Integer(1), Integer(3)], Integer(1) :␣˓→[Integer(2)], Integer(2) : [Integer(3)], Integer(4) : [Integer(5), Integer(6)],␣
˓→Integer(5) : [Integer(6)] } )>>> D.connected_components(sort=True)[[0, 1, 2, 3], [4, 5, 6]]>>> D = DiGraph( { Integer(0) : [Integer(1), Integer(3)], Integer(1) :␣˓→[Integer(2)], Integer(2) : [Integer(3)], Integer(4) : [Integer(5), Integer(6)],␣
˓→Integer(5) : [Integer(6)] } )>>> D.strongly_connected_components()[[3], [2], [1], [0], [6], [5], [4]]>>> D.add_edge([Integer(2),Integer(0)])>>> D.strongly_connected_components()[[3], [0, 1, 2], [6], [5], [4]]>>> D = DiGraph([( a , b ), ( b , c ), ( c , d ), ( d , b ), ( c , e )])>>> [sorted(scc) for scc in D.strongly_connected_components()][[ e ], [ b , c , d ], [ a ]]sage.graphs.base.static_sparse_graph.triangles_count(G)Return the number of triangles containing 𝑣, for every 𝑣.
INPUT:• 𝐺 – a graph
EXAMPLES:

3.6. Static sparse graphs1469

Graph Theory, Release 10.4

sage: from sage.graphs.base.static_sparse_graph import triangles_countsage: 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)␣
˓→# needs sage.symbolicTrue>>> from sage.all import *>>> from sage.graphs.base.static_sparse_graph import triangles_count>>> triangles_count(graphs.PetersenGraph()){0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}>>> sum(triangles_count(graphs.CompleteGraph(Integer(15))).values()) ==␣
˓→Integer(3)*binomial(Integer(15),Integer(3))# needs sage.symbolicTrue

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 andmultiple 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 thoseincident 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 theshort_digraph structure. It does not know anything about labels on vertices.
• StaticSparseBackend extends CGraphBackend and is a Python class that does know about vertex labels
and contains an instance of StaticSparseCGraph as an internal variable. The input/output of its methods arelabeled 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: CGraphBackend
A graph backend for static sparse graphs.
EXAMPLES:
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)sage: D.add_edge(0, 1, None, False)
sage: list(D.iterator_edges(range(9), True))[(0, 1, None)]

1470

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> D = sage.graphs.base.sparse_graph.SparseGraphBackend(Integer(9))>>> D.add_edge(Integer(0), Integer(1), None, False)>>> list(D.iterator_edges(range(Integer(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)]>>> from sage.all import *>>> from sage.graphs.base.static_sparse_backend import StaticSparseBackend>>> g = StaticSparseBackend(graphs.PetersenGraph())>>> list(g.iterator_edges([Integer(0)], Integer(1)))[(0, 1, None), (0, 4, None), (0, 5, None)]sage: # needs sage.combinat
sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse")
sage: gi = DiGraph(g, data_structure="static_sparse")
sage: gi.edges(sort=True)[0]( 000 , 000 , 0 )sage: sorted(gi.edges_incident( 111 ))[( 111 , 110 , 0 ),( 111 , 111 , 1 ),( 111 , 112 , 2 ),( 111 , 113 , 3 )]sage: set(g.edges(sort=False)) == set(gi.edges(sort=False))
˓→needs sage.combinat
True

#␣

>>> from sage.all import *>>> # needs sage.combinat>>> g = DiGraph(digraphs.DeBruijn(Integer(4), Integer(3)), data_structure="static_
˓→sparse")>>> gi = DiGraph(g, data_structure="static_sparse")>>> gi.edges(sort=True)[Integer(0)]( 000 , 000 , 0 )>>> sorted(gi.edges_incident( 111 ))[( 111 , 110 , 0 ),( 111 , 111 , 1 ),( 111 , 112 , 2 ),( 111 , 113 , 3 )]>>> set(g.edges(sort=False)) == set(gi.edges(sort=False))
˓→sage.combinat
True# needs␣

sage: g = graphs.PetersenGraph()
sage: gi = Graph(g, data_structure="static_sparse")
sage: g == gi
True
sage: set(g.edges(sort=False)) == set(gi.edges(sort=False))
True

3.7. Static sparse graph backend

1471

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> gi = Graph(g, data_structure="static_sparse")>>> g == gi
True>>> set(g.edges(sort=False)) == set(gi.edges(sort=False))
True
sage: gi = Graph({ 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, data_
˓→structure="static_sparse")
sage: (0, 4, 2) in gi.edges(sort=False)
True
sage: gi.has_edge(0, 4)
True>>> from sage.all import *>>> gi = Graph({ Integer(0): {Integer(1): Integer(1)}, Integer(1): {Integer(2):␣
˓→Integer(1)}, Integer(2): {Integer(3): Integer(1)}, Integer(3): {Integer(4):␣
˓→Integer(2)}, Integer(4): {Integer(0): Integer(2)}}, data_structure="static_
˓→sparse")>>> (Integer(0), Integer(4), Integer(2)) in gi.edges(sort=False)
True>>> gi.has_edge(Integer(0), Integer(4))
Truesage: 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>>> from sage.all import *>>> G = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
˓→Integer(7):Integer(24)}})>>> GI = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
˓→Integer(7):Integer(24)}}, data_structure="static_sparse")>>> G == GI
True
sage: G = graphs.OddGraph(4)sage: d = G.diameter()sage: H = G.distance_graph(list(range(d + 1)))
sage: HI = Graph(H, data_structure="static_sparse")
sage: HI.size() == len(HI.edges(sort=False))
True>>> from sage.all import *>>> G = graphs.OddGraph(Integer(4))(continues on next page)

1472

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)>>> d = G.diameter()>>> H = G.distance_graph(list(range(d + Integer(1))))>>> HI = Graph(H, data_structure="static_sparse")>>> HI.size() == len(HI.edges(sort=False))
True
sage: g = Graph({1: {1: [1, 2, 3]}}, data_structure="static_sparse")
sage: g.size()3
sage: g.order()1sage: g.vertices(sort=False)[1]
sage: g.edges(sort=True)[(1, 1, 1), (1, 1, 2), (1, 1, 3)]>>> from sage.all import *>>> g = Graph({Integer(1): {Integer(1): [Integer(1), Integer(2), Integer(3)]}},␣
˓→data_structure="static_sparse")>>> g.size()3>>> g.order()1>>> g.vertices(sort=False)[1]>>> g.edges(sort=True)[(1, 1, 1), (1, 1, 2), (1, 1, 3)]

Issue #15810 is fixed:
sage: DiGraph({1: {2: [ a ,˓→directed_acyclic()Trueb ], 3: [ c ]}, 2: {3: [ d ]}}, immutable=True).is_>>> from sage.all import *>>> DiGraph({Integer(1): {Integer(2): [ a , b ], Integer(3): [ c ]}, Integer(2):˓→{Integer(3): [ d ]}}, immutable=True).is_directed_acyclic()
True

add_edge(u, v, l, directed)
Set edge label. No way.
add_edges(edges, directed)
Set edge label. No way.
add_vertex(v)Addition of vertices is not available on an immutable graph.
EXAMPLES:
sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")
sage: g.add_vertex(1)Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
(continues on next page)

3.7. Static sparse graph backend

1473

Graph Theory, Release 10.4

(continued from previous page)copy())
sage: g.add_vertices([1,2,3])
Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())˓→>>> from sage.all import *>>> g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.add_vertex(Integer(1))
Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())>>> g.add_vertices([Integer(1),Integer(2),Integer(3)])
Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())

add_vertices(vertices)
Set edge label. No way.
allows_loops(value=None)
Return whether the graph allows loops
INPUT:• value – only useful for compatibility with other graph backends, where this method can be used todefine this boolean. This method raises an exception if value is not equal to None.
degree(v, directed)
Return the degree of a vertex
INPUT:• v – a vertex• directed – boolean; whether to take into account the orientation of this graph in counting the degree
of v
EXAMPLES:
sage: g = Graph(graphs.PetersenGraph(), data_structure="static_sparse")
sage: g.degree(0)3>>> from sage.all import *>>> g = Graph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.degree(Integer(0))
3Issue #17225 about the degree of a vertex with a loop:
sage: Graph({0: [0]}, immutable=True).degree(0)2sage: Graph({0: [0], 1: [0, 1, 1, 1]}, immutable=True).degree(1)71474

Chapter 3. Low-level implementation

Graph Theory, Release 10.4>>> from sage.all import *>>> Graph({Integer(0): [Integer(0)]}, immutable=True).degree(Integer(0))
2>>> Graph({Integer(0): [Integer(0)], Integer(1): [Integer(0), Integer(1),␣
˓→Integer(1), Integer(1)]}, immutable=True).degree(Integer(1))
7del_edge(u, v, l, directed)
Set edge label. No way.
del_vertex(v)Removal of vertices is not available on an immutable graph.
EXAMPLES:
sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")
sage: g.delete_vertex(1)Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())
sage: g.delete_vertices([1,2,3])
Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())>>> from sage.all import *>>> g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.delete_vertex(Integer(1))
Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())>>> g.delete_vertices([Integer(1),Integer(2),Integer(3)])
Traceback (most recent call last):...
ValueError: graph is immutable; please change a copy instead (use function␣
˓→copy())

get_edge_label(u, v)
Return the edge label for (u, v).
INPUT:• u, v – two vertices
has_edge(u, v, l)Return whether this graph has edge (u, v) with label l.
If l is None, return whether this graph has an edge (u, v) with any label.
INPUT:• u, v – two vertices• l – a label

3.7. Static sparse graph backend

1475

Graph Theory, Release 10.4

has_vertex(v)Test if the vertex belongs to the graph
INPUT:• v – a vertex (or not?)in_degree(v)Return the in-degree of a vertex
INPUT:• v – a vertex
EXAMPLES:
sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")
sage: g.in_degree(0)3>>> from sage.all import *>>> g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.in_degree(Integer(0))
3iterator_edges(vertices, labels)
Iterate over the graph’s edges.
INPUT:• vertices – list; only returns the edges incident to at least one vertex of vertices• labels – boolean; whether to return edge labels too
iterator_in_edges(vertices, labels)
Iterate over the incoming edges incident to a sequence of vertices.
INPUT:• vertices – a list of vertices• labels – whether to return labels too
iterator_in_nbrs(v)Iterate over the in-neighbors of a vertex
INPUT:• v – a vertex
EXAMPLES:
sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")
sage: g.neighbors_in(0)[1, 4, 5]>>> from sage.all import *>>> g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.neighbors_in(Integer(0))[1, 4, 5]1476

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

iterator_nbrs(v)Iterate over 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]>>> from sage.all import *>>> g = Graph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.neighbors(Integer(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)Iterate over 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]>>> from sage.all import *>>> g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.neighbors_out(Integer(0))[1, 4, 5]

iterator_unsorted_edges(vertices, labels)
Iterate over the graph’s edges.
INPUT:• vertices – list; only returns the edges incident to at least one vertex of vertices• labels – boolean; whether to return edge labels too
iterator_verts(vertices)
Iterate over the vertices
INPUT:• vertices – a list of objects; the method will only return the elements of the graph which are containedin vertices. It’s not very efficient. If vertices is equal to None, all the vertices are returned.

3.7. Static sparse graph backend

1477

Graph Theory, Release 10.4

multiple_edges(value=None)
Return whether the graph allows multiple edges
INPUT:• value – only useful for compatibility with other graph backends, where this method can be used todefine this boolean. This method raises an exception if value is not equal to None.
num_edges(directed)
Return the number of edges
INPUT:• directed – boolean; whether to consider the graph as directed or not.
num_verts()
Return the number of vertices
out_degree(v)Return the out-degree of a vertex
INPUT:• v – a vertex
EXAMPLES:
sage: g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")
sage: g.out_degree(0)3>>> from sage.all import *>>> g = DiGraph(graphs.PetersenGraph(), data_structure="static_sparse")>>> g.out_degree(Integer(0))
3relabel(perm, directed)
Relabel the graphs’ vertices. No way.
set_edge_label(u, v, l, directed)
Set edge label. No way.
class sage.graphs.base.static_sparse_backend.StaticSparseCGraph
Bases: CGraph
CGraph class based on the sparse graph data structure static sparse graphs.
add_vertex(k)Add a vertex to the graph. No way.
del_vertex(k)Remove a vertex from the graph. No way.
has_arc(u, v)
Test if 𝑢𝑣 is an edge of the graph
INPUT:• u, v – integers

1478

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

has_vertex(v)Test if a vertex belongs to the graph
INPUT:• n – an integer
in_degree(u)Return the in-degree of a vertex
INPUT:• u – a vertex
in_neighbors(u)Return the in-neighbors of a vertex
INPUT:• u – a vertex
out_degree(u)Return the out-degree of a vertex
INPUT:• u – a vertex
out_neighbors(u)List the out-neighbors of a vertex
INPUT:• u – a vertex
verts()
Returns the list of vertices

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)

3.8. Backends for Sage (di)graphs1479

Graph Theory, Release 10.4

add_edge()
add_edges()
add_vertex()
add_vertices()
degree()in_degree()out_degree()del_edge()
del_vertex()
del_vertices()
get_edge_label()
has_edge()
has_vertex()
iterator_edges()
iterator_in_edges()
iterator_out_edges()
iterator_nbrs()
iterator_in_nbrs()
iterator_out_nbrs()
iterator_verts()
loops()
multiple_edges()name()
num_edges()
num_verts()
relabel()
set_edge_label()

Add an edge (𝑢, 𝑣) to self, with label 𝑙.
Add a sequence of edges to self.
Add a labelled vertex to self.
Add labelled vertices to self.
Return the total number of vertices incident to 𝑣.
Return the in-degree of 𝑣
Return the out-degree of 𝑣
Delete the edge (𝑢, 𝑣) with label 𝑙.
Delete a labelled vertex in self.
Delete labelled vertices in self.
Return the edge label of (𝑢, 𝑣).
True if self has an edge (𝑢, 𝑣) with label 𝑙.
True if self has a vertex with label 𝑣.
Iterate over the edges incident to a sequence of vertices.
Iterate over the incoming edges incident to a sequence of vertices.
Iterate over the outbound edges incident to a sequence of vertices.
Iterate over the vertices adjacent to 𝑣.
Iterate over the in-neighbors of vertex 𝑣.
Iterate over the out-neighbors of vertex 𝑣.
Iterate over the vertices 𝑣 with labels in verts.
Get/set whether or not self allows loops.
Get/set whether or not self allows multiple edges.
Get/set name of self.
The number of edges in self
The number of vertices in self
Relabel the vertices of self by a permutation.
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: 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 thedoctests are rather silly.
add_edge(u, v, l, directed)
Add an edge (𝑢, 𝑣) to self, with label 𝑙.
If directed is True, this is interpreted as an arc from 𝑢 to 𝑣.
INPUT:• u, v – vertices• l – edge label• directed – boolean

1480

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

add_edges(edges, directed)
Add a sequence of edges to self.
If directed is True, these are interpreted as arcs.
INPUT:• edges – list/iterator of edges to be added• directed – boolean
add_vertex(name)
Add a labelled vertex to self.
INPUT:• name – vertex label
OUTPUT:
If name=None, the new vertex name is returned, None otherwise.
add_vertices(vertices)
Add labelled vertices to self.
INPUT:• vertices – iterator of vertex labels; a new label is created, used and returned in the output list for all
None values in vertices
OUTPUT:
Generated names of new vertices if there is at least one None value present in vertices. None otherwise.
EXAMPLES:
sage: G = sage.graphs.base.graph_backends.GenericGraphBackend()
sage: G.add_vertices([1,2,3])
Traceback (most recent call last):...
NotImplementedError>>> from sage.all import *>>> G = sage.graphs.base.graph_backends.GenericGraphBackend()>>> G.add_vertices([Integer(1),Integer(2),Integer(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 𝑣

3.8. Backends for Sage (di)graphs1481

Graph Theory, Release 10.4

del_edge(u, v, l, directed)
Delete the edge (𝑢, 𝑣) with label 𝑙.
INPUT:• u, v – vertices• l – edge label• directed – boolean
del_vertex(v)Delete a labelled vertex in self.
INPUT:• v – vertex label
del_vertices(vertices)
Delete labelled vertices in self.
INPUT:• vertices – iterator of vertex labels
get_edge_label(u, v)
Return the edge label of (𝑢, 𝑣).
INPUT:• u, v – vertex labels
OUTPUT:label of (𝑢, 𝑣)
has_edge(u, v, l)
Check whether self has an edge (𝑢, 𝑣) with label 𝑙.
INPUT:• u, v – vertex labels• l – label
OUTPUT:booleanhas_vertex(v)Check whether self has a vertex with label 𝑣.
INPUT:• v – vertex label
OUTPUT:booleanin_degree(v)Return the in-degree of 𝑣
INPUT:• v – a vertex label

1482

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

iterator_edges(vertices, labels)
Iterate over the edges incident to a sequence of vertices.
Edges are assumed to be undirected.
This method returns an iterator over the edges (𝑢, 𝑣) such that either 𝑢 or 𝑣 is in vertices and the edge(𝑢, 𝑣) is in self.
INPUT:• 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.
This method returns an iterator over the edges (𝑢, 𝑣) such that 𝑣 is in vertices and the edge (𝑢, 𝑣) is in
self.
INPUT:• vertices – a list of vertex labels• labels – boolean
OUTPUT:a generator which yields edges, with or without labels depending on the labels parameter.
iterator_in_nbrs(v)Iterate over the in-neighbors of vertex 𝑣.
This method returns an iterator over the vertices 𝑢 such that the edge (𝑢, 𝑣) is in self (that is, predecessorsof 𝑣).
INPUT:• v – vertex label
OUTPUT:a generator which yields vertex labels
iterator_nbrs(v)Iterate over the vertices adjacent to 𝑣.
This method returns an iterator over the vertices 𝑢 such that either the edge (𝑢, 𝑣) or the edge (𝑣, 𝑢) is inself (that is, neighbors of 𝑣).
INPUT:• v – vertex label
OUTPUT:a generator which yields vertex labels

3.8. Backends for Sage (di)graphs1483

Graph Theory, Release 10.4

iterator_out_edges(vertices, labels)
Iterate over the outbound edges incident to a sequence of vertices.
This method returns an iterator over the edges (𝑣, 𝑢) such that 𝑣 is in vertices and the edge (𝑣, 𝑢) is in
self.
INPUT:• vertices – a list of vertex labels• labels – boolean
OUTPUT:a generator which yields edges, with or without labels depending on the labels parameter.
iterator_out_nbrs(v)Iterate over the out-neighbors of 𝑣.
This method returns an iterator over the vertices 𝑢 such that the edge (𝑣, 𝑢) is in self (that is, successors of𝑣).
INPUT:• v – vertex label
OUTPUT:a generator which yields vertex labels
iterator_verts(verts)
Iterate over the vertices 𝑣 with labels in verts.
INPUT:• verts – vertex labels
OUTPUT:a generator which yields vertices
loops(new=None)
Get/set whether or not self allows loops.
INPUT:• new – can be a boolean (in which case it sets the value) or None, in which case the current value isreturned. It is set to None by default.
multiple_edges(new=None)
Get/set whether or not self allows multiple edges.
INPUT:• new – can be a boolean (in which case it sets the value) or None, in which case the current value isreturned. 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 isreturned. It is set to None by default.

1484

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

num_edges(directed)
Return the number of edges in self
INPUT:• directed – boolean
num_verts()
Return the number of vertices in self
out_degree(v)Return the out-degree of 𝑣
INPUT:• v – a vertex label
relabel(perm, directed)
Relabel the vertices of self by a permutation.
INPUT:• perm – permutation• directed – boolean
set_edge_label(u, v, l, directed)
Label the edge (𝑢, 𝑣) by 𝑙.
INPUT:• u, v – vertices• l – edge label• directed – boolean
sage.graphs.base.graph_backends.unpickle_graph_backend(directed, vertices, edges, kwds)
Return a backend from its pickled data
This methods is defined because Python’s pickling mechanism can only build objects from a pair (f,args) byrunning f(*args). In particular, there is apparently no way to define a **kwargs (i.e. define the value of
keyword arguments of f), which means that one must know the order of all arguments of f (here, f is Graph or
DiGraph).
As a consequence, this means that the order cannot change in the future, which is something we cannot swear.
INPUT:• directed – boolean• vertices – list of vertices• edges – list of edges• kwds – any dictionary whose keywords will be forwarded to the graph constructor
This function builds a Graph or DiGraph from its data, and returns the _backend attribute of this object.
EXAMPLES:
sage: 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(continues on next page)3.8. Backends for Sage (di)graphs1485

Graph Theory, Release 10.4

(continued from previous page)<sage.graphs.base.sparse_graph.SparseGraphBackend object at ...>
sage: list(b.iterator_edges(range(4), True))[(0, 0, 1), (0, 3, label )]>>> from sage.all import *>>> from sage.graphs.base.graph_backends import unpickle_graph_backend>>> b = unpickle_graph_backend(Integer(0), [Integer(0), Integer(1), Integer(2),␣
˓→Integer(3)], [(Integer(0), Integer(3),label ), (Integer(0), Integer(0),␣
˓→Integer(1))], { loops : True})>>> b<sage.graphs.base.sparse_graph.SparseGraphBackend object at ...>>>> list(b.iterator_edges(range(Integer(4)), True))[(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 somefeatures 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()
edge_connectivity()
dominator_tree()bandwidth_heuristics()
min_spanning_tree()shortest_paths()
johnson_shortest_paths()
floyd_warshall_shortest_paths()
johnson_closeness_centrality()
blocks_and_cut_vertices()
min_cycle_basis()1486

Return the clustering coefficient of all vertices in the graph.
Return the edge connectivity of the graph.
Return a dominator tree of the graph.
Use heuristics to approximate the bandwidth of the graph.
Compute a minimum spanning tree of a (weighted) graph.
Use Dijkstra or Bellman-Ford algorithm to compute the single-source shortest
paths.
Use Johnson algorithm to compute the all-pairs shortest paths.
Use Floyd-Warshall algorithm to compute the all-pairs shortest paths.
Use Johnson algorithm to compute the closeness centrality of all vertices.
Use Tarjan’s algorithm to compute the blocks and cut vertices of the graph.
Return a minimum weight cycle basis of the input graph.

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

3.9.1 Functions
sage.graphs.base.boost_graph.bandwidth_heuristics(g, algorithm='cuthill_mckee')
Use Boost heuristics to approximate the bandwidth of the input graph.
The bandwidth 𝑏𝑤(𝑀 ) of a matrix 𝑀 is the smallest integer 𝑘 such that all non-zero entries of 𝑀 are at distance𝑘 from the diagonal. The bandwidth 𝑏𝑤(𝑔) of an undirected graph 𝑔 is the minimum bandwidth of the adjacency
matrix of 𝑔, over all possible relabellings of its vertices (for more information, see the bandwidth module).
Unfortunately, exactly computing the bandwidth is NP-hard (and an exponential algorithm is implemented in Sagemath in routine bandwidth()). Here, we implement two heuristics to find good orderings: Cuthill-McKee,
reverse Cuthill-McKee (also known as RCM) and King.
This function works only in undirected graphs, and its running time is 𝑂(𝑚𝑑𝑚𝑎𝑥 log 𝑑𝑚𝑎𝑥 ) for the Cuthill-McKee
ordering, and 𝑂(𝑚𝑑2𝑚𝑎𝑥 log 𝑑𝑚𝑎𝑥 ) for the King ordering, where 𝑚 is the number of edges, and 𝑑𝑚𝑎𝑥 is the maximum degree in the graph.
INPUT:• g – the input Sage graph• algorithm – string (default: cuthill_mckee ); the heuristic used to compute the ordering among
cuthill_mckee , reverse_cuthill_mckee and king
OUTPUT:
A pair [bandwidth, ordering], where ordering is the ordering of vertices, bandwidth is the bandwidth of that specific ordering (which is not necessarily the bandwidth of the graph, because this is a heuristic).
EXAMPLES:
sage: 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= reverse_cuthill_˓→mckee )(3, [(2, 2), (1, 2), (2, 1), (0, 2), (1, 1), (2, 0), (0, 1), (1, 0), (0, 0)])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)])>>> from sage.all import *>>> from sage.graphs.base.boost_graph import bandwidth_heuristics>>> bandwidth_heuristics(graphs.PathGraph(Integer(10)))(1, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>>> bandwidth_heuristics(graphs.GridGraph([Integer(3),Integer(3)]))(3, [(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (2, 1), (1, 2), (2, 2)])>>> bandwidth_heuristics(graphs.GridGraph([Integer(3),Integer(3)]), algorithm=
˓→ reverse_cuthill_mckee )(3, [(2, 2), (1, 2), (2, 1), (0, 2), (1, 1), (2, 0), (0, 1), (1, 0), (0, 0)])>>> bandwidth_heuristics(graphs.GridGraph([Integer(3),Integer(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)Compute the blocks and cut vertices of the graph.
This method uses the implementation of Tarjan’s algorithm available in the Boost library .
INPUT:
3.9. Interface to run Boost algorithms

1487

Graph Theory, Release 10.4

• g – the input Sage graph
OUTPUT:A 2-dimensional vector with m+1 rows (m is the number of biconnected components), where each of the first m
rows correspond to vertices in a block, and the last row is the list of cut vertices.
See also:• sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices()
EXAMPLES:
sage: 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]], [])>>> from sage.all import *>>> from sage.graphs.base.boost_graph import blocks_and_cut_vertices>>> g = graphs.KrackhardtKiteGraph()>>> blocks_and_cut_vertices(g)([[8, 9], [7, 8], [0, 1, 2, 3, 5, 4, 6, 7]], [8, 7])>>> G = Graph([(Integer(0),Integer(1),{ name : a , weight :Integer(1)}),␣
˓→(Integer(0),Integer(2),{ name : b , weight :Integer(3)}), (Integer(1),˓→Integer(2),{ name : b , weight :Integer(1)})])>>> blocks_and_cut_vertices(G)([[0, 1, 2]], [])sage.graphs.base.boost_graph.clustering_coeff(g, vertices=None)
Compute the clustering coefficient of the input graph, using Boost.
See also:
sage.graphs.generic_graph.GenericGraph.clustering_coeff()
INPUT:• g – the input Sage Graph• vertices – list (default: None); the list of vertices to analyze (if None, compute the clustering coefficientof all vertices)
OUTPUT: a pair (average_clustering_coefficient, clust_of_v), where average_clustering_coefficient is the average clustering of the vertices in variable vertices, clust_of_v is adictionary 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)(continues on next page)

1488

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

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})>>> from sage.all import *>>> from sage.graphs.base.boost_graph import clustering_coeff>>> g = graphs.CompleteGraph(Integer(5))>>> clustering_coeff(g)(1.0, {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0})>>> clustering_coeff(g, vertices = [Integer(0),Integer(1),Integer(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})>>> from sage.all import *>>> g = graphs.IcosahedralGraph()>>> clustering_coeff(g, vertices=[Integer(1),Integer(2),Integer(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})>>> from sage.all import *>>> g.relabel(list("abcdefghiklm"))>>> clustering_coeff(g, vertices="abde")(0.5, { a : 0.5, b : 0.5, d : 0.5, e : 0.5})

sage.graphs.base.boost_graph.diameter(G, algorithm=None, source=None, weight_function=None,check_weight=True)
Return the diameter of 𝐺.
This method returns Infinity if the digraph is not strongly connected. It can also quickly return a lower bound on
the diameter using the 2Dsweep scheme.
INPUT:• G – the input sage digraph.
• algorithm – string (default: None); specifies the algorithm to use among:–

2Dsweep – Computes lower bound on the diameter of a weighted directed graph using the weighted
version of the algorithm proposed in [Broder2000]. See the code’s documentation for more details.

–

DiFUB – Computes the diameter of a weighted directed graph using the weighted version of thealgorithm proposed in [CGLM2012]. See the code’s documentation for more details.

• source – (default: None) vertex from which to start the computation. If source==None, an arbitrary
vertex of the graph is chosen. Raise an error if the initial vertex is not in 𝐺.

3.9. Interface to run Boost algorithms

1489

Graph Theory, Release 10.4

• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of G are used, if G.weighted()==True, otherwise all edges have weight 1.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge.
EXAMPLES:
sage: from sage.graphs.base.boost_graph import diametersage: G = DiGraph([(0, 1, 2), (1, 0, -1)])
sage: diameter(G, algorithm= DiFUB )1.0
sage: diameter(G, algorithm= DiFUB , weight_function=lambda e:e[2])2.0sage: G = DiGraph([(0, 1, -1), (1, 0, 2)])sage: diameter(G, algorithm= DiFUB , weight_function=lambda e:e[2])2.0>>> from sage.all import *>>> from sage.graphs.base.boost_graph import diameter>>> G = DiGraph([(Integer(0), Integer(1), Integer(2)), (Integer(1), Integer(0), ˓→Integer(1))])>>> diameter(G, algorithm= DiFUB )1.0>>> diameter(G, algorithm= DiFUB , weight_function=lambda e:e[Integer(2)])
2.0>>> G = DiGraph([(Integer(0), Integer(1), -Integer(1)), (Integer(1), Integer(0),␣
˓→Integer(2))])>>> diameter(G, algorithm= DiFUB , weight_function=lambda e:e[Integer(2)])
2.0

sage.graphs.base.boost_graph.diameter_DHV(g, weight_function=None, check_weight=True)
Return the diameter of weighted graph 𝑔.
This method computes the diameter of undirected graph using the algorithm proposed in [Dragan2018].
This method returns Infinity if graph is not connected.
INPUT:• g – the input Sage graph• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
EXAMPLES:
sage: from sage.graphs.base.boost_graph import diameter_DHV
sage: G = graphs.ButterflyGraph()
sage: diameter_DHV(G)2.0>>> from sage.all import *>>> from sage.graphs.base.boost_graph import diameter_DHV>>> G = graphs.ButterflyGraph()>>> diameter_DHV(G)
2.0

1490

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

sage.graphs.base.boost_graph.dominator_tree(g, root, return_dict=False, reverse=False)
Use 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 connectedcomponent of the root.
If the graph is directed, computing a dominator tree is more complicated, and it needs time 𝑂(𝑚 log 𝑚), where 𝑚 isthe number of edges. The implementation provided by Boost is the most general one, so it needs time 𝑂(𝑚 log 𝑚)even for undirected graphs.
INPUT:• g – the input Sage (Di)Graph• root – the root of the dominator tree
• return_dict – boolean (default: False); if True, the function returns a dictionary associating to eachvertex 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 adictionary, 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)]}>>> from sage.all import *>>> g = graphs.GridGraph([Integer(2),Integer(2)]).dominator_tree((Integer(0),˓→Integer(0)))>>> 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 eachvertex 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(continues on next page)

3.9. Interface to run Boost algorithms

1491

Graph Theory, Release 10.4

(continued from previous page)

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}>>> from sage.all import *>>> G = Integer(2) * graphs.CycleGraph(Integer(3))>>> v = Integer(0)>>> w = Integer(3)>>> G.add_edge(v,w)>>> G.dominator_tree(Integer(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]}>>> from sage.all import *>>> g = digraphs.Circuit(Integer(10)).dominator_tree(Integer(5))>>> g.to_dictionary(){0: [1], 1: [2], 2: [3], 3: [4], 4: [], 5: [6], 6: [7], 7: [8], 8: [9], 9: [0]}>>> g = digraphs.Circuit(Integer(10)).dominator_tree(Integer(5), reverse=True)>>> 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)}>>> from sage.all import *>>> graphs.GridGraph([Integer(2),Integer(2)]).dominator_tree((Integer(0),˓→Integer(0)), return_dict=True){(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 0)}sage.graphs.base.boost_graph.eccentricity_DHV(g, vertex_list=None, weight_function=None,check_weight=True)
Return the vector of eccentricities using the algorithm of [Dragan2018].
The array returned is of length 𝑛, and by default its 𝑖-th component is the eccentricity of the 𝑖-th vertex in g.
vertices(sort=True), if vertex_list is None, otherwise ecc[i] is the eccentricity of vertex
vertex_list[i].
The algorithm proposed in [Dragan2018] is based on the observation that for all nodes 𝑣, 𝑤 ∈ 𝑉 , we havemax(𝑒𝑐𝑐[𝑣] − 𝑑(𝑣, 𝑤), 𝑑(𝑣, 𝑤)) ≤ 𝑒𝑐𝑐[𝑤] ≤ 𝑒𝑐𝑐[𝑣] + 𝑑(𝑣, 𝑤). Also the algorithm iteratively improves upperand lower bounds on the eccentricity of each vertex until no further improvements can be done.
INPUT:• g – the input Sage graph.
• vertex_list – list (default: None); a list of 𝑛 vertices specifying a mapping from (0, . . . , 𝑛−1) to vertex
labels in 𝑔. When set, ecc[i] is the eccentricity of vertex vertex_list[i]. When vertex_list
1492

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

is None, ecc[i] is the eccentricity of vertex g.vertices(sort=True)[i].
• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
EXAMPLES:
sage: from sage.graphs.base.boost_graph import eccentricity_DHV
sage: G = graphs.BullGraph()
sage: eccentricity_DHV(G)[2.0, 2.0, 2.0, 3.0, 3.0]>>> from sage.all import *>>> from sage.graphs.base.boost_graph import eccentricity_DHV>>> G = graphs.BullGraph()>>> eccentricity_DHV(G)[2.0, 2.0, 2.0, 3.0, 3.0]

sage.graphs.base.boost_graph.edge_connectivity(g)Compute the edge connectivity of the input graph, using Boost.
OUTPUT: a pair (ec, edges), where ec is the edge connectivity, edges is the list of edges in a minimum
cut.
See also:
sage.graphs.generic_graph.GenericGraph.edge_connectivity()
EXAMPLES:
Computing the edge connectivity of a clique: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)])>>> from sage.all import *>>> from sage.graphs.base.boost_graph import edge_connectivity>>> g = graphs.CompleteGraph(Integer(5))>>> edge_connectivity(g)(4, [(0, 1), (0, 2), (0, 3), (0, 4)])

Vertex-labeled graphs:
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))])>>> from sage.all import *>>> from sage.graphs.base.boost_graph import edge_connectivity>>> g = graphs.GridGraph([Integer(2),Integer(2)])>>> edge_connectivity(g)(2, [((0, 0), (0, 1)), ((0, 0), (1, 0))])3.9. Interface to run Boost algorithms

1493

Graph Theory, Release 10.4

sage.graphs.base.boost_graph.floyd_warshall_shortest_paths(g, weight_function=None,distances=True,
predecessors=False)
Use Floyd-Warshall algorithm to solve the all-pairs-shortest-paths.
This routine outputs the distance between each pair of vertices and the predecessors matrix (depending on thevalues of boolean distances and predecessors) using a dictionary of dictionaries. This method should be
preferred only if the graph is dense. If the graph is sparse the much faster johnson_shortest_paths should be used.
The time-complexity is 𝑂(𝑛3 + 𝑛𝑚), where 𝑛 is the number of nodes and 𝑚 the number of edges. The factor 𝑛𝑚
in the complexity is added only when predecessors is set to True.
INPUT:• g – the input Sage graph• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• distances – boolean (default: True); whether to return the dictionary of shortest distances• predecessors – boolean (default: False); whether to return the predecessors matrix
OUTPUT:
Depending on the input, this function return the dictionary of predecessors, the dictionary of distances, or a pair ofdictionaries (distances, predecessors) where distance[u][v] denotes the distance of a shortest
path from 𝑢 to 𝑣 and predecessors[u][v] indicates the predecessor of 𝑤 on a shortest path from 𝑢 to 𝑣.
EXAMPLES:
Undirected graphs:
sage: from sage.graphs.base.boost_graph import floyd_warshall_shortest_paths
sage: g = Graph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True)
sage: floyd_warshall_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}}sage: expected = {0: {0: None, 1: 0, 2: 1, 3: 2},....:
1: {0: 1, 1: None, 2: 1, 3: 2},....:
2: {0: 1, 1: 2, 2: None, 3: 2},....:
3: {0: 1, 1: 2, 2: 3, 3: None}}sage: floyd_warshall_shortest_paths(g, distances=False, predecessors=True) ==␣
˓→expected
True>>> from sage.all import *>>> from sage.graphs.base.boost_graph import floyd_warshall_shortest_paths>>> g = Graph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> floyd_warshall_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}}>>> expected = {Integer(0): {Integer(0): None, Integer(1): Integer(0),␣
˓→Integer(2): Integer(1), Integer(3): Integer(2)},(continues on next page)

1494

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)...
Integer(1): {Integer(0): Integer(1), Integer(1): None,␣˓→Integer(2): Integer(1), Integer(3): Integer(2)},...
Integer(2): {Integer(0): Integer(1), Integer(1): Integer(2),␣
˓→Integer(2): None, Integer(3): Integer(2)},...
Integer(3): {Integer(0): Integer(1), Integer(1): Integer(2),␣
˓→Integer(2): Integer(3), Integer(3): None}}>>> floyd_warshall_shortest_paths(g, distances=False, predecessors=True) ==␣
˓→expected
True

Directed graphs:
sage: g = DiGraph([(0,1,1),(1,2,-2),(1,3,4),(2,3,1)], weighted=True)
sage: floyd_warshall_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: g = DiGraph([(1,2,3),(2,3,2),(1,4,1),(4,2,1)], weighted=True)
sage: floyd_warshall_shortest_paths(g, distances=False, predecessors=True){1: {1: None, 2: 4, 3: 2, 4: 1},
2: {2: None, 3: 2},
3: {3: None},
4: {2: 4, 3: 2, 4: None}}>>> from sage.all import *>>> g = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> floyd_warshall_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}}>>> g = DiGraph([(Integer(1),Integer(2),Integer(3)),(Integer(2),Integer(3),˓→Integer(2)),(Integer(1),Integer(4),Integer(1)),(Integer(4),Integer(2),˓→Integer(1))], weighted=True)>>> floyd_warshall_shortest_paths(g, distances=False, predecessors=True){1: {1: None, 2: 4, 3: 2, 4: 1},
2: {2: None, 3: 2},
3: {3: None},
4: {2: 4, 3: 2, 4: None}}sage.graphs.base.boost_graph.johnson_closeness_centrality(g, weight_function=None)
Use Johnson algorithm to compute the closeness centrality of all vertices.
This routine is preferable to johnson_shortest_paths() because it does not create a doubly indexed dictionary of distances, saving memory.
The time-complexity is 𝑂(𝑚𝑛 log 𝑛), where 𝑛 is the number of nodes and 𝑚 is the number of edges.
INPUT:• g – the input Sage graph• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
OUTPUT:3.9. Interface to run Boost algorithms

1495

Graph Theory, Release 10.4

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}>>> from sage.all import *>>> from sage.graphs.base.boost_graph import johnson_closeness_centrality>>> g = Graph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> 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}>>> from sage.all import *>>> from sage.graphs.base.boost_graph import johnson_closeness_centrality>>> g = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> johnson_closeness_centrality(g){0: inf, 1: -0.4444444444444444, 2: 0.3333333333333333}

sage.graphs.base.boost_graph.johnson_shortest_paths(g, weight_function=None,distances=True, predecessors=False)
Use Johnson algorithm to solve the all-pairs-shortest-paths.
This routine outputs the distance between each pair of vertices and the predecessors matrix (depending on thevalues of boolean distances and predecessors) using a dictionary of dictionaries. It works on all kinds ofgraphs, 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 – the input Sage graph• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• distances – boolean (default: True); whether to return the dictionary of shortest distances• predecessors – boolean (default: False); whether to return the predecessors matrix
OUTPUT:
Depending on the input, this function return the dictionary of predecessors, the dictionary of distances, or a pair ofdictionaries (distances, predecessors) where distance[u][v] denotes the distance of a shortest
path from 𝑢 to 𝑣 and predecessors[u][v] indicates the predecessor of 𝑤 on a shortest path from 𝑢 to 𝑣.
1496

Chapter 3. Low-level implementation

Graph Theory, Release 10.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}}sage: expected = {0: {0: None, 1: 0, 2: 1, 3: 2},....:
1: {0: 1, 1: None, 2: 1, 3: 2},....:
2: {0: 1, 1: 2, 2: None, 3: 2},....:
3: {0: 1, 1: 2, 2: 3, 3: None}}sage: johnson_shortest_paths(g, distances=False, predecessors=True) == expected
True>>> from sage.all import *>>> from sage.graphs.base.boost_graph import johnson_shortest_paths>>> g = Graph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> 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}}>>> expected = {Integer(0): {Integer(0): None, Integer(1): Integer(0),␣
˓→Integer(2): Integer(1), Integer(3): Integer(2)},...
Integer(1): {Integer(0): Integer(1), Integer(1): None,␣˓→Integer(2): Integer(1), Integer(3): Integer(2)},...
Integer(2): {Integer(0): Integer(1), Integer(1): Integer(2),␣
˓→Integer(2): None, Integer(3): Integer(2)},...
Integer(3): {Integer(0): Integer(1), Integer(1): Integer(2),␣
˓→Integer(2): Integer(3), Integer(3): None}}>>> johnson_shortest_paths(g, distances=False, predecessors=True) == expected
True

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: g = DiGraph([(1,2,3),(2,3,2),(1,4,1),(4,2,1)], weighted=True)
sage: johnson_shortest_paths(g, distances=False, predecessors=True){1: {1: None, 2: 4, 3: 2, 4: 1},
2: {2: None, 3: 2},
3: {3: None},
4: {2: 4, 3: 2, 4: None}}>>> from sage.all import *>>> g = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)(continues on next page)

3.9. Interface to run Boost algorithms

1497

Graph Theory, Release 10.4

(continued from previous page)>>> 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}}>>> g = DiGraph([(Integer(1),Integer(2),Integer(3)),(Integer(2),Integer(3),˓→Integer(2)),(Integer(1),Integer(4),Integer(1)),(Integer(4),Integer(2),˓→Integer(1))], weighted=True)>>> johnson_shortest_paths(g, distances=False, predecessors=True){1: {1: None, 2: 4, 3: 2, 4: 1},
2: {2: None, 3: 2},
3: {3: None},
4: {2: 4, 3: 2, 4: None}}sage.graphs.base.boost_graph.min_cycle_basis(g_sage, weight_function=None, by_weight=False)
Return a minimum weight cycle basis of the input graph g_sage.
A cycle basis is a list of cycles (list of vertices forming a cycle) of g_sage. Note that the vertices are not necessarily
returned in the order in which they appear in the cycle.
A minimum weight cycle basis is a cycle basis that minimizes the sum of the weights (length for unweighted graphs)of its cycles.
Not implemented for directed graphs and multigraphs.
INPUT:• g_sage – a Sage Graph• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weightis True, the weights of g_sage are used, if g_sage.weighted()==True, otherwise all edges haveweight 1.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1
EXAMPLES:
sage: g = Graph([(1, 2, 3), (2, 3, 5), (3, 4, 8), (4, 1, 13), (1, 3, 250), (5, 6,␣
˓→9), (6, 7, 17), (7, 5, 20)])
sage: sorted(g.minimum_cycle_basis(by_weight=True))[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]
sage: sorted(g.minimum_cycle_basis())[[1, 2, 3], [1, 3, 4], [5, 6, 7]]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2), Integer(3)), (Integer(2), Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(4), Integer(8)), (Integer(4), Integer(1),␣
˓→Integer(13)), (Integer(1), Integer(3), Integer(250)), (Integer(5), Integer(6),␣
˓→Integer(9)), (Integer(6), Integer(7), Integer(17)), (Integer(7), Integer(5),␣
˓→Integer(20))])>>> sorted(g.minimum_cycle_basis(by_weight=True))[[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]]>>> sorted(g.minimum_cycle_basis())[[1, 2, 3], [1, 3, 4], [5, 6, 7]]

See also:

1498

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

• Wikipedia article Cycle_basis
sage.graphs.base.boost_graph.min_spanning_tree(g, weight_function=None, algorithm='Kruskal')
Use Boost to compute the minimum spanning tree of the input graph.
INPUT:• g – the input Sage graph• weight_function – function (default: None); 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 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), foreach 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 canbe any spanning tree).
Note that, if the weight is not convertible to a number with function float(), an error is raised (see tests
below).
• algorithm – string (default: Kruskal ); the algorithm to use among Kruskal and PrimOUTPUT:
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)]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})]>>> from sage.all import *>>> from sage.graphs.base.boost_graph import min_spanning_tree>>> min_spanning_tree(graphs.PathGraph(Integer(4)))[(0, 1, None), (1, 2, None), (2, 3, None)]>>> G = Graph([(Integer(0),Integer(1),{ name : a , weight :Integer(1)}),␣
˓→(Integer(0),Integer(2),{ name : b , weight :Integer(3)}), (Integer(1),˓→Integer(2),{ name : b , weight :Integer(1)})])>>> min_spanning_tree(G, weight_function=lambda e: e[Integer(2)][ weight ])[(0, 1, { name : a , weight : 1}), (1, 2, { name : b , weight : 1})]sage.graphs.base.boost_graph.radius_DHV(g, weight_function=None, check_weight=True)
Return the radius of weighted graph 𝑔.
This method computes the radius of undirected graph using the algorithm given in [Dragan2018].

3.9. Interface to run Boost algorithms

1499

Graph Theory, Release 10.4

This method returns Infinity if graph is not connected.
INPUT:• g – the input Sage graph• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge.
EXAMPLES:
sage: from sage.graphs.base.boost_graph import radius_DHV
sage: G = Graph([(0,1,1), (1,2,1), (0,2,3)])
sage: radius_DHV(G)1.0
sage: G = graphs.PathGraph(7)sage: radius_DHV(G) == G.radius(algorithm= Dijkstra_Boost )True>>> from sage.all import *>>> from sage.graphs.base.boost_graph import radius_DHV>>> G = Graph([(Integer(0),Integer(1),Integer(1)), (Integer(1),Integer(2),˓→Integer(1)), (Integer(0),Integer(2),Integer(3))])>>> radius_DHV(G)1.0>>> G = graphs.PathGraph(Integer(7))>>> radius_DHV(G) == G.radius(algorithm= Dijkstra_Boost )Truesage.graphs.base.boost_graph.shortest_paths(g, start, weight_function=None, algorithm=None)
Compute 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 beweighted: 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 anegative cycle: for this reason, in this case, Dijkstra algorithm is always better.
The running-time is 𝑂(𝑛 log 𝑛 + 𝑚) for Dijkstra algorithm and 𝑂(𝑚𝑛) for Bellman-Ford algorithm, where 𝑛 is
the number of nodes and 𝑚 is the number of edges.
INPUT:• g – the input Sage graph• start – the starting vertex to compute shortest paths• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• algorithm – string (default: None); one of the following algorithms:

1500

–

Dijkstra , Dijkstra_Boost : the Dijkstra algorithm implemented in Boost (works only withpositive weights)–

Bellman-Ford , Bellman-Ford_Boost : the Bellman-Ford algorithm implemented in
Boost (works also with negative weights, if there is no negative cycle)

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

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)})>>> from sage.all import *>>> from sage.graphs.base.boost_graph import shortest_paths>>> g = Graph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> shortest_paths(g, Integer(1))({0: 1, 1: 0, 2: 2, 3: 3}, {0: 1, 1: None, 2: 1, 3: 2})>>> g = graphs.GridGraph([Integer(2),Integer(2)])>>> shortest_paths(g,(Integer(0),Integer(0)),weight_function=lambda e:Integer(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})>>> from sage.all import *>>> g = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> shortest_paths(g, Integer(1))({1: 0, 2: 2, 3: 3}, {1: None, 2: 1, 3: 2})sage.graphs.base.boost_graph.shortest_paths_from_vertices(g, vertex_list=None,order=None,weight_function=None,algorithm=None)
Compute the shortest paths to all vertices from each vertex in vertex_list.
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).
The running-time for each vertex is 𝑂(𝑛 log 𝑛+𝑚) for Dijkstra algorithm and 𝑂(𝑚𝑛) for Bellman-Ford algorithm,
where 𝑛 is the number of nodes and 𝑚 is the number of edges.

3.9. Interface to run Boost algorithms

1501

Graph Theory, Release 10.4

INPUT:• g – the input Sage graph• vertex_list – list (default: None); list of vertices to compute shortest paths from. By default (None),compute shortest paths from all vertices.
• order – list (default: None); order of vertices of 𝑔
• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• algorithm – string (default: None); one of the following algorithms:–

Dijkstra , Dijkstra_Boost – the Dijkstra algorithm implemented in Boost (works onlywith positive weights)–

Bellman-Ford , Bellman-Ford_Boost – the Bellman-Ford algorithm implemented in
Boost (works also with negative weights, if there is no negative cycle)

OUTPUT:
The type of output depends on the input. More precisely • A pair of dictionaries of list (distances, predecessors), when order is not None, suchthat for each vertex v in vertex_list, distances[v][i] store the shortest distance between v andorder[i] and predecessors[v][i] store the last vertex in the shortest path from v to order[i].
• A pair of dictionaries of dictionaries (distances, predecessors) such that for each vertex v invertex_list, distances[v] store the shortest distances of all the other vertices from v, predecessors[v] store the last vertices in the shortest path from v to all the other vertices.
EXAMPLES:
Undirected graphs:
sage: from sage.graphs.base.boost_graph import shortest_paths_from_vertices
sage: g = Graph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True)
sage: shortest_paths_from_vertices(g,[1,2])({1: {0: 1.0, 1: 0.0, 2: 2.0, 3: 3.0}, 2: {0: 3.0, 1: 2.0, 2: 0.0, 3: 1.0}},{1: {0: 1, 1: None, 2: 1, 3: 2}, 2: {0: 1, 1: 2, 2: None, 3: 2}})>>> from sage.all import *>>> from sage.graphs.base.boost_graph import shortest_paths_from_vertices>>> g = Graph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),˓→Integer(2)),(Integer(1),Integer(3),Integer(4)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> shortest_paths_from_vertices(g,[Integer(1),Integer(2)])({1: {0: 1.0, 1: 0.0, 2: 2.0, 3: 3.0}, 2: {0: 3.0, 1: 2.0, 2: 0.0, 3: 1.0}},{1: {0: 1, 1: None, 2: 1, 3: 2}, 2: {0: 1, 1: 2, 2: None, 3: 2}})

Directed graphs:
sage: g = DiGraph([(0,1,1),(1,2,-1),(2,0,2),(2,3,1)], weighted=True)
sage: shortest_paths_from_vertices(g,1)({1: {0: 1.0, 1: 0.0, 2: -1.0, 3: 0.0}}, {1: {0: 2, 1: None, 2: 1, 3: 2}})sage: shortest_paths_from_vertices(g, 1, [0,1,2,3])({1: [1.0, 0.0, -1.0, 0.0]}, {1: [2, None, 1, 2]})>>> from sage.all import *>>> g = DiGraph([(Integer(0),Integer(1),Integer(1)),(Integer(1),Integer(2),(continues on next page)1502

Chapter 3. Low-level implementation

Graph Theory, Release 10.4

(continued from previous page)

Integer(1)),(Integer(2),Integer(0),Integer(2)),(Integer(2),Integer(3),˓→Integer(1))], weighted=True)>>> shortest_paths_from_vertices(g,Integer(1))({1: {0: 1.0, 1: 0.0, 2: -1.0, 3: 0.0}}, {1: {0: 2, 1: None, 2: 1, 3: 2}})>>> shortest_paths_from_vertices(g, Integer(1), [Integer(0),Integer(1),Integer(2),˓→Integer(3)])({1: [1.0, 0.0, -1.0, 0.0]}, {1: [2, None, 1, 2]})˓→sage.graphs.base.boost_graph.wiener_index(g, algorithm=None, weight_function=None,check_weight=True)
Return the Wiener index of the graph.
The Wiener index of an undirected graph 𝐺 is defined as 𝑊 (𝐺) = 12
distance between vertices 𝑢 and 𝑣 (see [KRG1996]).

∑︀

𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣) where 𝑑(𝑢, 𝑣) denotes the

The Wiener∑︀ index of a directed graph 𝐺 is defined as the sum of the distances between each pairs of vertices,
𝑊 (𝐺) = 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣).
INPUT:• g – the input Sage graph• algorithm – string (default: None); one of the following algorithms:–

Dijkstra , Dijkstra_Boost : the Dijkstra algorithm implemented in Boost (works only withpositive weights)–

Bellman-Ford , Bellman-Ford_Boost : the Bellman-Ford algorithm implemented in
Boost (works also with negative weights, if there is no negative cycle)• weight_function – function (default: None); a function that associates a weight to each edge. If None(default), the weights of g are used, if g.weighted()==True, otherwise all edges have weight 1.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge.
EXAMPLES:
sage: from sage.graphs.base.boost_graph import wiener_index sage: g = Graph([(0,1,9), (1,2,7),(2,3,4), (3,0,3)]) sage: wiener_index(g) 8.0 sage: g.weighted(True) sage: wiener_index(g) 41.0
Wiener index of circuit digraphs:
sage: n = 10
sage: g = digraphs.Circuit(n)sage: w = lambda x: (x*x*(x-1))/2
sage: wiener_index(g) == w(n)True>>> from sage.all import *>>> n = Integer(10)>>> g = digraphs.Circuit(n)>>> w = lambda x: (x*x*(x-Integer(1)))/Integer(2)>>> wiener_index(g) == w(n)True

Wiener index of a graph of order 1:
sage: wiener_index(Graph(1))
03.9. Interface to run Boost algorithms

1503

Graph Theory, Release 10.4>>> from sage.all import *>>> wiener_index(Graph(Integer(1)))
0The Wiener index is not defined on the empty graph:
sage: wiener_index(Graph())
Traceback (most recent call last):...
ValueError: Wiener index is not defined for the empty graph>>> from sage.all import *>>> wiener_index(Graph())
Traceback (most recent call last):...
ValueError: Wiener index is not defined for the empty graph

1504

Chapter 3. Low-level implementation

CHAPTER

FOUR

HYPERGRAPHS

4.1 Hypergraph generators
This module implements generators of hypergraphs. All hypergraphs can be built through the hypergraphs object.
For instance, to build a complete 3-uniform hypergraph on 5 points, one can do:sage: H = hypergraphs.CompleteUniform(5, 3)>>> from sage.all import *>>> H = hypergraphs.CompleteUniform(Integer(5), Integer(3))

To enumerate hypergraphs with certain properties up to isomorphism, one can use method nauty(), which calls Brendan
McKay’s Nauty (http://cs.anu.edu.au/ bdm/nauty/):sage: list(hypergraphs.nauty(2, 2, connected=True))[((0,), (0, 1))]>>> from sage.all import *>>> list(hypergraphs.nauty(Integer(2), Integer(2), connected=True))[((0,), (0, 1))]This module contains the following hypergraph generators
nauty()
CompleteUniform()
UniformRandomUniform()

Enumerate hypergraphs up to isomorphism using Nauty.
Return the complete 𝑘-uniform hypergraph on 𝑛 points.
Return a uniformly sampled 𝑘-uniform hypergraph on 𝑛 points with 𝑚 hyperedges.

4.1.1 Functions and methods
class sage.graphs.hypergraph_generators.HypergraphGenerators
Bases: object
A class consisting of constructors for common hypergraphs.
BinomialRandomUniform(n, k, p)
Return a random 𝑘-uniform hypergraph on 𝑛 points, in which each edge is inserted independently with probability 𝑝.
• n – number of nodes of the graph

1505

Graph Theory, Release 10.4

• k – uniformity• p – probability of an edge
EXAMPLES:
sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks()
˓→needs numpy
19600
sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks()
˓→needs numpy
0

#␣

#␣

>>> from sage.all import *>>> hypergraphs.BinomialRandomUniform(Integer(50), Integer(3), Integer(1)).
˓→num_blocks()# needs numpy
19600>>> hypergraphs.BinomialRandomUniform(Integer(50), Integer(3), Integer(0)).
˓→num_blocks()# needs numpy
0CompleteUniform(n, k)
Return the complete 𝑘-uniform hypergraph on 𝑛 points.
INPUT:• k, n – nonnegative integers with 𝑘 ≤ 𝑛
EXAMPLES:
sage: h = hypergraphs.CompleteUniform(5, 2); hIncidence structure with 5 points and 10 blocks
sage: len(h.packing())
˓→needs sage.numerical.mip2#␣>>> from sage.all import *>>> h = hypergraphs.CompleteUniform(Integer(5), Integer(2)); h
Incidence structure with 5 points and 10 blocks>>> len(h.packing())
˓→needs sage.numerical.mip2#␣

UniformRandomUniform(n, k, m)
Return a uniformly sampled 𝑘-uniform hypergraph on 𝑛 points with 𝑚 hyperedges.
• n – number of nodes of the graph• k – uniformity• m – number of edges
EXAMPLES:
sage: H = hypergraphs.UniformRandomUniform(52, 3, 17)
sage: H
Incidence structure with 52 points and 17 blocks
sage: H.is_connected()
False

1506

Chapter 4. Hypergraphs

Graph Theory, Release 10.4>>> from sage.all import *>>> H = hypergraphs.UniformRandomUniform(Integer(52), Integer(3), Integer(17))>>> H
Incidence structure with 52 points and 17 blocks>>> 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, uniform=False,
max_intersection=None, connected=False, debug=False, options='')Enumerate hypergraphs up to isomorphism using Nauty.
INPUT:• number_of_sets – integer, at most 64 minus number_of_vertices• number_of_vertices – integer, at most 30• multiple_sets – boolean (default: False); whether to allow several sets of the hypergraph to beequal.
• vertex_min_degree, vertex_max_degree – integers (default: None); define the maximum
and minimum degree of an element from the ground set (i.e. the number of sets which contain it).
• set_min_size, set_max_size – integers (default: None); define the maximum and minimum
size of a set.
• regular – integers (default: False); if set to an integer value 𝑘, requires the hypergraphs to be
𝑘-regular. It is actually a shortcut for the corresponding min/max values.
• uniform – integers (default: False); 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 – integers (default: None); constraints the maximum cardinality of the intersection of two sets from the hypergraphs.
• connected – boolean (default: False); whether to require the hypergraphs to be connected.
• debug – boolean (default: False); if True the first line of genbgL’s output to standard error is captured and the first call to the generator’s next() function will return this line as a string. A line leadingwith “>A” indicates a successful initiation of the program with some information on the arguments, whilea line beginning with “>E” indicates an error with the input.
• options – string (default: "") – anything else that should be forwarded as input to Nauty’s genbgL.
See its documentation for more information : http://cs.anu.edu.au/ bdm/nauty/.
Note: For genbgL the first class elements are vertices, and second class elements are the hypergraph’s
sets.
OUTPUT:
A tuple of tuples.
EXAMPLES:
Small hypergraphs:
sage: list(hypergraphs.nauty(4, 2))[((), (0,), (1,), (0, 1))]4.1. Hypergraph generators

1507

Graph Theory, Release 10.4>>> from sage.all import *>>> list(hypergraphs.nauty(Integer(4), Integer(2)))[((), (0,), (1,), (0, 1))]

Only connected ones:sage: list(hypergraphs.nauty(2, 2, connected=True))[((0,), (0, 1))]>>> from sage.all import *>>> list(hypergraphs.nauty(Integer(2), Integer(2), connected=True))[((0,), (0, 1))]Non-empty sets only:
sage: list(hypergraphs.nauty(3, 2, set_min_size=1))[((0,), (1,), (0, 1))]>>> from sage.all import *>>> list(hypergraphs.nauty(Integer(3), Integer(2), set_min_size=Integer(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))>>> from sage.all import *>>> fano = next(hypergraphs.nauty(Integer(7), Integer(7), uniform=Integer(3),␣
˓→max_intersection=Integer(1)))>>> 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))>>> from sage.all import *>>> fano = next(hypergraphs.nauty(Integer(7), Integer(7), regular=Integer(3),␣
˓→max_intersection=Integer(1)))>>> print(fano)((0, 1, 2), (0, 3, 4), (0, 5, 6), (1, 3, 5), (2, 4, 5), (2, 3, 6), (1, 4, 6))1508

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

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

block_sizes()
blocks()canonical_label()coloring()
complement()
copy()
degree()degrees()dual()
edge_coloring()
ground_set()
incidence_graph()incidence_matrix()
induced_substructure()intersection_graph()
is_berge_cyclic()
is_connected()
is_generalized_quadrangle()
is_isomorphic()
is_regular()is_resolvable()
is_simple()is_spread()
is_t_design()
is_uniform()isomorphic_substructures_iterator()
num_blocks()
num_points()
packing()rank()
relabel()trace()

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 theblock design, although the degrees differ.
Return the set of block sizes.
Return the list of blocks.
Return a canonical label for the incidence structure.
Compute a (weak) 𝑘-coloring of the hypergraph
Return the complement of the incidence structure.
Return a copy of the incidence structure.
Return the degree of a point p (or a set of points).
Return the degree of all sets of given size, or the degree of all points.
Return the dual of the incidence structure.
Compute a proper edge-coloring.
Return the ground set (i.e the list of points).
Return the incidence graph of the incidence structure
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.
Return the substructure induced by a set of points.
Return the intersection graph of the incidence structure.
Check whether self is a Berge-Cyclic uniform hypergraph.
Test whether the design is connected.
Test if the incidence structure is a generalized quadrangle.
Return whether the two incidence structures are isomorphic.
Test whether the incidence structure is 𝑟-regular.
Test whether the hypergraph is resolvable
Test whether this design is simple (i.e. no repeated block).
Check whether the input is a spread for self.
Test whether self is a 𝑡 − (𝑣, 𝑘, 𝑙) design.
Test whether the incidence structure is 𝑘-uniform
Iterates over all copies of H2 contained in self.
Return the number of blocks.
Return the size of the ground set.
Return a maximum packing
Return the rank of the hypergraph (the maximum size of a block).
Relabel the ground set
Return the trace of a set of points.

REFERENCES:AUTHORS:• Peter Dobcsanyi and David Joyner (2007-2008)
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)

1509

Graph Theory, Release 10.4

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,
incidence_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 froma binary incidence matrix.
INPUT:• points – (i.e. ground set, i.e. vertex set) the underlying set. If points is an integer 𝑣, then the set isconsidered to be {0, ..., 𝑣 − 1}.
Note: The following syntax, where points is omitted, automatically defines the ground set as the union of
the blocks:
sage: H = IncidenceStructure([[ a , b , c ],[ c , d , e ]])sage: sorted(H.ground_set())[ a , b , c , d , e ]>>> from sage.all import *>>> H = IncidenceStructure([[ a , b , c ],[ c , d , e ]])>>> sorted(H.ground_set())[ a , b , c , d , e ]• blocks – (i.e. edges, i.e. sets) the blocks defining the incidence structure. Can be any iterable.
• incidence_matrix – a binary incidence matrix. Each column represents a set.
• name (a string, such as “Fano plane”).
• check – whether to check the input• copy – (use with caution) if set to False then blocks must be a list of lists of integers. The list will not
be copied but will be modified in place (each block is sorted, and the whole list is sorted). Your blocks
object will become the IncidenceStructure instance’s internal data.
EXAMPLES:
An incidence structure can be constructed by giving the number of points and the list of blocks:

1510

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

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>>> from sage.all import *>>> IncidenceStructure(Integer(7), [[Integer(0),Integer(1),Integer(2)],
˓→[Integer(0),Integer(3),Integer(4)],[Integer(0),Integer(5),Integer(6)],
˓→[Integer(1),Integer(3),Integer(5)],[Integer(1),Integer(4),Integer(6)],
˓→[Integer(2),Integer(3),Integer(6)],[Integer(2),Integer(4),Integer(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>>> from sage.all import *>>> IncidenceStructure([[Integer(1),Integer(2),Integer(3)],[Integer(2),Integer(3),˓→Integer(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]])
˓→needs sage.modules
sage: IncidenceStructure(m)˓→needs sage.modules
Incidence structure with 4 points and 3 blocks#␣#␣>>> from sage.all import *>>> m = matrix([[Integer(0),Integer(1),Integer(0)],[Integer(0),Integer(0),˓→Integer(1)],[Integer(1),Integer(0),Integer(1)],[Integer(1),Integer(1),˓→Integer(1)]])# needs sage.modules>>> IncidenceStructure(m)˓→needs sage.modules
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 )]]>>> from sage.all import *>>> V = [(Integer(0), a ),(Integer(0), b ),(Integer(1), a ),(Integer(1), b )]>>> B = [(V[Integer(0)],V[Integer(1)],V[Integer(2)]), (V[Integer(1)],
˓→V[Integer(2)]), (V[Integer(0)],V[Integer(2)])]>>> I = IncidenceStructure(V, B)>>> I.ground_set()[(0, a ), (0, b ), (1, a ), (1, b )]>>> I.blocks()[[(0, a ), (0, b ), (1, a )], [(0, a ), (1, a )], [(0, b ), (1, a )]]4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1511

Graph Theory, Release 10.4

The order of the points and blocks does not matter as they are sorted on input (see Issue #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>>> from sage.all import *>>> A = IncidenceStructure([Integer(0),Integer(1),Integer(2)], [[Integer(0)],˓→[Integer(0),Integer(2)]])>>> B = IncidenceStructure([Integer(1),Integer(0),Integer(2)], [[Integer(0)],˓→[Integer(2),Integer(0)]])>>> B == A
True>>> C = BlockDesign(Integer(2), [[Integer(0)], [Integer(1),Integer(0)]])>>> D = BlockDesign(Integer(2), [[Integer(0),Integer(1)], [Integer(0)]])>>> C == DTrue

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>>> from sage.all import *>>> blocks = [[Integer(0),Integer(1)],[Integer(2),Integer(0)],[Integer(1),˓→Integer(2)]]# a list of lists of integers>>> I = IncidenceStructure(Integer(3), blocks, copy=False)>>> I._blocks is blocks
Trueautomorphism_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: # needs sage.groups sage.rings.finite_rings
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

1512

Chapter 4. Hypergraphs

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.groups sage.rings.finite_rings>>> P = designs.DesarguesianProjectivePlaneDesign(Integer(2)); P(7,3,1)-Balanced Incomplete Block Design>>> G = P.automorphism_group()>>> G.is_isomorphic(PGL(Integer(3),Integer(2)))
True
>>> G
Permutation Group with generators [...]>>> 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()
˓→needs sage.groups6
sage: IS.dual().automorphism_group().cardinality()
˓→needs sage.groups sage.modules
1

#␣

#␣

>>> from sage.all import *>>> IS = IncidenceStructure(list(range(Integer(4))), [[Integer(0),Integer(1),˓→Integer(2),Integer(3)],[Integer(1),Integer(2),Integer(3)]])>>> IS.automorphism_group().cardinality()#␣˓→needs sage.groups6>>> IS.dual().automorphism_group().cardinality()#␣˓→needs sage.groups sage.modules
1

Examples with non-integer points:
sage: I = IncidenceStructure( abc , ( ab , ac , bc ))sage: I.automorphism_group()
˓→needs sage.groups
Permutation Group with generators [( b , c ), ( a , b )]sage: IncidenceStructure([[(1,2),(3,4)]]).automorphism_group()
˓→needs sage.groups
Permutation Group with generators [((1,2),(3,4))]#␣#␣>>> from sage.all import *>>> I = IncidenceStructure( abc , ( ab , ac , bc ))>>> I.automorphism_group()#␣˓→needs sage.groups
Permutation Group with generators [( b , c ), ( a , b )]>>> IncidenceStructure([[(Integer(1),Integer(2)),(Integer(3),Integer(4))]]).
˓→automorphism_group()# needs sage.groups
Permutation Group with generators [((1,2),(3,4))]

block_sizes()
Return the set of block sizes.
EXAMPLES:

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1513

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> BD = IncidenceStructure(Integer(8), [[Integer(0),Integer(1),Integer(3)],
˓→[Integer(1),Integer(4),Integer(5),Integer(6)],[Integer(1),Integer(2)],
˓→[Integer(5),Integer(6),Integer(7)]])>>> BD.block_sizes()[3, 2, 4, 3]>>> BD = IncidenceStructure(Integer(7),[[Integer(0),Integer(1),Integer(2)],
˓→[Integer(0),Integer(3),Integer(4)],[Integer(0),Integer(5),Integer(6)],
˓→[Integer(1),Integer(3),Integer(5)],[Integer(1),Integer(4),Integer(6)],
˓→[Integer(2),Integer(3),Integer(6)],[Integer(2),Integer(4),Integer(5)]])>>> 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]]>>> from sage.all import *>>> BD = IncidenceStructure(Integer(7),[[Integer(0),Integer(1),Integer(2)],
˓→[Integer(0),Integer(3),Integer(4)],[Integer(0),Integer(5),Integer(6)],
˓→[Integer(1),Integer(3),Integer(5)],[Integer(1),Integer(4),Integer(6)],
˓→[Integer(2),Integer(3),Integer(6)],[Integer(2),Integer(4),Integer(5)]])>>> BD.blocks()[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]canonical_label()
Return a canonical label for the incidence structure.
A canonical label is relabeling of the points into integers {0, ..., 𝑛 − 1} such that isomorphic incidence structures are relabelled to equal objects.
EXAMPLES:
sage: # needs sage.schemes
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

1514

Chapter 4. Hypergraphs

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs sage.schemes>>> fano1 = designs.balanced_incomplete_block_design(Integer(7),Integer(3))>>> fano2 = designs.projective_plane(Integer(2))>>> fano1 == fano2
False>>> fano1.relabel(fano1.canonical_label())>>> fano2.relabel(fano2.canonical_label())>>> fano1 == fano2
Truecoloring(k, solver=None, verbose=None, integrality_tolerance=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 monochromatic.
INPUT:• k (integer) – compute a coloring with 𝑘 colors if an integer is provided, otherwise returns an optimalcoloring (i.e. with the minimum possible number of colors).
• solver – (default: None) Specify a Mixed Integer Linear Programming (MILP) solver to be used. If
set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – non-negative integer (default: 0). Set the level of verbosity you want from the linear program
solver. Since the problem is 𝑁 𝑃 -complete, its solving may take some time depending on the graph. A
value of 0 means that there will be no message printed by the solver.
• integrality_tolerance – parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
The Fano plane has chromatic number 3:
sage: len(designs.steiner_triple_system(7).coloring())
˓→needs sage.numerical.mip3#␣>>> from sage.all import *>>> len(designs.steiner_triple_system(Integer(7)).coloring())˓→# needs sage.numerical.mip
3␣

One admissible 3-coloring:sage: designs.steiner_triple_system(7).coloring()
˓→needs sage.numerical.mip[[0, 2, 5, 1], [4, 3], [6]]# not tested>>> from sage.all import *>>> designs.steiner_triple_system(Integer(7)).coloring()˓→# needs sage.numerical.mip[[0, 2, 5, 1], [4, 3], [6]]# not tested#␣␣The chromatic number of a graph is equal to the chromatic number of its 2-uniform corresponding hypergraph:4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1515

Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: H = IncidenceStructure(g.edges(sort=True, labels=False))
sage: len(g.coloring())
3
sage: len(H.coloring())
˓→needs sage.numerical.mip
3>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> H = IncidenceStructure(g.edges(sort=True, labels=False))>>> len(g.coloring())
3>>> len(H.coloring())
˓→needs sage.numerical.mip
3

#␣

#␣

complement(uniform=False)
Return the complement of the incidence structure.
Two different definitions of “complement” are made available, according to the value of uniform.
INPUT:• uniform (boolean) –– if set to False (default), returns the incidence structure whose blocks are the complements of all
blocks of the incidence structure.
– If set to True and the incidence structure is 𝑘-uniform, returns the incidence structure whose blocks
are all 𝑘-sets of the ground set that do not appear in self.
EXAMPLES:
The complement of a BalancedIncompleteBlockDesign is also a 2-design:
sage: bibd = designs.balanced_incomplete_block_design(13,4)
˓→needs sage.schemes
sage: bibd.is_t_design(return_parameters=True)
˓→needs sage.schemes(True, (2, 13, 4, 1))
sage: bibd.complement().is_t_design(return_parameters=True)
˓→needs sage.schemes(True, (2, 13, 9, 6))

#␣
#␣

#␣

>>> from sage.all import *>>> bibd = designs.balanced_incomplete_block_design(Integer(13),Integer(4)) ␣˓→# needs sage.schemes>>> bibd.is_t_design(return_parameters=True)#␣˓→needs sage.schemes(True, (2, 13, 4, 1))>>> bibd.complement().is_t_design(return_parameters=True)#␣˓→needs sage.schemes(True, (2, 13, 9, 6))

The “uniform” complement of a graph is a graph:

1516

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: G = IncidenceStructure(g.edges(sort=True, labels=False))
sage: H = G.complement(uniform=True)
sage: h = Graph(H.blocks())
sage: g == hFalse
sage: g == h.complement()True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> G = IncidenceStructure(g.edges(sort=True, labels=False))>>> H = G.complement(uniform=True)>>> h = Graph(H.blocks())>>> g == hFalse>>> 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)._nameTest>>> from sage.all import *>>> IS = IncidenceStructure([[Integer(1),Integer(2),Integer(3),"e"]],name=
˓→"Test")>>> IS
Incidence structure with 4 points and 1 blocks>>> copy(IS)Incidence structure with 4 points and 1 blocks>>> [Integer(1), Integer(2), Integer(3), e ] in copy(IS)True>>> copy(IS)._nameTestdegree(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:
4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1517

Graph Theory, Release 10.4

sage: designs.steiner_triple_system(9).degree(3)4sage: designs.steiner_triple_system(9).degree({1,2},subset=True)
1>>> from sage.all import *>>> designs.steiner_triple_system(Integer(9)).degree(Integer(3))
4>>> designs.steiner_triple_system(Integer(9)).degree({Integer(1),Integer(2)},˓→subset=True)1degrees(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 tuplesof 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}>>> from sage.all import *>>> IncidenceStructure([[Integer(1),Integer(2),Integer(3)],[Integer(1),˓→Integer(4)]]).degrees(Integer(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>>> from sage.all import *>>> S13 = designs.steiner_triple_system(Integer(13))>>> all(v == Integer(1) for v in S13.degrees(Integer(2)).values())
Truedual(algorithm=None)
Return the dual of the incidence structure.
INPUT:
1518

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

• 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)˓→needs sage.rings.finite_rings
sage: PP.dual().is_t_design(return_parameters=True)
˓→needs sage.modules sage.rings.finite_rings(True, (2, 21, 5, 1))>>> from sage.all import *>>> PP = designs.DesarguesianProjectivePlaneDesign(Integer(4))˓→# needs sage.rings.finite_rings>>> PP.dual().is_t_design(return_parameters=True)
˓→needs sage.modules sage.rings.finite_rings(True, (2, 21, 5, 1))

#␣
#␣

␣
#␣

REFERENCE:• Leonard Soicher, Design package manualedge_coloring()
Compute a proper edge-coloring.
A proper edge-coloring is an assignment of colors to the sets of the incidence structure such that two sets with
non-empty intersection receive different colors. The coloring returned minimizes the number of colors.
OUTPUT:
A partition of the sets into color classes.
EXAMPLES:
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
Incidence structure with 6 points and 4 blocks
sage: C = H.edge_coloring()sage: C # random[[[3, 4, 5]], [[2, 3, 4]], [[4, 5, 6], [1, 2, 3]]]sage: Set(map(Set,sum(C,[]))) == Set(map(Set,H.blocks()))
True>>> from sage.all import *>>> H = Hypergraph([{Integer(1),Integer(2),Integer(3)},{Integer(2),Integer(3),˓→Integer(4)},{Integer(3),Integer(4),Integer(5)},{Integer(4),Integer(5),˓→Integer(6)}]); H
Incidence structure with 6 points and 4 blocks>>> C = H.edge_coloring()>>> C # random[[[3, 4, 5]], [[2, 3, 4]], [[4, 5, 6], [1, 2, 3]]]>>> Set(map(Set,sum(C,[]))) == Set(map(Set,H.blocks()))
True

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1519

Graph Theory, Release 10.4

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]>>> from sage.all import *>>> IncidenceStructure(Integer(3), [[Integer(0),Integer(1)],[Integer(0),˓→Integer(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 ofground_set(), and appear in the same order. Similarly, the following vertices represent theelements 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()˓→needs sage.modules
Bipartite graph on 14 vertices
sage: A = BD.incidence_matrix()
˓→needs sage.modules
sage: Graph(block_matrix([[A*0, A],
˓→needs sage.modules....:[A.transpose(),A*0]])) == BD.incidence_graph()
True

#␣

#␣
#␣

>>> from sage.all import *>>> BD = IncidenceStructure(Integer(7), [[Integer(0),Integer(1),Integer(2)],
˓→[Integer(0),Integer(3),Integer(4)],[Integer(0),Integer(5),Integer(6)],
˓→[Integer(1),Integer(3),Integer(5)],...
[Integer(1),Integer(4),Integer(6)],
˓→[Integer(2),Integer(3),Integer(6)],[Integer(2),Integer(4),Integer(5)]])>>> BD.incidence_graph()#␣˓→needs sage.modules
Bipartite graph on 14 vertices>>> A = BD.incidence_matrix()#␣˓→needs sage.modules>>> Graph(block_matrix([[A*Integer(0), A],␣˓→# needs sage.modules...
[A.transpose(),A*Integer(0)]])) == BD.incidence_(continues on next page)

1520

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)graph()
True˓→

incidence_matrix()
Return the incidence matrix 𝐴 of the design. A is a (𝑣 × 𝑏) matrix defined by: A[i,j] = 1 if i is in block
B_j and 0 otherwise.
EXAMPLES:
sage: BD = 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()
˓→needs sage.modules[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()
˓→needs sage.modules[1 1 1 0][1 1 0 0][0 1 1 1]#␣>>> from sage.all import *>>> BD = IncidenceStructure(Integer(7), [[Integer(0),Integer(1),Integer(2)],
˓→[Integer(0),Integer(3),Integer(4)],[Integer(0),Integer(5),Integer(6)],
˓→[Integer(1),Integer(3),Integer(5)],...
[Integer(1),Integer(4),Integer(6)],
˓→[Integer(2),Integer(3),Integer(6)],[Integer(2),Integer(4),Integer(5)]])>>> BD.block_sizes()[3, 3, 3, 3, 3, 3, 3]>>> BD.incidence_matrix()#␣˓→needs sage.modules[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]>>> I = IncidenceStructure( abc , ( ab , abc , ac , c ))>>> I.incidence_matrix()
˓→needs sage.modules[1 1 1 0][1 1 0 0][0 1 1 1]#␣induced_substructure(points)
Return the substructure induced by a set of points.
4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1521

Graph Theory, Release 10.4

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>>> from sage.all import *>>> F = designs.steiner_triple_system(Integer(7))>>> F.induced_substructure((ellipsis_range(Integer(0),Ellipsis,Integer(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 thesize 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 regulargraph (when it is not trivial):
sage: BIBD = designs.balanced_incomplete_block_design(19,3)
sage: G = BIBD.intersection_graph(1)sage: G.is_strongly_regular(parameters=True)(57, 24, 11, 9)>>> from sage.all import *>>> BIBD = designs.balanced_incomplete_block_design(Integer(19),Integer(3))>>> G = BIBD.intersection_graph(Integer(1))>>> G.is_strongly_regular(parameters=True)(57, 24, 11, 9)

is_berge_cyclic()
Check whether self is a Berge-Cyclic uniform hypergraph.
A 𝑘-uniform Berge cycle (named after Claude Berge) of length ℓ is a cyclic list of distinct 𝑘-sets 𝐹1 , . . . , 𝐹ℓ ,ℓ > 1, and distinct vertices 𝐶 = {𝑣1 , . . . , 𝑣ℓ } such that for each 1 ≤ 𝑖 ≤ ℓ, 𝐹𝑖 contains 𝑣𝑖 and 𝑣𝑖+1 (where
𝑣𝑙+1 = 𝑣1 ).
A uniform hypergraph is Berge-cyclic if its incidence graph is cyclic. It is called “Berge-acyclic” otherwise.

1522

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

For more information, see [Fag1983] and Wikipedia article Hypergraph.
EXAMPLES:
sage: Hypergraph(5, [[1, 2, 3], [2, 3, 4]]).is_berge_cyclic()
˓→needs sage.modules
True
sage: Hypergraph(6, [[1, 2, 3], [3, 4, 5]]).is_berge_cyclic()
˓→needs sage.modules
False

#␣

#␣

>>> from sage.all import *>>> Hypergraph(Integer(5), [[Integer(1), Integer(2), Integer(3)], [Integer(2),˓→ Integer(3), Integer(4)]]).is_berge_cyclic()# needs sage.
˓→modules
True>>> Hypergraph(Integer(6), [[Integer(1), Integer(2), Integer(3)], [Integer(3),˓→ Integer(4), Integer(5)]]).is_berge_cyclic()# needs sage.
˓→modules
False

is_connected()
Test whether the design is connected.
EXAMPLES:
sage: IncidenceStructure(3, [[0,1],[0,2]]).is_connected()Truesage: IncidenceStructure(4, [[0,1],[2,3]]).is_connected()
False>>> from sage.all import *>>> IncidenceStructure(Integer(3), [[Integer(0),Integer(1)],[Integer(0),˓→Integer(2)]]).is_connected()
True>>> IncidenceStructure(Integer(4), [[Integer(0),Integer(1)],[Integer(2),˓→Integer(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 [BH2012], section 9.6):• two blocks intersect on at most one point.
• For every point 𝑝 not in a block 𝐵, there is a unique block 𝐵 ′ intersecting both {𝑝} and 𝐵
It is a regular generalized quadrangle if furthermore:• it is 𝑠 + 1-uniform for some positive integer 𝑠.
• it is 𝑡 + 1-regular for some positive integer 𝑡.
For more information, see the Wikipedia article Generalized_quadrangle.
Note: Some references (e.g. [PT2009] or Wikipedia article Generalized_quadrangle) only allow regular
generalized quadrangles. To use such a definition, see the parameters optional argument described below,
or the methods is_regular() and is_uniform().

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1523

Graph Theory, Release 10.4

INPUT:• verbose (boolean) – whether to print an explanation when the instance is not a generalized quadrangle.
• parameters (boolean; False) – if set to True, the function returns a pair (s,t) instead of True
answers. In this case, 𝑠 and 𝑡 are the integers defined above if they exist (each can be set to False
otherwise).
EXAMPLES:
sage: h = designs.CremonaRichmondConfiguration()
˓→needs networkx
sage: h.is_generalized_quadrangle()
˓→needs networkx
True

#␣
#␣

>>> from sage.all import *>>> h = designs.CremonaRichmondConfiguration()
˓→needs networkx>>> h.is_generalized_quadrangle()
˓→needs networkx
True

#␣
#␣

This is actually a regular generalized quadrangle:
sage: h.is_generalized_quadrangle(parameters=True)
˓→needs networkx(2, 2)#␣>>> from sage.all import *>>> h.is_generalized_quadrangle(parameters=True)
˓→needs networkx(2, 2)#␣is_isomorphic(other, certificate=False)
Return whether the two incidence structures are isomorphic.
INPUT:• other – an incidence structure.
• certificate (boolean) – whether to return an isomorphism from self to other instead of aboolean answer.
EXAMPLES:
sage: # needs sage.schemes
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}>>> from sage.all import *>>> # needs sage.schemes>>> fano1 = designs.balanced_incomplete_block_design(Integer(7),Integer(3))>>> fano2 = designs.projective_plane(Integer(2))>>> fano1.is_isomorphic(fano2)(continues on next page)1524

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)True>>> 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 asatisfied condition.
EXAMPLES:
sage: designs.balanced_incomplete_block_design(7,3).is_regular()˓→needs sage.schemes3
sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=3)˓→needs sage.schemes
True
sage: designs.balanced_incomplete_block_design(7,3).is_regular(r=4)
˓→needs sage.schemes
False

#␣

#␣

#␣

>>> from sage.all import *>>> designs.balanced_incomplete_block_design(Integer(7),Integer(3)).is_˓→regular()# needs sage.schemes3>>> designs.balanced_incomplete_block_design(Integer(7),Integer(3)).is_˓→regular(r=Integer(3))# needs sage.schemes
True>>> designs.balanced_incomplete_block_design(Integer(7),Integer(3)).is_˓→regular(r=Integer(4))# needs sage.schemes
False

is_resolvable(certificate, solver=False, verbose=None, check=0, integrality_tolerance=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 partitionof the ground set.
Note: This problem is solved using an Integer Linear Program, and GLPK (the default LP solver) has beenreported to be very slow on some instances. If you hit this wall, consider installing a more powerful MILP
solver (CPLEX, Gurobi, …).
INPUT:
4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1525

Graph Theory, Release 10.4

• certificate (boolean) – whether to return the classes along with the binary answer (see examples
below).
• solver – (default: None) Specify a Mixed Integer Linear Programming (MILP) solver to be used. If
set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
• check (boolean) – whether to check that output is correct before returning it. As this is expected to beuseless (but we are cautious guys), you may want to disable it whenever you want speed. Set to Trueby default.
• integrality_tolerance – parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
Some resolvable designs:
sage: TD = designs.transversal_design(2,2,resolvable=True)
sage: TD.is_resolvable()True
sage: AG = designs.AffineGeometryDesign(3,1,GF(2))˓→needs sage.combinat
sage: AG.is_resolvable()
˓→needs sage.combinat
True

#␣
#␣

>>> from sage.all import *>>> TD = designs.transversal_design(Integer(2),Integer(2),resolvable=True)>>> TD.is_resolvable()
True>>> AG = designs.AffineGeometryDesign(Integer(3),Integer(1),GF(Integer(2))) ␣˓→# needs sage.combinat>>> AG.is_resolvable()#␣˓→needs sage.combinat
True

Their classes:
sage: b, cls = TD.is_resolvable(True)
sage: bTrue
sage: cls # random[[[0, 3], [1, 2]], [[1, 3], [0, 2]]]sage: # needs sage.combinat
sage: b, cls = AG.is_resolvable(True)
sage: bTrue
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]],
(continues on next page)

1526

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)[[0, 6], [2, 7], [1, 4], [3, 5]],[[4, 6], [0, 3], [2, 5], [1, 7]]]>>> from sage.all import *>>> b, cls = TD.is_resolvable(True)
>>> b
True
>>> cls # random[[[0, 3], [1, 2]], [[1, 3], [0, 2]]]>>> # needs sage.combinat>>> b, cls = AG.is_resolvable(True)
>>> b
True
>>> 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)˓→needs sage.schemes
sage: Fano.is_resolvable()
˓→needs sage.schemes
False
sage: Fano.is_resolvable(True)
˓→needs sage.schemes(False, [])

#␣
#␣

#␣

>>> from sage.all import *>>> Fano = designs.balanced_incomplete_block_design(Integer(7),Integer(3))␣˓→# needs sage.schemes>>> Fano.is_resolvable()#␣˓→needs sage.schemes
False>>> Fano.is_resolvable(True)#␣˓→needs sage.schemes(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]]](continues on next page)

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1527

Graph Theory, Release 10.4

(continued from previous page)

sage: I = IncidenceStructure(V, B)
sage: I.is_simple()True
sage: I2 = IncidenceStructure(V, B*2)
sage: I2.is_simple()
False>>> from sage.all import *>>> IncidenceStructure(Integer(3), [[Integer(0),Integer(1)],[Integer(1),˓→Integer(2)],[Integer(0),Integer(2)]]).is_simple()
True>>> IncidenceStructure(Integer(3), [[Integer(0)],[Integer(0)]]).is_simple()
False>>> V = [(Integer(0), a ),(Integer(0), b ),(Integer(1), a ),(Integer(1), b )]>>> B = [[V[Integer(0)],V[Integer(1)]], [V[Integer(1)],V[Integer(2)]]]>>> I = IncidenceStructure(V, B)>>> I.is_simple()
True>>> I2 = IncidenceStructure(V, B*Integer(2))>>> I2.is_simple()False

is_spread(spread)
Check whether the input is a spread for self.
A spread of an incidence structure (𝑃, 𝐵) is a subset of 𝐵 which forms a partition of 𝑃 .
INPUT:• spread – iterable; defines the spread
EXAMPLES:
sage: E = IncidenceStructure([[1, 2, 3], [4, 5, 6], [1, 5, 6]])sage: E.is_spread([[1, 2, 3], [4, 5, 6]])True
sage: E.is_spread([1, 2, 3, 4, 5, 6])
Traceback (most recent call last):...
TypeError: sage.rings.integer.Integer object is not iterable
sage: E.is_spread([[1, 2, 3, 4], [5, 6]])False>>> from sage.all import *>>> E = IncidenceStructure([[Integer(1), Integer(2), Integer(3)], [Integer(4),˓→ Integer(5), Integer(6)], [Integer(1), Integer(5), Integer(6)]])>>> E.is_spread([[Integer(1), Integer(2), Integer(3)], [Integer(4),␣
˓→Integer(5), Integer(6)]])
True>>> E.is_spread([Integer(1), Integer(2), Integer(3), Integer(4), Integer(5),␣
˓→Integer(6)])
Traceback (most recent call last):...
TypeError: sage.rings.integer.Integer object is not iterable>>> E.is_spread([[Integer(1), Integer(2), Integer(3), Integer(4)],␣
(continues on next page)

1528

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)[Integer(5), Integer(6)]])
False
˓→

Order of blocks or of points within each block doesn’t matter:
sage: E = IncidenceStructure([[1, 2, 3], [4, 5, 6], [1, 5, 6]])sage: E.is_spread([[5, 6, 4], [3, 1, 2]])True>>> from sage.all import *>>> E = IncidenceStructure([[Integer(1), Integer(2), Integer(3)], [Integer(4),˓→ Integer(5), Integer(6)], [Integer(1), Integer(5), Integer(6)]])>>> E.is_spread([[Integer(5), Integer(6), Integer(4)], [Integer(3),␣
˓→Integer(1), Integer(2)]])
True

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𝑡 − (𝑣, 𝑘, 𝑙) design using the provided values and guesses the others. Note that l 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()
Truesage: 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))˓→needs sage.combinat
sage: BD.is_t_design(1)#␣#␣(continues on next page)

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1529

Graph Theory, Release 10.4

(continued from previous page)needs sage.combinat
Truesage: BD.is_t_design(2)˓→needs sage.combinat
True
˓→

#␣

>>> from sage.all import *>>> fano_blocks = [[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(3),˓→Integer(4)],[Integer(0),Integer(5),Integer(6)],[Integer(1),Integer(3),˓→Integer(5)],[Integer(1),Integer(4),Integer(6)],[Integer(2),Integer(3),˓→Integer(6)],[Integer(2),Integer(4),Integer(5)]]>>> BD = IncidenceStructure(Integer(7), fano_blocks)>>> BD.is_t_design()
True>>> BD.is_t_design(return_parameters=True)(True, (2, 7, 3, 1))>>> BD.is_t_design(Integer(2), Integer(7), Integer(3), Integer(1))
True>>> BD.is_t_design(Integer(1), Integer(7), Integer(3), Integer(3))
True>>> BD.is_t_design(Integer(0), Integer(7), Integer(3), Integer(7))
True>>> BD.is_t_design(Integer(0),Integer(6),Integer(3),Integer(7)) or BD.is_t_
˓→design(Integer(0),Integer(7),Integer(4),Integer(7)) or BD.is_t_
˓→design(Integer(0),Integer(7),Integer(3),Integer(8))
False>>> BD = designs.AffineGeometryDesign(Integer(3), Integer(1), GF(Integer(2)))␣
˓→# needs sage.combinat>>> BD.is_t_design(Integer(1))␣˓→# needs sage.combinat
True>>> BD.is_t_design(Integer(2))␣˓→# needs sage.combinat
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
sage: blocks = designs.steiner_quadruple_system(14)sage: S4_14 = IncidenceStructure(14, blocks)
sage: S4_14.is_t_design(3,14,4,1)
True>>> from sage.all import *>>> S3_9 = designs.steiner_triple_system(Integer(9))>>> S3_9.is_t_design(Integer(2),Integer(9),Integer(3),Integer(1))(continues on next page)

1530

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)True>>> blocks = designs.steiner_quadruple_system(Integer(8))>>> S4_8 = IncidenceStructure(Integer(8), blocks)>>> S4_8.is_t_design(Integer(3),Integer(8),Integer(4),Integer(1))
True>>> blocks = designs.steiner_quadruple_system(Integer(14))>>> S4_14 = IncidenceStructure(Integer(14), blocks)>>> S4_14.is_t_design(Integer(3),Integer(14),Integer(4),Integer(1))
True

Some examples of Witt designs that need the gap database:sage: # optional - gap_package_design
sage: BD = designs.WittDesign(9)sage: BD.is_t_design(2,9,3,1)
True
sage: W12 = designs.WittDesign(12)sage: W12.is_t_design(5,12,6,1)
True
sage: W12.is_t_design(4)True>>> from sage.all import *>>> # optional - gap_package_design>>> BD = designs.WittDesign(Integer(9))>>> BD.is_t_design(Integer(2),Integer(9),Integer(3),Integer(1))
True>>> W12 = designs.WittDesign(Integer(12))>>> W12.is_t_design(Integer(5),Integer(12),Integer(6),Integer(1))
True>>> W12.is_t_design(Integer(4))
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))

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1531

Graph Theory, Release 10.4>>> from sage.all import *>>> D = IncidenceStructure(Integer(4),[[],[]])>>> D.is_t_design(return_parameters=True)(True, (0, 4, 0, 2))>>> D = IncidenceStructure(Integer(4), [[Integer(0),Integer(1)],[Integer(0),˓→Integer(2)],[Integer(0),Integer(3)]])>>> D.is_t_design(return_parameters=True)(True, (0, 4, 2, 3))>>> D = IncidenceStructure(Integer(4), [[Integer(0)],[Integer(1)],
˓→[Integer(2)],[Integer(3)]])>>> D.is_t_design(return_parameters=True)(True, (1, 4, 1, 1))>>> D = IncidenceStructure(Integer(4),[[Integer(0),Integer(1)],[Integer(2),˓→Integer(3)]])>>> D.is_t_design(return_parameters=True)(True, (1, 4, 2, 1))>>> D = IncidenceStructure(Integer(4), [list(range(Integer(4)))])>>> 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 asatisfied condition.
EXAMPLES:
sage: designs.balanced_incomplete_block_design(7,3).is_uniform()
˓→needs sage.schemes3
sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=3)˓→needs sage.schemes
True
sage: designs.balanced_incomplete_block_design(7,3).is_uniform(k=4)˓→needs sage.schemes
False

#␣

#␣

#␣

>>> from sage.all import *>>> designs.balanced_incomplete_block_design(Integer(7),Integer(3)).is_
˓→uniform()# needs sage.schemes
3(continues on next page)

1532

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)>>> designs.balanced_incomplete_block_design(Integer(7),Integer(3)).is_
˓→uniform(k=Integer(3))# needs sage.schemes
True>>> designs.balanced_incomplete_block_design(Integer(7),Integer(3)).is_
˓→uniform(k=Integer(4))# needs sage.schemes
False

isomorphic_substructures_iterator(H2, induced=False)
Iterates over all copies of H2 contained in self.
A hypergraph 𝐻1 contains an isomorphic copy of a hypergraph 𝐻2 if there exists an injection 𝑓 : 𝑉 (𝐻2 ) ↦→𝑉 (𝐻1 ) such that for any set 𝑆2 ∈ 𝐸(𝐻2 ) the set 𝑆1 = 𝑓 (𝑆2) belongs to 𝐸(𝐻1 ).
It is an induced copy if no other set of 𝐸(𝐻1 ) is contained in 𝑓 (𝑉 (𝐻2 )), i.e. |𝐸(𝐻2 )| = {𝑆 : 𝑆 ∈𝐸(𝐻1 ) and 𝑓 (𝑉 (𝐻2 ))}.
This function lists all such injections. In particular, the number of copies of 𝐻 in itself is equal to the size of
its automorphism group.
See subhypergraph_search for more information.
INPUT:• H2 an IncidenceStructure object.
• induced (boolean) – whether to require the copies to be induced. Set to False by default.
EXAMPLES:
How many distinct 𝐶5 in Petersen’s graph ?
sage: P = graphs.PetersenGraph()
sage: C = graphs.CycleGraph(5)sage: IP = IncidenceStructure(P.edges(sort=True, labels=False))
sage: IC = IncidenceStructure(C.edges(sort=True, labels=False))
sage: sum(1 for _ in IP.isomorphic_substructures_iterator(IC))
120>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> C = graphs.CycleGraph(Integer(5))>>> IP = IncidenceStructure(P.edges(sort=True, labels=False))>>> IC = IncidenceStructure(C.edges(sort=True, labels=False))>>> sum(Integer(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 checkthat 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(sort=True,␣
˓→labels=False))>>> from sage.all import *>>> for f in IP.isomorphic_substructures_iterator(IC):...
assert all(P.has_edge(f[x],f[y]) for x,y in C.edges(sort=True,␣
˓→labels=False))

The number of induced copies, in this case, is the same:
4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1533

Graph Theory, Release 10.4

sage: sum(1 for _ in IP.isomorphic_substructures_iterator(IC,induced=True))120>>> from sage.all import *>>> sum(Integer(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(sort=True, labels=False))
sage: IC = IncidenceStructure(C.edges(sort=True, 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>>> from sage.all import *>>> P.add_edges([(Integer(0),x) for x in P], loops=False)>>> IP = IncidenceStructure(P.edges(sort=True, labels=False))>>> IC = IncidenceStructure(C.edges(sort=True, labels=False))>>> sum(Integer(1) for _ in IP.isomorphic_substructures_iterator(IC))
420>>> sum(Integer(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:sage: H = designs.projective_plane(3)˓→needs sage.schemes
sage: sum(1 for _ in H.isomorphic_substructures_iterator(H))˓→needs sage.schemes
5616
sage: H.automorphism_group().cardinality()
˓→needs sage.groups sage.schemes
5616

#␣
#␣

#␣

>>> from sage.all import *>>> H = designs.projective_plane(Integer(3))˓→# needs sage.schemes>>> sum(Integer(1) for _ in H.isomorphic_substructures_iterator(H))˓→# needs sage.schemes
5616>>> H.automorphism_group().cardinality()
˓→needs sage.groups sage.schemes
5616

␣
␣

#␣

num_blocks()
Return the number of blocks.
EXAMPLES:
sage: designs.DesarguesianProjectivePlaneDesign(2).num_blocks()
7(continues on next page)

1534

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)

sage: B = IncidenceStructure(4, [[0,1],[0,2],[0,3],[1,2], [1,2,3]])
sage: B.num_blocks()
5>>> from sage.all import *>>> designs.DesarguesianProjectivePlaneDesign(Integer(2)).num_blocks()
7>>> B = IncidenceStructure(Integer(4), [[Integer(0),Integer(1)],[Integer(0),˓→Integer(2)],[Integer(0),Integer(3)],[Integer(1),Integer(2)], [Integer(1),˓→Integer(2),Integer(3)]])>>> B.num_blocks()
5

num_points()
Return the size of the ground set.
EXAMPLES:
sage: designs.DesarguesianProjectivePlaneDesign(2).num_points()
7sage: B = IncidenceStructure(4, [[0,1],[0,2],[0,3],[1,2], [1,2,3]])
sage: B.num_points()
4>>> from sage.all import *>>> designs.DesarguesianProjectivePlaneDesign(Integer(2)).num_points()
7>>> B = IncidenceStructure(Integer(4), [[Integer(0),Integer(1)],[Integer(0),˓→Integer(2)],[Integer(0),Integer(3)],[Integer(1),Integer(2)], [Integer(1),˓→Integer(2),Integer(3)]])>>> B.num_points()
4packing(solver, verbose=None, integrality_tolerance=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 Mixed Integer Linear Programming (MILP) solver to be used. If
set to None, the default one is used. For more information on LP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0). Sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
sage: P = IncidenceStructure([[1,2],[3,4],[2,3]]).packing()
˓→needs sage.numerical.mip#␣(continues on next page)

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1535

Graph Theory, Release 10.4

(continued from previous page)

sage: sorted(sorted(b) for b in P)
˓→needs sage.numerical.mip[[1, 2], [3, 4]]
sage: len(designs.steiner_triple_system(9).packing())
˓→needs sage.numerical.mip
3

#␣

#␣

>>> from sage.all import *>>> P = IncidenceStructure([[Integer(1),Integer(2)],[Integer(3),Integer(4)],
˓→[Integer(2),Integer(3)]]).packing()# needs sage.numerical.
˓→mip>>> sorted(sorted(b) for b in P)#␣˓→needs sage.numerical.mip[[1, 2], [3, 4]]>>> len(designs.steiner_triple_system(Integer(9)).packing())␣˓→# needs sage.numerical.mip
3

rank()
Return the rank of the hypergraph (the maximum size of a block).
EXAMPLES:
sage: h = Hypergraph(8, [[0,1,3],[1,4,5,6],[1,2]])
sage: h.rank()
4>>> from sage.all import *>>> h = Hypergraph(Integer(8), [[Integer(0),Integer(1),Integer(3)],
˓→[Integer(1),Integer(4),Integer(5),Integer(6)],[Integer(1),Integer(2)]])>>> 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], thesecond to l[1], …
– None – the incidence structure is relabeled to be on {0, 1, ..., 𝑛 − 1} in the ordering given byground_set().
• inplace – If True then return a relabeled graph and does not touch self (default is False).
EXAMPLES:
sage: # needs sage.schemes
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 ,n , o , p , q , r , s , t , u , v , w , x ,

l ,
y ]

m ,
(continues on next page)

1536

Chapter 4. Hypergraphs

Graph Theory, Release 10.4

(continued from previous page)

sage: TD.blocks()[:3][[ a , f , k , p ,˓→ ]]u ], [ a ,

g ,

m ,

s ,

y ], [ a ,

h ,

o ,

>>> from sage.all import *>>> # needs sage.schemes>>> TD = designs.transversal_design(Integer(5),Integer(5))>>> TD.relabel({i: chr(Integer(97)+i) for i in range(Integer(25))})>>> 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 ]>>> TD.blocks()[:Integer(3)][[ a , f , k , p , u ], [ a , g , m , s , y ], [ a , h , o ,
˓→ ]]

q ,

x

q ,

x

Relabel to integer points:
sage: TD.relabel()
˓→needs sage.schemes
sage: TD.blocks()[:3]
˓→needs sage.schemes[[0, 5, 10, 15, 20], [0, 6, 12, 18, 24], [0, 7, 14, 16, 23]]#␣#␣>>> from sage.all import *>>> TD.relabel()
˓→needs sage.schemes>>> TD.blocks()[:Integer(3)]˓→# needs sage.schemes[[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:
sage: # needs sage.schemes
sage: P4 = designs.projective_plane(4)sage: F = designs.projective_plane(2)sage: for x in Subsets(P4.ground_set(),7):(continues on next page)

4.2. Incidence structures (i.e. hypergraphs, i.e. set systems)

1537

Graph Theory, Release 10.4

(continued from previous page)....: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>>> from sage.all import *>>> # needs sage.schemes>>> P4 = designs.projective_plane(Integer(4))>>> F = designs.projective_plane(Integer(2))>>> for x in Subsets(P4.ground_set(),Integer(7)):...
if P4.trace(x,min_size=Integer(2)).is_isomorphic(F):
...
break
>>> subplane = P4.trace(x,min_size=Integer(2)); subplane
Incidence structure with 7 points and 7 blocks>>> subplane.is_isomorphic(F)
True

1538

Chapter 4. Hypergraphs

CHAPTERFIVE

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()
first_coloring()
number_of_n_colorings()
numbers_of_colorings()
chromatic_number()vertex_coloring()

Compute all 𝑛-colorings a graph
Return the first vertex coloring foundCompute the number of 𝑛-colorings of a graph
Compute the number of colorings of a graph
Return the chromatic number of the graph
Compute vertex colorings and chromatic numbers

Fractional relaxations
fractional_chromatic_number()fractional_chromatic_index()

Return the fractional chromatic number of the graph
Return the fractional chromatic index of the graph

Other colorings
grundy_coloring()
b_coloring()
edge_coloring()round_robin()linear_arboricity()
acyclic_edge_coloring()

Compute Grundy numbers and Grundy colorings
Compute b-chromatic numbers and b-colorings
Compute chromatic index and edge colorings
Compute a round-robin coloring of the complete graph on 𝑛 vertices
Compute the linear arboricity of the given graph
Compute 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
1539

Graph Theory, Release 10.4

5.1.1 Methods
class sage.graphs.graph_coloring.Test
Bases: object
This class performs randomized testing for all_graph_colorings().
Since everything else in this file is derived from all_graph_colorings(), this is a pretty good randomized
tester for the entire file. Note that for a graph 𝐺, G.chromatic_polynomial() uses an entirely different
algorithm, so we provide a good, independent test.
random(tests=1000)
Call self.random_all_graph_colorings().
In the future, if other methods are added, it should call them, too.
random_all_graph_colorings(tests=2)
Verify the results of all_graph_colorings() in three ways:
1. all colorings are unique
2. number of m-colorings is 𝑃 (𝑚) (where 𝑃 is the chromatic polynomial of the graph being tested)
3. colorings are valid – that is, that no two vertices of the same color share an edge.
sage.graphs.graph_coloring.acyclic_edge_coloring(g, hex_colors=False, value_only=False,
k=0, solver=None, verbose=0,
integrality_tolerance=0.001)
Compute an acyclic edge coloring of the current graph.
An edge coloring of a graph is a assignment of colors to the edges of a graph such that :• the coloring is proper (no adjacent edges share a color)• For any two colors 𝑖, 𝑗, the union of the edges colored with 𝑖 or 𝑗 is a forest.
The least number of colors such that such a coloring exists for a graph 𝐺 is written 𝜒′𝑎 (𝐺), also called the acyclic
chromatic index of 𝐺.
It is conjectured that this parameter cannot be too different from the obvious lower bound Δ(𝐺) ≤ 𝜒′𝑎 (𝐺), Δ(𝐺)being the maximum degree of 𝐺, which is given by the first of the two constraints. Indeed, it is conjectured that
Δ(𝐺) ≤ 𝜒′𝑎 (𝐺) ≤ Δ(𝐺) + 2.
INPUT:• hex_colors – boolean (default: False):– If hex_colors = True, the function returns a dictionary associating to each color a list of edges(meant as an argument to the edge_colors keyword of the plot method).
– If hex_colors = False (default value), returns a list of graphs corresponding to each color class.
• value_only – boolean (default: False):– If value_only = True, only returns the acyclic chromatic index as an integer value– If value_only = False, returns the color classes according to the value of hex_colors• k – integer; the number of colors to use.
– If k > 0, computes an acyclic edge coloring using 𝑘 colors.
– If k = 0 (default), computes a coloring of 𝐺 into Δ(𝐺) + 2 colors, which is the conjectured generalbound.

1540

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

– If k = None, computes a decomposition using the least possible number of colors.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Linear Programming
EXAMPLES:
The complete graph on 8 vertices cannot be acyclically edge-colored with less Δ + 1 colors, but it can be coloredwith Δ + 2 = 9:sage: from sage.graphs.graph_coloring import acyclic_edge_coloringsage: g = graphs.CompleteGraph(8)sage: colors = acyclic_edge_coloring(g)˓→needs sage.numerical.mip>>> from sage.all import *>>> from sage.graphs.graph_coloring import acyclic_edge_coloring>>> g = graphs.CompleteGraph(Integer(8))>>> colors = acyclic_edge_coloring(g)˓→needs sage.numerical.mip#␣#␣Each color class is of course a matchingsage: all(max(gg.degree()) <= 1 for gg in colors)
˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> all(max(gg.degree()) <= Integer(1) for gg in colors)˓→# needs sage.numerical.mip
True␣

These matchings being a partition of the edge set:sage: all(any(gg.has_edge(e) for gg in colors)
˓→needs sage.numerical.mip....:
for e in g.edge_iterator(labels=False))
True>>> from sage.all import *>>> all(any(gg.has_edge(e) for gg in colors)
˓→needs sage.numerical.mip...
for e in g.edge_iterator(labels=False))
True

#␣

#␣

Besides, the union of any two of them is a forest

5.1. Graph coloring

1541

Graph Theory, Release 10.4

sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors)
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> all(g1.union(g2).is_forest() for g1 in colors for g2 in colors)
˓→needs sage.numerical.mip
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)
˓→needs sage.numerical.mip
Traceback (most recent call last):...
ValueError: this graph cannot be colored with the given number of colors#␣>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(4))>>> acyclic_edge_coloring(g, k=Integer(2))˓→# needs sage.numerical.mip
Traceback (most recent call last):...
ValueError: this graph cannot be colored with the given number of colors

␣

The optimal coloring give us 3 classes:
sage: colors = acyclic_edge_coloring(g, k=None)˓→needs sage.numerical.mip
sage: len(colors)
˓→needs sage.numerical.mip
3>>> from sage.all import *>>> colors = acyclic_edge_coloring(g, k=None)˓→needs sage.numerical.mip>>> len(colors)
˓→needs sage.numerical.mip
3

#␣
#␣

#␣
#␣

sage.graphs.graph_coloring.all_graph_colorings(G, n, count_only=False, hex_colors=False,vertex_color_dict=False, color_classes=False)
Compute all 𝑛-colorings of a graph.
This method casts the graph coloring problem into an exact cover problem, and passes this into an implementationof 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• count_only – boolean (default: False); when set to True, it returns 1 for each coloring and ignores
other parameters

1542

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• hex_colors – boolean (default: False); when set to False, colors are labeled [0, 1, …, 𝑛−1], otherwise
the RGB Hex labeling is used• vertex_color_dict – boolean (default: False); when set to True, it returns a dictionary {vertex:
color}, otherwise it returns a dictionary {color: [list of vertices]}• color_classes – boolean (default: False); when set to True, the method returns only a list of thecolor classes and ignores parameters hex_colors and vertex_color_dict
Warning: This method considers only colorings using exactly 𝑛 colors, even if a coloring using fewer colors
can be found.
The construction works as follows. Columns:• The first |𝑉 | columns correspond to a vertex – a 1 in this column indicates that this vertex has a color.
• After those |𝑉 | columns, we add 𝑛 * |𝐸| columns – a 1 in these columns indicate that a particular edge isincident 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, anda 1 in the appropriate column for each edge incident to the vertex, indicating that that edge is incident to thecolor 𝑐.
• 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):
˓→needs sage.plot....:
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)
˓→needs sage.plot
G has 12 3-colorings.

5.1. Graph coloring

#␣

#␣

1543

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_coloring import all_graph_colorings>>> G = Graph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(1):␣
˓→[Integer(2)]})>>> n = Integer(0)>>> for C in all_graph_colorings(G, Integer(3), hex_colors=True):␣˓→# needs sage.plot...
parts = [C[k] for k in C]...
for P in parts:...
l = len(P)...
for i in range(l):...
for j in range(i + Integer(1), l):...
if G.has_edge(P[i], P[j]):...
raise RuntimeError("Coloring Failed.")...
n += Integer(1)>>> print("G has %s 3-colorings." % n)#␣˓→needs sage.plot
G has 12 3-colorings.

sage.graphs.graph_coloring.b_coloring(g, k, value_only=True, solver=None, verbose=0,
integrality_tolerance=0.001)
Compute b-chromatic numbers and b-colorings.
This function computes a b-coloring with at most 𝑘 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 othercolor 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 beeliminated with the same idea. So, one can define a b-coloring as a proper coloring where each color class has ab-vertex.
In the worst case, after successive applications of the above procedure, one get a proper coloring that uses a numberof colors equal to the b-chromatic number of 𝐺 (denoted 𝜒𝑏 (𝐺)): the maximum 𝑘 such that 𝐺 admits a b-coloringwith 𝑘 colors.
A useful upper bound for calculating the b-chromatic number is the following. If 𝐺 admits a b-coloring with𝑘 colors, then there are 𝑘 vertices of degree at least 𝑘 − 1 (the b-vertices of each color class). So, if we set
𝑚(𝐺) = max{𝑘|there are 𝑘 vertices of degree at least 𝑘 − 1}, we have that 𝜒𝑏 (𝐺) ≤ 𝑚(𝐺).
Note: This method computes a b-coloring that uses at MOST 𝑘 colors. If this method returns a value equal to 𝑘,
it cannot be assumed that 𝑘 is equal to 𝜒𝑏 (𝐺). Meanwhile, if it returns any value 𝑘 ′ < 𝑘, this is a certificate that
the Grundy number of the given graph is 𝑘 ′ .
As 𝜒𝑏 (𝐺) ≤ 𝑚(𝐺), it can be assumed that 𝜒𝑏 (𝐺) = 𝑘 if b_coloring(g, k) returns 𝑘 when 𝑘 = 𝑚(𝐺).
INPUT:• k – integer; maximum number of colors• value_only – boolean (default: True); when set to True, only the number of colors is returned. Otherwise, the pair (nb_colors, coloring) is returned, where coloring is a dictionary associating its
color (integer) to each vertex of the graph.

1544

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Integer Linear Program.
EXAMPLES:
The b-chromatic number of a 𝑃5 is equal to 3:
sage: from sage.graphs.graph_coloring import b_coloringsage: g = graphs.PathGraph(5)sage: b_coloring(g, 5)
˓→needs sage.numerical.mip
3>>> from sage.all import *>>> from sage.graphs.graph_coloring import b_coloring>>> g = graphs.PathGraph(Integer(5))>>> b_coloring(g, Integer(5))˓→# needs sage.numerical.mip
3

#␣

␣

The b-chromatic number of the Petersen Graph is equal to 3:
sage: g = graphs.PetersenGraph()
sage: b_coloring(g, 5)
˓→needs sage.numerical.mip
3>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> b_coloring(g, Integer(5))˓→# needs sage.numerical.mip
3

#␣

␣

It would have been sufficient to set the value of k to 4 in this case, as 4 = 𝑚(𝐺).
sage.graphs.graph_coloring.chromatic_number(G)Return the chromatic number of the graph.
The chromatic number is the minimal number of colors needed to color the vertices of the graph 𝐺.
EXAMPLES:
sage: from sage.graphs.graph_coloring import chromatic_number
sage: G = Graph({0: [1, 2, 3], 1: [2]})sage: chromatic_number(G)3sage: G = graphs.PetersenGraph()
sage: G.chromatic_number()3

5.1. Graph coloring

1545

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_coloring import chromatic_number>>> G = Graph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(1):␣
˓→[Integer(2)]})>>> chromatic_number(G)3>>> G = graphs.PetersenGraph()>>> G.chromatic_number()3

sage.graphs.graph_coloring.edge_coloring(g, value_only=False, vizing=False, hex_colors=False,
solver=None, verbose=0, integrality_tolerance=0.001)
Compute chromatic index and edge colorings.
INPUT:• g – a graph.
• value_only – boolean (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 – boolean (default: False):– When set to True, finds an edge coloring using the algorithm described at [MG1992]. This always
results in a coloring with Δ + 1 colors, where Δ is equal to the maximum degree in the graph, even if
one of the colors is empty, for the sake of consistency.
– When set to False, tries to find a Δ-edge-coloring using Mixed Integer Linear Programming (MILP).
If impossible, returns a (Δ + 1)-edge-coloring. Please note that determinating if the chromatic index ofa graph equals Δ is computationally difficult, and could take a long time.
• hex_colors – boolean (default: False); when set to True, the partition returned is a dictionary whose
keys are colors and whose values are the color classes (ideal for plotting)• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
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 numberof matchings.
• If vizing=True and value_only=True, should return something, but mainly you are just trying tocompute 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.

1546

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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:
sage: # needs sage.numerical.mip
sage: from sage.graphs.graph_coloring import edge_coloringsage: g = graphs.PetersenGraph()
sage: edge_coloring(g, value_only=True, solver= GLPK )4
sage: color_classes = edge_coloring(g, value_only=False, solver= GLPK )sage: len(color_classes)
4
sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size()
True
sage: all(g.has_edge(e) for C in color_classes for e in C)
True
sage: all(len(Graph(C).matching()) == len(C) for C in color_classes)
˓→needs networkx
True
sage: color_classes = edge_coloring(g, value_only=False,....:
hex_colors=True, solver= GLPK )sage: sorted(color_classes.keys())[ #00ffff , #7f00ff , #7fff00 , #ff0000 ]>>> from sage.all import *>>> # needs sage.numerical.mip>>> from sage.graphs.graph_coloring import edge_coloring>>> g = graphs.PetersenGraph()>>> edge_coloring(g, value_only=True, solver= GLPK )4>>> color_classes = edge_coloring(g, value_only=False, solver= GLPK )>>> len(color_classes)
4>>> len(set(frozenset(e) for C in color_classes for e in C)) == g.size()True>>> all(g.has_edge(e) for C in color_classes for e in C)
True>>> all(len(Graph(C).matching()) == len(C) for C in color_classes)
˓→needs networkx
True>>> color_classes = edge_coloring(g, value_only=False,#␣#␣(continues on next page)

5.1. Graph coloring

1547

Graph Theory, Release 10.4

(continued from previous page)...
hex_colors=True, solver= GLPK )>>> sorted(color_classes.keys())[ #00ffff , #7f00ff , #7fff00 , #ff0000 ]Complete graphs are colored using the linear-time round-robin coloring:sage: from sage.graphs.graph_coloring import edge_coloringsage: len(edge_coloring(graphs.CompleteGraph(20)))
˓→needs sage.numerical.mip
19#␣>>> from sage.all import *>>> from sage.graphs.graph_coloring import edge_coloring>>> len(edge_coloring(graphs.CompleteGraph(Integer(20))))˓→# needs sage.numerical.mip
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)
˓→needs sage.numerical.mip
9>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4)) + graphs.CompleteGraph(Integer(10))>>> edge_coloring(g, value_only=True)
˓→needs sage.numerical.mip
9

#␣

#␣

sage.graphs.graph_coloring.first_coloring(G, n=0, hex_colors=False)
Return the first vertex coloring found.
If a natural number 𝑛 is provided, returns the first found coloring with at least 𝑛 colors. That is, 𝑛 is a lower boundon the number of colors to use.
INPUT:• n – integer (default: 0); the minimal number of colors to try• hex_colors – boolean (default: False); when set to True, the partition returned is a dictionary whose
keys are colors and whose values are the color classes (ideal for plotting)
EXAMPLES:
sage: from sage.graphs.graph_coloring import first_coloringsage: G = Graph({0: [1, 2, 3], 1: [2]})sage: sorted(first_coloring(G, 3))[[0], [1, 3], [2]]>>> from sage.all import *>>> from sage.graphs.graph_coloring import first_coloring>>> G = Graph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(1):␣
˓→[Integer(2)]})>>> sorted(first_coloring(G, Integer(3)))[[0], [1, 3], [2]]1548

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage.graphs.graph_coloring.format_coloring(data, value_only=False, hex_colors=False,vertex_color_dict=False)
Helper method for vertex and edge coloring methods.
INPUT:• data – either a number when value_only is True or a list of color classes• value_only – boolean (default: False); when set to True, it simply returns data
• hex_colors – boolean (default: False); when set to False, colors are labeled [0, 1, …, 𝑛−1], otherwise
the RGB Hex labeling is used• vertex_color_dict – boolean (default: False); when set to True, it returns a dictionary {vertex:
color}, otherwise it returns a dictionary {color: [list of vertices]}
EXAMPLES:
sage: from sage.graphs.graph_coloring import format_coloringsage: color_classes = [[ a , b ], [ c ], [ d ]]sage: format_coloring(color_classes, value_only=True)[[ a , b ], [ c ], [ d ]]sage: format_coloring(len(color_classes), value_only=True)3
sage: format_coloring(color_classes, value_only=False){0: [ a , b ], 1: [ c ], 2: [ d ]}sage: format_coloring(color_classes, value_only=False, hex_colors=True)
˓→needs sage.plot{ #0000ff : [ d ], #00ff00 : [ c ], #ff0000 : [ a , b ]}sage: format_coloring(color_classes, value_only=False, hex_colors=False,....:vertex_color_dict=True){ a : 0, b : 0, c : 1, d : 2}sage: format_coloring(color_classes, value_only=False, hex_colors=True,
˓→needs sage.plot....:
vertex_color_dict=True){ a : #ff0000 , b : #ff0000 , c : #00ff00 , d : #0000ff }>>> from sage.all import *>>> from sage.graphs.graph_coloring import format_coloring>>> color_classes = [[ a , b ], [ c ], [ d ]]>>> format_coloring(color_classes, value_only=True)[[ a , b ], [ c ], [ d ]]>>> format_coloring(len(color_classes), value_only=True)
3>>> format_coloring(color_classes, value_only=False){0: [ a , b ], 1: [ c ], 2: [ d ]}>>> format_coloring(color_classes, value_only=False, hex_colors=True)
˓→needs sage.plot{ #0000ff : [ d ], #00ff00 : [ c ], #ff0000 : [ a , b ]}>>> format_coloring(color_classes, value_only=False, hex_colors=False,...
vertex_color_dict=True){ a : 0, b : 0, c : 1, d : 2}>>> format_coloring(color_classes, value_only=False, hex_colors=True,
˓→needs sage.plot...
vertex_color_dict=True){ a : #ff0000 , b : #ff0000 , c : #00ff00 , d : #0000ff }

#␣

#␣

#␣

#␣

sage.graphs.graph_coloring.fractional_chromatic_index(G, solver='PPL',
verbose_constraints=False,verbose=0)
5.1. Graph coloring

1549

Graph Theory, Release 10.4

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 actuallya 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:• G – a graph• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, the default
one is used. For more information on LP solvers and which default solver is used, see the method solve of
the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number, although
this may be slower that using other solvers. Be aware that this method may loop endlessly when using somenon exact solvers as reported in Issue #23658 and Issue #23798.
• verbose_constraints – boolean (default: False); whether to display which constraints are being
generated• verbose – integer (default: 0); sets the level of verbosity of the LP solver
EXAMPLES:
The fractional chromatic index of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)sage: g.fractional_chromatic_index()
˓→needs sage.numerical.mip
5/2>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.fractional_chromatic_index()
˓→needs sage.numerical.mip
5/2

1550

#␣

#␣

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage.graphs.graph_coloring.fractional_chromatic_number(G, solver='PPL', verbose=0,
check_components=True,
check_bipartite=True)
Return the fractional chromatic number of the graph.
Fractional coloring is a relaxed version of vertex coloring with several equivalent definitions, such as the optimum
value in a linear relaxation of the integer program that gives the usual chromatic number. It is also equal to thefractional clique number by LP-duality.
ALGORITHM:
The fractional chromatic number is computed via the usual Linear Program. The LP solved by sage is essentially,∑︁
Minimize :𝑥𝐼
𝐼∈ℐ(𝐺)Such that :∀𝑣 ∈ 𝑉 (𝐺),∑︁𝑥𝑣 ≥ 1𝐼∈ℐ(𝐺), 𝑣∈𝐼∀𝐼 ∈ ℐ(𝐺), 𝑥𝐼 ≥ 0
where ℐ(𝐺) is the set of maximal independent sets of 𝐺 (see Section 2.1 of [CFKPR2010] to know why it is sufficient to consider maximal independent sets). As optional optimisations, we construct the LP on each biconnectedcomponent of 𝐺 (and output the maximum value), and avoid using the LP if G is bipartite (as then the output mustbe 1 or 2).
Note: Computing the fractional chromatic number can be very slow. Since the variables of the LP are independent
sets, in general the LP has size exponential in the order of the graph. In the current implementation a list of all
maximal independent sets is created and stored, which can be both slow and memory-hungry.
INPUT:• G – a graph• solver – (default: "PPL"); specify a Linear Program (LP) solver to be used. If set to None, the default
one is used. For more information on LP solvers and which default solver is used, see the method solve of
the class MixedIntegerLinearProgram.
Note: The default solver used here is "PPL" which provides exact results, i.e. a rational number, although
this may be slower that using other solvers.
• verbose – integer (default: 0); sets the level of verbosity of the LP solver• check_components – boolean (default: True); whether the method is called on each biconnected component of 𝐺
• check_bipartite – boolean (default: True); whether the graph is checked for bipartiteness. If thegraph is bipartite then we can avoid creating and solving the LP.
EXAMPLES:
The fractional chromatic number of a 𝐶5 is 5/2:
sage: g = graphs.CycleGraph(5)sage: g.fractional_chromatic_number()˓→needs sage.numerical.mip
5/2

5.1. Graph coloring

#␣

1551

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.fractional_chromatic_number()˓→needs sage.numerical.mip
5/2#␣

sage.graphs.graph_coloring.grundy_coloring(g, k, value_only=True, solver=None, verbose=0,
integrality_tolerance=0.001)
Compute Grundy numbers and Grundy colorings.
The method 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 notalready assigned to one of its neighbors. The result is clearly a proper coloring, which usually requires much morecolors 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 numberof a graph.
Note: This method computes a grundy coloring using at MOST 𝑘 colors. If this method returns a value equal to𝑘, it cannot be assumed that 𝑘 is equal to Γ(𝐺). Meanwhile, if it returns any value 𝑘 ′ < 𝑘, this is a certificate that
the Grundy number of the given graph is 𝑘 ′ .
As Γ(𝐺) ≤ Δ(𝐺) + 1, it can also be assumed that Γ(𝐺) = 𝑘 if grundy_coloring(g, k) returns 𝑘 when𝑘 = Δ(𝐺) + 1.
INPUT:• k – integer; maximum number of colors• value_only – boolean (default: True); when set to True, only the number of colors is returned. Otherwise, the pair (nb_colors, coloring) is returned, where coloring is a dictionary associating its
color (integer) to each vertex of the graph.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Integer Linear Program.
EXAMPLES:The Grundy number of a 𝑃4 is equal to 3:

1552

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: from sage.graphs.graph_coloring import grundy_coloringsage: g = graphs.PathGraph(4)sage: grundy_coloring(g, 4)
˓→needs sage.numerical.mip3#␣>>> from sage.all import *>>> from sage.graphs.graph_coloring import grundy_coloring>>> g = graphs.PathGraph(Integer(4))>>> grundy_coloring(g, Integer(4))˓→# needs sage.numerical.mip
3

␣

The Grundy number of the PetersenGraph is equal to 4:
sage: g = graphs.PetersenGraph()
sage: grundy_coloring(g, 5)
˓→needs sage.numerical.mip
4#␣>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> grundy_coloring(g, Integer(5))˓→# needs sage.numerical.mip
4␣

It would have been sufficient to set the value of k to 4 in this case, as 4 = Δ(𝐺) + 1.
sage.graphs.graph_coloring.linear_arboricity(g, plus_one=None, hex_colors=False,
value_only=False, solver=None, verbose=0,
integrality_tolerance=0.001)
Compute the linear arboricity of the given graph.
The linear arboricity of a graph 𝐺 is the least number 𝑙𝑎(𝐺) such that the edges of 𝐺 can be partitioned into linear
forests (i.e. into forests of paths).
⌈︁⌉︁Obviously, 𝑙𝑎(𝐺) ≥ Δ(𝐺)
.
2
⌈︁
⌉︁
It is conjectured in [Aki1980] that 𝑙𝑎(𝐺) ≤ Δ(𝐺)+1.
2
INPUT:⌈︁⌉︁ ⌈︁⌉︁• plus_one – integer (default: None); whether to use Δ(𝐺)or Δ(𝐺)+1
colors.
22⌈︁⌉︁– If 0, computes a decomposition of 𝐺 into Δ(𝐺)forests of paths2⌈︁⌉︁– If 1, computes a decomposition of 𝐺 into Δ(𝐺)+1
colors, which is the conjectured general bound.
2– If plus_one = None (default), computes a decomposition using the least possible number of colors.
• hex_colors – boolean (default: False):– If hex_colors = True, the function returns a dictionary associating to each color a list of edges(meant as an argument to the edge_colors keyword of the plot method).
– If hex_colors = False (default value), returns a list of graphs corresponding to each color class.
• value_only – boolean (default: False):

5.1. Graph coloring

1553

Graph Theory, Release 10.4

– If value_only = True, only returns the linear arboricity as an integer value.
– If value_only = False, returns the color classes according to the value of hex_colors• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
ALGORITHM:
Linear Programming
COMPLEXITY:
NP-Hard
EXAMPLES:
Obviously, a square grid has a linear arboricity of 2, as the set of horizontal lines and the set of vertical lines are an
admissible partition:
sage: from sage.graphs.graph_coloring import linear_arboricity
sage: g = graphs.Grid2dGraph(4, 4)
˓→needs sage.numerical.mip
sage: g1,g2 = linear_arboricity(g)˓→needs sage.numerical.mip>>> from sage.all import *>>> from sage.graphs.graph_coloring import linear_arboricity>>> g = graphs.Grid2dGraph(Integer(4), Integer(4))˓→# needs sage.numerical.mip>>> g1,g2 = linear_arboricity(g)˓→needs sage.numerical.mip

#␣
#␣

␣
#␣

Each graph is of course a forest:
sage: g1.is_forest() and g2.is_forest()
˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> g1.is_forest() and g2.is_forest()
˓→needs sage.numerical.mip
True

#␣

Of maximum degree 2:
sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> max(g1.degree()) <= Integer(2) and max(g2.degree()) <= Integer(2)˓→# needs sage.numerical.mip
True

1554

#␣

␣

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

Which constitutes a partition of the whole edge set:sage: all((g1.has_edge(e) or g2.has_edge(e))˓→needs sage.numerical.mip....:
for e in g.edge_iterator(labels=None))True>>> from sage.all import *>>> all((g1.has_edge(e) or g2.has_edge(e))˓→needs sage.numerical.mip...
for e in g.edge_iterator(labels=None))
True

#␣

#␣

sage.graphs.graph_coloring.number_of_n_colorings(G, n)
Compute the number of 𝑛-colorings of a graph
INPUT:• G – a graph• n – a positive integer; the number of colors
EXAMPLES:
sage: 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>>> from sage.all import *>>> from sage.graphs.graph_coloring import number_of_n_colorings>>> G = Graph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(1):␣
˓→[Integer(2)]})>>> number_of_n_colorings(G, Integer(3))
12

sage.graphs.graph_coloring.numbers_of_colorings(G)Compute the number of colorings of a graph.
Return the number of 𝑛-colorings of the graph 𝐺 for all 𝑛 from 0 to |𝑉 |.
EXAMPLES:
sage: 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, 24]>>> from sage.all import *>>> from sage.graphs.graph_coloring import numbers_of_colorings>>> G = Graph({Integer(0): [Integer(1), Integer(2), Integer(3)], Integer(1):␣
˓→[Integer(2)]})>>> numbers_of_colorings(G)[0, 0, 0, 12, 24]

sage.graphs.graph_coloring.round_robin(n)Compute a round-robin coloring of the complete graph on 𝑛 vertices.

5.1. Graph coloring

1555

Graph Theory, Release 10.4

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 graphwith 𝑛 + 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_robinsage: round_robin(3).edges(sort=True)[(0, 1, 2), (0, 2, 1), (1, 2, 0)]>>> from sage.all import *>>> from sage.graphs.graph_coloring import round_robin>>> round_robin(Integer(3)).edges(sort=True)[(0, 1, 2), (0, 2, 1), (1, 2, 0)]
sage: round_robin(4).edges(sort=True)[(0, 1, 2), (0, 2, 1), (0, 3, 0), (1, 2, 0), (1, 3, 1), (2, 3, 2)]>>> from sage.all import *>>> round_robin(Integer(4)).edges(sort=True)[(0, 1, 2), (0, 2, 1), (0, 3, 0), (1, 2, 0), (1, 3, 1), (2, 3, 2)]

For higher orders, the coloring is still proper and uses the expected number of colors:
sage: g = round_robin(9)sage: sum(Set(e[2] for e in g.edges_incident(v)).cardinality() for v in g) == 2 *␣˓→g.size()
True
sage: Set(e[2] for e in g.edge_iterator()).cardinality()
9>>> from sage.all import *>>> g = round_robin(Integer(9))>>> sum(Set(e[Integer(2)] for e in g.edges_incident(v)).cardinality() for v in g)␣
˓→== Integer(2) * g.size()
True>>> Set(e[Integer(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>>> from sage.all import *>>> g = round_robin(Integer(10))(continues on next page)

1556

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> sum(Set(e[Integer(2)] for e in g.edges_incident(v)).cardinality() for v in g)␣
˓→== Integer(2) * g.size()
True>>> Set(e[Integer(2)] for e in g.edge_iterator()).cardinality()
9sage.graphs.graph_coloring.vertex_coloring(g, k=None, value_only=False, hex_colors=False,
solver=None, verbose=0,
integrality_tolerance=0.001)
Compute Vertex colorings and chromatic numbers.
This function can compute the chromatic number of the given graph or test its 𝑘-colorability.
See the Wikipedia article Graph_coloring for further details on graph coloring.
INPUT:• g – a graph.
• k – integer (default: None); tests whether the graph is 𝑘-colorable. The function returns a partition of thevertex set in 𝑘 independent sets if possible and False otherwise.
• value_only – boolean (default: False):– When set to True, only the chromatic number is returned.
– When set to False (default), a partition of the vertex set into independent sets is returned if possible.
• hex_colors – boolean (default: False); when set to True, the partition returned is a dictionary whose
keys are colors and whose values are the color classes (ideal for plotting).
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:• If k=None and value_only=False, then return a partition of the vertex set into the minimum possibleof 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 thevertex 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_coloringsage: g = graphs.PetersenGraph()
sage: vertex_coloring(g, value_only=True)
˓→# needs sage.numerical.mip
3

5.1. Graph coloring

1557

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_coloring import vertex_coloring>>> g = graphs.PetersenGraph()>>> vertex_coloring(g, value_only=True)
˓→needs sage.numerical.mip
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 (Issue #11252)• Nico Van Cleemput (2013-05-27): Handle the empty graph (Issue #14525)
REFERENCE:[NO2003]5.2.1 Methods
sage.graphs.cliquer.all_cliques(graph, min_size=0, max_size=0)
Iterator over the cliques in graph.
A clique is an induced complete subgraph. This method is an iterator over all the cliques with size in between
min_size and max_size. By default, this method returns only maximum cliques. Each yielded clique isrepresented by a list of vertices.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.
INPUT:• min_size – integer (default: 0); minimum size of reported cliques. When set to 0 (default), this method
searches for maximum cliques. In such case, parameter max_size must also be set to 0.
• max_size – integer (default: 0); maximum size of reported cliques. When set to 0 (default), the maximum
size of the cliques is unbounded. When min_size is set to 0, this parameter must be set to 0.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
sage: G = graphs.CompleteGraph(5)sage: list(sage.graphs.cliquer.all_cliques(G))[[0, 1, 2, 3, 4]]
sage: list(sage.graphs.cliquer.all_cliques(G, 2, 3))[[3, 4],(continues on next page)

1558

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)[2, 3],[2, 3, 4],[2, 4],[1, 2],[1, 2, 3],[1, 2, 4],[1, 3],[1, 3, 4],[1, 4],[0, 1],[0, 1, 2],[0, 1, 3],[0, 1, 4],[0, 2],[0, 2, 3],[0, 2, 4],[0, 3],[0, 3, 4],[0, 4]]
sage: G.delete_edge([1,3])
sage: list(sage.graphs.cliquer.all_cliques(G))[[0, 2, 3, 4], [0, 1, 2, 4]]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> list(sage.graphs.cliquer.all_cliques(G))[[0, 1, 2, 3, 4]]>>> list(sage.graphs.cliquer.all_cliques(G, Integer(2), Integer(3)))[[3, 4],[2, 3],[2, 3, 4],[2, 4],[1, 2],[1, 2, 3],[1, 2, 4],[1, 3],[1, 3, 4],[1, 4],[0, 1],[0, 1, 2],[0, 1, 3],[0, 1, 4],[0, 2],[0, 2, 3],[0, 2, 4],[0, 3],[0, 3, 4],[0, 4]]>>> G.delete_edge([Integer(1),Integer(3)])>>> list(sage.graphs.cliquer.all_cliques(G))[[0, 2, 3, 4], [0, 1, 2, 4]]

Todo: Use the re-entrant functionality of Cliquer [NO2003] to avoid storing all cliques.
sage.graphs.cliquer.all_max_clique(graph)5.2. Interface with Cliquer (clique-related problems)1559

Graph Theory, Release 10.4

Return the vertex sets of ALL the maximum complete subgraphs.
Returns the list of all maximum cliques, with each clique represented by a list of vertices. A clique is an induced
complete subgraph, and a maximum clique is one of maximal order.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.
ALGORITHM:
This function is based on Cliquer [NO2003].
EXAMPLES:
sage: graphs.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])
˓→needs sage.plot
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]]>>> from sage.all import *>>> 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]]>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> G.cliques_maximum()[[0, 1, 2], [0, 1, 3]]>>> C = graphs.PetersenGraph()>>> 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]]>>> C = Graph( DJ{ )>>> C.cliques_maximum()[[1, 2, 3, 4]]#␣␣

sage.graphs.cliquer.clique_number(graph)
Return the size of the largest clique of the graph (clique number).
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.

1560

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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])
˓→needs sage.plot
sage: G.clique_number()3>>> from sage.all import *>>> C = Graph( DJ{ )>>> C.clique_number()4>>> G = Graph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(1):[Integer(2)], Integer(3):[Integer(0),Integer(1)]})>>> G.show(figsize=[Integer(2),Integer(2)])˓→# needs sage.plot>>> G.clique_number()
3

#␣

␣

sage.graphs.cliquer.max_clique(graph)
Return the vertex set of a maximum complete subgraph.
Note: Currently only implemented for undirected graphs. Use to_undirected() to convert a digraph to an
undirected graph.
EXAMPLES:
sage: C = graphs.PetersenGraph()
sage: from sage.graphs.cliquer import max_clique
sage: max_clique(C)[7, 9]>>> from sage.all import *>>> C = graphs.PetersenGraph()>>> from sage.graphs.cliquer import max_clique>>> max_clique(C)[7, 9]

5.3 Centrality
This module is meant for all functions related to centrality in networks.
centrality_betweenness()
centrality_closeness_top_k()
centrality_closeness_random_k()

5.3. Centrality

Return the centrality betweenness of 𝐺
Return the k most closeness central vertices of 𝐺
Return an estimation of the closeness centrality of 𝐺.

1561

Graph Theory, Release 10.4

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.
(︀)︀• normalize – boolean (default: True); whether to renormalize the values by dividing them by 𝑛−1(for2(︀𝑛−1)︀
graphs) or 2 2 (for digraphs).
ALGORITHM:
To compute 𝑐(𝑣), we fix 𝑠 and define 𝑐𝑠 (𝑣) as ∑︀the centrality of 𝑣 due to 𝑠, obtained from the formula above byrunning 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𝑐𝑠 (𝑣) =∑︁1≤𝑖≤𝑘𝑐𝑠 (𝑣𝑖 )#{shortest 𝑠𝑣𝑖 − paths}#{shortest 𝑠𝑣 − paths}

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}>>> from sage.all import *>>> from sage.graphs.centrality import centrality_betweenness>>> centrality_betweenness(digraphs.Circuit(Integer(6))) # abs tol 1e-10{0: 0.5, 1: 0.5, 2: 0.5, 3: 0.5, 4: 0.5, 5: 0.5}>>> centrality_betweenness(graphs.CycleGraph(Integer(6))) # abs tol 1e-10{0: 0.2, 1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2, 5: 0.2}

Exact computations:sage: graphs.PetersenGraph().centrality_betweenness(exact=True){0: 1/12, 1: 1/12, 2: 1/12, 3: 1/12, 4: 1/12, 5: 1/12, 6: 1/12, 7: 1/12, 8: 1/12,␣
˓→9: 1/12}

1562

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> 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 eachvertex in 𝑆 (using Dijkstra for weighted graph and breadth-first-search (BFS) for unweighted graph) and uses thisknowledge to estimate the closeness centrality of all vertices.
For more information, see [EDI2014].
INPUT:• G – an undirected connected Graph• k – integer (default: 1); number of random nodes to choose
OUTPUT:
A dictionary associating to each vertex its estimated closeness centrality.
EXAMPLES:
Estimation of the closeness centrality of the Petersen Graph when 𝑘 == 𝑛: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}>>> from sage.all import *>>> from sage.graphs.centrality import centrality_closeness_random_k>>> G = graphs.PetersenGraph()>>> centrality_closeness_random_k(G, Integer(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)Compute the k vertices with largest closeness centrality.

5.3. Centrality

1563

Graph Theory, Release 10.4

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 isapproximately 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 verticesof positive (out)degree.
• verbose – integer (default: 0); define 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 (𝑐𝑙𝑜𝑠𝑣, 𝑣), where 𝑣 is one of the k most central vertices, and 𝑐𝑙𝑜𝑠𝑣 is its closenesscentrality. If 𝑘 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)]>>> from sage.all import *>>> from sage.graphs.centrality import centrality_closeness_top_k>>> g = graphs.PathGraph(Integer(10))>>> centrality_closeness_top_k(g, Integer(4), Integer(1))
Final performance ratio: 0.711111111111...
[(0.36, 5),(0.36, 4),(0.3333333333333333, 6),(0.3333333333333333, 3)]>>> g = digraphs.Path(Integer(10))>>> centrality_closeness_top_k(g, Integer(5), Integer(1))
Final performance ratio: 0.422222222222...
[(0.2, 0),(0.19753086419753085, 1),(0.19444444444444442, 2),(continues on next page)

1564

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)(0.19047619047619047, 3),(0.18518518518518517, 4)]

5.4 Asteroidal triples
This module contains the following function:
is_asteroidal_triple_free()

Test if the input graph 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[LB1962].
Use graph_classes.AT_free.description() to get some known properties of AT-free graphs, or visit thispage.

5.4.2 Algorithm
This module implements the Straightforward algorithm recalled in [Koh2004] and due to [LB1962] for testing if a graphis AT-free or not. This algorithm has time complexity in 𝑂(𝑛3 ) and space complexity in 𝑂(𝑛2 ).
This algorithm uses the connected structure of the graph, stored into a 𝑛 × 𝑛 matrix 𝑀 . This matrix is such that
𝑀 [𝑢][𝑣] == 0 if 𝑣 ∈ ({𝑢} ∪ 𝑁 (𝑢)), and otherwise 𝑀 [𝑢][𝑣] is the unique identifier (a strictly positive integer) of
the connected component of 𝐺 ∖ ({𝑢} ∪ 𝑁 (𝑢)) to which 𝑣 belongs. This connected structure can be computed in time𝑂(𝑛(𝑛 + 𝑚)) using 𝑛 BFS.
Now, a triple 𝑢, 𝑣, 𝑤 ∈ 𝑉 is an asteroidal triple if and only if it satisfies 𝑀 [𝑢][𝑣] == 𝑀 [𝑢][𝑤] and 𝑀 [𝑣][𝑢] == 𝑀 [𝑣][𝑤]and 𝑀 [𝑤][𝑢] == 𝑀 [𝑤][𝑣], assuming all these values are positive. Indeed, if 𝑀 [𝑢][𝑣] == 𝑀 [𝑢][𝑤], 𝑣 and 𝑤 are in thesame connected component of 𝐺 ∖ ({𝑢} ∪ 𝑁 (𝑢)), and so there is a path between 𝑣 and 𝑤 avoiding the neighborhood of𝑢. The algorithm iterates over all triples.

5.4.3 Functions
sage.graphs.asteroidal_triples.is_asteroidal_triple_free(G, certificate=False)
Test if the input graph is asteroidal triple-free
An independent set of three vertices such that each pair is joined by a path that avoids the neighborhood of thethird 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 Graph5.4. Asteroidal triples

1565

Graph Theory, Release 10.4

• certificate – boolean (default: False); by default, this method returns True if the graph is asteroidal
triple-free and False otherwise. When certificate==True, this method returns in addition a list of
three vertices forming an asteroidal triple if such a triple is found, and the empty list otherwise.
EXAMPLES:
The complete graph is AT-free, as well as its line graph:
sage: G = graphs.CompleteGraph(5)sage: G.is_asteroidal_triple_free()True
sage: G.is_asteroidal_triple_free(certificate=True)(True, [])sage: LG = G.line_graph()
sage: LG.is_asteroidal_triple_free()True
sage: LLG = LG.line_graph()
sage: LLG.is_asteroidal_triple_free()False>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G.is_asteroidal_triple_free()True>>> G.is_asteroidal_triple_free(certificate=True)(True, [])>>> LG = G.line_graph()>>> LG.is_asteroidal_triple_free()True>>> LLG = LG.line_graph()>>> 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])>>> from sage.all import *>>> from sage.graphs.asteroidal_triples import *>>> G = graphs.PetersenGraph()>>> G.is_asteroidal_triple_free()False>>> G.is_asteroidal_triple_free(certificate=True)(False, [0, 2, 6])1566

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.5 Independent sets
This module implements the IndependentSets class which can be used to :• List the independent sets (or cliques) of a graph• 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 (default: False); whether to only consider (inclusionwise) maximal independent sets.
• complement – boolean (default: False); whether to consider the graph’s complement (i.e. cliques insteadof independent sets).
ALGORITHM:
The enumeration of independent sets is done naively : given an independent set, this implementation considers all
ways to add a new vertex to it (while keeping it an independent set), and then creates new independent sets fromall those that were created this way.
The implementation, however, is not recursive.
Note: This implementation of the enumeration of maximal independent sets is not much faster than NetworkX’,
which is surprising as it is written in Cython. This being said, the algorithm from NetworkX appears to be slightly
different from this one, and that would be a good thing to explore if one wants to improve the implementation.
A simple generalization can also be done without too much modifications: iteration through independent sets withgiven 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], []]5.5. Independent sets

1567

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.independent_sets import IndependentSets>>> g = graphs.ClawGraph()>>> I = IndependentSets(g)>>> list(I)[[0], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3], []]Count them:sage: I.cardinality()
9>>> from sage.all import *>>> I.cardinality()
9

List only the maximal independent sets:
sage: Im = IndependentSets(g, maximal=True)
sage: list(Im)[[0], [1, 2, 3]]>>> from sage.all import *>>> Im = IndependentSets(g, maximal=True)>>> list(Im)[[0], [1, 2, 3]]

And count them:sage: Im.cardinality()2>>> from sage.all import *>>> 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]>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> number_of = [Integer(0)] * g.order()>>> for x in IndependentSets(g):...
number_of[len(x)] += Integer(1)>>> 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 setsof size 4 in this way can thus take a very long time:
1568

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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]]>>> from sage.all import *>>> is4 = (x for x in IndependentSets(g) if len(x) == Integer(4))>>> 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>>> from sage.all import *>>> g = graphs.DurerGraph()>>> I = IndependentSets(g)>>> [Integer(0), Integer(2)] in I
True>>> [Integer(0), Integer(3), Integer(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>>> from sage.all import *>>> [Integer(0), a , b , c ] in I
Traceback (most recent call last):...
ValueError: a is not a vertex of the graphcardinality()
Compute and return the number of independent sets.

5.6 Cographs
A cograph is a 𝑃4 -free graph, that is a graph without induced path of order 4. Any cograph may be constructed, startingfrom the single vertex graph, by a sequence of join and disjoint union operations. See the Wikipedia article Cograph formore details on this graph class, and OEIS sequence A000084 to know the number of cographs of order 𝑛 ≥ 1.
This module implements the folowing methods concerning cographs:
cographs()

5.6. Cographs

Return an iterator over the cographs of order 𝑛.

1569

Graph Theory, Release 10.4

5.6.1 Methods
class sage.graphs.cographs.CoTree(name='root')
Bases: object
Generic cotree node.
This data structure is used for the generation of cographs in cographs().
add_child(node)
Add cotree node in the list of children of self.
INPUT:• node – a CoTree
EXAMPLES:
sage: from sage.graphs.cographs import CoTree
sage: T = CoTree( J )sage: T.add_child(CoTree(1))
sage: T
[ J ( 1 ) ]>>> from sage.all import *>>> from sage.graphs.cographs import CoTree>>> T = CoTree( J )>>> T.add_child(CoTree(Integer(1)))>>> T[ J ( 1 ) ]copy_tree(T)Make 𝑇 a copy of self.
INPUT:• T – a CoTree
EXAMPLES:
sage: from sage.graphs.cographs import CoTree
sage: T = CoTree( J )sage: T.add_child(CoTree(1))
sage: T.add_child(CoTree(2))
sage: T
[ J ( 1 ) ( 2 ) ]sage: B = CoTree( U )sage: T.copy_tree(B)sage: B[ U ( 1 ) ( 2 ) ]>>> from sage.all import *>>> from sage.graphs.cographs import CoTree>>> T = CoTree( J )>>> T.add_child(CoTree(Integer(1)))>>> T.add_child(CoTree(Integer(2)))>>> T[ J ( 1 ) ( 2 ) ]>>> B = CoTree( U )(continues on next page)

1570

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> T.copy_tree(B)>>> B[ U ( 1 ) ( 2 ) ]reset_info()
Reset parameter info from all nodes of self.
EXAMPLES:
sage: from sage.graphs.cographs import CoTree
sage: T = CoTree(1)sage: B = CoTree(2)sage: T.add_child(B)sage: C = CoTree(3)sage: B.add_child(C)sage: C.info = info
sage: T.reset_info()sage: C.info is None
True>>> from sage.all import *>>> from sage.graphs.cographs import CoTree>>> T = CoTree(Integer(1))>>> B = CoTree(Integer(2))>>> T.add_child(B)>>> C = CoTree(Integer(3))>>> B.add_child(C)>>> C.info = info>>> T.reset_info()>>> C.info is None
True

sage.graphs.cographs.change_label(tree, status, counter)Set the names of the nodes of tree.
This is a helper method to method cographs().
The input tree is such that each node has as label its number of children. This method changes the label of eachnode so that a parallel node is labeled ‘U’, a series node is labeled ‘J’ and a leaf node gets a unique number.
INPUT:• tree – the tree to relabel• status – boolean; used to to detect series (True) and parallel (False) internal nodes• counter – list; the first integer of the list is used to assign a unique number to the leaves of the tree
EXAMPLES:
sage: next(graphs.cographs(4, as_graph=True)).vertices()[0, 1, 2, 3]# indirect doctest>>> from sage.all import *>>> next(graphs.cographs(Integer(4), as_graph=True)).vertices()
˓→doctest[0, 1, 2, 3]

5.6. Cographs# indirect␣

1571

Graph Theory, Release 10.4

sage.graphs.cographs.cographs(n, as_graph=True, immutable=False)
Return an iterator over the cographs of order 𝑛.
A cograph is a 𝑃4 -free graph, that is a graph without induced path of order 4. Any cograph may be constructed,
starting from the single vertex graph, by a sequence of sage.graphs.graph.Graph.join() and sage.
graphs.generic_graph.GenericGraph.disjoint_union() operations. See the Wikipedia article Cograph for more details.
This method implements the generator of all cographs of order 𝑛 proposed in [JPD2018]. The algorithm generates
one by one every cotree with 𝑛 nodes, and each cotree is generated by using its previous cotree. The time toconstruct the first cotree is 𝑂(𝑛) and the time spent between two consecutive outputs is 𝑂(𝑛). Hence, the overall
complexity of the algorithm is 𝑂(𝑛 * 𝑀𝑛 ), where 𝑛 is the number of nodes and 𝑀𝑛 is the total number of cographswith 𝑛 nodes (see OEIS sequence A000084).
INPUT:• n – an integer larger or equal to 1
• as_graph – boolean (default: True); whether to return graphs or the tree data structure encoding the graph• immutable – boolean (default: False); whether to return an immutable or a mutable graph. This parameter is used only when as_graph is True.
EXAMPLES:
The output can be either cotrees or graphs:
sage: for t in graphs.cographs(3, as_graph=False):....:
print(t)[ J ( 0 ) ( 1 ) ( 2 ) ][ J [ U ( 0 ) ( 1 ) ( 2 ) ] ][ J ( 0 ) [ U ( 1 ) ( 2 ) ] ][ J [ U ( 0 ) [ J ( 1 ) ( 2 ) ] ] ]sage: for g in graphs.cographs(3, as_graph=True):....:
print(g.edges(labels=False, sort=True))[(0, 1), (0, 2), (1, 2)][][(0, 1), (0, 2)][(1, 2)]>>> from sage.all import *>>> for t in graphs.cographs(Integer(3), as_graph=False):...
print(t)[ J ( 0 ) ( 1 ) ( 2 ) ][ J [ U ( 0 ) ( 1 ) ( 2 ) ] ][ J ( 0 ) [ U ( 1 ) ( 2 ) ] ][ J [ U ( 0 ) [ J ( 1 ) ( 2 ) ] ] ]>>> for g in graphs.cographs(Integer(3), as_graph=True):...
print(g.edges(labels=False, sort=True))[(0, 1), (0, 2), (1, 2)][][(0, 1), (0, 2)][(1, 2)]Check that we agree with OEIS sequence A000084:
sage: [sum(1 for _ in graphs.cographs(n, as_graph=False))....: for n in range(1, 8)][1, 2, 4, 10, 24, 66, 180]

1572

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> [sum(Integer(1) for _ in graphs.cographs(n, as_graph=False))... for n in range(Integer(1), Integer(8))][1, 2, 4, 10, 24, 66, 180]

sage.graphs.cographs.find_pivot(T)Search for a pivot node in 𝑇 .
This is a helper method to method cographs().
A node in 𝑇 is a pivot if it is not a leaf, it does not induce a maximum partition and it is the first such node in
the inverse postorder traversal.
INPUT:• T – a CoTree
EXAMPLES:
sage: next(graphs.cographs(3, as_graph=True)).vertices()[0, 1, 2]# indirect doctest>>> from sage.all import *>>> next(graphs.cographs(Integer(3), as_graph=True)).vertices()
˓→doctest[0, 1, 2]# indirect␣

sage.graphs.cographs.next_tree(T)Check if there is another tree after 𝑇 .
This is a helper method to method cographs().
This methods returns True if there is a tree after 𝑇 , and if so it modifies the input tree 𝑇 that becomes the nexttree.
INPUT:• T – a CoTree
EXAMPLES:
sage: next(graphs.cographs(3, as_graph=True)).vertices()[0, 1, 2]# indirect doctest>>> from sage.all import *>>> next(graphs.cographs(Integer(3), as_graph=True)).vertices()
˓→doctest[0, 1, 2]# indirect␣

sage.graphs.cographs.rebuild_node(u, P)
Replace the subtree rooted at 𝑢 by a subtree induced by partition 𝑃 .
This is a helper method to method cographs().
INPUT:• u – a CoTree• P – a partition encoding the new structure of the children of 𝑢
EXAMPLES:

5.6. Cographs1573

Graph Theory, Release 10.4

sage: next(graphs.cographs(3, as_graph=True)).vertices()[0, 1, 2]# indirect doctest>>> from sage.all import *>>> next(graphs.cographs(Integer(3), as_graph=True)).vertices()
˓→doctest[0, 1, 2]# indirect␣

sage.graphs.cographs.tree_to_graph(tree, immutable=False)
Return the cograph represented by tree.
This is a helper method to method cographs().
EXAMPLES:
sage: for t in graphs.cographs(3, as_graph=True):....:
print(t.edges(labels=False, sort=True))[(0, 1), (0, 2), (1, 2)][][(0, 1), (0, 2)][(1, 2)]# indirect doctest>>> from sage.all import *>>> for t in graphs.cographs(Integer(3), as_graph=True):...
print(t.edges(labels=False, sort=True))[(0, 1), (0, 2), (1, 2)][][(0, 1), (0, 2)][(1, 2)]# indirect doctest

5.7 Comparability and permutation graphs
This module implements method related to Wikipedia article Comparability_graph and Wikipedia article Permutation_graph, that is, for the moment, only recognition algorithms.
Most of the information found here can also be found in [ST1994] or [Sha1997].
The following methods are implemented in this module
is_comparability_MILP()
greedy_is_comparability()
greedy_is_comparability_with_certificate()
is_comparability()
is_permutation()
is_transitive()

Tests whether the graph is a comparability graph (MILP)
Tests whether the graph is a comparability graph (greedy algorithm)
Tests whether the graph is a comparability graph and returns certificates (greedy
algorithm)
Tests whether the graph is a comparability graph
Tests whether the graph is a permutation graph.
Tests whether the digraph is transitive.

Author:• Nathann Cohen 2012-04

1574

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.7.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 arecomparable. 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 segmentsintersecting 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.7.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 edgesof 𝐺 :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 theother leaves it, these two edges form a path of length two, which is not possible in any transitive orientationof 𝐺 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 𝐶𝑢𝑣
tobe the equivalence class in 𝐺 of the oriented edge 𝑢𝑣.
Of course, if there exists a transitive orientation of a graph 𝐺, then no edge 𝑢𝑣 implies its contrary 𝑣𝑢, i.e. it is necessary
𝐺to ensure that ∀𝑢𝑣 ∈ 𝐺, 𝑣𝑢 ̸∈ 𝐶𝑢𝑣. The key result on which the greedy algorithm is built is the following (see [ST1994]):
Theorem – The following statements are equivalent :• 𝐺 is a comparability graph𝐺• ∀𝑢𝑣 ∈ 𝐺, 𝑣𝑢 ̸∈ 𝐶𝑢𝑣• The edges of 𝐺 can be partitionned into 𝐵1 , ..., 𝐵𝑘 where 𝐵𝑖 is the equivalence class of some orientededge in 𝐺 − 𝐵1 − · · · − 𝐵𝑖−1
Hence, ensuring that a graph is a comparability graph can be done by checking that no equivalence class is contradictory.
Building the orientation, however, requires to build equivalence classes step by step until an orientation has been foundfor all of them.
Mixed Integer Linear Program
A MILP formulation is available to check the other methods for correction. It is easily built :5.7. Comparability and permutation graphs

1575

Graph Theory, Release 10.4

To each edge are associated two binary variables (one for each possible direction). We then ensure that eachtriangle is transitively oriented, and that each pair of incident edges 𝑢𝑣, 𝑢𝑣 ′ such that 𝑣𝑣 ′ ̸∈ 𝐺 do not createa 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 tocheck 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.7.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. Thisis 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, negativecertificates 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).

5.7.4 Implementation details
Test that the equivalence classes are not self-contradictoryThis 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 class ofedges 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. allshould go toward 𝑢 at the same time, or leave it at the same time. To represent this, we create a graph withvertices for all equivalent classes around all vertices of 𝐺, and link (𝑣, 𝐶) to (𝑢, 𝐶 ′ ) if 𝑢 ∈ 𝐶 and 𝑣 ∈ 𝐶 ′ .
1576

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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 isreaaaaaaaaaaaalllly bad whenever you look at it with performance in mind.

5.7.5 Methods
sage.graphs.comparability.greedy_is_comparability(g, no_certificate=False,
equivalence_class=False)
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. Thiscertificate 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) according
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
sage: is_comparability(g, no_certificate=True)(False, [2, 1, 0, 4, 3, 2])>>> from sage.all import *>>> from sage.graphs.comparability import greedy_is_comparability as is_
˓→comparability>>> g = graphs.PetersenGraph()>>> is_comparability(g)False>>> is_comparability(g, no_certificate=True)(False, [2, 1, 0, 4, 3, 2])

But the Bull graph is:

5.7. Comparability and permutation graphs

1577

Graph Theory, Release 10.4

sage: g = graphs.BullGraph()
sage: is_comparability(g)True>>> from sage.all import *>>> g = graphs.BullGraph()>>> is_comparability(g)Truesage.graphs.comparability.greedy_is_comparability_with_certificate(g, certificate=False)
Tests whether the graph is a comparability graph and returns certificates(greedy algorithm).
This method can return certificates of both yes and no answers.
To understand how this method works, please consult the documentation of the comparability module.
INPUT:• certificate (boolean) – whether to return a certificate. Yes-answers the certificate is a transitive 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, [2, 1, 0, 4, 3, 2])
sage: g = graphs.PetersenGraph()
sage: is_comparability(g)False
sage: is_comparability(g, certificate=True)(False, [2, 1, 0, 4, 3, 2])>>> from sage.all import *>>> from sage.graphs.comparability import greedy_is_comparability_with_
˓→certificate as is_comparability>>> is_comparability(graphs.CycleGraph(Integer(5)), certificate=True)(False, [2, 1, 0, 4, 3, 2])>>> g = graphs.PetersenGraph()>>> is_comparability(g)False>>> is_comparability(g, certificate=True)(False, [2, 1, 0, 4, 3, 2])

But the Bull graph is:
sage: g = graphs.BullGraph()
sage: is_comparability(g)Truesage: is_comparability(g, certificate = True)(True, Digraph on 5 vertices)sage: is_comparability(g, certificate = True)[1].is_transitive()
True

1578

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.BullGraph()>>> is_comparability(g)True>>> is_comparability(g, certificate = True)(True, Digraph on 5 vertices)>>> is_comparability(g, certificate = True)[Integer(1)].is_transitive()
True

sage.graphs.comparability.is_comparability(g, algorithm='greedy', certificate=False, check=True,
solver=None, verbose=0)
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 implementationis unable to return negative certificates ! When certificate = True, negative certificates arealways equal to None. True certificates are valid, though.
• certificate (boolean) – whether to return a certificate. Yes-answers the certificate is a transitive orientation of 𝐺, and a no certificates is an odd cycle of sequentially forcing edges.
• check (boolean) – whether to check that the yes-certificates are indeed transitive. As it is very quick compared to the rest of the operation, it is enabled by default.
• solver – (default: None); Specify a Linear Program (LP) solver to be used. If set to None, the default
one is used. For more information on LP solvers and which default solver is used, see the method solve()of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
EXAMPLES:
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)>>> from sage.all import *>>> from sage.graphs.comparability import is_comparability>>> g = graphs.PetersenGraph()>>> is_comparability(g)False>>> is_comparability(graphs.CompleteGraph(Integer(5)), certificate=True)(True, Digraph on 5 vertices)sage.graphs.comparability.is_comparability_MILP(g, certificate=False, solver=None, verbose=0)
Tests whether the graph is a comparability graph (MILP)INPUT:• certificate (boolean) – whether to return a certificate for yes instances. This method cannot return
negative certificates.

5.7. Comparability and permutation graphs

1579

Graph Theory, Release 10.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.
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)
˓→# needs sage.numerical.mip(False, None)sage: g = graphs.PetersenGraph()
sage: is_comparability(g, certificate=True)
˓→# needs sage.numerical.mip(False, None)>>> from sage.all import *>>> from sage.graphs.comparability import is_comparability_MILP as is_
˓→comparability>>> is_comparability(graphs.CycleGraph(Integer(5)), certificate=True)˓→# needs sage.numerical.mip(False, None)>>> g = graphs.PetersenGraph()>>> is_comparability(g, certificate=True)
˓→needs sage.numerical.mip(False, None)␣#␣

But the Bull graph is:
sage: g = graphs.BullGraph()
sage: is_comparability(g)˓→# needs sage.numerical.mip
True
sage: is_comparability(g, certificate=True)
˓→# needs sage.numerical.mip(True, Digraph on 5 vertices)sage: is_comparability(g, certificate=True)[1].is_transitive()
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.BullGraph()>>> is_comparability(g)˓→needs sage.numerical.mip
True>>> is_comparability(g, certificate=True)
˓→needs sage.numerical.mip(True, Digraph on 5 vertices)>>> is_comparability(g, certificate=True)[Integer(1)].is_transitive()˓→# needs sage.numerical.mip
True

#␣

#␣

␣

sage.graphs.comparability.is_permutation(g, algorithm='greedy', certificate=False, check=True,
solver=None, verbose=0)
1580

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

Tests whether the graph is a permutation graph.
For more information on permutation graphs, refer to the documentation of the comparability module.
INPUT:• 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 implementationis unable to return negative certificates ! When certificate = True, negative certificates arealways 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 Permutationgraph. 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 default
one is used. For more information on LP solvers and which default solver is used, see the method solve()of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
Note: As the True certificate is a Permutation object, the segment intersection model of the permutationgraph 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>>> from sage.all import *>>> from sage.graphs.comparability import is_permutation>>> g = graphs.BullGraph()>>> _ , certif = is_permutation(g, certificate=True)>>> h = graphs.PermutationGraph(*certif)>>> 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")
˓→needs sage.plot

5.7. Comparability and permutation graphs

#␣

1581

Graph Theory, Release 10.4>>> from sage.all import *>>> true, perm = is_permutation(g, certificate=True)>>> p1 = Permutation([nn+Integer(1) for nn in perm[Integer(0)]])>>> p2 = Permutation([nn+Integer(1) for nn in perm[Integer(1)]])>>> p = p2 * p1.inverse()>>> p.show(representation="braid")
˓→needs sage.plot#␣

sage.graphs.comparability.is_transitive(g, certificate=False)
Tests whether the digraph is transitive.
A digraph is transitive if for any pair of vertices 𝑢, 𝑣 ∈ 𝐺 linked by a 𝑢𝑣-path the edge 𝑢𝑣 belongs to 𝐺.
INPUT:• certificate – whether to return a certificate for negative answers.
– If certificate = False (default), this method returns True or False according to the graph.
– If certificate = True, this method either returns True answers or yield a pair of vertices 𝑢𝑣
such that there exists a 𝑢𝑣-path in 𝐺 but 𝑢𝑣 ̸∈ 𝐺.
EXAMPLES:
sage: digraphs.Circuit(4).is_transitive()
False
sage: digraphs.Circuit(4).is_transitive(certificate=True)(0, 2)
sage: digraphs.RandomDirectedGNP(30,.2).is_transitive()
False
sage: D = digraphs.DeBruijn(5, 2)
˓→needs sage.combinat
sage: D.is_transitive()
˓→needs sage.combinat
False
sage: cert = D.is_transitive(certificate=True)
˓→needs sage.combinat
sage: D.has_edge(*cert)
˓→needs sage.combinat
False
sage: bool(D.shortest_path(*cert))
˓→needs sage.combinat
Truesage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive()
˓→needs networkx
True>>> from sage.all import *>>> digraphs.Circuit(Integer(4)).is_transitive()
False>>> digraphs.Circuit(Integer(4)).is_transitive(certificate=True)(0, 2)>>> digraphs.RandomDirectedGNP(Integer(30),RealNumber( .2 )).is_transitive()
False>>> D = digraphs.DeBruijn(Integer(5), Integer(2))˓→# needs sage.combinat>>> D.is_transitive()
˓→needs sage.combinat
False

#␣
#␣

#␣
#␣

#␣

#␣

␣
#␣

(continues on next page)

1582

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> cert = D.is_transitive(certificate=True)#␣˓→needs sage.combinat>>> D.has_edge(*cert)#␣˓→needs sage.combinat
False>>> bool(D.shortest_path(*cert))#␣˓→needs sage.combinat
True>>> digraphs.RandomDirectedGNP(Integer(20),RealNumber( .2 )).transitive_closure().
˓→is_transitive()# needs networkx
True

5.8 Line graphs
This module gather everything which is related to line graphs. Right now, this amounts to the following functions :line_graph()
is_line_graph()root_graph()

Return the line graph of a given graph
Check whether a graph is a line graph
Return 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.
• David Coudert (10-2018), use maximal cliques iterator in root_graph(), and use root_graph() insteadof forbidden subgraph search in is_line_graph() (Issue #26444).

5.8.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 theorigin of 𝑒′ .
For more information, see the Wikipedia article Line_graph.

5.8.2 Root graph
A graph whose line graph is 𝐿𝐺 is called the root graph of 𝐿𝐺. The root graph of a (connected) graph is unique([Whi1932], [Har1969]), except when 𝐿𝐺 = 𝐾3 , as both 𝐿(𝐾3 ) and 𝐿(𝐾1,3 ) are equal to 𝐾3 .
Here is how we can “see” 𝐺 by staring (very intently) at 𝐿𝐺 :A graph 𝐿𝐺 is the line graph of 𝐺 if there exists a collection (𝑆𝑣 )𝑣∈𝐺 of subsets of 𝑉 (𝐿𝐺) such that :• Every 𝑆𝑣 is a complete subgraph of 𝐿𝐺.
• Every 𝑣 ∈ 𝐿𝐺 belongs to exactly two sets of the family (𝑆𝑣 )𝑣∈𝐺 .
5.8. Line graphs1583

Graph Theory, Release 10.4

• Any two sets of (𝑆𝑣 )𝑣∈𝐺 have at most one common elements• For any edge (𝑢, 𝑣) ∈ 𝐿𝐺 there exists a set of (𝑆𝑣 )𝑣∈𝐺 containing both 𝑢 and 𝑣.
In this family, each set 𝑆𝑣 represent a vertex of 𝐺, and contains “the set of edges incident to 𝑣 in 𝐺”. Twoelements 𝑆𝑣 , 𝑆𝑣′ 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 andodd triangles :A triangle {𝑒1 , 𝑒2 , 𝑒3 } ⊆ 𝑉 (𝐿𝐺) is said to be an odd triangle if there exists a vertex 𝑒 ∈ 𝑉 (𝐺) incident toexactly one or all of {𝑒1 , 𝑒2 , 𝑒3 }, and it is said to be even otherwise.
The very good point of this definition is that an inclusionwise maximal clique which is an odd triangle will always correspond to a vertex of degree 3 in 𝐺, while an even triangle could result from either a vertex of degree 3 in 𝐺 or a triangle
in 𝐺. And in order to build the root graph we obviously have to decide which.
Beineke proves in [Bei1970] that the collection of sets we are looking for can be easily found. Indeed it turns out that itis 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 ) inthis case. Pay very close attention to that, for this answer is not theoretically correct : there is no unique answer in thiscase, and we deal with it by returning one of the two possible answers.

5.8.3 Functions
sage.graphs.line_graph.is_line_graph(g, certificate=False)
Check whether the graph 𝑔 is a line graph.
INPUT:• certificate (boolean) – whether to return a certificate along with the boolean result. Here is what
happens when certificate = True:– If the graph is not a line graph, the method returns a pair (b, subgraph) where b is False andsubgraph is a subgraph isomorphic to one of the 9 forbidden induced subgraphs of a line graph.

1584

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

– If the graph is a line graph, the method returns a triple (b,R,isom) where b is True, R is a graphwhose line graph is the graph given as input, and isom is a map associating an edge of R to each vertexof the graph.
Note: This method wastes a bit of time when the input graph is not connected. If you have performance in mind,
it is probably better to only feed it with connected graphs only.
See also:• 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>>> from sage.all import *>>> graphs.CompleteGraph(Integer(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>>> from sage.all import *>>> graphs.PetersenGraph().is_line_graph()
False

This is indeed the subgraph returned:
sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1]˓→needs sage.modules
sage: C.is_isomorphic(graphs.ClawGraph())˓→needs sage.modules
True>>> from sage.all import *>>> C = graphs.PetersenGraph().is_line_graph(certificate=True)[Integer(1)]˓→# needs sage.modules>>> C.is_isomorphic(graphs.ClawGraph())˓→needs sage.modules
True

#␣
#␣

␣
#␣

The house graph is a line graph:
sage: g = graphs.HouseGraph()
sage: g.is_line_graph()
True

5.8. Line graphs

1585

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.HouseGraph()>>> g.is_line_graph()
True

But what is the graph whose line graph is the house ?:sage: # needs sage.modules
sage: is_line, R, isom = g.is_line_graph(certificate=True)
sage: R.sparse6_string():DaHI~
sage: R.show()˓→needs sage.plot
sage: isom
{0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)}>>> from sage.all import *>>> # needs sage.modules>>> is_line, R, isom = g.is_line_graph(certificate=True)>>> R.sparse6_string():DaHI~>>> R.show()˓→needs sage.plot>>> isom{0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)}#␣#␣

sage.graphs.line_graph.line_graph(g, labels=True)
Return the line graph of the (di)graph g.
INPUT:• labels – boolean (default: True); whether edge labels should be taken in consideration. If labels=True, the vertices of the line graph will be triples (u,v,label), and pairs of vertices otherwise.
The line graph of an undirected graph G is an undirected graph H such that the vertices of H are the edges of G
and two vertices e and f of H are adjacent if e and f share a common vertex in G. In other words, an edge in H
represents a path of length 2 in G.
The line graph of a directed graph G is a directed graph H such that the vertices of H are the edges of G and two
vertices e and f of H are adjacent if e and f share a common vertex in G and the terminal vertex of e is the initialvertex 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:

1586

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g = graphs.CompleteGraph(4)sage: h = g.line_graph()
sage: h.vertices(sort=True)[(0, 1, None),(0, 2, None),(0, 3, None),(1, 2, None),(1, 3, None),(2, 3, None)]sage: h.am()
˓→needs sage.modules[0 1 1 1 1 0]
[1 0 1 1 0 1]
[1 1 0 0 1 1]
[1 1 0 0 1 1]
[1 0 1 1 0 1]
[0 1 1 1 1 0]
sage: h2 = g.line_graph(labels=False)
sage: h2.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
sage: h2.am() == h.am()
˓→needs sage.modules
True
sage: g = DiGraph([[1..4], lambda i,j: i < j])sage: h = g.line_graph()
sage: h.vertices(sort=True)[(1, 2, None),(1, 3, None),(1, 4, None),(2, 3, None),(2, 4, None),(3, 4, None)]sage: h.edges(sort=True)[((1, 2, None), (2, 3, None), None),((1, 2, None), (2, 4, None), None),((1, 3, None), (3, 4, None), None),((2, 3, None), (3, 4, None), None)]>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(4))>>> h = g.line_graph()>>> h.vertices(sort=True)[(0, 1, None),(0, 2, None),(0, 3, None),(1, 2, None),(1, 3, None),(2, 3, None)]>>> h.am()
˓→needs sage.modules[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]>>> h2 = g.line_graph(labels=False)

#␣

#␣

#␣

(continues on next page)

5.8. Line graphs

1587Graph Theory, Release 10.4

(continued from previous page)>>> h2.vertices(sort=True)[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]>>> h2.am() == h.am()#␣˓→needs sage.modules
True>>> g = DiGraph([(ellipsis_range(Integer(1),Ellipsis,Integer(4))), lambda i,j: i
˓→< j])>>> h = g.line_graph()>>> h.vertices(sort=True)[(1, 2, None),(1, 3, None),(1, 4, None),(2, 3, None),(2, 4, None),(3, 4, None)]>>> h.edges(sort=True)[((1, 2, None), (2, 3, None), None),((1, 2, None), (2, 4, None), None),((1, 3, None), (3, 4, None), None),((2, 3, None), (3, 4, None), None)]sage.graphs.line_graph.root_graph(g, verbose=False)
Return the root graph corresponding to the given graph g.
See the documentation of sage.graphs.line_graph to know how it works.
INPUT:• g – a graph• verbose – boolean (default: False); display some information about what is happening inside of thealgorithm.
Warning: This code assumes that 𝑔 is a line graph, and is a connected, undirected graph without multiple
edges.

5.9 Spanning trees
This module is a collection of algorithms on spanning trees. Also included in the collection are algorithms for minimum
spanning trees. See the book [JNC2010] for descriptions of spanning tree algorithms, including minimum spanning trees.
See also:• GenericGraph.min_spanning_tree.
Todo:• Parallel version of Boruvka’s algorithm.

1588

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.9.1 Methods
sage.graphs.spanning_tree.boruvka(G, by_weight=True, weight_function=None, check_weight=True,
check=False)
Minimum spanning tree using Boruvka’s algorithm.
This function assumes that we can only compute minimum spanning trees for undirected graphs. Such graphs canbe weighted or unweighted, and they can have multiple edges (since we are computing the minimum spanning tree,
only the minimum weight among all (𝑢, 𝑣)-edges is considered, for each pair of vertices 𝑢, 𝑣).
INPUT:• G – an undirected graph.
• by_weight – boolean (default: True); if True, the edges in the graph are weighted; if False, all edges
have weight 1.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs anumber for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior torunning 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 function 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.
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 [Sah2000]:
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)]
sage: sorted(boruvka(G, by_weight=False))[(1, 2, 28), (1, 6, 10), (2, 3, 16), (2, 7, 14), (3, 4, 12), (4, 5, 22)]5.9. Spanning trees

1589Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.spanning_tree import boruvka>>> G = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
˓→Integer(7):Integer(24)}})>>> G.weighted(True)>>> E = boruvka(G, check=True); E[(1, 6, 10), (2, 7, 14), (3, 4, 12), (4, 5, 22), (5, 6, 25), (2, 3, 16)]>>> boruvka(G, by_weight=True)[(1, 6, 10), (2, 7, 14), (3, 4, 12), (4, 5, 22), (5, 6, 25), (2, 3, 16)]>>> sorted(boruvka(G, by_weight=False))[(1, 2, 28), (1, 6, 10), (2, 3, 16), (2, 7, 14), (3, 4, 12), (4, 5, 22)]

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, weight_function=lambda e:3-e[0]-e[1], by_weight=True)[(0, 2, 10), (1, 2, 1)]
sage: boruvka(G, weight_function=lambda e:float(1/e[2]), by_weight=True)[(0, 2, 10), (0, 1, 1)]>>> from sage.all import *>>> G = Graph([[Integer(0),Integer(1),Integer(1)],[Integer(1),Integer(2),˓→Integer(1)],[Integer(2),Integer(0),Integer(10)]], weighted=True)>>> weight = lambda e:Integer(3)-e[Integer(0)]-e[Integer(1)]>>> boruvka(G, weight_function=lambda e:Integer(3)-e[Integer(0)]-e[Integer(1)],␣
˓→by_weight=True)[(0, 2, 10), (1, 2, 1)]>>> boruvka(G, weight_function=lambda e:float(Integer(1)/e[Integer(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)[]>>> from sage.all import *>>> from sage.graphs.spanning_tree import boruvka>>> G = Graph({Integer(1):{Integer(2):Integer(28)}, Integer(3):˓→{Integer(4):Integer(16)}}, weighted=True)>>> boruvka(G, check=False)[]

sage.graphs.spanning_tree.edge_disjoint_spanning_trees(G, k, by_weight=False,
weight_function=None,check_weight=True)
Return 𝑘 edge-disjoint spanning trees of minimum cost.
This method implements the Roskind-Tarjan algorithm for finding 𝑘 minimum-cost edge-disjoint spanning trees in
simple undirected graphs [RT1985]. When edge weights are taken into account, the algorithm ensures that the sum

1590

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4of the weights of the returned spanning trees is minimized. The time complexity of the algorithm is in 𝑂(𝑘 2 𝑛2 )for the unweighted case and otherwise in 𝑂(𝑚 log 𝑚 + 𝑘 2 𝑛2 ).
This method raises an error if the graph does not contain the requested number of spanning trees.
INPUT:• G – a simple undirected graph• k – the requested number of edge-disjoint spanning trees• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: True); if True, we check that the weight_function outputs anumber for each edge
EXAMPLES:
Example from [RT1985]:
sage: from sage.graphs.spanning_tree import edge_disjoint_spanning_trees
sage: G = Graph({ a : [ b , c , d , e ], b : [ c , e ], c : [ d ],˓→ ]})
sage: F = edge_disjoint_spanning_trees(G, 2)
sage: F
[Graph on 5 vertices, Graph on 5 vertices]sage: [f.is_tree() for f in F][True, True]>>> from sage.all import *>>> from sage.graphs.spanning_tree import edge_disjoint_spanning_trees>>> G = Graph({ a : [ b , c , d , e ], b : [ c , e ], c : [ d ],˓→)>>> F = edge_disjoint_spanning_trees(G, Integer(2))>>> F[Graph on 5 vertices, Graph on 5 vertices]>>> [f.is_tree() for f in F][True, True]d : [ ed : [ e ]}This method raises an error if the graph does not contain the required number of trees:
sage: edge_disjoint_spanning_trees(G, 3)
Traceback (most recent call last):...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences>>> from sage.all import *>>> edge_disjoint_spanning_trees(G, Integer(3))
Traceback (most recent call last):...
EmptySetError: this graph does not contain the required number of trees/
˓→arborescences

A clique of order 𝑛 has ⌊𝑛/2⌋ edge disjoint spanning trees:

5.9. Spanning trees

1591

Graph Theory, Release 10.4

sage: for n in range(1, 10):....:g = graphs.CompleteGraph(n)....:F = edge_disjoint_spanning_trees(g, n//2)>>> from sage.all import *>>> for n in range(Integer(1), Integer(10)):...
g = graphs.CompleteGraph(n)...
F = edge_disjoint_spanning_trees(g, n//Integer(2))

The sum of the weights of the returned spanning trees is minimum:
sage: g = graphs.CompleteGraph(5)sage: for u, v in g.edges(sort=True, labels=False):....:
g.set_edge_label(u, v, 1)
sage: g.set_edge_label(0, 1, 33)
sage: g.set_edge_label(1, 3, 33)
sage: F = edge_disjoint_spanning_trees(g, 2, by_weight=True)
sage: sum(F[0].edge_labels()) + sum(F[1].edge_labels())
8>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> for u, v in g.edges(sort=True, labels=False):...
g.set_edge_label(u, v, Integer(1))>>> g.set_edge_label(Integer(0), Integer(1), Integer(33))>>> g.set_edge_label(Integer(1), Integer(3), Integer(33))>>> F = edge_disjoint_spanning_trees(g, Integer(2), by_weight=True)>>> sum(F[Integer(0)].edge_labels()) + sum(F[Integer(1)].edge_labels())
8

sage.graphs.spanning_tree.filter_kruskal(G, threshold=10000, by_weight=True,
weight_function=None, check_weight=True,
check=False)
Minimum spanning tree using Filter Kruskal algorithm.
This function implements the variant of Kruskal’s algorithm proposed in [OSS2009]. Instead of directly sorting
the whole set of edges, it partitions it in a similar way to quicksort and filter out edges that connect vertices of thesame tree to reduce the cost of sorting.
This function assumes that we can only compute minimum spanning trees for undirected graphs. Such graphs canbe weighted or unweighted, and they can have multiple edges (since we are computing the minimum spanning tree,
only the minimum weight among all (𝑢, 𝑣)-edges is considered, for each pair of vertices 𝑢, 𝑣).
INPUT:• G – an undirected graph• threshold – integer (default: 10000); maximum number of edges on
which to run kruskal algorithm. Above that value, edges are partitioned into sets of size at mostthreshold• by_weight – boolean (default: True); if True, the edges in the graph are weighted; if False, all edges
have weight 1.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l, if l is not None, else 1 as a weight.

1592

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• check_weight – boolean (default: False); whether to check that the weight_function outputs anumber for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior torunning Kruskal’s algorithm on that input graph:– Is G the null graph?
– Is G disconnected?
– Is G a tree?
– Does G have self-loops?
– Does G have multiple edges?
OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()• Wikipedia article Kruskal%27s_algorithm• kruskal()• filter_kruskal_iterator()
EXAMPLES:
sage: from sage.graphs.spanning_tree import filter_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: filter_kruskal(G, check=True)[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]
sage: filter_kruskal(Graph(2), check=True)[]>>> from sage.all import *>>> from sage.graphs.spanning_tree import filter_kruskal>>> G = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
˓→Integer(7):Integer(24)}})>>> G.weighted(True)>>> filter_kruskal(G, check=True)[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]>>> filter_kruskal(Graph(Integer(2)), check=True)[]sage.graphs.spanning_tree.filter_kruskal_iterator(G, threshold=10000, by_weight=True,
weight_function=None,check_weight=True, check=False)
Return an iterator implementation of Filter Kruskal’s algorithm.

5.9. Spanning trees

1593

Graph Theory, Release 10.4

INPUT:• G – an undirected graph• threshold – integer (default: 10000); maximum number of edges on
which to run kruskal algorithm. Above that value, edges are partitioned into sets of size at mostthreshold• by_weight – boolean (default: True); if True, the edges in the graph are weighted; if False, all edges
have weight 1.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs anumber for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior torunning Kruskal’s algorithm on that input graph:– Is G the null graph?
– Is G disconnected?
– Is G a tree?
– Does G have self-loops?
– Does G have multiple edges?
OUTPUT:
The edges of a minimum spanning tree of G, one by one.
See also:• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()• Wikipedia article Kruskal%27s_algorithm• kruskal()• filter_kruskal()
EXAMPLES:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
sage: from sage.graphs.spanning_tree import filter_kruskal_iterator
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: list(filter_kruskal_iterator(G, threshold=3, check=True))[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]>>> from sage.all import *>>> from sage.graphs.spanning_tree import filter_kruskal_iterator>>> G = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
(continues on next page)

1594

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

Integer(7):Integer(24)}})>>> G.weighted(True)>>> list(filter_kruskal_iterator(G, threshold=Integer(3), check=True))[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]
˓→The weights of the spanning trees returned by kruskal_iterator() and filter_kruskal_iterator() are the same:
sage: # needs networkx
sage: from sage.graphs.spanning_tree import kruskal_iterator
sage: G = graphs.RandomBarabasiAlbert(50, 2)
sage: for u, v in G.edge_iterator(labels=False):....:
G.set_edge_label(u, v, randint(1, 10))sage: G.weighted(True)
sage: sum(e[2] for e in kruskal_iterator(G)) == sum(e[2]....:for e in filter_kruskal_iterator(G, threshold=20))
True>>> from sage.all import *>>> # needs networkx>>> from sage.graphs.spanning_tree import kruskal_iterator>>> G = graphs.RandomBarabasiAlbert(Integer(50), Integer(2))>>> for u, v in G.edge_iterator(labels=False):...
G.set_edge_label(u, v, randint(Integer(1), Integer(10)))>>> G.weighted(True)>>> sum(e[Integer(2)] for e in kruskal_iterator(G)) == sum(e[Integer(2)]...
for e in filter_kruskal_iterator(G, threshold=Integer(20)))
True

sage.graphs.spanning_tree.kruskal(G, by_weight=True, weight_function=None, check_weight=False,
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 canbe weighted or unweighted, and they can have multiple edges (since we are computing the minimum spanning tree,
only the minimum weight among all (𝑢, 𝑣)-edges is considered, for each pair of vertices 𝑢, 𝑣).
INPUT:• G – an undirected graph• by_weight – boolean (default: True); if True, the edges in the graph are weighted; if False, all edges
have weight 1.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs anumber for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior torunning Kruskal’s algorithm on that input graph:– Is G the null graph?
– Is G disconnected?

5.9. Spanning trees

1595Graph Theory, Release 10.4

– 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 function 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, thealgorithm still works, but the running-time can be improved if these edges are removed. To further improve
the runtime of this function, you should call it directly instead of using it indirectly via sage.graphs.
generic_graph.GenericGraph.min_spanning_tree().
OUTPUT:
The edges of a minimum spanning tree of G, if one exists, otherwise returns the empty list.
See also:• sage.graphs.generic_graph.GenericGraph.min_spanning_tree()• kruskal_iterator()• filter_kruskal() and filter_kruskal_iterator()
EXAMPLES:
An example from pages 727–728 in [Sah2000].
sage: 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), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]>>> from sage.all import *>>> from sage.graphs.spanning_tree import kruskal>>> G = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
˓→Integer(7):Integer(24)}})>>> G.weighted(True)>>> E = kruskal(G, check=True); E[(1, 6, 10), (3, 4, 12), (2, 7, 14), (2, 3, 16), (4, 5, 22), (5, 6, 25)]

Variants of the previous example.
sage: H = Graph(G.edges(sort=True, 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)(continues on next page)

1596

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)....: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)....:
G.allow_multiple_edges(False, keep_label= min )sage: sanitize(H)sage: H
Graph on 7 vertices
sage: sum(e[2] for e in kruskal(G, check=True)) == sum(e[2] for e in kruskal(H,␣˓→check=True))
True>>> from sage.all import *>>> H = Graph(G.edges(sort=True, labels=False))>>> kruskal(H, check=True)[(1, 2, None), (1, 6, None), (2, 3, None), (2, 7, None), (3, 4, None), (4, 5,␣
˓→None)]>>> G.allow_loops(True)>>> G.allow_multiple_edges(True)>>> G
Looped multi-graph on 7 vertices>>> for i in range(Integer(20)):...
u = randint(Integer(1), Integer(7))...
v = randint(Integer(1), Integer(7))...
w = randint(Integer(0), Integer(20))...
G.add_edge(u, v, w)>>> H = copy(G)>>> H
Looped multi-graph on 7 vertices>>> def sanitize(G):...
G.allow_loops(False)...
G.allow_multiple_edges(False, keep_label= min )>>> sanitize(H)>>> HGraph on 7 vertices>>> sum(e[Integer(2)] for e in kruskal(G, check=True)) == sum(e[Integer(2)] for e␣˓→in kruskal(H, check=True))
True

An example from pages 599–601 in [GT2001].
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)[( JFK , PVD , 144),( BWI , JFK , 184),(continues on next page)

5.9. Spanning trees

1597Graph Theory, Release 10.4

(continued from previous page)( BOS ,( LAX ,
( BWI ,
( DFW ,
( BWI ,
( DFW ,JFK , 187),
SFO , 337),
ORD , 621),
ORD , 802),
MIA , 946),
LAX , 1235)]>>> from sage.all import *>>> G = Graph({"SFO":{"BOS":Integer(2704), "ORD":Integer(1846), "DFW
˓→":Integer(1464), "LAX":Integer(337)},... "BOS":{"ORD":Integer(867), "JFK":Integer(187), "MIA":Integer(1258)},... "ORD":{"PVD":Integer(849), "JFK":Integer(740), "BWI":Integer(621), "DFW
˓→":Integer(802)},... "DFW":{"JFK":Integer(1391), "MIA":Integer(1121), "LAX":Integer(1235)},... "LAX":{"MIA":Integer(2342)},... "PVD":{"JFK":Integer(144)},... "JFK":{"MIA":Integer(1090), "BWI":Integer(184)},... "BWI":{"MIA":Integer(946)}})>>> G.weighted(True)>>> kruskal(G, check=True)[( JFK , PVD , 144),( BWI , JFK , 184),( BOS , JFK , 187),( LAX , SFO , 337),( BWI , ORD , 621),( DFW , ORD , 802),( BWI , MIA , 946),( DFW , LAX , 1235)]

An example from pages 568–569 in [CLRS2001].
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: T = Graph(kruskal(G, check=True), format= list_of_edges )sage: sum(T.edge_labels())
37
sage: T.is_tree()True>>> from sage.all import *>>> G = Graph({"a":{"b":Integer(4), "h":Integer(8)}, "b":{"c":Integer(8), "h˓→":Integer(11)},... "c":{"d":Integer(7), "f":Integer(4), "i":Integer(2)}, "d":{"e":Integer(9), "f
˓→":Integer(14)},... "e":{"f":Integer(10)}, "f":{"g":Integer(2)}, "g":{"h":Integer(1), "i
˓→":Integer(6)}, "h":{"i":Integer(7)}})>>> G.weighted(True)>>> T = Graph(kruskal(G, check=True), format= list_of_edges )>>> sum(T.edge_labels())
37>>> T.is_tree()True

An example with custom edge labels:

1598

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: G = Graph([[0,1,1],[1,2,1],[2,0,10]], weighted=True)
sage: weight = lambda e:3-e[0]-e[1]sage: sorted(kruskal(G, check=True))[(0, 1, 1), (1, 2, 1)]
sage: sorted(kruskal(G, weight_function=weight, check=True))[(0, 2, 10), (1, 2, 1)]
sage: sorted(kruskal(G, weight_function=weight, check=False))[(0, 2, 10), (1, 2, 1)]>>> from sage.all import *>>> G = Graph([[Integer(0),Integer(1),Integer(1)],[Integer(1),Integer(2),˓→Integer(1)],[Integer(2),Integer(0),Integer(10)]], weighted=True)>>> weight = lambda e:Integer(3)-e[Integer(0)]-e[Integer(1)]>>> sorted(kruskal(G, check=True))[(0, 1, 1), (1, 2, 1)]>>> sorted(kruskal(G, weight_function=weight, check=True))[(0, 2, 10), (1, 2, 1)]>>> sorted(kruskal(G, weight_function=weight, check=False))[(0, 2, 10), (1, 2, 1)]

sage.graphs.spanning_tree.kruskal_iterator(G, by_weight=True, weight_function=None,check_weight=False, check=False)
Return an iterator implementation of Kruskal algorithm.
INPUT:• G – an undirected graph• by_weight – boolean (default: True); if True, the edges in the graph are weighted; if False, all edges
have weight 1.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs anumber for each edge
• check – boolean (default: False); whether to first perform sanity checks on the input graph G. Default:
check=False. If we toggle check=True, the following sanity checks are first performed on G prior torunning 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 function 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, thealgorithm still works, but the running-time can be improved if these edges are removed. To further improve
the runtime of this function, you should call it directly instead of using it indirectly via sage.graphs.
generic_graph.GenericGraph.min_spanning_tree().
OUTPUT:5.9. Spanning trees

1599Graph Theory, Release 10.4

The edges of a minimum spanning tree of G, one by one.
See also:
kruskal()
EXAMPLES:
sage: from sage.graphs.spanning_tree import kruskal_iterator
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: next(kruskal_iterator(G, check=True))(1, 6, 10)>>> from sage.all import *>>> from sage.graphs.spanning_tree import kruskal_iterator>>> G = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
˓→Integer(7):Integer(24)}})>>> G.weighted(True)>>> next(kruskal_iterator(G, check=True))(1, 6, 10)

sage.graphs.spanning_tree.kruskal_iterator_from_edges(edges, union_find, by_weight=True,
weight_function=None,check_weight=False)
Return an iterator implementation of Kruskal algorithm on list of edges.
INPUT:• edges – list of edges• union_find – a DisjointSet_of_hashables encoding a forest• by_weight – boolean (default: True); if True, the edges in the graph are weighted; if False, all edges
have weight 1.
• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l, if l is not None, else 1 as a weight.
• check_weight – boolean (default: False); whether to check that the weight_function outputs anumber for each edge
OUTPUT:
The edges of a minimum spanning tree of G, one by one.
See also:• kruskal()• filter_kruskal()
EXAMPLES:

1600

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: from sage.graphs.spanning_tree import kruskal_iterator_from_edges
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: union_set = DisjointSet(G)sage: next(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_
˓→weight=G.weighted()))(1, 6, 10)>>> from sage.all import *>>> from sage.graphs.spanning_tree import kruskal_iterator_from_edges>>> G = Graph({Integer(1):{Integer(2):Integer(28), Integer(6):Integer(10)},␣
˓→Integer(2):{Integer(3):Integer(16), Integer(7):Integer(14)}, Integer(3):˓→{Integer(4):Integer(12)}, Integer(4):{Integer(5):Integer(22),␣
˓→Integer(7):Integer(18)}, Integer(5):{Integer(6):Integer(25),␣
˓→Integer(7):Integer(24)}})>>> G.weighted(True)>>> union_set = DisjointSet(G)>>> next(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_weight=G.
˓→weighted()))(1, 6, 10)

Check that the method is robust to incomparable vertices:sage: G = Graph([(1, 2, 10), (1, a , 1), ( a , b , 1), ( b , 2, 1)])
sage: union_set = DisjointSet(G)sage: E = list(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_
˓→weight=True))sage: sum(w for _, _, w in E)
3>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2), Integer(10)), (Integer(1), a ,␣˓→Integer(1)), ( a ,b , Integer(1)), ( b , Integer(2), Integer(1))])>>> union_set = DisjointSet(G)>>> E = list(kruskal_iterator_from_edges(G.edges(sort=False), union_set, by_
˓→weight=True))>>> sum(w for _, _, w in E)
3sage.graphs.spanning_tree.random_spanning_tree(G, output_as_graph=False, by_weight=False,
weight_function=None, check_weight=True)
Return a random spanning tree of the graph.
This uses the Aldous-Broder algorithm ([Bro1989], [Ald1990]) 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. Everytime a new vertex 𝑗 is met, add the edge (𝑖, 𝑗) to the spanning tree, where 𝑖 is the previous vertex in the random
walk.
When by_weight is True or a weight function is given, the selection of the neighbor is done proportionaly tothe edge weights.
INPUT:• G – an undirected graph• output_as_graph – boolean (default: False); whether to return a list of edges or a graph5.9. Spanning trees

1601Graph Theory, Release 10.4

• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l , if l is not None, else 1 as a weight. The weight_function can be used
to transform the label into a weight (note that, if the weight returned is not convertible to a float, an error israised)• check_weight – boolean (default: True); whether to check that the weight_function outputs anumber for each edge.
See also:
spanning_trees_count() and spanning_trees()
EXAMPLES:
sage: G = graphs.TietzeGraph()
sage: G.random_spanning_tree(output_as_graph=True)
Graph on 12 vertices
sage: rg = G.random_spanning_tree(); rg # random[(0, 9),(9, 11),(0, 8),(8, 7),(7, 6),(7, 2),(2, 1),(1, 5),(9, 10),(5, 4),(2, 3)]
sage: Graph(rg).is_tree()True>>> from sage.all import *>>> G = graphs.TietzeGraph()>>> G.random_spanning_tree(output_as_graph=True)
Graph on 12 vertices>>> rg = G.random_spanning_tree(); rg # random[(0, 9),(9, 11),(0, 8),(8, 7),(7, 6),(7, 2),(2, 1),(1, 5),(9, 10),(5, 4),(2, 3)]>>> Graph(rg).is_tree()True

A visual example for the grid graph:
sage: G = graphs.Grid2dGraph(6, 6)
sage: pos = G.get_pos()(continues on next page)

1602

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: T = G.random_spanning_tree(True)
sage: T.set_pos(pos)sage: T.show(vertex_labels=False)
˓→needs sage.plot>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(6), Integer(6))>>> pos = G.get_pos()>>> T = G.random_spanning_tree(True)>>> T.set_pos(pos)>>> T.show(vertex_labels=False)
˓→needs sage.plot#␣#␣

We can also use edge weights to change the probability of returning a spanning tree:
sage: def foo(G, k):....:
S = set()....:for _ in range(k):....:E = G.random_spanning_tree(by_weight=True)....:
S.add(Graph(E).graph6_string())....:
return S
sage: K3 = graphs.CompleteGraph(3)sage: for u, v in K3.edges(sort=True, labels=False):....:
K3.set_edge_label(u, v, randint(1, 2))
sage: foo(K3, 100) == { BW , Bg , Bo } # random
True
sage: K4 = graphs.CompleteGraph(4)sage: for u, v in K4.edges(sort=True, labels=False):....:
K4.set_edge_label(u, v, randint(1, 2))
sage: print(len(foo(K4, 100))) # random
16>>> from sage.all import *>>> def foo(G, k):...
S = set()...
for _ in range(k):...
E = G.random_spanning_tree(by_weight=True)...
S.add(Graph(E).graph6_string())...
return S>>> K3 = graphs.CompleteGraph(Integer(3))>>> for u, v in K3.edges(sort=True, labels=False):...
K3.set_edge_label(u, v, randint(Integer(1), Integer(2)))>>> foo(K3, Integer(100)) == { BW , Bg , Bo } # random
True>>> K4 = graphs.CompleteGraph(Integer(4))>>> for u, v in K4.edges(sort=True, labels=False):...
K4.set_edge_label(u, v, randint(Integer(1), Integer(2)))>>> print(len(foo(K4, Integer(100)))) # random
16

Check that the spanning tree returned when using weights is a tree:
sage: # needs networkx
sage: G = graphs.RandomBarabasiAlbert(50, 2)
sage: for u, v in G.edge_iterator(labels=False):....:
G.set_edge_label(u, v, randint(1, 10))(continues on next page)

5.9. Spanning trees1603

Graph Theory, Release 10.4

(continued from previous page)

sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True)
sage: T.is_tree()True>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomBarabasiAlbert(Integer(50), Integer(2))>>> for u, v in G.edge_iterator(labels=False):...
G.set_edge_label(u, v, randint(Integer(1), Integer(10)))>>> T = G.random_spanning_tree(by_weight=True, output_as_graph=True)>>> T.is_tree()Truesage.graphs.spanning_tree.spanning_trees(g, labels=False)
Return an iterator over all spanning trees of the graph 𝑔.
A disconnected graph has no spanning tree.
Uses the Read-Tarjan backtracking algorithm [RT1975a].
INPUT:• labels – boolean (default: False); whether to return edges labels in the spanning trees or not
EXAMPLES:
sage: G = Graph([(1,2),(1,2),(1,3),(1,3),(2,3),(1,4)], multiedges=True)
sage: len(list(G.spanning_trees()))
8
sage: G.spanning_trees_count()
˓→needs sage.modules
8
sage: G = Graph([(1,2),(2,3),(3,1),(3,4),(4,5),(4,5),(4,6)], multiedges=True)
sage: len(list(G.spanning_trees()))
6
sage: G.spanning_trees_count()
˓→needs sage.modules
6>>> from sage.all import *>>> G = Graph([(Integer(1),Integer(2)),(Integer(1),Integer(2)),(Integer(1),˓→Integer(3)),(Integer(1),Integer(3)),(Integer(2),Integer(3)),(Integer(1),˓→Integer(4))], multiedges=True)>>> len(list(G.spanning_trees()))
8>>> G.spanning_trees_count()
˓→needs sage.modules
8>>> G = Graph([(Integer(1),Integer(2)),(Integer(2),Integer(3)),(Integer(3),˓→Integer(1)),(Integer(3),Integer(4)),(Integer(4),Integer(5)),(Integer(4),˓→Integer(5)),(Integer(4),Integer(6))], multiedges=True)>>> len(list(G.spanning_trees()))
6>>> G.spanning_trees_count()
˓→needs sage.modules
6

#␣

#␣

#␣

#␣

See also:
1604

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• spanning_trees_count() – counts the number of spanning trees• random_spanning_tree() – returns a random spanning tree

5.10 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 ofthem.
2. We select some element 𝑥 and update the data structure 𝑇 to restrict the permutations it describes to those thatkeep the occurrences of 𝑥 on an interval of [1, ..., 𝑘]. This will result in a new 𝑃 -tree whose children are:• all 𝑐¯𝑥 sets 𝑆𝑖 which do not contain 𝑥.
• a new 𝑃 -tree whose children are the 𝑐𝑥 sets 𝑆𝑖 containing 𝑥.
This describes the set of all 𝑐𝑥 ! × 𝑐¯′𝑥 ! permutations of 𝑆1 , ..., 𝑆𝑘 that keep the sets containing 𝑥 on an interval.
3. We take a second element 𝑥′ and update the data structure 𝑇 to restrict the permutations it describes to those thatkeep 𝑥′ 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:

5.10. PQ-Trees

1605

Graph Theory, Release 10.4

• 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 thepossible permutations of our sets satisfying our constraints, or to prove that no such ordering exists. This is thewhole purpose of this module, and is explained with more details in many places, for example in the following
document from Hajiaghayi [Haj2000].
Authors:
Nathann Cohen (initial implementation)

5.10.1 Methods and functionsclass sage.graphs.pq_trees.P(seq)Bases: 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:
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>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = P([[Integer(0),Integer(3)], [Integer(1),Integer(2)], [Integer(2),˓→Integer(3)], [Integer(2),Integer(4)], [Integer(4),Integer(0)],[Integer(2),˓→Integer(8)], [Integer(2),Integer(9)]])>>> p.cardinality()
5040>>> p.set_contiguous(Integer(3))(1, True)(continues on next page)

1606

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> 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})...
>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = P([[Integer(2),Integer(4)], [Integer(1),Integer(2)], [Integer(0),˓→Integer(8)], [Integer(0),Integer(5)]])>>> 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 theright 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 alignthem 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:
5.10. PQ-Trees

1607

Graph Theory, Release 10.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.set_contiguous(0)(1, True)sage: print(p)( P , [{1, 2}, {2, 3}, {2, 4}, {8, 2}, {9, 2}, ( P , [{0, 3}, {0, 4}])])>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = P([[Integer(0),Integer(3)], [Integer(1),Integer(2)], [Integer(2),˓→Integer(3)], [Integer(2),Integer(4)], [Integer(4),Integer(0)],[Integer(2),˓→Integer(8)], [Integer(2),Integer(9)]])>>> p.set_contiguous(Integer(0))(1, True)>>> print(p)( P , [{1, 2}, {2, 3}, {2, 4}, {8, 2}, {9, 2}, ( P , [{0, 3}, {0, 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>>> from sage.all import *>>> p = P([[Integer(0),Integer(1)], [Integer(1),Integer(2)], [Integer(2),˓→Integer(3)], [Integer(3),Integer(0)]])>>> p.set_contiguous(Integer(0))(1, True)>>> p.set_contiguous(Integer(1))(1, True)>>> p.set_contiguous(Integer(2))(1, True)>>> p.set_contiguous(Integer(3))
Traceback (most recent call last):...
ValueError: Impossibleclass sage.graphs.pq_trees.PQ(seq)Bases: object
PQ-Trees
This class should not be instantiated by itself: it is extended by P and Q. See the documentation of sage.graphs.
pq_trees for more information.
AUTHOR : Nathann Cohen
flatten()
Returns a flattened copy of self

1608

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

If self has only one child, we may as well consider its child’s children, as self encodes no information. Thismethod 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}])>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = Q([P([[Integer(2),Integer(4)], [Integer(2),Integer(8)], [Integer(2),˓→Integer(9)]])])>>> 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>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = Q([[Integer(1),Integer(2)], [Integer(2),Integer(3)], P([[Integer(2),˓→Integer(4)], [Integer(2),Integer(8)], [Integer(2),Integer(9)]])])>>> 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}]>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = Q([[Integer(1),Integer(2)], [Integer(2),Integer(3)], P([[Integer(2),˓→Integer(4)], [Integer(2),Integer(8)], [Integer(2),Integer(9)]])])>>> p.ordering()[{1, 2}, {2, 3}, {2, 4}, {8, 2}, {9, 2}]reverse()Recursively reverses self and its children
EXAMPLES:

5.10. PQ-Trees

1609

Graph Theory, Release 10.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}]>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = Q([[Integer(1),Integer(2)], [Integer(2),Integer(3)], P([[Integer(2),˓→Integer(4)], [Integer(2),Integer(8)], [Integer(2),Integer(9)]])])>>> p.ordering()[{1, 2}, {2, 3}, {2, 4}, {8, 2}, {9, 2}]>>> p.reverse()>>> 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 thecase when this method is called).
INPUT:• left, right – booleans; 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 𝑃 -Treesage: 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}])]>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> p = P([[Integer(2),Integer(4)], [Integer(1),Integer(2)], [Integer(0),˓→Integer(8)], [Integer(0),Integer(5)]])>>> p.simplify(Integer(0), right = True)[( P , [{2, 4}, {1, 2}]), ( P , [{0, 8}, {0, 5}])]1610

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

A 𝑄-Treesage: q = Q([[2,4], [1,2], [0,8], [0,5]])
sage: q.simplify(0, right = True)[{2, 4}, {1, 2}, {0, 8}, {0, 5}]>>> from sage.all import *>>> q = Q([[Integer(2),Integer(4)], [Integer(1),Integer(2)], [Integer(0),˓→Integer(8)], [Integer(0),Integer(5)]])>>> q.simplify(Integer(0), right = True)[{2, 4}, {1, 2}, {0, 8}, {0, 5}]class sage.graphs.pq_trees.Q(seq)Bases: PQ
A Q-Tree is a PQ-Tree whose children are ordered up to reversal
For more information, see the documentation of sage.graphs.pq_trees.
cardinality()
Return the number of orderings allowed by the structure.
See also:orderings() – iterate over all admissible orderings
EXAMPLES:
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>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> q = Q([[Integer(0),Integer(3)], [Integer(1),Integer(2)], [Integer(2),˓→Integer(3)], [Integer(2),Integer(4)], [Integer(4),Integer(0)],[Integer(2),˓→Integer(8)], [Integer(2),Integer(9)]])>>> q.cardinality()
2orderings()
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})>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q
(continues on next page)

5.10. PQ-Trees

1611

Graph Theory, Release 10.4

(continued from previous page)>>> q = Q([[Integer(2),Integer(4)], [Integer(1),Integer(2)], [Integer(0),˓→Integer(8)], [Integer(0),Integer(5)]])>>> 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 theright 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 alignthem 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}])>>> from sage.all import *>>> from sage.graphs.pq_trees import P, Q>>> q = Q([[Integer(2),Integer(3)], Q([[Integer(3),Integer(0)],[Integer(3),˓→Integer(1)]]), Q([[Integer(4),Integer(0)],[Integer(4),Integer(5)]])])>>> q.set_contiguous(Integer(0))(1, False)>>> 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)Traceback (most recent call last):...
ValueError: Impossible

1612

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> p = Q([[Integer(0),Integer(1)], [Integer(1),Integer(2)], [Integer(2),˓→Integer(0)]])>>> p.set_contiguous(Integer(0))
Traceback (most recent call last):...
ValueError: Impossible

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 waythat ∀𝑥 ∈ 𝑋 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)]>>> from sage.all import *>>> from sage.graphs.pq_trees import reorder_sets>>> seq = [Set([i-Integer(1),i,i+Integer(1)]) for i in range(Integer(1),˓→Integer(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}]>>> from sage.all import *>>> p = Permutations(len(seq)).random_element()>>> seq = [ seq[p(i+Integer(1))-Integer(1)] for i in range(len(seq)) ]>>> ordered = reorder_sets(seq)>>> if not Integer(0) in ordered[Integer(0)]:...
ordered = ordered.reverse()>>> 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}]

5.10. PQ-Trees

1613

Graph Theory, Release 10.4

5.11 Generation of trees
This is an implementation of the algorithm for generating trees with 𝑛 vertices (up to isomorphism) in constant time pertree described in [WROM1986].
AUTHORS:• Ryan Dingman (2009-04-16): initial version
class sage.graphs.trees.TreeIterator
Bases: object
This class iterates over all trees with n vertices (up to isomorphism).
EXAMPLES:
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>>> from sage.all import *>>> from sage.graphs.trees import TreeIterator>>> 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 - Integer(1):...
return False...
for tree in trees:...
if tree.is_isomorphic(t):...
return False...
trees.append(t)...
return True>>> check_trees(Integer(10))
True
sage: from sage.graphs.trees import TreeIterator
sage: count = 0
sage: for t in TreeIterator(15):....:count += 1
(continues on next page)

1614

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: count7741>>> from sage.all import *>>> from sage.graphs.trees import TreeIterator>>> count = Integer(0)>>> for t in TreeIterator(Integer(15)):...
count += Integer(1)>>> count
7741

5.12 Matching polynomial
This module contains the following methods:
matching_polynomial()
complete_poly()

Computes the matching polynomial of a given graph
Compute the matching polynomial of the complete graph on 𝑛 vertices.

AUTHORS:• Robert Miller, Tom Boothby - original implementation
REFERENCE:[God1993]

5.12.1 Methods
sage.graphs.matchpoly.complete_poly(n)Compute the matching polynomial of the complete graph on 𝑛 vertices.
INPUT:• n – order of the complete graphTodo: 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: fx^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))
4068245.12. Matching polynomial

1615Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.matchpoly import complete_poly>>> f = complete_poly(Integer(10))>>> fx^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945>>> f = complete_poly(Integer(20))>>> f[Integer(8)]1309458150>>> f = complete_poly(Integer(1000))>>> len(str(f))
406824sage.graphs.matchpoly.matching_polynomial(G, complement=True, name=None)
Computes the matching polynomial of the graph 𝐺.
If 𝑝(𝐺, 𝑘) denotes the number of 𝑘-matchings (matchings with 𝑘 edges) in 𝐺, then the matching polynomial isdefined as [God1993]:∑︁𝜇(𝑥) =(−1)𝑘 𝑝(𝐺, 𝑘)𝑥𝑛−2𝑘𝑘≥0INPUT:• complement – (default: True) whether to use Godsil’s duality theorem to compute the matching polynomial from that of the graphs complement (see ALGORITHM).
• name – optional string for the variable name in the polynomial
Note: The complement option uses matching polynomials of complete graphs, which are cached. So if you are
crazy enough to try computing the matching polynomial on a graph with millions of vertices, you might not want
to use this option, since it will end up caching millions of polynomials of degree in the millions.
ALGORITHM:
The algorithm used is a recursive one, based on the following observation [God1993]:• If 𝑒 is an edge of 𝐺, 𝐺′ is the result of deleting the edge 𝑒, and 𝐺′′ is the result of deleting each vertex in 𝑒,then the matching polynomial of 𝐺 is equal to that of 𝐺′ minus that of 𝐺′′ .
(the algorithm actually computes the signless matching polynomial, for which the recursion is the same when
one replaces the subtraction by an addition. It is then converted into the matching polynomial and returned)
Depending on the value of complement, Godsil’s duality theorem [God1993] can also be used to compute 𝜇(𝑥):∑︁
𝜇(𝐺, 𝑥) =𝑝(𝐺, 𝑘)𝜇(𝐾𝑛−2𝑘 , 𝑥)𝑘≥0

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

1616

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.matching_polynomial()x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6>>> g.matching_polynomial(complement=False)x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6>>> g.matching_polynomial(name= tom )tom^10 - 15*tom^8 + 75*tom^6 - 145*tom^4 + 90*tom^2 - 6>>> g = Graph()>>> L = [graphs.RandomGNP(Integer(8), RealNumber( .3 )) for i in range(Integer(1),˓→ Integer(6))]>>> 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))>>> from sage.all import *>>> for i in range(Integer(1), Integer(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))
1sage: matching_polynomial(graphs.CompleteGraph(1))
xsage: 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
(continues on next page)

5.12. Matching polynomial

1617

Graph Theory, Release 10.4

(continued from previous page)

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>>> from sage.all import *>>> from sage.graphs.matchpoly import matching_polynomial>>> matching_polynomial(graphs.CompleteGraph(Integer(0)))
1>>> matching_polynomial(graphs.CompleteGraph(Integer(1)))
x>>> matching_polynomial(graphs.CompleteGraph(Integer(2)))
x^2 - 1>>> matching_polynomial(graphs.CompleteGraph(Integer(3)))
x^3 - 3*x>>> matching_polynomial(graphs.CompleteGraph(Integer(4)))
x^4 - 6*x^2 + 3>>> matching_polynomial(graphs.CompleteGraph(Integer(5)))
x^5 - 10*x^3 + 15*x>>> matching_polynomial(graphs.CompleteGraph(Integer(6)))
x^6 - 15*x^4 + 45*x^2 - 15>>> matching_polynomial(graphs.CompleteGraph(Integer(7)))
x^7 - 21*x^5 + 105*x^3 - 105*x>>> matching_polynomial(graphs.CompleteGraph(Integer(8)))
x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105>>> matching_polynomial(graphs.CompleteGraph(Integer(9)))
x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x>>> matching_polynomial(graphs.CompleteGraph(Integer(10)))x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945>>> matching_polynomial(graphs.CompleteGraph(Integer(11)))x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x>>> matching_polynomial(graphs.CompleteGraph(Integer(12)))x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395>>> matching_polynomial(graphs.CompleteGraph(Integer(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 - xsage: G = Graph({0:[], 1:[], 2:[]})(continues on next page)

1618

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: matching_polynomial(G)x^3>>> from sage.all import *>>> G = Graph({Integer(0):[Integer(1),Integer(2)], Integer(1):[Integer(2)]})>>> matching_polynomial(G)x^3 - 3*x>>> G = Graph({Integer(0):[Integer(1),Integer(2)]})>>> matching_polynomial(G)x^3 - 2*x>>> G = Graph({Integer(0):[Integer(1)], Integer(2):[]})>>> matching_polynomial(G)x^3 - x>>> G = Graph({Integer(0):[], Integer(1):[], Integer(2):[]})>>> matching_polynomial(G)x^3sage: matching_polynomial(graphs.CompleteGraph(0), complement=False)1
sage: matching_polynomial(graphs.CompleteGraph(1), complement=False)xsage: 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 - 15sage: 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>>> from sage.all import *>>> matching_polynomial(graphs.CompleteGraph(Integer(0)), complement=False)1>>> matching_polynomial(graphs.CompleteGraph(Integer(1)), complement=False)x>>> matching_polynomial(graphs.CompleteGraph(Integer(2)), complement=False)x^2 - 1>>> matching_polynomial(graphs.CompleteGraph(Integer(3)), complement=False)x^3 - 3*x>>> matching_polynomial(graphs.CompleteGraph(Integer(4)), complement=False)(continues on next page)

5.12. Matching polynomial

1619

Graph Theory, Release 10.4

(continued from previous page)x^4 - 6*x^2 + 3>>> matching_polynomial(graphs.CompleteGraph(Integer(5)), complement=False)x^5 - 10*x^3 + 15*x>>> matching_polynomial(graphs.CompleteGraph(Integer(6)), complement=False)x^6 - 15*x^4 + 45*x^2 - 15>>> matching_polynomial(graphs.CompleteGraph(Integer(7)), complement=False)x^7 - 21*x^5 + 105*x^3 - 105*x>>> matching_polynomial(graphs.CompleteGraph(Integer(8)), complement=False)x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105>>> matching_polynomial(graphs.CompleteGraph(Integer(9)), complement=False)x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x>>> matching_polynomial(graphs.CompleteGraph(Integer(10)), complement=False)x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945>>> matching_polynomial(graphs.CompleteGraph(Integer(11)), complement=False)x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x>>> matching_polynomial(graphs.CompleteGraph(Integer(12)), complement=False)x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395>>> matching_polynomial(graphs.CompleteGraph(Integer(13)), complement=False)x^13 - 78*x^11 + 2145*x^9 - 25740*x^7 + 135135*x^5 - 270270*x^3 + 135135*x5.13 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 theEuler 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 cancompute the genus of a graph by
2 − 2𝑔 = 𝑉 − 𝐸 + 𝐹
where 𝐸, 𝑉 , and 𝐹 denote the number of orbits of 𝑒, 𝑣, and 𝑓 respectively.
We make several optimizations to the naive algorithm, which are described throughout the file.
class sage.graphs.genus.simple_connected_genus_backtracker
Bases: object
A class which computes the genus of a DenseGraph through an extremely slow but relatively optimized algorithm.
This is “only” exponential for graphs of bounded degree, and feels pretty snappy for 3-regular graphs. The genericruntime is∏︀|𝑉 (𝐺)| 𝑣∈𝑉 (𝐺) (𝑑𝑒𝑔(𝑣) − 1)!
which is 2|𝑉 (𝐺)| for 3-regular graphs, and can achieve 𝑛(𝑛 − 1)!𝑛 for the complete graph on 𝑛 vertices. We canhandily compute the genus of 𝐾6 in milliseconds on modern hardware, but 𝐾7 may take a few days. Don’t botherwith 𝐾8 , or any graph with more than one vertex of degree 10 or worse, unless you can find an a priori lower boundon the genus and expect the graph to have that genus.
Warning:

1620

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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, sparse=False)
sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])sage: bt.genus() #long time1
sage: bt.genus(cutoff=1)
1
sage: G = graphs.PetersenGraph()
sage: G = Graph(G, sparse=False)
sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])sage: bt.genus()
1sage: G = graphs.FlowerSnark()
sage: G = Graph(G, sparse=False)
sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])sage: bt.genus()
2>>> from sage.all import *>>> import sage.graphs.genus>>> G = graphs.CompleteGraph(Integer(6))>>> G = Graph(G, sparse=False)>>> bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> bt.genus() #long time1>>> bt.genus(cutoff=Integer(1))
1>>> G = graphs.PetersenGraph()>>> G = Graph(G, sparse=False)>>> bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> bt.genus()1>>> G = graphs.FlowerSnark()>>> G = Graph(G, sparse=False)>>> bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> bt.genus()
2

genus(style=1, cutoff=0, record_embedding=False)

5.13. Genus

1621

Graph Theory, Release 10.4

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 takemillennia to finish, with the exception of graphs with max degree 3.
INPUT:• style – integer (default: 1); find minimum genus if 1, maximum genus if 2
• cutoff – integer (default: 0); 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 – boolean (default: False); whether or not to remember the best embedding
seen. This embedding can be retrieved with self.get_embedding().
OUTPUT:the minimal or maximal genus for self’s graph.
EXAMPLES:
sage: import sage.graphs.genus
sage: G = Graph(graphs.CompleteGraph(5), 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(sparse=False)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])sage: gb.genus()0>>> from sage.all import *>>> import sage.graphs.genus>>> G = Graph(graphs.CompleteGraph(Integer(5)), sparse=False)>>> gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> gb.genus(cutoff=Integer(2), record_embedding=True)
2>>> E = gb.get_embedding()>>> gb.genus(record_embedding=False)1>>> gb.get_embedding() == E
True>>> gb.genus(style=Integer(2), cutoff=Integer(5))
3>>> G = Graph(sparse=False)>>> gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> gb.genus()
01622

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

get_embedding()
Return an embedding for the graph.
If min_genus_backtrack has been called with record_embedding = True, then this will returnthe 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), 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(sparse=False)
sage: G.add_edge(0,1)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])sage: gb.get_embedding(){0: [1], 1: [0]}sage: G = Graph(sparse=False)
sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[0])sage: gb.get_embedding(){}>>> from sage.all import *>>> import sage.graphs.genus>>> G = Graph(graphs.CompleteGraph(Integer(5)), sparse=False)>>> gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> gb.genus(record_embedding=True)
1>>> 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]}>>> G = Graph(sparse=False)>>> G.add_edge(Integer(0),Integer(1))>>> gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> gb.get_embedding(){0: [1], 1: [0]}>>> G = Graph(sparse=False)>>> gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_
˓→graph()[Integer(0)])>>> 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:

5.13. Genus

1623

Graph Theory, Release 10.4

THIS MAY SEGFAULT OR HANG ON:• DISCONNECTED GRAPHS• DIRECTED GRAPHS• LOOPED GRAPHS• MULTIGRAPHSDO 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)13sage: G = graphs.FlowerSnark()
sage: genus(G) # see [1]2sage: G = graphs.BubbleSortGraph(4)sage: genus(G)0sage: G = graphs.OddGraph(3)sage: genus(G)1>>> from sage.all import *>>> import sage.graphs.genus>>> from sage.graphs.genus import simple_connected_graph_genus as genus>>> [genus(g) for g in graphs(Integer(6)) if g.is_connected()].count(Integer(1))
13>>> G = graphs.FlowerSnark()>>> genus(G) # see [1]2>>> G = graphs.BubbleSortGraph(Integer(4))>>> genus(G)0>>> G = graphs.OddGraph(Integer(3))>>> genus(G)1

REFERENCES:[1] http://www.springerlink.com/content/0776127h0r7548v7/

5.14 Lovász theta-function of graphs
AUTHORS:• Dima Pasechnik (2015-06-30): Initial version
REFERENCE:[Lov1979]

1624

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.14.1 Functions
sage.graphs.lovasz_theta.lovasz_theta(graph)
Return the value of Lovász theta-function of graph.
For a graph 𝐺 this function is denoted by 𝜃(𝐺), and it can be computed in polynomial time. Mathematically, its
most important property is the following:𝛼(𝐺) ≤ 𝜃(𝐺) ≤ 𝜒(𝐺)with 𝛼(𝐺) and 𝜒(𝐺) being, respectively, the maximum size of an independent set set of 𝐺 and the chromatic number of the complement 𝐺 of 𝐺.
For more information, see the Wikipedia article Lovász_number.
Note:• Implemented for undirected graphs only. Use to_undirected to convert a digraph to an undirected
graph.
• This function requires the optional package csdp, which you can install with sage -i csdp.
EXAMPLES:
sage: C = graphs.PetersenGraph()
sage: C.lovasz_theta()
4.0
sage: graphs.CycleGraph(5).lovasz_theta()
2.236068# optional - csdp
# optional - csdp>>> from sage.all import *>>> C = graphs.PetersenGraph()>>> C.lovasz_theta()# optional - csdp
4.0>>> graphs.CycleGraph(Integer(5)).lovasz_theta()# optional - csdp
2.236068

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 atleast three vertices. Uses Walter Schnyder’s Algorithm from [Sch1990].
AUTHORS:• Jonathan Bober, Emily Kirkman (2008-02-09) – initial version
class sage.graphs.schnyder.TreeNode(parent=None, children=None, label=None)
Bases: object
A class to represent each node in the trees used by _realizer and _compute_coordinates when finding
a planar geometric embedding in the grid.
Each tree node is doubly linked to its parent and children.
INPUT:• parent – the parent TreeNode of self
5.15. Schnyder’s algorithm for straight-line planar embeddings

1625

Graph Theory, Release 10.4

• children – a list of TreeNode children of self
• label – the associated realizer vertex label
EXAMPLES:
sage: from sage.graphs.schnyder import TreeNodesage: 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()
2sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()sage: tn3.depth
2>>> from sage.all import *>>> from sage.graphs.schnyder import TreeNode>>> tn = TreeNode(label=Integer(5))>>> tn2 = TreeNode(label=Integer(2),parent=tn)>>> tn3 = TreeNode(label=Integer(3))>>> tn.append_child(tn3)>>> tn.compute_number_of_descendants()
2>>> tn.number_of_descendants
2>>> tn3.number_of_descendants
1>>> tn.compute_depth_of_self_and_children()>>> tn3.depth
2

append_child(child)
Add a child to list of children.
EXAMPLES:
sage: from sage.graphs.schnyder import TreeNodesage: 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()
2sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()sage: tn3.depth21626

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.schnyder import TreeNode>>> tn = TreeNode(label=Integer(5))>>> tn2 = TreeNode(label=Integer(2),parent=tn)>>> tn3 = TreeNode(label=Integer(3))>>> tn.append_child(tn3)>>> tn.compute_number_of_descendants()
2>>> tn.number_of_descendants
2>>> tn3.number_of_descendants
1>>> tn.compute_depth_of_self_and_children()>>> tn3.depth
2compute_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 TreeNodesage: 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()
2sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()sage: tn3.depth
2>>> from sage.all import *>>> from sage.graphs.schnyder import TreeNode>>> tn = TreeNode(label=Integer(5))>>> tn2 = TreeNode(label=Integer(2),parent=tn)>>> tn3 = TreeNode(label=Integer(3))>>> tn.append_child(tn3)>>> tn.compute_number_of_descendants()
2>>> tn.number_of_descendants
2>>> tn3.number_of_descendants
1>>> tn.compute_depth_of_self_and_children()>>> tn3.depth
2compute_number_of_descendants()
Computes the number of descendants of self and all descendants.
For each TreeNode, sets result as attribute self.number_of_descendants
5.15. Schnyder’s algorithm for straight-line planar embeddings

1627Graph Theory, Release 10.4

EXAMPLES:
sage: from sage.graphs.schnyder import TreeNodesage: 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()
2sage: tn.number_of_descendants
2
sage: tn3.number_of_descendants
1
sage: tn.compute_depth_of_self_and_children()sage: tn3.depth
2>>> from sage.all import *>>> from sage.graphs.schnyder import TreeNode>>> tn = TreeNode(label=Integer(5))>>> tn2 = TreeNode(label=Integer(2),parent=tn)>>> tn3 = TreeNode(label=Integer(3))>>> tn.append_child(tn3)>>> tn.compute_number_of_descendants()
2>>> tn.number_of_descendants
2>>> tn3.number_of_descendants
1>>> tn.compute_depth_of_self_and_children()>>> tn3.depth
2sage.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 -1 to -2) The third boundary vertex is then determined using
the orientation and will be labelled -3.
• 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. For thethree outer vertices the list of the neighbors stored in the combinatorial embedding is in the order of the incident
edges between the two incident (and removed) outer edges, and not a cyclic shift of it.
The algorithm is taken from [Bre2000] (section 4.2).
EXAMPLES:
sage: from sage.graphs.schnyder import minimal_schnyder_wood
sage: g = Graph([(0,-1),(0,-2),(0,-3),(-1,-2),(-2,-3),....: (-3,-1)], format= list_of_edges )(continues on next page)

1628

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: g.set_embedding({-1:[-2,0,-3],-2:[-3,0,-1],....: -3:[-1,0,-2],0:[-1,-2,-3]})
sage: newg = minimal_schnyder_wood(g)sage: newg.edges(sort=True)[(0, -3, red ), (0, -2, blue ), (0, -1, green )]sage: newg.plot(color_by_label={ red : red , blue : blue ,˓→needs sage.plot....:
green : green ,None: black })Graphics object consisting of 8 graphics primitives#␣>>> from sage.all import *>>> from sage.graphs.schnyder import minimal_schnyder_wood>>> g = Graph([(Integer(0),-Integer(1)),(Integer(0),-Integer(2)),(Integer(0),˓→Integer(3)),(-Integer(1),-Integer(2)),(-Integer(2),-Integer(3)),... (-Integer(3),-Integer(1))], format= list_of_edges )>>> g.set_embedding({-Integer(1):[-Integer(2),Integer(0),-Integer(3)],˓→Integer(2):[-Integer(3),Integer(0),-Integer(1)],... -Integer(3):[-Integer(1),Integer(0),-Integer(2)],Integer(0):[-Integer(1),˓→Integer(2),-Integer(3)]})>>> newg = minimal_schnyder_wood(g)>>> newg.edges(sort=True)[(0, -3, red ), (0, -2, blue ), (0, -1, green )]>>> newg.plot(color_by_label={ red : red , blue : blue ,#␣˓→needs sage.plot...
green : green ,None: black })Graphics object consisting of 8 graphics primitives

A larger example:
sage: g = Graph([(0,-1),(0,2),(0,1),(0,-3),(-1,-3),(-1,2),....: (-1,-2),(1,2),(1,-3),(2,-2),(1,-2),(-2,-3)], format= list_of_edges )sage: g.set_embedding({-1:[-2,2,0,-3],-2:[-3,1,2,-1],....: -3:[-1,0,1,-2],0:[-1,2,1,-3],1:[-2,-3,0,2],2:[-1,-2,1,0]})
sage: newg = minimal_schnyder_wood(g)sage: newg.edges(sort=True, key=lambda e:(str(e[0]),str(e[1])))[(0, -1, green ),(0, -3, red ),(0, 2, blue ),(1, -2, blue ),(1, -3, red ),(1, 0, green ),(2, -1, green ),(2, -2, blue ),(2, 1, red )]sage: newg2 = minimal_schnyder_wood(g, minimal=False)
sage: newg2.edges(sort=True, key=lambda e:(str(e[0]),str(e[1])))[(0, -1, green ),(0, -3, red ),(0, 1, blue ),(1, -2, blue ),(1, -3, red ),(1, 2, green ),(2, -1, green ),(2, -2, blue ),(2, 0, red )]5.15. Schnyder’s algorithm for straight-line planar embeddings

1629

Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph([(Integer(0),-Integer(1)),(Integer(0),Integer(2)),(Integer(0),˓→Integer(1)),(Integer(0),-Integer(3)),(-Integer(1),-Integer(3)),(-Integer(1),˓→Integer(2)),... (-Integer(1),-Integer(2)),(Integer(1),Integer(2)),(Integer(1),-Integer(3)),˓→(Integer(2),-Integer(2)),(Integer(1),-Integer(2)),(-Integer(2),-Integer(3))],␣
˓→format= list_of_edges )>>> g.set_embedding({-Integer(1):[-Integer(2),Integer(2),Integer(0),-Integer(3)],˓→Integer(2):[-Integer(3),Integer(1),Integer(2),-Integer(1)],... -Integer(3):[-Integer(1),Integer(0),Integer(1),-Integer(2)],Integer(0):[˓→Integer(1),Integer(2),Integer(1),-Integer(3)],Integer(1):[-Integer(2),˓→Integer(3),Integer(0),Integer(2)],Integer(2):[-Integer(1),-Integer(2),˓→Integer(1),Integer(0)]})>>> newg = minimal_schnyder_wood(g)>>> newg.edges(sort=True, key=lambda e:(str(e[Integer(0)]),str(e[Integer(1)])))[(0, -1, green ),(0, -3, red ),(0, 2, blue ),(1, -2, blue ),(1, -3, red ),(1, 0, green ),(2, -1, green ),(2, -2, blue ),(2, 1, red )]>>> newg2 = minimal_schnyder_wood(g, minimal=False)>>> newg2.edges(sort=True, key=lambda e:(str(e[Integer(0)]),str(e[Integer(1)])))[(0, -1, green ),(0, -3, red ),(0, 1, blue ),(1, -2, blue ),(1, -3, red ),(1, 2, green ),(2, -1, green ),(2, -2, blue ),(2, 0, red )]5.16 Wrapper for Boyer’s (C) planarity algorithm
sage.graphs.planarity.is_planar(g, kuratowski=False, set_pos=False, set_embedding=False)
Check whether g is planar using Boyer’s planarity algorithm.
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 attributefor the graph g if set_embedding is set to True.
INPUT:• kuratowski – boolean (default: False); when set to True, return a tuple of a boolean and either Noneor a Kuratowski subgraph (i.e. an edge subdivision of 𝐾5 or 𝐾3,3 ). When set to False, returns True if g
is planar, False otherwise.
• set_pos – boolean (default: False); whether to use Schnyder’s algorithm to determine and set positions• set_embedding – boolean (default: False); whether to record the combinatorial embedding returned(see get_embedding())

1630

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

EXAMPLES:
sage: G = graphs.DodecahedralGraph()
sage: from sage.graphs.planarity import is_planar
sage: is_planar(G)True
sage: Graph( @ ).is_planar()True>>> from sage.all import *>>> G = graphs.DodecahedralGraph()>>> from sage.graphs.planarity import is_planar>>> is_planar(G)True>>> Graph( @ ).is_planar()True

5.17 Graph traversals
This module implements the following graph traversals
lex_BFS()
lex_DFS()
lex_UP()
lex_DOWN()
lex_M()
lex_M_slow()lex_M_fast()
maximum_cardinality_search()
maximum_cardinality_search_M()

Perform a lexicographic breadth first search (LexBFS) on the graph.
Perform a lexicographic depth first search (LexDFS) on the graph.
Perform a lexicographic UP search (LexUP) on the graph.
Perform a lexicographic DOWN search (LexDOWN) on the graph.
Return an ordering of the vertices according the LexM graph traversal.
Return an ordering of the vertices according the LexM graph traversal.
Return an ordering of the vertices according the LexM graph traversal.
Return an ordering of the vertices according a maximum cardinality search.
Return the ordering and the edges of the triangulation produced by MCS-M.

5.17.1 Methods
sage.graphs.traversals.is_valid_lex_M_order(G, alpha, F)
Check whether the ordering alpha and the triangulation F are valid for G.
Given the graph 𝐺 = (𝑉, 𝐸) with vertex set 𝑉 and edge set 𝐸, and the set 𝐹 of edges of a triangulation of𝐺, let 𝐻 = (𝑉, 𝐸 ∪ 𝐹 ). By induction one can see that for every 𝑖 ∈ {1, ..., 𝑛 − 1} the neighbors of 𝛼(𝑖) in
𝐻[{𝛼(𝑖), ..., 𝛼(𝑛)}] induce a clique. The ordering 𝛼 is a perfect elimination ordering of 𝐻, so 𝐻 is chordal. See[RTL76] for more details.
INPUT:• G – a Graph• alpha – list; an ordering of the vertices of 𝐺
• F – an iterable of edges given either as (u, v) or (u, v, label), the edges of the triangulation of 𝐺

5.17. Graph traversals

1631Graph Theory, Release 10.4

sage.graphs.traversals.lex_BFS(G, reverse=False, tree=False, initial_vertex=None, algorithm='fast')
Perform a lexicographic breadth first search (LexBFS) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being linked
to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider• algorithm – string (default: "fast"); algorithm to use among:– "slow" – This algorithm maintains for each vertex left in the graph a code corresponding to the vertices
already removed. The vertex of maximal code (according to the lexicographic order) is then removed,
and the codes are updated. See for instance [CK2008] for more details. The time complexity of thisalgorithm as described in [CK2008] is in 𝑂(𝑛 + 𝑚), where 𝑛 is the number of vertices and 𝑚 is thenumber of edges, but our implementation is in 𝑂(𝑛2 ).
– "fast" – This algorithm uses the notion of slices to refine the position of the vertices in the ordering.
The time complexity of this algorithm is in 𝑂(𝑛 + 𝑚), and our implementation follows that complexity
for SparseGraph. For DenseGraph, the complexity is 𝑂(𝑛2 ). See [HMPV2000] and next section
for more details.
ALGORITHM:
The "fast" algorithm is the 𝑂(𝑛 + 𝑚) time algorithm proposed in [HMPV2000], where 𝑛 is the number ofvertices and 𝑚 is the number of edges. It uses the notion of slices, i.e., subsets of consecutive vertices in theordering, and iteratively refines the slices by subdividing them into sub-slices to determine the exact position of thevertices in the ordering.
Consider an ordering 𝜎 of the vertices. For a vertex 𝑣, we define 𝑁𝑖 (𝑣) = {𝑢|𝑢 ∈ 𝑁 (𝑣) and 𝜎(𝑢) < 𝑖}, that is
the subset of neighbors of 𝑣 appearing before the 𝑖-th vertex in the ordering 𝜎. Now, a slice of an ordering 𝜎 is aset of consecutive vertices, 𝑆 = {𝑢|𝑖 ≤ 𝜎(𝑢) ≤ 𝑗}, such that for any 𝑢 ∈ 𝑆, we have 𝑁𝑖 (𝑢) = 𝑁𝑖 (𝜎 −1 (𝑖)) andfor any 𝑣 such that 𝑗 < 𝜎(𝑣), 𝑁𝑖 (𝑣) ̸= 𝑁𝑖 (𝜎 −1 (𝑖)). The head of a slice is the first position of its vertices.
The algorithm starts with a single slice containing all vertices. Then, when the position of the 𝑖-th vertex 𝑣 is fixed,
it explores the neighbors of 𝑣 that have not yet been ordered. Consider a slice 𝑆 such that 𝑁 (𝑥) ∩ 𝑆 ̸= ∅. The
algorithm will rearrange the ordering of the vertices in 𝑆 so that the first vertices are the neighbors of 𝑣. The
sub-slice containing the neighbors of 𝑣 is assigned a new slice name, and the head of slice 𝑆 is set to the positionof the first vertex of 𝑆 ∖ 𝑁 (𝑣) in the ordering 𝜎.
Observe that each arc of the graph can induce the subdivision of a slice. Hence, the algorithm can use up to 𝑚 + 1
different slices.
See also:• Wikipedia article Lexicographic_breadth-first_search• lex_DFS() – perform a lexicographic depth first search (LexDFS) on the graph• lex_UP() – perform a lexicographic UP search (LexUP) on the graph• lex_DOWN() – perform a lexicographic DOWN search (LexDOWN) on the graph
EXAMPLES:
A Lex BFS is obviously an ordering of the vertices:

1632

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g = graphs.CompleteGraph(6)sage: len(g.lex_BFS()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_BFS()) == g.order()True

Lex BFS ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),␣
˓→(5, 6)])sage: g.lex_BFS()[1, 2, 3, 5, 4, 6]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4)), (Integer(2), Integer(5)), (Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(6)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(6))])>>> g.lex_BFS()[1, 2, 3, 5, 4, 6]

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_BFS(initial_vertex=2, algorithm="slow")[2, 3, 1]
sage: G.lex_BFS(initial_vertex=2, algorithm="fast")[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1),␣
˓→Integer(3))])>>> G.lex_BFS(initial_vertex=Integer(2), algorithm="slow")[2, 3, 1]>>> G.lex_BFS(initial_vertex=Integer(2), algorithm="fast")[2, 3, 1]

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)]>>> from sage.all import *>>> g = graphs.PathGraph(Integer(3)).lexicographic_product(graphs.
˓→CompleteGraph(Integer(2)))>>> 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):5.17. Graph traversals

1633Graph Theory, Release 10.4

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>>> from sage.all import *>>> g = graphs.ClawGraph().lexicographic_product(graphs.CompleteGraph(Integer(2)))>>> v = g.lex_BFS()[-Integer(1)]>>> peo, tree = g.lex_BFS(initial_vertex = v, tree=True)>>> leaves = [v for v in tree if tree.in_degree(v) ==Integer(0)]>>> all(g.subgraph(g.neighbors(v)).is_clique() for v in leaves)
True

Different orderings for different traversals:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 , algorithm="fast")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]sage: G.lex_BFS(initial_vertex= 000 , algorithm="slow")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 , 111 ]sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 , 100 ]sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 , 101 ]>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 , algorithm="fast")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]>>> G.lex_BFS(initial_vertex= 000 , algorithm="slow")[ 000 , 001 , 100 , 010 , 011 , 110 , 101 , 111 ]>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 , 111 ]>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 , 100 ]>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 , 101 ]sage.graphs.traversals.lex_DFS(G, reverse=False, tree=False, initial_vertex=None)
Perform a lexicographic depth first search (LexDFS) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being linked
to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider
ALGORITHM:
1634

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

This algorithm maintains for each vertex left in the graph a code corresponding to the vertices already removed.
The vertex of maximal code (according to the lexicographic order) is then removed, and the codes are updated.
Lex DFS differs from Lex BFS only in the way codes are updated after each iteration.
Time complexity is 𝑂(𝑛+𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number of vertices
and 𝑚 is the number of edges.
See [CK2008] for more details on the algorithm.
See also:• lex_BFS() – perform a lexicographic breadth first search (LexBFS) on the graph• lex_UP() – perform a lexicographic UP search (LexUP) on the graph• lex_DOWN() – perform a lexicographic DOWN search (LexDOWN) on the graph
EXAMPLES:
A Lex DFS is obviously an ordering of the vertices:sage: g = graphs.CompleteGraph(6)sage: len(g.lex_DFS()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_DFS()) == g.order()True

Lex DFS ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),␣
˓→(5, 6)])sage: g.lex_DFS()[1, 2, 3, 5, 6, 4]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4)), (Integer(2), Integer(5)), (Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(6)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(6))])>>> g.lex_DFS()[1, 2, 3, 5, 6, 4]

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_DFS(initial_vertex=2)[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1),␣
˓→Integer(3))])>>> G.lex_DFS(initial_vertex=Integer(2))[2, 3, 1]

Different orderings for different traversals:

5.17. Graph traversals

1635Graph Theory, Release 10.4

sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 ,sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 ,sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

101 ,

111 ]

011 ,

111 ]

011 ,

100 ]

111 ,

101 ]

>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 , 101 ,>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 ,>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 ,>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 ,

111 ]
111 ]
100 ]
101 ]

sage.graphs.traversals.lex_DOWN(G, reverse=False, tree=False, initial_vertex=None)
Perform a lexicographic DOWN search (LexDOWN) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being linked
to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider
ALGORITHM:
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.
During the 𝑖-th iteration of the algorithm 𝑛 − 𝑖 is prepended to the codes of all neighbors of the selected vertex
that are left in the graph.
Time complexity is 𝑂(𝑛+𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number of vertices
and 𝑚 is the number of edges.
See [Mil2017] for more details on the algorithm.
See also:• lex_BFS() – perform a lexicographic breadth first search (LexBFS) on the graph• lex_DFS() – perform a lexicographic depth first search (LexDFS) on the graph• lex_UP() – perform a lexicographic UP search (LexUP) on the graph
EXAMPLES:
A Lex DOWN is obviously an ordering of the vertices:

1636

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g = graphs.CompleteGraph(6)sage: len(g.lex_DOWN()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_DOWN()) == g.order()True

Lex DOWN ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),␣
˓→(5, 6)])sage: g.lex_DOWN()[1, 2, 3, 4, 6, 5]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4)), (Integer(2), Integer(5)), (Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(6)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(6))])>>> g.lex_DOWN()[1, 2, 3, 4, 6, 5]

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_DOWN(initial_vertex=2)[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1),␣
˓→Integer(3))])>>> G.lex_DOWN(initial_vertex=Integer(2))[2, 3, 1]

Different orderings for different traversals:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 ,sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 ,sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

101 ,

111 ]

011 ,

111 ]

011 ,

100 ]

111 ,

101 ]

>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 , 101 ,>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 ,

111 ]
111 ]
(continues on next page)

5.17. Graph traversals

1637Graph Theory, Release 10.4

(continued from previous page)>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

011 ,

100 ]

111 ,

101 ]

sage.graphs.traversals.lex_M(self, triangulation=False, labels=False, initial_vertex=None,algorithm=None)
Return an ordering of the vertices according the LexM graph traversal.
LexM is a lexicographic ordering scheme that is a special type of breadth-first-search. LexM can also producea triangulation of the given graph. This functionality is implemented in this method. For more details on thealgorithms used see Sections 4 ( lex_M_slow ) and 5.3 ( lex_M_fast ) of [RTL76].
Note: This method works only for undirected graphs.
INPUT:• triangulation – boolean (default: False); whether to return a list of edges that need to be added inorder to triangulate the graph• labels – boolean (default: False); whether to return the labels assigned to each vertex• initial_vertex – (default: None); the first vertex to consider• algorithm – string (default: None); one of the following algorithms:–

lex_M_slow : slower implementation of LexM traversal–

lex_M_fast : faster implementation of LexM traversal (works only when labels is set to
False)– None: Sage chooses the best algorithm:
lex_M_fast otherwise.

lex_M_slow

if labels is set to True,OUTPUT:
Depending on the values of the parameters triangulation and labels the method will return one or moreof the following (in that order):• an ordering of vertices of the graph according to LexM ordering scheme• the labels assigned to each vertex• a list of edges that when added to the graph will triangulate it
EXAMPLES:
LexM produces an ordering of the vertices:sage: g = graphs.CompleteGraph(6)sage: ord = g.lex_M(algorithm= lex_M_fast )sage: len(ord) == g.order()True
sage: set(ord) == set(g.vertices(sort=False))
True
sage: ord = g.lex_M(algorithm= lex_M_slow )sage: len(ord) == g.order()True
sage: set(ord) == set(g.vertices(sort=False))
True

1638

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> ord = g.lex_M(algorithm= lex_M_fast )>>> len(ord) == g.order()True>>> set(ord) == set(g.vertices(sort=False))
True>>> ord = g.lex_M(algorithm= lex_M_slow )>>> len(ord) == g.order()True>>> set(ord) == set(g.vertices(sort=False))
True

Both algorithms produce a valid LexM ordering 𝛼 (i.e the neighbors of 𝛼(𝑖) in 𝐺[{𝛼(𝑖), ..., 𝛼(𝑛)}] induce a clique):sage: from sage.graphs.traversals import is_valid_lex_M_ordersage: G = graphs.PetersenGraph()
sage: ord, F = G.lex_M(triangulation=True, algorithm= lex_M_slow )sage: is_valid_lex_M_order(G, ord, F)
True
sage: ord, F = G.lex_M(triangulation=True, algorithm= lex_M_fast )sage: is_valid_lex_M_order(G, ord, F)
True>>> from sage.all import *>>> from sage.graphs.traversals import is_valid_lex_M_order>>> G = graphs.PetersenGraph()>>> ord, F = G.lex_M(triangulation=True, algorithm= lex_M_slow )>>> is_valid_lex_M_order(G, ord, F)
True>>> ord, F = G.lex_M(triangulation=True, algorithm= lex_M_fast )>>> is_valid_lex_M_order(G, ord, F)
True

LexM produces a triangulation of given graph:
sage: G = graphs.PetersenGraph()
sage: _, F = G.lex_M(triangulation=True)
sage: H = Graph(F, format= list_of_edges )sage: H.is_chordal()True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> _, F = G.lex_M(triangulation=True)>>> H = Graph(F, format= list_of_edges )>>> H.is_chordal()
True

LexM ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),␣
˓→(5, 6)])sage: g.lex_M()[6, 4, 5, 3, 2, 1]

5.17. Graph traversals

1639Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4)), (Integer(2), Integer(5)), (Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(6)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(6))])>>> g.lex_M()[6, 4, 5, 3, 2, 1]

sage.graphs.traversals.lex_M_fast(G, triangulation=False, initial_vertex=None)
Return an ordering of the vertices according the LexM graph traversal.
LexM is a lexicographic ordering scheme that is a special type of breadth-first-search. This function implements
the algorithm described in Section 5.3 of [RTL76].
Note that instead of using labels 1, 2, . . . , 𝑘 and adding 1/2, we use labels 2, 4, . . . , 𝑘 and add 1, thus avoiding touse floats or rationals.
Note: This method works only for undirected graphs.
INPUT:• G – a sage graph• triangulation – boolean (default: False); whether to return the triangulation of given graph producedby the method• initial_vertex – (default: None); the first vertex to consider
OUTPUT:
This method will return an ordering of the vertices of G according to the LexM ordering scheme. Furthermore, if
triangulation is set to True the method also returns a list of edges F such that when added to G the resulting
graph is a triangulation of G.
EXAMPLES:
A LexM ordering is obviously an ordering of the vertices:sage: from sage.graphs.traversals import lex_M_fast
sage: g = graphs.CompleteGraph(6)sage: len(lex_M_fast(g)) == g.order()True>>> from sage.all import *>>> from sage.graphs.traversals import lex_M_fast>>> g = graphs.CompleteGraph(Integer(6))>>> len(lex_M_fast(g)) == g.order()
True

LexM ordering of the 3-sun graph:
sage: from sage.graphs.traversals import lex_M_fast
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),␣
˓→(5, 6)])sage: lex_M_fast(g)[6, 4, 5, 3, 2, 1]

1640

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.traversals import lex_M_fast>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4)), (Integer(2), Integer(5)), (Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(6)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(6))])>>> lex_M_fast(g)[6, 4, 5, 3, 2, 1]

LexM produces a triangulation of given graph:
sage: from sage.graphs.traversals import lex_M_fast
sage: G = graphs.PetersenGraph()
sage: _, F = lex_M_fast(G, triangulation=True)
sage: H = G.copy()
sage: H.add_edges(F)sage: H.is_chordal()True>>> from sage.all import *>>> from sage.graphs.traversals import lex_M_fast>>> G = graphs.PetersenGraph()>>> _, F = lex_M_fast(G, triangulation=True)>>> H = G.copy()>>> H.add_edges(F)>>> H.is_chordal()Truesage.graphs.traversals.lex_M_slow(G, triangulation=False, labels=False, initial_vertex=None)
Return an ordering of the vertices according the LexM graph traversal.
LexM is a lexicographic ordering scheme that is a special type of breadth-first-search. This function implements
the algorithm described in Section 4 of [RTL76].
During the search, the vertices are numbered from 𝑛 to 1. Let 𝛼(𝑖) denote the vertex numbered 𝑖 and let 𝛼−1 (𝑢)denote the number assigned to 𝑢. Each vertex 𝑢 has also a label, denoted by 𝑙𝑎𝑏𝑒𝑙(𝑢), consisting of a list of
numbers selected from [1, 𝑛] and ordered in decreasing order. Given two labels 𝐿1 = [𝑝1 , 𝑝2 , . . . , 𝑝𝑘 ] and 𝐿1 =[𝑞1 , 𝑞2 , . . . , 𝑞𝑙 ], we define 𝐿1 < 𝐿2 if, for some 𝑗, 𝑝𝑖 == 𝑞𝑖 for 𝑖 = 1, . . . , 𝑗 − 1 and 𝑝𝑗 < 𝑞𝑗 , or if 𝑝𝑖 == 𝑞𝑖 for
𝑖 = 1, . . . , 𝑘 and 𝑘 < 𝑙. Observe that this is exactly how Python compares two lists.
Note: This method works only for undirected graphs.
INPUT:• G – a sage graph• triangulation – boolean (default: False); whether to return the triangulation of the graph producedby the method• labels – boolean (default: False); whether to return the labels assigned to each vertex• initial_vertex – (default: None); the first vertex to consider. If not specified, an arbitrary vertex ischosen.
OUTPUT:
Depending on the values of the parameters triangulation and labels the method will return one or moreof the following (in that order):5.17. Graph traversals

1641Graph Theory, Release 10.4

• the ordering of vertices of 𝐺
• the labels assigned to each vertex• a list of edges that when added to 𝐺 will produce a triangulation of 𝐺
EXAMPLES:
A LexM ordering is obviously an ordering of the vertices:sage: from sage.graphs.traversals import lex_M_slow
sage: g = graphs.CompleteGraph(6)sage: len(lex_M_slow(g)) == g.order()True>>> from sage.all import *>>> from sage.graphs.traversals import lex_M_slow>>> g = graphs.CompleteGraph(Integer(6))>>> len(lex_M_slow(g)) == g.order()
True

LexM ordering and label assignments on the vertices of the 3-sun graph:
sage: from sage.graphs.traversals import lex_M_slow
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),␣
˓→(5, 6)])sage: lex_M_slow(g, labels=True)([6, 4, 5, 3, 2, 1],{1: [], 2: [5], 3: [5, 4], 4: [4, 2], 5: [4, 3], 6: [3, 2]})>>> from sage.all import *>>> from sage.graphs.traversals import lex_M_slow>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4)), (Integer(2), Integer(5)), (Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(6)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(6))])>>> lex_M_slow(g, labels=True)([6, 4, 5, 3, 2, 1],{1: [], 2: [5], 3: [5, 4], 4: [4, 2], 5: [4, 3], 6: [3, 2]})

LexM produces a triangulation of given graph:
sage: from sage.graphs.traversals import lex_M_slow
sage: G = graphs.PetersenGraph()
sage: _, F = lex_M_slow(G, triangulation=True)
sage: H = G.copy()
sage: H.add_edges(F)sage: H.is_chordal()True>>> from sage.all import *>>> from sage.graphs.traversals import lex_M_slow>>> G = graphs.PetersenGraph()>>> _, F = lex_M_slow(G, triangulation=True)>>> H = G.copy()>>> H.add_edges(F)>>> H.is_chordal()
True

1642

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage.graphs.traversals.lex_UP(G, reverse=False, tree=False, initial_vertex=None)
Perform a lexicographic UP search (LexUP) on the graph.
INPUT:• G – a sage graph• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to return the discovery directed tree (each vertex being linked
to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider
ALGORITHM:
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.
During the 𝑖-th iteration of the algorithm 𝑖 is appended to the codes of all neighbors of the selected vertex that areleft in the graph.
Time complexity is 𝑂(𝑛+𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number of vertices
and 𝑚 is the number of edges.
See [Mil2017] for more details on the algorithm.
See also:• lex_BFS() – perform a lexicographic breadth first search (LexBFS) on the graph• lex_DFS() – perform a lexicographic depth first search (LexDFS) on the graph• lex_DOWN() – perform a lexicographic DOWN search (LexDOWN) on the graph
EXAMPLES:
A Lex UP is obviously an ordering of the vertices:sage: g = graphs.CompleteGraph(6)sage: len(g.lex_UP()) == g.order()True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> len(g.lex_UP()) == g.order()True

Lex UP ordering of the 3-sun graph:
sage: g = Graph([(1, 2), (1, 3), (2, 3), (2, 4), (2, 5), (3, 5), (3, 6), (4, 5),␣
˓→(5, 6)])sage: g.lex_UP()[1, 2, 4, 5, 6, 3]>>> from sage.all import *>>> g = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(3)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4)), (Integer(2), Integer(5)), (Integer(3),␣
˓→Integer(5)), (Integer(3), Integer(6)), (Integer(4), Integer(5)), (Integer(5),␣
˓→Integer(6))])>>> g.lex_UP()[1, 2, 4, 5, 6, 3]

5.17. Graph traversals

1643Graph Theory, Release 10.4

The method also works for directed graphs:
sage: G = DiGraph([(1, 2), (2, 3), (1, 3)])sage: G.lex_UP(initial_vertex=2)[2, 3, 1]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1),␣
˓→Integer(3))])>>> G.lex_UP(initial_vertex=Integer(2))[2, 3, 1]

Different orderings for different traversals:
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 ,sage: G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 ,sage: G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 ,sage: G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 ,

101 ,

111 ]

011 ,

111 ]

011 ,

100 ]

111 ,

101 ]

>>> from sage.all import *>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> G.lex_BFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 011 , 110 , 101 ,>>> G.lex_DFS(initial_vertex= 000 )[ 000 , 001 , 100 , 010 , 101 , 110 , 011 ,>>> G.lex_UP(initial_vertex= 000 )[ 000 , 001 , 010 , 101 , 110 , 111 , 011 ,>>> G.lex_DOWN(initial_vertex= 000 )[ 000 , 001 , 100 , 011 , 010 , 110 , 111 ,

111 ]
111 ]
100 ]
101 ]

sage.graphs.traversals.maximum_cardinality_search(G, reverse=False, tree=False,
initial_vertex=None)
Return an ordering of the vertices according a maximum cardinality search.
Maximum cardinality search (MCS) is a graph traversal introduced in [TY1984]. It starts by assigning an arbitrary
vertex (or the specified initial_vertex) of 𝐺 the last position in the ordering 𝛼. Every vertex keeps a weightequal to the number of its already processed neighbors (i.e., already added to 𝛼), and a vertex of largest such number
is chosen at each step 𝑖 to be placed in position 𝑛 − 𝑖 in 𝛼. This ordering can be computed in time 𝑂(𝑛 + 𝑚).
Time complexity is 𝑂(𝑛+𝑚) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph where 𝑛 is the number of vertices
and 𝑚 is the number of edges.
When the graph is chordal, the ordering returned by MCS is a perfect elimination ordering, like lex_BFS(). So
this ordering can be used to recognize chordal graphs. See [He2006] for more details.
Note: The current implementation is for connected graphs only.
INPUT:• G – a Sage graph
1644

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• reverse – boolean (default: False); whether to return the vertices in discovery order, or the reverse• tree – boolean (default: False); whether to also return the discovery directed tree (each vertex being
linked to the one that saw it for the first time)• initial_vertex – (default: None); the first vertex to consider
OUTPUT:
By default, return the ordering 𝛼 as a list. When tree is True, the method returns a tuple (𝛼, 𝑇 ), where 𝑇 is adirected tree with the same set of vertices as 𝐺 and a directed edge from 𝑢 to 𝑣 if 𝑢 was the first vertex to see 𝑣.
EXAMPLES:
When specified, the initial_vertex is placed at the end of the ordering, unless parameter reverse isTrue, in which case it is placed at the beginning:sage: G = graphs.PathGraph(4)sage: G.maximum_cardinality_search(initial_vertex=0)[3, 2, 1, 0]
sage: G.maximum_cardinality_search(initial_vertex=1)[0, 3, 2, 1]
sage: G.maximum_cardinality_search(initial_vertex=2)[0, 1, 3, 2]
sage: G.maximum_cardinality_search(initial_vertex=3)[0, 1, 2, 3]
sage: G.maximum_cardinality_search(initial_vertex=3, reverse=True)[3, 2, 1, 0]>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.maximum_cardinality_search(initial_vertex=Integer(0))[3, 2, 1, 0]>>> G.maximum_cardinality_search(initial_vertex=Integer(1))[0, 3, 2, 1]>>> G.maximum_cardinality_search(initial_vertex=Integer(2))[0, 1, 3, 2]>>> G.maximum_cardinality_search(initial_vertex=Integer(3))[0, 1, 2, 3]>>> G.maximum_cardinality_search(initial_vertex=Integer(3), reverse=True)[3, 2, 1, 0]

Returning the discovery tree:
sage: G = graphs.PathGraph(4)sage: _, T = G.maximum_cardinality_search(tree=True, initial_vertex=0)
sage: T.order(), T.size()(4, 3)
sage: T.edges(labels=False, sort=True)[(1, 0), (2, 1), (3, 2)]
sage: _, T = G.maximum_cardinality_search(tree=True, initial_vertex=3)
sage: T.edges(labels=False, sort=True)[(0, 1), (1, 2), (2, 3)]>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> _, T = G.maximum_cardinality_search(tree=True, initial_vertex=Integer(0))>>> T.order(), T.size()(4, 3)(continues on next page)

5.17. Graph traversals

1645Graph Theory, Release 10.4

(continued from previous page)>>> T.edges(labels=False, sort=True)[(1, 0), (2, 1), (3, 2)]>>> _, T = G.maximum_cardinality_search(tree=True, initial_vertex=Integer(3))>>> T.edges(labels=False, sort=True)[(0, 1), (1, 2), (2, 3)]

sage.graphs.traversals.maximum_cardinality_search_M(G, initial_vertex=None)
Return the ordering and the edges of the triangulation produced by MCS-M.
Maximum cardinality search M (MCS-M) is an extension of MCS (maximum_cardinality_search()) in
the same way that Lex-M (lex_M()) is an extension of Lex-BFS (lex_BFS()). That is, in MCS-M when 𝑢
receives number 𝑖 at step 𝑛 − 𝑖 + 1, it increments the weight of all unnumbered vertices 𝑣 for which there exists
a path between 𝑢 and 𝑣 consisting only of unnumbered vertices with weight strictly less than 𝑤− (𝑢) and 𝑤− (𝑣),where 𝑤− is the number of times a vertex has been reached during previous iterations. See [BBHP2004] for thedetails of this 𝑂(𝑛𝑚) time algorithm.
If 𝐺 is not connected, the orderings of each of its connected components are added consecutively. Furthermore,
if 𝐺 has 𝑘 connected components 𝐶𝑖 for 0 ≤ 𝑖 < 𝑘, 𝑋 contains at least one vertex of 𝐶𝑖 for each 𝑖 ≥ 1. Hence,|𝑋| ≥ 𝑘 − 1. In particular, some isolated vertices (i.e., of degree 0) can appear in 𝑋 as for such a vertex 𝑥, wehave that 𝐺 ∖ 𝑁 (𝑥) = 𝐺 is not connected.
INPUT:• G – a Sage graph• initial_vertex – (default: None); the first vertex to consider
OUTPUT: a tuple (𝛼, 𝐹, 𝑋), where• 𝛼 is the resulting ordering of the vertices. If an initial vertex is specified, it gets the last position in the ordering𝛼.
• 𝐹 is the list of edges of a minimal triangulation of 𝐺 according 𝛼• 𝑋 is a list of vertices such that for each 𝑥 ∈ 𝑋, the neighborhood of 𝑥 in 𝐺 is a separator (i.e., 𝐺 ∖ 𝑁 (𝑥) is
not connected). Note that we may have 𝑁 (𝑥) = ∅ if 𝐺 is not connected and 𝑥 has degree 0.
EXAMPLES:
Chordal graphs have a perfect elimination ordering, and so the set 𝐹 of edges of the triangulation is empty:
sage: G = graphs.RandomChordalGraph(20)sage: alpha, F, X = G.maximum_cardinality_search_M(); F[]>>> from sage.all import *>>> G = graphs.RandomChordalGraph(Integer(20))>>> alpha, F, X = G.maximum_cardinality_search_M(); F[]

The cycle of order 4 is not chordal and so the triangulation has one edge:
sage: G = graphs.CycleGraph(4)sage: alpha, F, X = G.maximum_cardinality_search_M(); len(F)1>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))(continues on next page)

1646

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> alpha, F, X = G.maximum_cardinality_search_M(); len(F)1

The number of edges needed to triangulate of a cycle graph or order 𝑛 is 𝑛 − 3, independently of the initial vertex:
sage: n = randint(3, 20)
sage: C = graphs.CycleGraph(n)sage: _, F, X = C.maximum_cardinality_search_M()
sage: len(F) == n - 3
True
sage: _, F, X = C.maximum_cardinality_search_M(initial_vertex=C.random_vertex())
sage: len(F) == n - 3
True>>> from sage.all import *>>> n = randint(Integer(3), Integer(20))>>> C = graphs.CycleGraph(n)>>> _, F, X = C.maximum_cardinality_search_M()>>> len(F) == n - Integer(3)True>>> _, F, X = C.maximum_cardinality_search_M(initial_vertex=C.random_vertex())>>> len(F) == n - Integer(3)TrueWhen an initial vertex is specified, it gets the last position in the ordering:sage: G = graphs.PathGraph(4)sage: G.maximum_cardinality_search_M(initial_vertex=0)([3, 2, 1, 0], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=1)([3, 2, 0, 1], [], [2, 3])
sage: G.maximum_cardinality_search_M(initial_vertex=2)([0, 1, 3, 2], [], [0, 1])
sage: G.maximum_cardinality_search_M(initial_vertex=3)([0, 1, 2, 3], [], [0, 1])>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.maximum_cardinality_search_M(initial_vertex=Integer(0))([3, 2, 1, 0], [], [2, 3])>>> G.maximum_cardinality_search_M(initial_vertex=Integer(1))([3, 2, 0, 1], [], [2, 3])>>> G.maximum_cardinality_search_M(initial_vertex=Integer(2))([0, 1, 3, 2], [], [0, 1])>>> G.maximum_cardinality_search_M(initial_vertex=Integer(3))([0, 1, 2, 3], [], [0, 1])

When 𝐺 is not connected, the orderings of each of its connected components are added consecutively, the verticesof the component containing the initial vertex occupying the last positions:sage: G = graphs.CycleGraph(4) * 2
sage: G.maximum_cardinality_search_M()[0][5, 4, 6, 7, 2, 3, 1, 0]
sage: G.maximum_cardinality_search_M(initial_vertex=7)[0][2, 1, 3, 0, 5, 6, 4, 7]

5.17. Graph traversals

1647Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4)) * Integer(2)>>> G.maximum_cardinality_search_M()[Integer(0)][5, 4, 6, 7, 2, 3, 1, 0]>>> G.maximum_cardinality_search_M(initial_vertex=Integer(7))[Integer(0)][2, 1, 3, 0, 5, 6, 4, 7]

Furthermore, if 𝐺 has 𝑘 connected components, 𝑋 contains at least one vertex per connected component, except
for the first one, and so at least 𝑘 − 1 vertices:sage: for k in range(1, 5):....:_, _, X = Graph(k).maximum_cardinality_search_M()....:
if len(X) < k - 1:....:
raise ValueError("something goes wrong")
sage: G = graphs.RandomGNP(10, .2)
sage: cc = G.connected_components(sort=False)
sage: _, _, X = G.maximum_cardinality_search_M()
sage: len(X) >= len(cc) - 1
True>>> from sage.all import *>>> for k in range(Integer(1), Integer(5)):...
_, _, X = Graph(k).maximum_cardinality_search_M()...
if len(X) < k - Integer(1):...
raise ValueError("something goes wrong")>>> G = graphs.RandomGNP(Integer(10), RealNumber( .2 ))>>> cc = G.connected_components(sort=False)>>> _, _, X = G.maximum_cardinality_search_M()>>> len(X) >= len(cc) - Integer(1)True

In the example of [BPS2010], the triangulation has 3 edges:
sage: G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],....:d : [ e , f , j , k ], e : [ g ],....:f : [ g , j , k ], g : [ j , k ], h : [ i , j ],....:i : [ k ], j : [ k ]})sage: _, F, _ = G.maximum_cardinality_search_M(initial_vertex= a )sage: len(F)3>>> from sage.all import *>>> G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],...
d : [ e , f , j , k ], e : [ g ],...
f : [ g , j , k ], g : [ j , k ], h : [ i , j ],...
i : [ k ], j : [ k ]})>>> _, F, _ = G.maximum_cardinality_search_M(initial_vertex= a )>>> len(F)3

1648

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.18 Graph plotting(For LaTeX drawings of graphs, see the graph_latex module.)
All graphs have an associated Sage graphics object, which you can display:sage: G = graphs.WheelGraph(15)sage: P = G.plot()
sage: P.show() # long time>>> from sage.all import *>>> G = graphs.WheelGraph(Integer(15))>>> P = G.plot()>>> P.show() # long time

2

1

14

3

13

4

12
0

5

11

6

10
7

8

9

When plotting a graph created using Sage’s Graph command, node positions are determined using the spring-layout
algorithm. Special graphs available from graphs.* have preset positions. For example, compare the two plots of thePetersen graph, as obtained using Graph or as obtained from that database:sage: petersen_spring = Graph( :I ES@obGkqegW~ )sage: petersen_spring.show() # long time

5.18. Graph plotting

1649

Graph Theory, Release 10.4>>> from sage.all import *>>> petersen_spring = Graph( :I ES@obGkqegW~ )>>> petersen_spring.show() # long time

8

7
3

6
9

5
2

4
1
0
sage: petersen_database = graphs.PetersenGraph()
sage: petersen_database.show() # long time>>> from sage.all import *>>> petersen_database = graphs.PetersenGraph()>>> petersen_database.show() # long time

All constructors in this database (except some random graphs) prefill the position dictionary, bypassing the spring-layout
positioning 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().

1650

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

0

5
1

4
6

9

7

2

5.18. Graph plotting

8

3

1651

Graph Theory, Release 10.4

layoutiterations
heights
springtree_root

forest_roots

tree_orientation
save_posdim
prog
by_component
posvertex_labelsvertex_color
vertex_colors
vertex_size
vertex_shapeedge_labels
edge_styleedge_thickness
edge_color
edge_colors
color_by_label
partitionloop_size
dist
max_dist
talk
graph_border
edge_labels_backgroundA 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” (thetree will be plotted in levels, depending on minimum distance for the root).
The number of times to execute the spring layout algorithm.
A dictionary mapping heights to the list of vertices at this height.
Use spring layout to finalize the current layout.
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 .
An iterable specifying which vertices to use as roots for the layout= forest
option. If no root is specified for a tree, then one is chosen close to the center of
the tree. Ignored unless layout= forest .
The direction of tree branches – ‘up’, ‘down’, ‘left’ or ‘right’.
Whether or not to save the computed position for the graph.
The dimension of the layout – 2 or 3.
Which graphviz layout program to use – one of “circo”, “dot”, “fdp”, “neato”, or“twopi”.
Whether to do the spring layout by connected component – a boolean.
The position dictionary of vertices.
Vertex labels to draw. This can be True/False to indicate whether to print thevertex string representation of not, a dictionary keyed by vertices and associating
to each vertex a label string, or a function taking as input a vertex and returning alabel string.
Default color for vertices not listed in vertex_colors dictionary.
A dictionary specifying vertex colors: each key is a color recognizable by matplotlib, and each corresponding value is a list of vertices.
The size to draw the vertices.
The shape to draw the vertices. Currently unavailable for Multi-edged DiGraphs.
Whether or not to draw edge labels.
The linestyle of the edges. It should be one of “solid”, “dashed”, “dotted”, dashdot”, or “-”, “–”, “:”, “-.”, respectively.
The thickness of the edges.
The default color for edges not listed in edge_colors.
A dictionary specifying edge colors: each key is a color recognized by matplotlib,
and each corresponding value is a list of edges.
Whether to color the edges according to their labels. This also accepts a function
or dictionary mapping labels to colors.
A partition of the vertex set. If specified, plot will show each cell in a different
color; vertex_colors takes precedence.
The radius of the smallest loop.
The distance between multiedges.
The max distance range to allow multiedges.
Whether to display the vertices in talk mode (larger and white).
Whether or not to draw a frame around the graph.
The color of the background of the edge labels.

Default options
This module defines two dictionaries containing default options for the plot() and show() methods. These two dictionaries are sage.graphs.graph_plot.DEFAULT_PLOT_OPTIONS and sage.graphs.graph_plot.
DEFAULT_SHOW_OPTIONS, respectively.
1652

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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):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>>> from sage.all import *>>> import sage.graphs.graph_plot>>> sage.graphs.graph_plot.DEFAULT_SHOW_OPTIONS[ figsize ] = (Integer(6), Integer(6))>>> graphs.PetersenGraph().show() # long time>>> graphs.ChvatalGraph().show() # long time>>> graphs.PetersenGraph().show(figsize=(Integer(4), Integer(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>>> from sage.all import *>>> sage.graphs.graph_plot.DEFAULT_SHOW_OPTIONS[ figsize ] = (Integer(4), Integer(4))>>> graphs.PetersenGraph().show() # long time>>> graphs.ChvatalGraph().show() # long time

Note:
• While DEFAULT_PLOT_OPTIONS affects both G.show() and G.plot(),
FAULT_SHOW_OPTIONS only affects G.show().

settings from DE-• 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)>>> from sage.all import *>>> import sage.graphs.graph_plot>>> sage.graphs.graph_plot.DEFAULT_SHOW_OPTIONS[ figsize ] = (Integer(4),␣
˓→Integer(4))

Index of methods and functions
GraphPlot.set_pos()
GraphPlot.
set_vertices()
GraphPlot.set_edges()
GraphPlot.show()
GraphPlot.plot()
GraphPlot.
layout_tree()

5.18. Graph plotting

Set the position plotting parameters for this GraphPlot.
Set the vertex plotting parameters for this GraphPlot.
Set the edge (or arrow) plotting parameters for the GraphPlot object.
Show the (Di)Graph associated with this GraphPlot object.
Return a graphics object representing the (di)graph.
Compute a nice layout of a tree.

1653

Graph Theory, Release 10.4class sage.graphs.graph_plot.GraphPlot(graph, options)
Bases: SageObject
Return 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,....: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)>>> from sage.all import *>>> from sage.graphs.graph_plot import GraphPlot>>> options = {...
vertex_size : Integer(200),...
vertex_labels : True,...
layout : None,...
edge_style : solid ,...
edge_color : black ,...
edge_colors : None,...
edge_labels : False,...
iterations : Integer(50),...
tree_orientation : down ,...
heights : None,...
graph_border : False,...
talk : False,...
color_by_label : False,...
partition : None,...
dist : RealNumber( .075 ),...
max_dist : RealNumber( 1.5 ),...
loop_size : RealNumber( .075 ),...
edge_labels_background : transparent }>>> g = Graph({Integer(0): [Integer(1), Integer(2)], Integer(2): [Integer(3)],␣
˓→Integer(4): [Integer(0), Integer(1)]})>>> GP = GraphPlot(g, options)layout_tree(root, orientation)
1654

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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: 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>>> from sage.all import *>>> from sage.graphs.graph_plot import GraphPlot>>> G = graphs.HoffmanSingletonGraph()>>> T = Graph()>>> T.add_edges(G.min_spanning_tree(starting_vertex=Integer(0)))>>> T.show(layout= tree , tree_root=Integer(0)) # indirect doctest

plot(**kwds)
Return a graphics object representing the (di)graph.
INPUT:The options accepted by this method are to be found in the documentation of the sage.graphs.
graph_plot module, and the show() method.
Note: See the module s documentation for information on default values of this method.
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):....: 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()

5.18. Graph plotting

1655

Graph Theory, Release 10.4>>> from sage.all import *>>> from math import sin, cos, pi>>> P = graphs.PetersenGraph()>>> d = { #FF0000 : [Integer(0), Integer(5)], #FF9900 : [Integer(1),␣
˓→Integer(6)],#FFFF00 : [Integer(2), Integer(7)],...
#00FF00 : [Integer(3), Integer(8)], #0000FF : [Integer(4),˓→Integer(9)]}>>> pos_dict = {}>>> for i in range(Integer(5)):... x = float(cos(pi/Integer(2) + ((Integer(2)*pi)/Integer(5))*i))... y = float(sin(pi/Integer(2) + ((Integer(2)*pi)/Integer(5))*i))... pos_dict[i] = [x,y]...
>>> for i in range(Integer(5), Integer(10)):... x = float(RealNumber( 0.5 )*cos(pi/Integer(2) + ((Integer(2)*pi)/
˓→Integer(5))*i))... y = float(RealNumber( 0.5 )*sin(pi/Integer(2) + ((Integer(2)*pi)/
˓→Integer(5))*i))... pos_dict[i] = [x,y]...
>>> pl = P.graphplot(pos=pos_dict, vertex_colors=d)>>> pl.show()

0

5
1

4
6

9

7

2

8

3

Here are some more common graphs with typical options:

1656

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: C = graphs.CubeGraph(8)sage: P = C.graphplot(vertex_labels=False, vertex_size=0,....:
graph_border=True)
sage: P.show()>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(8))>>> P = C.graphplot(vertex_labels=False, vertex_size=Integer(0),...
graph_border=True)>>> P.show()

sage: G = graphs.HeawoodGraph().copy(sparse=True)
sage: for u, v, l in G.edges(sort=True):....:
G.set_edge_label(u, v, f ({u},{v}) )sage: G.graphplot(edge_labels=True).show()>>> from sage.all import *>>> G = graphs.HeawoodGraph().copy(sparse=True)>>> for u, v, l in G.edges(sort=True):...
G.set_edge_label(u, v, f ({u},{v}) )>>> G.graphplot(edge_labels=True).show()The options for plotting also work with directed graphs:

5.18. Graph plotting

1657

Graph Theory, Release 10.4

1

(0,1)

0

(0,13)

13(1,2)(12,13)

2

12

(2,3)

(3,12)

3(11,12)(1,10)

11

(0,5)

(3,4)

(8,13)(10,11)

(2,7)

4
(4,5)

10
(6,11)(4,9)(9,10)

5

9
(5,6)

(8,9)
6

1658

(6,7)

7

(7,8)

8

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: D = DiGraph({....:
0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4],....:
4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9],....:9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13],....:
13: [14], 14: [15], 15: [16], 16: [17], 17: [18],....:18: [19], 19: []})
sage: for u, v, l in D.edges(sort=True):....:D.set_edge_label(u, v, f ({u},{v}) )sage: D.graphplot(edge_labels=True, layout= circular ).show()>>> from sage.all import *>>> D = DiGraph({...
Integer(0): [Integer(1), Integer(10), Integer(19)], Integer(1):␣
˓→[Integer(8), Integer(2)], Integer(2): [Integer(3), Integer(6)], Integer(3):␣
˓→[Integer(19), Integer(4)],...
Integer(4): [Integer(17), Integer(5)], Integer(5): [Integer(6),␣
˓→Integer(15)], Integer(6): [Integer(7)], Integer(7): [Integer(8),␣
˓→Integer(14)], Integer(8): [Integer(9)],...
Integer(9): [Integer(10), Integer(13)], Integer(10): [Integer(11)],␣
˓→Integer(11): [Integer(12), Integer(18)], Integer(12): [Integer(16),␣
˓→Integer(13)],...
Integer(13): [Integer(14)], Integer(14): [Integer(15)], Integer(15):␣
˓→[Integer(16)], Integer(16): [Integer(17)], Integer(17): [Integer(18)],...
Integer(18): [Integer(19)], Integer(19): []})>>> for u, v, l in D.edges(sort=True):...
D.set_edge_label(u, v, f ({u},{v}) )>>> 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(sort=True):....: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()>>> from sage.all import *>>> from sage.plot.colors import rainbow>>> C = graphs.CubeGraph(Integer(5))>>> R = rainbow(Integer(5))>>> edge_colors = {}>>> for i in range(Integer(5)):...
edge_colors[R[i]] = []>>> for u, v, l in C.edges(sort=True):...
for i in range(Integer(5)):...
if u[i] != v[i]:...
edge_colors[R[i]].append((u, v, l))>>> C.graphplot(vertex_labels=False, vertex_size=Integer(0),...
edge_colors=edge_colors).show()

5.18. Graph plotting

1659

Graph Theory, Release 10.4

(2,3)

3
(3,4)
4
(2,6)
(4,5)
5
(5,6)

2

(1,2)

1 (0,1)0 (0,19)(3,19)(4,17)(1,8)

19(18,19)18(17,18)17(16,17)
16(15,16)(0,10)(5,15)(11,18)15(14,15)(12,16)6
14(6,7)(7,14)(13,14)7
13(7,8)(12,13)(9,13)
812(8,9)(11,12)9 (9,10) (10,11) 11
10

1660

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.18. Graph plotting

1661

Graph Theory, Release 10.4

With the partition option, we can separate out same-color groups of vertices:sage: D = graphs.DodecahedralGraph()
sage: Pi = [[6, 5, 15, 14, 7], [16, 13, 8, 2, 4],....:[12, 17, 9, 3, 1], [0, 19, 18, 10, 11]]sage: D.show(partition=Pi)>>> from sage.all import *>>> D = graphs.DodecahedralGraph()>>> Pi = [[Integer(6), Integer(5), Integer(15), Integer(14), Integer(7)],␣
˓→[Integer(16), Integer(13), Integer(8), Integer(2), Integer(4)],...
[Integer(12), Integer(17), Integer(9), Integer(3), Integer(1)],␣
˓→[Integer(0), Integer(19), Integer(18), Integer(10), Integer(11)]]>>> D.show(partition=Pi)

0

10
9
1

11

8

13
14

7

18

12
16

17

15

6
2

5

19

4
3

Loops are also plotted correctly:
sage: G = graphs.PetersenGraph()
sage: G.allow_loops(True)
sage: G.add_edge(0,0)
sage: G.show()>>> from sage.all import *>>> G = graphs.PetersenGraph()(continues on next page)

1662

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> G.allow_loops(True)>>> G.add_edge(Integer(0),Integer(0))>>> G.show()

0

5
1

4
6

9

7

2

8

3

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)]})>>> from sage.all import *>>> D = DiGraph({Integer(0):[Integer(0),Integer(1)], Integer(1):[Integer(2)],␣
˓→Integer(2):[Integer(3)]}, loops=True)>>> D.show()>>> D.show(edge_colors={(Integer(0), Integer(1), Integer(0)): [(Integer(0),␣
˓→Integer(1), None), (Integer(1), Integer(2), None)],...
(Integer(0), Integer(0), Integer(0)): [(Integer(2),␣
˓→Integer(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]})(continues on next page)

5.18. Graph plotting

1663

Graph Theory, Release 10.4

3
2
1
0

1664

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: g.graphplot(pos=pos, layout= spring , iterations=0).plot()
Graphics object consisting of 11 graphics primitives>>> from sage.all import *>>> pos = {Integer(0): [RealNumber( 0.0 ), RealNumber( 1.5 )], Integer(1): [˓→RealNumber( 0.8 ), RealNumber( 0.3 )], Integer(2): [-RealNumber( 0.6 ), ˓→RealNumber( 0.8 )],...
Integer(3):[RealNumber( 0.6 ), -RealNumber( 0.8 )],␣˓→Integer(4):[RealNumber( 0.8 ), RealNumber( 0.3 )]}>>> g = Graph({Integer(0): [Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(3): [Integer(4)], Integer(4):␣
˓→[Integer(0)]})>>> g.graphplot(pos=pos, layout= spring , iterations=Integer(0)).plot()
Graphics object consisting of 11 graphics primitives

4

3

2
0
1
sage: G = Graph()
sage: P = G.graphplot().plot()
sage: P.axes()
False
sage: G = DiGraph()
sage: P = G.graphplot().plot()
sage: P.axes()
False

5.18. Graph plotting

1665

Graph Theory, Release 10.4>>> from sage.all import *>>> G = Graph()>>> P = G.graphplot().plot()>>> P.axes()
False>>> G = DiGraph()>>> P = G.graphplot().plot()>>> 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>>> from sage.all import *>>> T = list(graphs.trees(Integer(7)))>>> t = T[Integer(3)]>>> t.graphplot(heights={Integer(0): [Integer(0)], Integer(1): [Integer(4),␣
˓→Integer(5), Integer(1)],...
Integer(2): [Integer(2)], Integer(3): [Integer(3),␣
˓→Integer(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>>> from sage.all import *>>> T = list(graphs.trees(Integer(7)))>>> t = T[Integer(3)]>>> t.graphplot(heights={Integer(0): [Integer(0)], Integer(1): [Integer(4),␣
˓→Integer(5), Integer(1)],...
Integer(2): [Integer(2)], Integer(3): [Integer(3),␣
˓→Integer(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)
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(continues on next page)

1666

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

6
5

4
0
1
3

2

5.18. Graph plotting

1667

Graph Theory, Release 10.4

2
3

4
1

0

5

6

1668

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)....:).plot()Graphics object consisting of 20 graphics primitives>>> from sage.all import *>>> t.set_edge_label(Integer(0), Integer(1), -Integer(7))>>> t.set_edge_label(Integer(0), Integer(5), Integer(3))>>> t.set_edge_label(Integer(0), Integer(5), Integer(99))>>> t.set_edge_label(Integer(1), Integer(2), Integer(1000))>>> t.set_edge_label(Integer(3), Integer(2), spam )>>> t.set_edge_label(Integer(2), Integer(6), Integer(3)/Integer(2))>>> t.set_edge_label(Integer(0), Integer(4), Integer(66))>>> t.graphplot(heights={Integer(0): [Integer(0)], Integer(1): [Integer(4),␣
˓→Integer(5), Integer(1)],...
Integer(2): [Integer(2)], Integer(3): [Integer(3),␣
˓→Integer(6)]},...
edge_labels=True...
).plot()Graphics object consisting of 20 graphics primitives

4
None
1

None

3

-7
0
99
5

1000
2

None
6

sage: T = list(graphs.trees(7))
sage: t = T[3]sage: t.graphplot(layout= tree ).show()

5.18. Graph plotting

1669

Graph Theory, Release 10.4>>> from sage.all import *>>> T = list(graphs.trees(Integer(7)))>>> t = T[Integer(3)]>>> t.graphplot(layout= tree ).show()

0

5

1

6

4

3

2

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()>>> from sage.all import *>>> t = DiGraph( JCC???@A??GO??CO??GO?? )>>> t.graphplot(layout= tree , tree_root=Integer(0),...
tree_orientation="up"...
).show()More examples:sage: D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]})sage: D.graphplot().show()

1670

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

6

10

1

8

5

4

7

9

2

3

0

5.18. Graph plotting

1671

Graph Theory, Release 10.4>>> from sage.all import *>>> D = DiGraph({Integer(0):[Integer(1),Integer(2),Integer(3)],␣
˓→Integer(2):[Integer(1),Integer(4)], Integer(3):[Integer(0)]})>>> D.graphplot().show()

4
3

2

0

1

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>>> from sage.all import *>>> D = DiGraph(multiedges=True, sparse=True)>>> for i in range(Integer(5)):...
D.add_edge((i, i + Integer(1), a ))...
D.add_edge((i, i - Integer(1), b ))>>> D.graphplot(edge_labels=True,...
edge_colors=D._color_by_label()...
).plot()Graphics object consisting of 34 graphics primitives

1672

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

-1

b

0

b
a

b

1
a

b

2
a

b

3
a

5.18. Graph plotting

4

a

5

1673

Graph Theory, Release 10.4

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 22 graphics primitives>>> from sage.all import *>>> g = Graph({}, loops=True, multiedges=True, sparse=True)>>> g.add_edges([(Integer(0), Integer(0), a ), (Integer(0), Integer(0),˓→ (Integer(0), Integer(1),c ),...
(Integer(0), Integer(1), d ), (Integer(0), Integer(1),˓→ (Integer(0), Integer(1),f ),...
(Integer(0), Integer(1), f ), (Integer(2), Integer(1),˓→ (Integer(2), Integer(2),h )])>>> g.graphplot(edge_labels=True,...
color_by_label=True,...
edge_style= dashed...
).plot()Graphics object consisting of 22 graphics primitives

0
b
a

e
f
c
f
d

1

g

b ),
e ),
g ),

2
h

The edge_style option may be provided in the short format too:
1674

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g.graphplot(edge_labels=True,....:
color_by_label=True,....:
edge_style= -....:).plot()Graphics object consisting of 22 graphics primitives>>> from sage.all import *>>> g.graphplot(edge_labels=True,...
color_by_label=True,...
edge_style= -...
).plot()Graphics object consisting of 22 graphics primitives

set_edges(**edge_options)Set edge plotting parameters for the GraphPlot object.
This function is called by the constructor but can also be called to update the edge 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_edges(edge_style= solid )sage: GP.plot()
Graphics object consisting of 22 graphics primitives>>> from sage.all import *>>> g = Graph(loops=True, multiedges=True, sparse=True)>>> g.add_edges([(Integer(0), Integer(0), a ), (Integer(0), Integer(0),˓→ (Integer(0), Integer(1),c ),...
(Integer(0), Integer(1), d ), (Integer(0), Integer(1),˓→ (Integer(0), Integer(1),f ),...
(Integer(0), Integer(1), f ), (Integer(2), Integer(1),˓→ (Integer(2), Integer(2),h )])>>> GP = g.graphplot(vertex_size=Integer(100), edge_labels=True,...
color_by_label=True, edge_style= dashed )>>> GP.set_edges(edge_style= solid )>>> GP.plot()
Graphics object consisting of 22 graphics primitives

b ),
e ),
g ),

sage: GP.set_edges(edge_color= black )sage: GP.plot()
Graphics object consisting of 22 graphics primitives>>> from sage.all import *>>> GP.set_edges(edge_color= black )>>> GP.plot()
Graphics object consisting of 22 graphics primitives
sage: d = DiGraph(loops=True, multiedges=True, sparse=True)
sage: d.add_edges([(0, 0, a ), (0, 0, b ), (0, 1, c ),(continues on next page)

5.18. Graph plotting

1675

Graph Theory, Release 10.4

0
b
a
d

f

c

f

e

1

g

2
h

1676

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

1
g

d
f
c
f
e

0
b
a

2
h

5.18. Graph plotting

1677

Graph Theory, Release 10.4

(continued from previous page)....:(0, 1, d ), (0, 1, e ), (0, 1, f ),....:(0, 1, f ), (2, 1, g ), (2, 2, h )])sage: GP = d.graphplot(vertex_size=100, edge_labels=True,....:
color_by_label=True, edge_style= dashed )sage: GP.set_edges(edge_style= solid )sage: GP.plot()
Graphics object consisting of 24 graphics primitives>>> from sage.all import *>>> d = DiGraph(loops=True, multiedges=True, sparse=True)>>> d.add_edges([(Integer(0), Integer(0), a ), (Integer(0), Integer(0),˓→ (Integer(0), Integer(1),c ),...
(Integer(0), Integer(1), d ), (Integer(0), Integer(1),˓→ (Integer(0), Integer(1),f ),...
(Integer(0), Integer(1), f ), (Integer(2), Integer(1),˓→ (Integer(2), Integer(2),h )])>>> GP = d.graphplot(vertex_size=Integer(100), edge_labels=True,...
color_by_label=True, edge_style= dashed )>>> GP.set_edges(edge_style= solid )>>> GP.plot()
Graphics object consisting of 24 graphics primitives

b ),
e ),
g ),

2
h

g
1

d

f

c

f

e

0
b
a

1678

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: GP.set_edges(edge_color= black )sage: GP.plot()
Graphics object consisting of 24 graphics primitives>>> from sage.all import *>>> GP.set_edges(edge_color= black )>>> GP.plot()
Graphics object consisting of 24 graphics primitives

g

2

1

h

d
f
c
f
e

0
b
a

set_pos()
Set 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 )GraphPlot object for Graph on 5 vertices# indirect doctest>>> from sage.all import *>>> g = Graph({Integer(0): [Integer(1), Integer(2)], Integer(2): [Integer(3)],
˓→ Integer(4): [Integer(0), Integer(1)]})(continues on next page)

5.18. Graph plotting

1679

Graph Theory, Release 10.4

(continued from previous page)>>> g.graphplot(save_pos=True, layout= circular )GraphPlot object for Graph on 5 vertices# indirect doctest

The following illustrates the format of a position dictionary, but due to numerical noise we do not check thevalues 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...)}>>> from sage.all import *>>> g.get_pos(){0: (0.0, 1.0),
1: (-0.951..., 0.309...),
2: (-0.587..., -0.809...),
3: (0.587..., -0.809...),
4: (0.951..., 0.309...)}
sage: T = list(graphs.trees(7))
sage: t = T[3]sage: t.plot(heights={0: [0], 1: [4, 5, 1], 2: [2], 3: [3, 6]})Graphics object consisting of 14 graphics primitives>>> from sage.all import *>>> T = list(graphs.trees(Integer(7)))>>> t = T[Integer(3)]>>> t.plot(heights={Integer(0): [Integer(0)], Integer(1): [Integer(4),␣
˓→Integer(5), Integer(1)], Integer(2): [Integer(2)], Integer(3): [Integer(3),␣
˓→Integer(6)]})Graphics object consisting of 14 graphics primitives

set_vertices(**vertex_options)Set the vertex plotting parameters for this GraphPlot.
This function is called by the constructor but can also be called to make updates to the vertex options of an
existing GraphPlot object. Note that the changes are cumulative.
EXAMPLES:
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 22 graphics primitives
sage: GP.set_vertices(vertex_color= green , vertex_shape= ^ )sage: GP.plot()
Graphics object consisting of 22 graphics primitives

1680

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

6

5

0

3

1

2
4

5.18. Graph plotting

1681

Graph Theory, Release 10.4>>> from sage.all import *>>> g = Graph({}, loops=True, multiedges=True, sparse=True)>>> g.add_edges([(Integer(0), Integer(0), a ), (Integer(0), Integer(0),˓→ (Integer(0), Integer(1),c ),...
(Integer(0), Integer(1), d ), (Integer(0), Integer(1),˓→ (Integer(0), Integer(1),f ),...
(Integer(0), Integer(1), f ), (Integer(2), Integer(1),˓→ (Integer(2), Integer(2),h )])>>> GP = g.graphplot(vertex_size=Integer(100), edge_labels=True,...
color_by_label=True, edge_style= dashed )>>> GP.set_vertices(talk=True)>>> GP.plot()
Graphics object consisting of 22 graphics primitives>>> GP.set_vertices(vertex_color= green , vertex_shape= ^ )>>> GP.plot()
Graphics object consisting of 22 graphics primitives

0
b
a

f
d

c

b ),
e ),
g ),

e
f
1
g
2
h

Vertex labels are flexible:
sage: g = graphs.PathGraph(4)sage: g.plot(vertex_labels=False)
Graphics object consisting of 4 graphics primitives

1682

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

2
h
g

1

d

f

c

f

e

0
b
a

5.18. Graph plotting

1683

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4))>>> g.plot(vertex_labels=False)
Graphics object consisting of 4 graphics primitives

sage: g = graphs.PathGraph(4)sage: g.plot(vertex_labels=True)
Graphics object consisting of 8 graphics primitives>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4))>>> g.plot(vertex_labels=True)
Graphics object consisting of 8 graphics primitives
sage: g = graphs.PathGraph(4)sage: g.plot(vertex_labels=dict(zip(g, [ + , - , / ,Graphics object consisting of 8 graphics primitives>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4))>>> g.plot(vertex_labels=dict(zip(g, [ + , - , / ,Graphics object consisting of 8 graphics primitives

1684* ])))* ])))

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

05.18. Graph plotting

1

2

3

1685

Graph Theory, Release 10.4

+

1686

-

/

*

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g = graphs.PathGraph(4)sage: g.plot(vertex_labels=lambda x: str(x % 2))
Graphics object consisting of 8 graphics primitives>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4))>>> g.plot(vertex_labels=lambda x: str(x % Integer(2)))
Graphics object consisting of 8 graphics primitives

0

1

0

1

show(**kwds)
Show the (di)graph associated with this GraphPlot object.
INPUT:
This method accepts all parameters of sage.plot.graphics.Graphics.show().
Note:• See the module s documentation for information on default values of this method.
• Any options not used by plot will be passed on to the show() method.
EXAMPLES:

5.18. Graph plotting

1687

Graph Theory, Release 10.4

sage: C = graphs.CubeGraph(8)sage: P = C.graphplot(vertex_labels=False, vertex_size=0,....:
graph_border=True)
sage: P.show()>>> from sage.all import *>>> C = graphs.CubeGraph(Integer(8))>>> P = C.graphplot(vertex_labels=False, vertex_size=Integer(0),...
graph_border=True)>>> P.show()

5.19 Graph plotting in Javascript with d3.js
This module implements everything that can be used to draw graphs with d3.js in Sage.
On Python’s side, this is mainly done by wrapping a graph’s edges and vertices in a structure that can then be used in thejavascript code. This javascript code is then inserted into a .html file to be opened by a browser.
In the browser, the displayed page contains at the bottom right a menu that allows to save the picture under the svg fileformat.
What Sage feeds javascript with is a “graph” object with the following content:

1688

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• 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 curveof 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 documentation 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 fromd3.js.
• Thierry Monteil (June 2014): allow offline use of d3.js provided by d3js spkg.

5.19.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)
Create 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().

5.19. Graph plotting in Javascript with d3.js

1689

Graph Theory, Release 10.4

INPUT:• G – the graph• vertex_labels – boolean (default: False); whether to display vertex labels• edge_labels – boolean (default: False); whether to display edge labels• vertex_partition – list (default: []); a list of lists representing a partition of the vertex set. Vertices
are then colored in the graph according to the partition• vertex_colors – dict (default: None); a dictionary representing a partition of the vertex set. Keys
are colors (ignored) and values are lists of vertices. Vertices are then colored in the graph according to thepartition• edge_partition – list (default: []); same as vertex_partition, with edges instead• force_spring_layout – boolean (default: False); whether to take previously computed position ofnodes into account if there is one, or to compute a spring layout• vertex_size – integer (default: 7); the size of a vertex’ circle• edge_thickness – integer (default: 4); thickness of an edge
• charge – integer (default: -120); the vertices’ charge. Defines how they repulse each other. See https://github.com/mbostock/d3/wiki/Force-Layout for more information• link_distance – integer (default: 30); see https://github.com/mbostock/d3/wiki/Force-Layout for
more information• link_strength – integer (default: 2); see https://github.com/mbostock/d3/wiki/Force-Layout for more
information• gravity – float (default: 0.04); see https://github.com/mbostock/d3/wiki/Force-Layout for more information
Warning: Since the d3js package is not standard yet, the javascript is fetched from d3js.org website by thebrowser. 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",˓→optional - internet....:
force_spring_layout=True)#␣sage: graphs.DodecahedralGraph().show(method="js")˓→optional - internet#␣

sage: # needs sage.combinat
sage: g = digraphs.DeBruijn(2, 2)
sage: g.allow_multiple_edges(True)
sage: g.add_edge("10", "10", "a")(continues on next page)

1690

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

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,
˓→optional - internet....:
link_distance=200, gravity=.05, charge=-500,....:
edge_partition=[[("11", "12", "2"), ("21", "21", "a")]],....:
edge_thickness=4)>>> from sage.all import *>>> graphs.RandomTree(Integer(50)).show(method="js")˓→optional - internet>>> g = graphs.PetersenGraph()>>> g.show(method="js", vertex_partition=g.coloring())˓→ internet#␣#␣# optional ->>> graphs.DodecahedralGraph().show(method="js",˓→ internet...
force_spring_layout=True)# optional ->>> graphs.DodecahedralGraph().show(method="js")˓→ internet# optional ->>> # needs sage.combinat>>> g = digraphs.DeBruijn(Integer(2), Integer(2))>>> g.allow_multiple_edges(True)>>> g.add_edge("10", "10", "a")>>> g.add_edge("10", "10", "b")>>> g.add_edge("10", "10", "c")>>> g.add_edge("10", "10", "d")>>> g.add_edge("01", "11", "1")>>> g.show(method="js", vertex_labels=True, edge_labels=True,# optional ˓→ internet...
link_distance=Integer(200), gravity=RealNumber( .05 ), charge=˓→Integer(500),...
edge_partition=[[("11", "12", "2"), ("21", "21", "a")]],...
edge_thickness=Integer(4))

5.20 Tree decompositions
This module implements tree-decomposition methods.
A tree-decomposition of a graph 𝐺 = (𝑉, 𝐸) is a pair (𝑋, 𝑇 ), where 𝑋 = {𝑋1 , 𝑋2 , . . . , 𝑋𝑡 } is a family of subsets of𝑉 , usually called bags, and 𝑇 is a tree of order 𝑡 whose nodes are the subsets 𝑋𝑖 satisfying the following properties:• The union of all sets 𝑋𝑖 equals 𝑉 . That is, each vertex of the graph 𝐺 is associated with at least one tree node.
• For every edge (𝑣, 𝑤) in the graph, there is a subset 𝑋𝑖 that contains both 𝑣 and 𝑤. That is, each edge of the graph
𝐺 appears in a tree node.
• The nodes associated with vertex 𝑣 ∈ 𝑉 form a connected subtree of 𝑇 . That is, if 𝑋𝑖 and 𝑋𝑗 both contain avertex 𝑣 ∈ 𝑉 , then all nodes 𝑋𝑘 of the tree in the (unique) path between 𝑋𝑖 and 𝑋𝑗 contain 𝑣 as well, and we have
𝑋𝑖 ∩ 𝑋𝑗 ⊆ 𝑋𝑘 .

5.20. Tree decompositions

1691

Graph Theory, Release 10.4

The width of a tree decomposition is the size of the largest set 𝑋𝑖 minus one, i.e., max𝑋𝑖 ∈𝑋 |𝑋𝑖 | − 1, and the treewidth𝑡𝑤(𝐺) of a graph 𝐺 is the minimum width among all possible tree decompositions of 𝐺. Observe that, the size of thelargest set is diminished by one in order to make the treewidth of a tree equal to one.
The length of a tree decomposition, as proposed in [DG2006], is the maximum diameter in 𝐺 of its bags, where thediameter of a bag 𝑋𝑖 is the largest distance in 𝐺 between the vertices in 𝑋𝑖 (i.e., max𝑢,𝑣∈𝑋𝑖 dist𝐺 (𝑢, 𝑣)). The treelength𝑡𝑙(𝐺) of a graph 𝐺 is the minimum length among all possible tree decompositions of 𝐺.
While deciding whether a graph has treelength 1 can be done in linear time (equivalent to deciding if the graph is chordal),deciding if it has treelength at most 𝑘 for any fixed constant 𝑘 ≤ 2 is NP-complete [Lokshtanov2009].
Treewidth and treelength are different measures of tree-likeness. In particular, trees have treewidth and treelength 1:
sage: T = graphs.RandomTree(20)sage: T.treewidth()1
sage: T.treelength()
1>>> from sage.all import *>>> T = graphs.RandomTree(Integer(20))>>> T.treewidth()1>>> T.treelength()1

The treewidth of a cycle is 2 and its treelength is ⌈𝑛/3⌉:
sage: [graphs.CycleGraph(n).treewidth() for n in range(3, 11)][2, 2, 2, 2, 2, 2, 2, 2]
sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)][1, 2, 2, 2, 3, 3, 3, 4]>>> from sage.all import *>>> [graphs.CycleGraph(n).treewidth() for n in range(Integer(3), Integer(11))][2, 2, 2, 2, 2, 2, 2, 2]>>> [graphs.CycleGraph(n).treelength() for n in range(Integer(3), Integer(11))][1, 2, 2, 2, 3, 3, 3, 4]

The treewidth of a clique is 𝑛 − 1 and its treelength is 1:
sage: [graphs.CompleteGraph(n).treewidth() for n in range(3, 11)][2, 3, 4, 5, 6, 7, 8, 9]
sage: [graphs.CompleteGraph(n).treelength() for n in range(3, 11)][1, 1, 1, 1, 1, 1, 1, 1]>>> from sage.all import *>>> [graphs.CompleteGraph(n).treewidth() for n in range(Integer(3), Integer(11))][2, 3, 4, 5, 6, 7, 8, 9]>>> [graphs.CompleteGraph(n).treelength() for n in range(Integer(3), Integer(11))][1, 1, 1, 1, 1, 1, 1, 1]

See also:• Wikipedia article Tree_decomposition• Wikipedia article TreewidthThis module contains the following methods
1692

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

treewidth()treelength()make_nice_tree_decomposition()label_nice_tree_decomposition()is_valid_tree_decomposition()
reduced_tree_decomposition()width_of_tree_decomposition()
length_of_tree_decomposition()

Compute the treewidth of 𝐺 (and provide a decomposition).
Compute the treelength of 𝐺 (and provide a decomposition).
Return a nice tree decomposition (TD) of the TD 𝑡𝑟𝑒𝑒𝑑 𝑒𝑐𝑜𝑚𝑝.
Return a nice tree decomposition with nodes labelled accordingly.
Check whether 𝑇 is a valid tree-decomposition for 𝐺.
Return a reduced tree-decomposition of 𝑇 .
Return the width of the tree decomposition 𝑇 of 𝐺.
Return the length of the tree decomposition 𝑇 of 𝐺.

5.20.1 Methods
class sage.graphs.graph_decompositions.tree_decomposition.TreelengthConnected
Bases: object
Compute the treelength of a connected graph (and provide a decomposition).
This class implements an algorithm for computing the treelength of a connected graph that virtually explores thegraph of all pairs (vertex_cut, connected_component), where vertex_cut is a vertex cut of thegraph of length ≤ 𝑘, and connected_component is a connected component of the graph induced by G vertex_cut.
We deduce that the pair (vertex_cut, connected_component) is feasible with treelength 𝑘 if connected_component is empty, or if a vertex v from vertex_cut can be replaced with a vertex from connected_component, such that the pair (vertex_cut + v, connected_component - v) is
feasible.
INPUT:• G – a sage Graph• k – integer (default: None); indicates the length to be considered. When 𝑘 is an integer, the method checks
that the graph has treelength ≤ 𝑘. If 𝑘 is None (default), the method computes the optimal treelength.
• certificate – boolean (default: False); whether to also compute the tree-decomposition itself
OUTPUT:
TreelengthConnected(G) returns the treelength of 𝐺. When 𝑘 is specified, it returns False whenno tree-decomposition of length ≤ 𝑘 exists or True otherwise. When certificate=True, thetree-decomposition is also returned.
EXAMPLES:
A clique has treelength 1:
sage: from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected
sage: TreelengthConnected(graphs.CompleteGraph(3)).get_length()1
sage: TC = TreelengthConnected(graphs.CompleteGraph(4), certificate=True)(continues on next page)

5.20. Tree decompositions

1693

Graph Theory, Release 10.4

(continued from previous page)

sage: TC.get_length()1
sage: TC.get_tree_decomposition()
Tree decomposition of Complete graph: Graph on 1 vertex>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected>>> TreelengthConnected(graphs.CompleteGraph(Integer(3))).get_length()
1>>> TC = TreelengthConnected(graphs.CompleteGraph(Integer(4)), certificate=True)>>> TC.get_length()
1>>> TC.get_tree_decomposition()
Tree decomposition of Complete graph: Graph on 1 vertex

A cycle has treelength ⌈𝑛/3⌉:
sage: TreelengthConnected(graphs.CycleGraph(6)).get_length()2
sage: TreelengthConnected(graphs.CycleGraph(7)).get_length()3
sage: TreelengthConnected(graphs.CycleGraph(7), k=3).is_less_than_k()
True
sage: TreelengthConnected(graphs.CycleGraph(7), k=2).is_less_than_k()
False>>> from sage.all import *>>> TreelengthConnected(graphs.CycleGraph(Integer(6))).get_length()
2>>> TreelengthConnected(graphs.CycleGraph(Integer(7))).get_length()
3>>> TreelengthConnected(graphs.CycleGraph(Integer(7)), k=Integer(3)).is_less_than_
˓→k()
True
>>> TreelengthConnected(graphs.CycleGraph(Integer(7)), k=Integer(2)).is_less_than_
˓→k()
False

get_length()
Return the length of the tree decomposition.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected
sage: G = graphs.CycleGraph(4)sage: TreelengthConnected(G).get_length()2
sage: TreelengthConnected(G, k=2).get_length()2
sage: TreelengthConnected(G, k=1).get_length()
Traceback (most recent call last):...
ValueError: no tree decomposition with length <= 1 was found

1694

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected>>> G = graphs.CycleGraph(Integer(4))>>> TreelengthConnected(G).get_length()
2>>> TreelengthConnected(G, k=Integer(2)).get_length()
2>>> TreelengthConnected(G, k=Integer(1)).get_length()
Traceback (most recent call last):...
ValueError: no tree decomposition with length <= 1 was foundget_tree_decomposition()
Return the tree-decomposition.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected
sage: G = graphs.CycleGraph(4)sage: TreelengthConnected(G, certificate=True).get_tree_decomposition()
Tree decomposition of Cycle graph: Graph on 2 vertices
sage: G.diameter()2
sage: TreelengthConnected(G, k=2, certificate=True).get_tree_decomposition()
Tree decomposition of Cycle graph: Graph on 1 vertex
sage: TreelengthConnected(G, k=1, certificate=True).get_tree_decomposition()
Traceback (most recent call last):...
ValueError: no tree decomposition with length <= 1 was found>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected>>> G = graphs.CycleGraph(Integer(4))>>> TreelengthConnected(G, certificate=True).get_tree_decomposition()
Tree decomposition of Cycle graph: Graph on 2 vertices>>> G.diameter()2>>> TreelengthConnected(G, k=Integer(2), certificate=True).get_tree_
˓→decomposition()
Tree decomposition of Cycle graph: Graph on 1 vertex>>> TreelengthConnected(G, k=Integer(1), certificate=True).get_tree_
˓→decomposition()
Traceback (most recent call last):...
ValueError: no tree decomposition with length <= 1 was foundis_less_than_k()
Return whether a tree decomposition with length at most 𝑘 was found.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected
sage: G = graphs.CycleGraph(4)(continues on next page)

5.20. Tree decompositions

1695

Graph Theory, Release 10.4

(continued from previous page)

sage: TreelengthConnected(G, k=1).is_less_than_k()
False
sage: TreelengthConnected(G, k=2).is_less_than_k()
True
sage: TreelengthConnected(G).is_less_than_k()
Traceback (most recent call last):...
ValueError: parameter k has not been specified>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import␣
˓→TreelengthConnected>>> G = graphs.CycleGraph(Integer(4))>>> TreelengthConnected(G, k=Integer(1)).is_less_than_k()
False>>> TreelengthConnected(G, k=Integer(2)).is_less_than_k()
True>>> TreelengthConnected(G).is_less_than_k()
Traceback (most recent call last):...
ValueError: parameter k has not been specified

sage.graphs.graph_decompositions.tree_decomposition.is_valid_tree_decomposition(G,T)
Check whether 𝑇 is a valid tree-decomposition for 𝐺.
INPUT:• G – a sage Graph• T – a tree decomposition, i.e., a tree whose vertices are the bags (subsets of vertices) of the decomposition
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import is_valid_
˓→tree_decomposition
sage: K = graphs.CompleteGraph(4)sage: T = Graph()
sage: T.add_vertex(Set(K))
sage: is_valid_tree_decomposition(K, T)
True
sage: G = graphs.RandomGNP(10, .2)
sage: T = G.treewidth(certificate=True)
sage: is_valid_tree_decomposition(G, T)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import is_valid_tree_
˓→decomposition>>> K = graphs.CompleteGraph(Integer(4))>>> T = Graph()>>> T.add_vertex(Set(K))>>> is_valid_tree_decomposition(K, T)
True>>> G = graphs.RandomGNP(Integer(10), RealNumber( .2 ))(continues on next page)

1696

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> T = G.treewidth(certificate=True)>>> is_valid_tree_decomposition(G, T)
True

The union of the bags is the set of vertices of 𝐺:
sage: G = graphs.PathGraph(4)sage: T = G.treewidth(certificate=True)
sage: _ = G.add_vertex()sage: is_valid_tree_decomposition(G, T)
False>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> T = G.treewidth(certificate=True)>>> _ = G.add_vertex()>>> is_valid_tree_decomposition(G, T)
False

Each edge of 𝐺 is contained in a bag:sage: G = graphs.PathGraph(4)sage: T = G.treewidth(certificate=True)
sage: G.add_edge(0, 3)
sage: is_valid_tree_decomposition(G, T)
False>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> T = G.treewidth(certificate=True)>>> G.add_edge(Integer(0), Integer(3))>>> is_valid_tree_decomposition(G, T)
False

The bags containing a vertex 𝑣 form a subtree of 𝑇 :sage: G = graphs.PathGraph(4)sage: X1, X2, X3 = Set([0, 1]), Set([1, 2]), Set([2, 3])
sage: T = Graph([(X1, X3), (X3, X2)])
sage: is_valid_tree_decomposition(G, T)
False>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> X1, X2, X3 = Set([Integer(0), Integer(1)]), Set([Integer(1), Integer(2)]),␣
˓→Set([Integer(2), Integer(3)])>>> T = Graph([(X1, X3), (X3, X2)])>>> is_valid_tree_decomposition(G, T)
False

sage.graphs.graph_decompositions.tree_decomposition.label_nice_tree_decomposition(nice_TD,root,
directed=False
Return a nice tree decomposition with nodes labelled accordingly.

5.20. Tree decompositions

1697

Graph Theory, Release 10.4

INPUT:• nice_TD – a nice tree decomposition• root – the root of the nice tree decomposition• directed – boolean (default: False); whether to return the nice tree decomposition as a directed graphrooted at vertex root or as an undirected graph
OUTPUT:
A nice tree decomposition with nodes labelled.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition, label_nice_tree_decomposition
sage: claw = graphs.CompleteBipartiteGraph(1, 3)
sage: claw_TD = claw.treewidth(certificate=True)
sage: nice_TD = make_nice_tree_decomposition(claw, claw_TD)
sage: root = sorted(nice_TD.vertices())[0]sage: label_TD = label_nice_tree_decomposition(nice_TD, root, directed=True)
sage: label_TD.name()
Labelled Nice tree decomposition of Tree decomposition
sage: for node in sorted(label_TD): # random....:
print(node, label_TD.get_vertex(node))(0, {}) forget(1, {0}) forget(2, {0, 1}) intro(3, {0}) forget(4, {0, 3}) intro(5, {0}) forget(6, {0, 2}) intro(7, {2}) intro(8, {}) leaf>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition, label_nice_tree_decomposition>>> claw = graphs.CompleteBipartiteGraph(Integer(1), Integer(3))>>> claw_TD = claw.treewidth(certificate=True)>>> nice_TD = make_nice_tree_decomposition(claw, claw_TD)>>> root = sorted(nice_TD.vertices())[Integer(0)]>>> label_TD = label_nice_tree_decomposition(nice_TD, root, directed=True)>>> label_TD.name()
Labelled Nice tree decomposition of Tree decomposition>>> for node in sorted(label_TD): # random...
print(node, label_TD.get_vertex(node))(0, {}) forget(1, {0}) forget(2, {0, 1}) intro(3, {0}) forget(4, {0, 3}) intro(5, {0}) forget(6, {0, 2}) intro(7, {2}) intro(8, {}) leaf

sage.graphs.graph_decompositions.tree_decomposition.length_of_tree_decomposition(G,T,
check=True)
1698

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

Return the length of the tree decomposition 𝑇 of 𝐺.
The length of a tree decomposition, as proposed in [DG2006], is the maximum diameter in 𝐺 of its bags, where
the diameter of a bag 𝑋𝑖 is the largest distance in 𝐺 between the vertices in 𝑋𝑖 (i.e., max𝑢,𝑣∈𝑋𝑖 dist𝐺 (𝑢, 𝑣)). See
the documentation of the tree_decomposition module for more details.
INPUT:• G – a graph• T – a tree-decomposition for 𝐺• check – boolean (default: True); whether to check that the tree-decomposition 𝑇 is valid for 𝐺
EXAMPLES:
Trees and cliques have treelength 1:
sage: from sage.graphs.graph_decompositions.tree_decomposition import length_of_
˓→tree_decomposition
sage: G = graphs.CompleteGraph(5)sage: tl, T = G.treelength(certificate=True)
sage: tl1
sage: length_of_tree_decomposition(G, T, check=True)1
sage: G = graphs.RandomTree(20)sage: tl, T = G.treelength(certificate=True)
sage: tl1
sage: length_of_tree_decomposition(G, T, check=True)
1>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import length_of_
˓→tree_decomposition>>> G = graphs.CompleteGraph(Integer(5))>>> tl, T = G.treelength(certificate=True)>>> tl1>>> length_of_tree_decomposition(G, T, check=True)
1>>> G = graphs.RandomTree(Integer(20))>>> tl, T = G.treelength(certificate=True)>>> tl1>>> length_of_tree_decomposition(G, T, check=True)
1

The Petersen graph has treelength 2:
sage: G = graphs.PetersenGraph()
sage: tl, T = G.treelength(certificate=True)
sage: tl2
sage: length_of_tree_decomposition(G, T)
2

5.20. Tree decompositions

1699

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> tl, T = G.treelength(certificate=True)>>> tl2>>> length_of_tree_decomposition(G, T)
2

When a tree-decomposition has a single bag containing all vertices of a graph, the length of this tree-decompositionis the diameter of the graph:
sage: G = graphs.Grid2dGraph(2, 5)
sage: G.treelength()2
sage: G.diameter()5
sage: T = Graph({Set(G): []})
sage: length_of_tree_decomposition(G, T)
5>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(2), Integer(5))>>> G.treelength()2>>> G.diameter()5>>> T = Graph({Set(G): []})>>> length_of_tree_decomposition(G, T)
5sage.graphs.graph_decompositions.tree_decomposition.make_nice_tree_decomposition(graph,tree_decomp)
Return a nice tree decomposition (TD) of the TD tree_decomp.
See page 161 of [CFKLMPPS15] for a description of the nice tree decomposition.
A nice TD 𝑁 𝑇 is a rooted tree with four types of nodes:• Leaf nodes have no children and bag size 1;• Introduce nodes have one child: If 𝑣 ∈ 𝑁 𝑇 is an introduce node and 𝑤 ∈ 𝑁 𝑇 its child, then 𝐵𝑎𝑔(𝑣) =𝐵𝑎𝑔(𝑤) ∪ {𝑥}, where 𝑥 is the introduced node;• Forget nodes have one child: If 𝑣 ∈ 𝑁 𝑇 is a forget node and 𝑤 ∈ 𝑁 𝑇 its child, then 𝐵𝑎𝑔(𝑣) = 𝐵𝑎𝑔(𝑤)∖{𝑥},where 𝑥 is the forgotten node;• Join nodes have two children, both identical to the parent.
INPUT:• graph – a Sage graph• tree_decomp – a tree decomposition
OUTPUT:
A nice tree decomposition.

1700

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

Warning: This method assumes that the vertices of the input tree 𝑡𝑟𝑒𝑒𝑑 𝑒𝑐𝑜𝑚𝑝 are hashable and have attributeissuperset, e.g., frozenset or Set_object_enumerated_with_category.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition
sage: petersen = graphs.PetersenGraph()
sage: petersen_TD = petersen.treewidth(certificate=True)
sage: make_nice_tree_decomposition(petersen, petersen_TD)
Nice tree decomposition of Tree decomposition: Graph on 28 vertices>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> petersen = graphs.PetersenGraph()>>> petersen_TD = petersen.treewidth(certificate=True)>>> make_nice_tree_decomposition(petersen, petersen_TD)
Nice tree decomposition of Tree decomposition: Graph on 28 vertices
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition
sage: cherry = graphs.CompleteBipartiteGraph(1, 2)
sage: cherry_TD = cherry.treewidth(certificate=True)
sage: make_nice_tree_decomposition(cherry, cherry_TD)
Nice tree decomposition of Tree decomposition: Graph on 7 vertices>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> cherry = graphs.CompleteBipartiteGraph(Integer(1), Integer(2))>>> cherry_TD = cherry.treewidth(certificate=True)>>> make_nice_tree_decomposition(cherry, cherry_TD)
Nice tree decomposition of Tree decomposition: Graph on 7 vertices
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition
sage: bip_one_four = graphs.CompleteBipartiteGraph(1, 4)
sage: bip_one_four_TD = bip_one_four.treewidth(certificate=True)
sage: make_nice_tree_decomposition(bip_one_four, bip_one_four_TD)
Nice tree decomposition of Tree decomposition: Graph on 15 vertices>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> bip_one_four = graphs.CompleteBipartiteGraph(Integer(1), Integer(4))>>> bip_one_four_TD = bip_one_four.treewidth(certificate=True)>>> make_nice_tree_decomposition(bip_one_four, bip_one_four_TD)
Nice tree decomposition of Tree decomposition: Graph on 15 vertices

Check that Issue #36843 is fixed:
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition(continues on next page)

5.20. Tree decompositions

1701

Graph Theory, Release 10.4

(continued from previous page)

sage: triangle = graphs.CompleteGraph(3)sage: triangle_TD = triangle.treewidth(certificate=True)
sage: make_nice_tree_decomposition(triangle, triangle_TD)
Nice tree decomposition of Tree decomposition: Graph on 7 vertices>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> triangle = graphs.CompleteGraph(Integer(3))>>> triangle_TD = triangle.treewidth(certificate=True)>>> make_nice_tree_decomposition(triangle, triangle_TD)
Nice tree decomposition of Tree decomposition: Graph on 7 vertices
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition
sage: graph = graphs.CompleteBipartiteGraph(2, 5)
sage: graph_TD = graph.treewidth(certificate=True)
sage: make_nice_tree_decomposition(graph, graph_TD)
Nice tree decomposition of Tree decomposition: Graph on 25 vertices>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> graph = graphs.CompleteBipartiteGraph(Integer(2), Integer(5))>>> graph_TD = graph.treewidth(certificate=True)>>> make_nice_tree_decomposition(graph, graph_TD)
Nice tree decomposition of Tree decomposition: Graph on 25 vertices
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition
sage: empty_graph = graphs.EmptyGraph()
sage: tree_decomp = empty_graph.treewidth(certificate=True)
sage: len(make_nice_tree_decomposition(empty_graph, tree_decomp))0>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> empty_graph = graphs.EmptyGraph()>>> tree_decomp = empty_graph.treewidth(certificate=True)>>> len(make_nice_tree_decomposition(empty_graph, tree_decomp))
0
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition
sage: singleton = graphs.CompleteGraph(1)sage: tree_decomp = singleton.treewidth(certificate=True)
sage: make_nice_tree_decomposition(singleton, tree_decomp)Nice tree decomposition of Tree decomposition: Graph on 3 vertices>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> singleton = graphs.CompleteGraph(Integer(1))(continues on next page)

1702

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> tree_decomp = singleton.treewidth(certificate=True)>>> make_nice_tree_decomposition(singleton, tree_decomp)Nice tree decomposition of Tree decomposition: Graph on 3 vertices
sage: from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition
sage: an_edge = graphs.CompleteGraph(2)sage: tree_decomp = an_edge.treewidth(certificate=True)
sage: make_nice_tree_decomposition(an_edge, tree_decomp)Nice tree decomposition of Tree decomposition: Graph on 5 vertices>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import make_nice_˓→tree_decomposition>>> an_edge = graphs.CompleteGraph(Integer(2))>>> tree_decomp = an_edge.treewidth(certificate=True)>>> make_nice_tree_decomposition(an_edge, tree_decomp)Nice tree decomposition of Tree decomposition: Graph on 5 vertices

sage.graphs.graph_decompositions.tree_decomposition.reduced_tree_decomposition(T)Return a reduced tree-decomposition of 𝑇 .
We merge all edges between two sets 𝑆 and 𝑆 ′ where 𝑆 is a subset of 𝑆 ′ . To do so, we use a simple union-finddata structure to record merge operations and the good sets.
Warning: This method assumes that the vertices of the input tree 𝑇 are hashable and have attribute issuperset, e.g., frozenset or Set_object_enumerated.
INPUT:• T – a tree-decomposition
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import reduced_
˓→tree_decomposition
sage: from sage.graphs.graph_decompositions.tree_decomposition import is_valid_
˓→tree_decomposition
sage: G = graphs.PathGraph(3)sage: T = Graph()
sage: T.add_path([Set([0]), Set([0, 1]), Set([1]), Set([1, 2]), Set([2])])sage: T.order()5sage: is_valid_tree_decomposition(G, T)
True
sage: T2 = reduced_tree_decomposition(T)sage: is_valid_tree_decomposition(G, T2)
True
sage: T2.order()2>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import reduced_tree_
˓→decomposition(continues on next page)

5.20. Tree decompositions

1703

Graph Theory, Release 10.4

(continued from previous page)>>> from sage.graphs.graph_decompositions.tree_decomposition import is_valid_tree_
˓→decomposition>>> G = graphs.PathGraph(Integer(3))>>> T = Graph()>>> T.add_path([Set([Integer(0)]), Set([Integer(0), Integer(1)]),␣
˓→Set([Integer(1)]), Set([Integer(1), Integer(2)]),Set([Integer(2)])])>>> T.order()5>>> is_valid_tree_decomposition(G, T)
True>>> T2 = reduced_tree_decomposition(T)>>> is_valid_tree_decomposition(G, T2)
True>>> T2.order()2sage.graphs.graph_decompositions.tree_decomposition.treelength(G, k=None,certificate=False)
Compute the treelength of 𝐺 (and provide a decomposition).
The length of a tree decomposition, as proposed in [DG2006], is the maximum diameter in 𝐺 of its bags, where
the diameter of a bag 𝑋𝑖 is the largest distance in 𝐺 between the vertices in 𝑋𝑖 (i.e., max𝑢,𝑣∈𝑋𝑖 dist𝐺 (𝑢, 𝑣)).
The treelength 𝑡𝑙(𝐺) of a graph 𝐺 is the minimum length among all possible tree decompositions of 𝐺. See thedocumentation of the tree_decomposition module for more details.
INPUT:• G – a sage Graph• k – integer (default: None); indicates the length to be considered. When 𝑘 is an integer, the method checks
that the graph has treelength ≤ 𝑘. If 𝑘 is None (default), the method computes the optimal treelength.
• certificate – boolean (default: False); whether to also return the tree-decomposition itself
OUTPUT:
G.treelength() returns the treelength of 𝐺. When 𝑘 is specified, it returns False when notree-decomposition of length ≤ 𝑘 exists or True otherwise.
When certificate=True, thetree-decomposition is also returned.
ALGORITHM:
This method virtually explores the graph of all pairs (vertex_cut, connected_component), wherevertex_cut is a vertex cut of the graph of length ≤ 𝑘, and connected_component is a connected component of the graph induced by G - vertex_cut.
We deduce that the pair (vertex_cut, connected_component) is feasible with treelength 𝑘 if connected_component is empty, or if a vertex v from vertex_cut can be replaced with a vertex from connected_component, such that the pair (vertex_cut + v, connected_component - v) is
feasible.
In practice, this method decomposes the graph by its clique minimal separators into atoms, computes the treelength of each of atom and returns the maximum value over all the atoms. Indeed, we have that 𝑡𝑙(𝐺) =max𝑋∈𝐴 𝑡𝑙(𝐺[𝑋]) where 𝐴 is the set of atoms of the decomposition by clique separators of 𝐺. When certificate == True, the tree-decompositions of the atoms are connected to each others by adding edges withrespect to the clique separators.
See also:• treewidth() computes the treewidth of a graph.
1704

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• path_decomposition() computes the pathwidth of a graph.
• module vertex_separation.
• atoms_and_clique_separators()
EXAMPLES:
The PetersenGraph has treelength 2:
sage: G = graphs.PetersenGraph()
sage: G.treelength()2>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.treelength()2

Disconnected graphs have infinite treelength:
sage: G = Graph(2)sage: G.treelength()+Infinity
sage: G.treelength(k=+Infinity)
True
sage: G.treelength(k=2)
False
sage: G.treelength(certificate=True)
Traceback (most recent call last):...
ValueError: the tree decomposition of a disconnected graph is not defined>>> from sage.all import *>>> G = Graph(Integer(2))>>> G.treelength()+Infinity>>> G.treelength(k=+Infinity)
True>>> G.treelength(k=Integer(2))
False>>> G.treelength(certificate=True)
Traceback (most recent call last):...
ValueError: the tree decomposition of a disconnected graph is not defined

Chordal graphs have treelength 1:
sage: G = graphs.RandomChordalGraph(30)sage: while not G.is_connected():....:G = graphs.RandomChordalGraph(30)sage: G.treelength()
1>>> from sage.all import *>>> G = graphs.RandomChordalGraph(Integer(30))>>> while not G.is_connected():...
G = graphs.RandomChordalGraph(Integer(30))(continues on next page)

5.20. Tree decompositions

1705

Graph Theory, Release 10.4

(continued from previous page)>>> G.treelength()1

Cycles have treelength ⌈𝑛/3⌉:
sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)][1, 2, 2, 2, 3, 3, 3, 4]>>> from sage.all import *>>> [graphs.CycleGraph(n).treelength() for n in range(Integer(3), Integer(11))][1, 2, 2, 2, 3, 3, 3, 4]

sage.graphs.graph_decompositions.tree_decomposition.treelength_lowerbound(G)Return a lower bound on the treelength of 𝐺.
See [DG2006] for more details.
INPUT:• G – a sage Graph
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import treelength_
˓→lowerboundsage: G = graphs.PetersenGraph()
sage: treelength_lowerbound(G)1
sage: G.treelength()2
sage: G = graphs.CycleGraph(5)sage: treelength_lowerbound(G)2
sage: G.treelength()2>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import treelength_
˓→lowerbound>>> G = graphs.PetersenGraph()>>> treelength_lowerbound(G)1>>> G.treelength()2>>> G = graphs.CycleGraph(Integer(5))>>> treelength_lowerbound(G)2>>> G.treelength()2

sage.graphs.graph_decompositions.tree_decomposition.treewidth(g, k=None, kmin=None,certificate=False,
algorithm=None,
nice=False)
Compute the treewidth of 𝑔 (and provide a decomposition).
INPUT:
1706

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• g – a Sage Graph• k – integer (default: None); indicates 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 treewidth.
• kmin – integer (default: None); when specified, search for a tree-decomposition of width at least kmin.
This parameter is useful when the graph can be decomposed into atoms. This parameter is ignored when k
is not None or when algorithm == tdlib .
• certificate – boolean (default: False); whether to return the tree-decomposition itself.
• algorithm – whether to use "sage" or "tdlib" (requires the installation of the sagemath_tdlib: Tree
decompositions with tdlib package). The default behaviour is to use ‘tdlib’ if it is available, and Sage’s own
algorithm when it is not.
• nice – boolean (default: False); whether or not to return the nice tree decomposition, provided certificate is True.
OUTPUT:g.treewidth() returns treewidth of the graph g.
When k is specified, it returns False if there is no tree decomposition of width ≤ 𝑘, and True otherwise.
When certificate=True, the tree decomposition is returned.
When nice=True, the nice tree decomposition is 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 graphinduced by G-vertex_cut.
We deduce that the pair (vertex_cut, cc) is feasible with treewidth 𝑘 if cc is empty, or if a vertex v fromvertex_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 wasteof time.
See also:
path_decomposition() computes the pathwidth of a graph. See also the vertex_separation module.
EXAMPLES:
The PetersenGraph has treewidth 4:
sage: petersen = graphs.PetersenGraph()
sage: petersen.treewidth(algorithm= sage )4sage: petersen.treewidth(algorithm= sage , certificate=True)
Tree decomposition: Graph on 6 vertices>>> from sage.all import *>>> petersen = graphs.PetersenGraph()>>> petersen.treewidth(algorithm= sage )4>>> petersen.treewidth(algorithm= sage , certificate=True)
Tree decomposition: Graph on 6 vertices

5.20. Tree decompositions

1707

Graph Theory, Release 10.4

The PetersenGraph has treewidth 4 (with tdlib):
sage: petersen = graphs.PetersenGraph()
sage: petersen.treewidth(algorithm= tdlib )4sage: petersen.treewidth(algorithm= tdlib , certificate=True)
Tree decomposition: Graph on 6 vertices>>> from sage.all import *>>> petersen = graphs.PetersenGraph()>>> petersen.treewidth(algorithm= tdlib )4>>> petersen.treewidth(algorithm= tdlib , certificate=True)
Tree decomposition: Graph on 6 vertices# optional - tdlib# optional - tdlib# optional - tdlib# optional - tdlib

Nice tree decomposition of the PetersenGraph has 28 nodes:
sage: petersen = graphs.PetersenGraph()
sage: petersen.treewidth(algorithm= sage , certificate=True, nice=True)
Nice tree decomposition of Tree decomposition: Graph on 28 vertices
sage: petersen.treewidth(algorithm= tdlib , certificate=True, nice=True)
˓→optional - tdlib
Nice tree decomposition of Tree decomposition: Graph on 28 vertices>>> from sage.all import *>>> petersen = graphs.PetersenGraph()>>> petersen.treewidth(algorithm= sage , certificate=True, nice=True)
Nice tree decomposition of Tree decomposition: Graph on 28 vertices>>> petersen.treewidth(algorithm= tdlib , certificate=True, nice=True)
˓→optional - tdlib
Nice tree decomposition of Tree decomposition: Graph on 28 vertices#␣#␣The treewidth of a 2-dimensional grid is its smallest side:
sage: graphs.Grid2dGraph(2,5).treewidth()2
sage: graphs.Grid2dGraph(3,5).treewidth()3>>> from sage.all import *>>> graphs.Grid2dGraph(Integer(2),Integer(5)).treewidth()2>>> graphs.Grid2dGraph(Integer(3),Integer(5)).treewidth()3

When parameter kmin is specified, the method searches for a tree-decomposition of width at least kmin:
sage: g = graphs.PetersenGraph()
sage: g.treewidth()4
sage: g.treewidth(kmin=2, algorithm= sage )4sage: g.treewidth(kmin=g.order(), certificate=True, algorithm= sage )Tree decomposition: Graph on 1 vertex

1708

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.treewidth()4>>> g.treewidth(kmin=Integer(2), algorithm= sage )4>>> g.treewidth(kmin=g.order(), certificate=True, algorithm= sage )Tree decomposition: Graph on 1 vertex

sage.graphs.graph_decompositions.tree_decomposition.width_of_tree_decomposition(G,T,
check=True)
Return the width of the tree decomposition 𝑇 of 𝐺.
The width of a tree-decomposition is the size of the largest bag minus 1. The empty graph and a graph of order 1have treewidth 0.
INPUT:• G – a sage Graph• T – a tree-decomposition for 𝐺• check – boolean (default: True); whether to check that the tree-decomposition 𝑇 is valid for 𝐺
EXAMPLES:
sage: from sage.graphs.graph_decompositions.tree_decomposition import width_of_
˓→tree_decomposition
sage: G = graphs.PathGraph(3)sage: T = G.treewidth(certificate=True)
sage: width_of_tree_decomposition(G, T, check=True)
1>>> from sage.all import *>>> from sage.graphs.graph_decompositions.tree_decomposition import width_of_tree_
˓→decomposition>>> G = graphs.PathGraph(Integer(3))>>> T = G.treewidth(certificate=True)>>> width_of_tree_decomposition(G, T, check=True)
1

5.21 Vertex separation
This module implements several algorithms to compute the vertex separation of a digraph and the corresponding orderingof 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.
5.21. Vertex separation

1709

Graph Theory, Release 10.4

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, andin which each edge 𝑢𝑣 of 𝐺 is replaced by two edges 𝑢𝑣 and 𝑣𝑢 in 𝐷. The vertex separation of 𝐷 is equal to the pathwidthof 𝐺, and the corresponding ordering of the vertices of 𝐷, also called a layout, encodes an optimal path-decompositionof 𝐺. This is a result of Kinnersley [Kin1992] and Bodlaender [Bod1998].
This module contains the following methods
pathwidth()path_decomposition()vertex_separation()vertex_separation_exp()
vertex_separation_MILP()
vertex_separation_BAB()
lower_bound()is_valid_ordering()
width_of_path_decomposition()
linear_ordering_to_path_decomposition()

Compute the pathwidth of self (and provides a decomposition)
Return the pathwidth of the given graph and the ordering of the vertices resulting
in a corresponding path decomposition
Return an optimal ordering of the vertices and its cost for vertex-separation
Compute the vertex separation of 𝐺 using an exponential time and space algorithm
Compute the vertex separation of 𝐺 and the optimal ordering of its vertices using
an MILP formulation
Compute the vertex separation of 𝐺 and the optimal ordering of its vertices usinga branch and bound algorithm
Return a lower bound on the vertex separation of 𝐺
Test if the linear vertex ordering 𝐿 is valid for (di)graph 𝐺
Return the width of the path decomposition induced by the linear ordering 𝐿 of
the vertices of 𝐺
Return the path decomposition encoded in the ordering 𝐿

5.21.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 asequence), 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 thatthe value 𝑐′ (𝑆) for a set 𝑆 is less than 𝑘 if all the paths leading to 𝑆 have a cost greater than 𝑘. For this reason, the valueof 𝑐′ (𝑆) 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 𝑘, thedepth-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 ofcomputational time is saved this way.

1710

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

Besides, some improvement is also made by “improving” the values found by 𝑐′ . Indeed, 𝑐′ (𝑆) is a lower bound on thecost 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 𝑐′ (𝑆), andreplace it by max(𝑐′ (𝑆), minnext ) (where minnext is the minimum of the costs of the out-neighbors of 𝑆) once the costs ofthese 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 bechanged to 64 if necessary, but 32 vertices already require 4GB of memory. Running it on 64 bits is not expected to bedoable 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 , ..., 𝑣𝑛 }ismax 𝑐′ ({𝑣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 theprevious exact algorithm), but it does not need much memory to run.

5.21.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 [SP2010]. It aims at building a sequence 𝑆𝑡 of sets suchthat an ordering 𝑣1 , ..., 𝑣𝑛 of the vertices correspond to 𝑆0 = {𝑣1 }, 𝑆2 = {𝑣1 , 𝑣2 }, ..., 𝑆𝑛−1 = {𝑣1 , ..., 𝑣𝑛 }.
Variables:• 𝑦𝑣𝑡 – Variable set to 1 if 𝑣 ∈ 𝑆𝑡 , and 0 otherwise. The order of 𝑣 in the layout is the smallest 𝑡 such that 𝑦𝑣𝑡 == 1.
• 𝑢𝑡𝑣 – Variable set to 1 if 𝑣 ̸∈ 𝑆𝑡 and 𝑣 has an in-neighbor in 𝑆𝑡 . It is set to 0 otherwise.
• 𝑥𝑡𝑣 – Variable set to 1 if either 𝑣 ∈ 𝑆𝑡 or if 𝑣 has an in-neighbor in 𝑆𝑡 . It is set to 0 otherwise.
• 𝑧 – Objective value to minimize. It is equal to the maximum over all step 𝑡 of the number of vertices such that𝑢𝑡𝑣 == 1.
MILP formulation:
Minimize:𝑧(5.1)

Such that:𝑥𝑡𝑣 ≤ 𝑥𝑡+1
∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 2𝑣
𝑡𝑡+1
𝑦𝑣 ≤ 𝑦𝑣∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 2𝑡𝑡𝑦𝑣 ≤ 𝑥𝑤 ∀𝑣 ∈ 𝑉, ∀𝑤 ∈ 𝑁 + (𝑣), 0 ≤ 𝑡 ≤ 𝑛 − 1∑︁

𝑦𝑣𝑡 = 𝑡 + 1𝑣∈𝑉
𝑥𝑡𝑣 − 𝑦𝑣𝑡 ≤ 𝑢𝑡𝑣

(5.2)
(5.3)
(5.4)

0≤𝑡≤𝑛−1(5.5)∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1(5.6)

𝑢𝑡𝑣 ≤ 𝑧0≤𝑡≤𝑛−1(5.7)

0 ≤ 𝑥𝑡𝑣 ≤ 1∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1(5.8)

0 ≤ 𝑢𝑡𝑣 ≤ 1
𝑦𝑣𝑡 ∈ {0, 1}∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1(5.9)∀𝑣 ∈ 𝑉, 0 ≤ 𝑡 ≤ 𝑛 − 1(5.10)

∑︁
𝑣∈𝑉

0≤𝑧≤𝑛
5.21. Vertex separation(5.11)
1711

Graph Theory, Release 10.4

The vertex separation of 𝐺 is given by the value of 𝑧, and the order of vertex 𝑣 in the optimal layout is given by thesmallest 𝑡 for which 𝑦𝑣𝑡 == 1.

5.21.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 thevertex separation of 𝐺, as proposed in [CMN2014].
Greedy steps:
Let us denote ℒ(𝑆) the set of all possible orderings of the vertices in 𝑆, and let ℒ𝑃 (𝑆) ⊆ ℒ(𝑆) be the orderings startingwith a prefix 𝑃 . Let also 𝑐(𝐿) be the cost of the ordering 𝐿 ∈ ℒ(𝑉 ) as defined above.
Given a digraph 𝐷 = (𝑉, 𝐴), a set 𝑆 ⊂ 𝑉 , and a prefix 𝑃 , it has been proved in [CMN2014] that min𝐿∈ℒ𝑃 (𝑉 ) 𝑐(𝐿) =min𝐿∈ℒ𝑃 +𝑣 (𝑉 ) 𝑐(𝐿) holds in two (non exhaustive) cases:{︃or𝑁 + (𝑣) ⊆ 𝑆 ∪ 𝑁 + (𝑆)𝑣 ∈ 𝑁 + (𝑆) and 𝑁 + (𝑣) ∖ (𝑆 ∪ 𝑁 + (𝑆)) = {𝑤}In other words, if we find a vertex 𝑣 satisfying the above conditions, the best possible ordering with prefix 𝑃 has the same
cost as the best possible ordering with prefix 𝑃 + 𝑣. So we can greedily extend the prefix with vertices satisfying theconditions which results in a significant reduction of the search space.
The algorithm:
Given the current prefix 𝑃 and the current upper bound 𝑈 𝐵 (either an input upper bound or the cost of the best solution
found so far), apply the following steps:• Extend the prefix 𝑃 into a prefix 𝑃 ′ using the greedy steps as described above.
• Sort the vertices 𝑣 ∈ 𝑉 ∖ 𝑃 ′ by increasing values of |𝑁 + (𝑃 + 𝑣)|, and prune the vertices with a value larger or
equal to 𝑈 𝐵. Let Δ be the resulting sorted list.
• Repeat with prefix 𝑃 ′ + 𝑣 for all 𝑣 ∈ Δ and keep the best found solution.
If a lower bound is passed to the algorithm, it will stop as soon as a solution with cost equal to that lower bound is found.
Storing prefixes:
If for a prefix 𝑃 we have 𝑐(𝑃 ) < min𝐿∈ℒ𝑃 (𝑉 ) 𝑐(𝐿) = 𝐶, then for any permutation 𝑃 ′ of 𝑃 we have min𝐿∈ℒ𝑃 ′ (𝑉 ) 𝑐(𝐿) ≥𝐶.
Thus, given such a prefix 𝑃 there is no need to explore any of the orderings starting with one of its permutations. To doso, we store 𝑃 (as a set of vertices) to cut branches later. See [CMN2014] for more details.
Since the number of stored sets can get very large, one can control the maximum length and the maximum number ofstored prefixes.

5.21.4 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

1712

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.21.5 Methods
sage.graphs.graph_decompositions.vertex_separation.is_valid_ordering(G, L)
Test if the linear vertex ordering 𝐿 is valid for (di)graph 𝐺.
A linear ordering 𝐿 of the vertices of a (di)graph 𝐺 is valid if all vertices of 𝐺 are in 𝐿, and if 𝐿 contains no othervertex 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 = G.vertices(sort=True)
sage: vertex_separation.is_valid_ordering(G, L)
True
sage: vertex_separation.is_valid_ordering(G, [1,2])
False>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation>>> G = graphs.CycleGraph(Integer(6))>>> L = G.vertices(sort=True)>>> vertex_separation.is_valid_ordering(G, L)
True>>> vertex_separation.is_valid_ordering(G, [Integer(1),Integer(2)])
False

sage.graphs.graph_decompositions.vertex_separation.linear_ordering_to_path_decomposition(G,L)
Return the path decomposition encoded in the ordering L
INPUT:• G – a Graph• L – a linear ordering for G
OUTPUT:
A path graph whose vertices are the bags of the path decomposition.
EXAMPLES:
The bags of an optimal path decomposition of a path-graph have two vertices each:sage: 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)(continues on next page)

5.21. Vertex separation

1713

Graph Theory, Release 10.4

(continued from previous page)

sage: pw, L = vertex_separation(g, algorithm = "BAB"); pw
1
sage: h = linear_ordering_to_path_decomposition(g, L)
sage: sorted(h, key=str)[{0, 1}, {1, 2}, {2, 3}, {3, 4}]
sage: sorted(h.edge_iterator(labels=None), key=str)[({0, 1}, {1, 2}), ({1, 2}, {2, 3}), ({2, 3}, {3, 4})]>>> from sage.all import *>>> from sage.graphs.graph_decompositions.vertex_separation import vertex_
˓→separation>>> from sage.graphs.graph_decompositions.vertex_separation import linear_
˓→ordering_to_path_decomposition>>> g = graphs.PathGraph(Integer(5))>>> pw, L = vertex_separation(g, algorithm = "BAB"); pw
1>>> h = linear_ordering_to_path_decomposition(g, L)>>> sorted(h, key=str)[{0, 1}, {1, 2}, {2, 3}, {3, 4}]>>> sorted(h.edge_iterator(labels=None), key=str)[({0, 1}, {1, 2}), ({1, 2}, {2, 3}), ({2, 3}, {3, 4})]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(sort=True)[{0, 2, 3, 4}, {0, 1, 2}]>>> from sage.all import *>>> g = graphs.PathGraph(Integer(5))>>> L = [Integer(1), Integer(4), Integer(0), Integer(2), Integer(3)]>>> from sage.graphs.graph_decompositions.vertex_separation import width_of_path_˓→decomposition>>> width_of_path_decomposition(g, L)
3>>> h = linear_ordering_to_path_decomposition(g, L)>>> h.vertices(sort=True)[{0, 2, 3, 4}, {0, 1, 2}]

The bags of the path decomposition of a cycle have three vertices each:sage: g = graphs.CycleGraph(6)sage: pw, L = vertex_separation(g, algorithm = "BAB"); pw
2
sage: h = linear_ordering_to_path_decomposition(g, L)
sage: sorted(h, key=str)[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}]
sage: sorted(h.edge_iterator(labels=None), key=str)[({0, 1, 5}, {1, 2, 5}), ({1, 2, 5}, {2, 4, 5}), ({2, 4, 5}, {2, 3, 4})]1714

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6))>>> pw, L = vertex_separation(g, algorithm = "BAB"); pw
2>>> h = linear_ordering_to_path_decomposition(g, L)>>> sorted(h, key=str)[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}]>>> sorted(h.edge_iterator(labels=None), key=str)[({0, 1, 5}, {1, 2, 5}), ({1, 2, 5}, {2, 4, 5}), ({2, 4, 5}, {2, 3, 4})]sage.graphs.graph_decompositions.vertex_separation.lower_bound(G)Return a lower bound on the vertex separation of 𝐺.
INPUT:• G – a Graph or a DiGraphOUTPUT:
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_boundsage: g = digraphs.Circuit(6)sage: lower_bound(g)1>>> from sage.all import *>>> from sage.graphs.graph_decompositions.vertex_separation import lower_bound>>> g = digraphs.Circuit(Integer(6))>>> lower_bound(g)1sage.graphs.graph_decompositions.vertex_separation.path_decomposition(G, algorithm='BAB',
cut_off=None,
upper_bound=None,verbose=False,
max_prefix_length=20,
max_prefix_number=1000000)
Return the pathwidth of the given graph and the ordering of the vertices resulting in a corresponding path decomposition.
INPUT:• G – a Graph5.21. Vertex separation

1715

Graph Theory, Release 10.4

• algorithm – string (default: "BAB"); algorithm to use among:– "BAB" – Use a branch-and-bound algorithm. This algorithm has no size restriction but could take a very
long time on large graphs. It can also be used to test is the input (di)graph has vertex separation at mostupper_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 graphson less than 32 vertices.
– MILP – Use a mixed integer linear programming formulation. This algorithm has no size restriction but
could take a very long time.
• upper_bound – integer (default: None); parameter used by the "BAB" algorithm. If specified, the algorithm searches for a solution with width < upper_bound. It helps cutting branches. However, if thegiven upper bound is too low, the algorithm may not be able to find a solution.
• cut_off – integer (default: None); parameter used by the "BAB" algorithm. This bound allows us tostop the search as soon as a solution with width at most cut_off is found, if any. If this bound cannot bereached, the best solution found is returned, unless a too low upper_bound is given.
• verbose – boolean (default: False); whether to display information on the computations• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing
too many prefixes. This parameter is used only when algorithm=="BAB".
• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used toprevent 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:
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
˓→needs sage.numerical.mip
2>>> from sage.all import *>>> from sage.graphs.graph_decompositions.vertex_separation import path_˓→decomposition>>> g = graphs.CycleGraph(Integer(6))>>> pw, L = path_decomposition(g, algorithm="BAB"); pw
2>>> pw, L = path_decomposition(g, algorithm="exponential"); pw
2>>> pw, L = path_decomposition(g, algorithm="MILP"); pw#␣#␣(continues on next page)

1716

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)needs sage.numerical.mip

˓→2

sage.graphs.graph_decompositions.vertex_separation.pathwidth(self, k=None,certificate=False,
algorithm='BAB',
verbose=False,
max_prefix_length=20,
max_prefix_number=1000000,
solver=None)
Compute the pathwidth of self (and provides a decomposition)
INPUT:• k – integer (default: None); the width to be considered. When k is an integer, the method checks that thegraph has pathwidth ≤ 𝑘. If k is None (default), the method computes the optimal pathwidth.
• certificate – boolean (default: False); whether to return the path-decomposition itself• algorithm – string (default: "BAB"); algorithm to use among:– "BAB" – Use a branch-and-bound algorithm. This algorithm has no size restriction but could take avery 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 graphson 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 (default: False); whether to display information on the computations• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing
too many prefixes. This parameter is used only when algorithm=="BAB".
• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used toprevent using too much memory. This parameter is used only when algorithm=="BAB".
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
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:

5.21. Vertex separation

1717

Graph Theory, Release 10.4

sage: g = graphs.CycleGraph(6)sage: g.pathwidth()2
sage: pw, decomp = g.pathwidth(certificate=True)
sage: sorted(decomp, key=str)[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}]>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6))>>> g.pathwidth()2>>> pw, decomp = g.pathwidth(certificate=True)>>> sorted(decomp, key=str)[{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {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)>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.pathwidth()5>>> g.pathwidth(k=Integer(2))
False>>> g.pathwidth(k=Integer(6))
True>>> g.pathwidth(k=Integer(6), certificate=True)(True, Graph on 5 vertices)sage.graphs.graph_decompositions.vertex_separation.vertex_separation(G, algorithm='BAB',
cut_off=None,
upper_bound=None,verbose=False,
max_prefix_length=20,
max_prefix_number=1000000,
solver=None,
integrality_tolerance=0.001)
Return an optimal ordering of the vertices and its cost for vertex-separation.

1718

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

INPUT:• G – a Graph or a DiGraph• algorithm – string (default: "BAB"); algorithm to use among:– "BAB" – Use a branch-and-bound algorithm. This algorithm has no size restriction but could take a very
long time on large graphs. It can also be used to test is the input (di)graph has vertex separation at mostupper_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 graphson less than 32 vertices.
– MILP – Use a mixed integer linear programming formulation. This algorithm has no size restriction but
could take a very long time.
• upper_bound – integer (default: None); parameter used by the "BAB" algorithm. If specified, the algorithm searches for a solution with width < upper_bound. It helps cutting branches. However, if thegiven upper bound is too low, the algorithm may not be able to find a solution.
• cut_off – integer (default: None); parameter used by the "BAB" algorithm. This bound allows us tostop the search as soon as a solution with width at most cut_off is found, if any. If this bound cannot bereached, the best solution found is returned, unless a too low upper_bound is given.
• verbose – boolean (default: False); whether to display information on the computations• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing
too many prefixes. This parameter is used only when algorithm=="BAB".
• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used toprevent using too much memory. This parameter is used only when algorithm=="BAB".
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Comparison of methods:
sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_
˓→separation
sage: # needs sage.combinat
sage: G = digraphs.DeBruijn(2,3)
sage: vs,L = vertex_separation(G, algorithm="BAB"); vs2
sage: vs,L = vertex_separation(G, algorithm="exponential"); vs2
sage: vs,L = vertex_separation(G, algorithm="MILP"); vs˓→needs sage.numerical.mip2#␣

sage: G = graphs.Grid2dGraph(3,3)
sage: vs,L = vertex_separation(G, algorithm="BAB"); vs(continues on next page)

5.21. Vertex separation

1719

Graph Theory, Release 10.4

(continued from previous page)3
sage: vs,L = vertex_separation(G, algorithm="exponential"); vs3
sage: vs,L = vertex_separation(G, algorithm="MILP"); vs˓→needs sage.numerical.mip3#␣>>> from sage.all import *>>> from sage.graphs.graph_decompositions.vertex_separation import vertex_
˓→separation>>> # needs sage.combinat>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> vs,L = vertex_separation(G, algorithm="BAB"); vs2>>> vs,L = vertex_separation(G, algorithm="exponential"); vs2>>> vs,L = vertex_separation(G, algorithm="MILP"); vs˓→needs sage.numerical.mip
2#␣>>> G = graphs.Grid2dGraph(Integer(3),Integer(3))>>> vs,L = vertex_separation(G, algorithm="BAB"); vs3>>> vs,L = vertex_separation(G, algorithm="exponential"); vs3>>> vs,L = vertex_separation(G, algorithm="MILP"); vs˓→needs sage.numerical.mip
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 = digraphs.RandomDirectedAcyclicGraph(10, .5)
sage: vs,L = vertex_separation(D); vs0
sage: K4 = DiGraph( graphs.CompleteGraph(4) )sage: D = K4+K4
sage: D.add_edge(0, 4)
sage: print(vertex_separation(D))(3, [4, 5, 6, 7, 0, 1, 2, 3])
sage: D = K4+K4+K4
sage: D.add_edge(0, 4)
sage: D.add_edge(0, 8)
sage: print(vertex_separation(D))(3, [10, 11, 8, 9, 4, 5, 6, 7, 0, 1, 2, 3])>>> from sage.all import *>>> from sage.graphs.graph_decompositions.vertex_separation import vertex_
˓→separation>>> D = digraphs.Path(Integer(8))>>> print(vertex_separation(D))(continues on next page)

1720

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)(0, [7, 6, 5, 4, 3, 2, 1, 0])>>> D = digraphs.RandomDirectedAcyclicGraph(Integer(10), RealNumber( .5 ))>>> vs,L = vertex_separation(D); vs0>>> K4 = DiGraph( graphs.CompleteGraph(Integer(4)) )>>> D = K4+K4>>> D.add_edge(Integer(0), Integer(4))>>> print(vertex_separation(D))(3, [4, 5, 6, 7, 0, 1, 2, 3])>>> D = K4+K4+K4>>> D.add_edge(Integer(0), Integer(4))>>> D.add_edge(Integer(0), Integer(8))>>> print(vertex_separation(D))(3, [10, 11, 8, 9, 4, 5, 6, 7, 0, 1, 2, 3])

Using a specific MILP solver:
sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_
˓→separation
sage: G = graphs.PetersenGraph()
sage: vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs#␣˓→optional - pyscipopt, needs sage.numerical.mip
5>>> from sage.all import *>>> from sage.graphs.graph_decompositions.vertex_separation import vertex_
˓→separation>>> G = graphs.PetersenGraph()>>> vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs#␣˓→optional - pyscipopt, needs sage.numerical.mip
5

sage.graphs.graph_decompositions.vertex_separation.vertex_separation_BAB(G,cut_off=None,
upper_bound=None,
max_prefix_length=20,
max_prefix_number=1000000,
verbose=False)
Branch and Bound algorithm for the vertex separation.
This method implements the branch and bound algorithm for the vertex separation of directed graphs and thepathwidth of undirected graphs proposed in [CMN2014]. 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 – integer (default: None); bound to consider in the branch and bound algorithm. This allows us
to stop the search as soon as a solution with width at most cut_off is found, if any. If this bound cannot
be reached, the best solution found is returned, unless a too low upper_bound is given.

5.21. Vertex separation

1721

Graph Theory, Release 10.4

• upper_bound – integer (default: None); if specified, the algorithm searches for a solution with width< upper_bound. It helps cutting branches. However, if the given upper bound is too low, the algorithm
may not be able to find a solution.
• max_prefix_length – integer (default: 20); limits the length of the stored prefixes to prevent storing
too many prefixes• max_prefix_number – integer (default: 10**6); upper bound on the number of stored prefixes used toprevent using too much memory• verbose – boolean (default: False); display some information when set to TrueOUTPUT:• 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>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> D = digraphs.RandomDirectedGNP(Integer(15), RealNumber( .2 ))>>> vb, seqb = VS.vertex_separation_BAB(D)>>> vd, seqd = VS.vertex_separation_exp(D)>>> vb == vd
True>>> 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>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> G = graphs.Grid2dGraph(Integer(4),Integer(4))>>> vs, seq = VS.vertex_separation_BAB(G); vs
4>>> vs == VS.width_of_path_decomposition(G, seq)
True

The vertex separation of a 𝑁 × 𝑀 grid with 𝑁 < 𝑀 is 𝑁 :1722

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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); vs3
sage: vs == VS.width_of_path_decomposition(G, seq)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> G = graphs.Grid2dGraph(Integer(3),Integer(5))>>> vs, seq = VS.vertex_separation_BAB(G); vs3>>> 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); vs1
sage: vs == VS.width_of_path_decomposition(D, seq)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> D = digraphs.Circuit(Integer(10))>>> vs, seq = VS.vertex_separation_BAB(D); vs1>>> 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); vs2>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> G = graphs.CycleGraph(Integer(10))>>> vs, seq = VS.vertex_separation_BAB(G); vs2

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); vs10>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> G = graphs.MycielskiGraph(Integer(5))(continues on next page)

5.21. Vertex separation

1723

Graph Theory, Release 10.4

(continued from previous page)>>> vs, seq = VS.vertex_separation_BAB(G); vs10

Searching for any solution with width less or equal to cut_off:
sage: from sage.graphs.graph_decompositions import vertex_separation as VS
sage: G = graphs.MycielskiGraph(5)sage: VS.vertex_separation_BAB(G, cut_off=11)[0] <= 11
Truesage: VS.vertex_separation_BAB(G, cut_off=10)[0] <= 10
Truesage: VS.vertex_separation_BAB(G, cut_off=9)[0] <= 9
False>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> G = graphs.MycielskiGraph(Integer(5))>>> VS.vertex_separation_BAB(G, cut_off=Integer(11))[Integer(0)] <= Integer(11)True>>> VS.vertex_separation_BAB(G, cut_off=Integer(10))[Integer(0)] <= Integer(10)True>>> VS.vertex_separation_BAB(G, cut_off=Integer(9))[Integer(0)] <= Integer(9)False

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>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> G = graphs.MycielskiGraph(Integer(5))>>> vs, seq = VS.vertex_separation_BAB(G, upper_bound=Integer(11)); vs
10>>> vs, seq = VS.vertex_separation_BAB(G, upper_bound=Integer(10)); vs-1>>> vs, seq = VS.vertex_separation_BAB(G, cut_off=Integer(11), upper_
˓→bound=Integer(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

1724

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation as VS>>> G = graphs.MycielskiGraph(Integer(5))>>> vs, seq = VS.vertex_separation_BAB(G, max_prefix_length=Integer(0)); vs
10>>> vs, seq = VS.vertex_separation_BAB(G, max_prefix_number=Integer(5)); vs
10>>> vs, seq = VS.vertex_separation_BAB(G, max_prefix_number=Integer(0)); vs10

sage.graphs.graph_decompositions.vertex_separation.vertex_separation_MILP(G, integrality=False,
solver=None,verbose=0,
integrality_tolerance=0.001)
Compute the vertex separation of 𝐺 and the optimal ordering of its vertices using an MILP formulation.
This function uses a mixed integer linear program (MILP) for determining an optimal layout for the vertex separation of 𝐺. This MILP is an improved version of the formulation proposed in [SP2010]. See the module s
documentation for more details on this MILP formulation.
INPUT:• G – a Graph or a DiGraph• integrality – boolean (default: False); specify if variables 𝑥𝑡𝑣 and 𝑢𝑡𝑣 must be integral or if they canbe relaxed. This has no impact on the validity of the solution, but it is sometimes faster to solve the problem
using binary variables only.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Vertex separation of a De Bruijn digraph:
sage: # needs sage.combinat
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˓→needs sage.numerical.mip
2
sage: vs == vertex_separation.width_of_path_decomposition(G, L)#␣#␣(continues on next page)

5.21. Vertex separation

1725

Graph Theory, Release 10.4

(continued from previous page)needs sage.numerical.mip
True
sage: vse, Le = vertex_separation.vertex_separation(G); vse
2
˓→>>> from sage.all import *>>> # needs sage.combinat>>> from sage.graphs.graph_decompositions import vertex_separation>>> G = digraphs.DeBruijn(Integer(2),Integer(3))>>> vs, L = vertex_separation.vertex_separation_MILP(G); vs˓→needs sage.numerical.mip
2>>> vs == vertex_separation.width_of_path_decomposition(G, L)
˓→needs sage.numerical.mip
True>>> 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˓→needs sage.numerical.mip
1#␣>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation>>> G = digraphs.Circuit(Integer(6))>>> vs, L = vertex_separation.vertex_separation_MILP(G); vs˓→needs sage.numerical.mip
1#␣

sage.graphs.graph_decompositions.vertex_separation.vertex_separation_exp(G, verbose=False)
Return an optimal ordering of the vertices and its cost for vertex-separation.
INPUT:• G – a Graph or a DiGraph• verbose – boolean (default: False); whether to display information on the computations
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
Note: Because of its current implementation, this algorithm only works on graphs on less than 32 vertices. Thiscan 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(continues on next page)

1726

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: g = digraphs.Circuit(6)sage: vertex_separation_exp(g)(1, [0, 1, 2, 3, 4, 5])>>> from sage.all import *>>> from sage.graphs.graph_decompositions.vertex_separation import vertex_
˓→separation_exp>>> g = digraphs.Circuit(Integer(6))>>> vertex_separation_exp(g)(1, [0, 1, 2, 3, 4, 5])

sage.graphs.graph_decompositions.vertex_separation.width_of_path_decomposition(G,L)
Return the width of the path decomposition induced by the linear ordering 𝐿 of the vertices of 𝐺.
If 𝐺 is an instance of Graph, this function returns the width 𝑝𝑤𝐿 (𝐺) of the path decomposition induced by thelinear 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|𝑁 + (𝐿[: 𝑖]) ∖ 𝐿[: 𝑖]|max|𝑁 (𝐿[: 𝑖]) ∖ 𝐿[: 𝑖]|0≤𝑖<|𝑉 |−10≤𝑖<|𝑉 |−1

INPUT:• G – a Graph or a DiGraph• L – a linear ordering of the vertices of G
EXAMPLES:Path decomposition of a cycle:
sage: from sage.graphs.graph_decompositions import vertex_separation
sage: G = graphs.CycleGraph(6)sage: L = G.vertices(sort=True)
sage: vertex_separation.width_of_path_decomposition(G, L)
2>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation>>> G = graphs.CycleGraph(Integer(6))>>> L = G.vertices(sort=True)>>> 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 = G.vertices(sort=True)
sage: vertex_separation.width_of_path_decomposition(G, L)
1>>> from sage.all import *>>> from sage.graphs.graph_decompositions import vertex_separation(continues on next page)

5.21. Vertex separation

1727

Graph Theory, Release 10.4

(continued from previous page)>>> G = digraphs.Circuit(Integer(6))>>> L = G.vertices(sort=True)>>> vertex_separation.width_of_path_decomposition(G, L)
1

5.22 Rank Decompositions of graphs
This module wraps C code from Philipp Klaus Krause computing an optimal rank-decomposition.
Definitions :Given a graph 𝐺 and a subset 𝑆 ⊆ 𝑉 (𝐺) of vertices, the rank-width of 𝑆 in 𝐺, denoted 𝑟𝑤𝐺 (𝑆), is equal to the rank in
𝐺𝐹 (2) of the |𝑆| × (|𝑉 | − |𝑆|) matrix of the adjacencies between the vertices of 𝑆 and 𝑉 ∖𝑆. By definition, 𝑟𝑤𝐺 (𝑆) isequal 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 forany edge 𝑒 ∈ 𝐸(𝐺) a width equal to the value 𝑟𝑤𝐺 (𝑆) or 𝑟𝑤𝐺 (𝑆), where 𝑆, 𝑆 is the bipartition obtained from 𝑒. The
rank-width associated to the whole decomposition is then set to the maximum of the width of all the edges it contains.
A rank-decomposition is said to be optimal for 𝐺 if it is the decomposition achieving the minimal rank-width.
RW – The original source code :RW is a program that calculates rank-width and rank-decompositions. It is based on ideas from:• “Computing rank-width exactly” by Sang-il Oum [Oum2009]• “Sopra una formula numerica” by Ernesto Pascal• “Generation of a Vector from the Lexicographical Index” by B.P. Buckles and M. Lybanon [BL1977]• “Fast additions on masked integers” by Michael D. Adams and David S. Wise [AW2006]
OUTPUT:The rank decomposition is returned as a tree whose vertices are subsets of 𝑉 (𝐺). Its leaves, corresponding to the vertices
of 𝐺 are sets of 1 elements, i.e. singletons.
sage: g = graphs.PetersenGraph()
sage: rw, tree = g.rank_decomposition()sage: all(len(v)==1 for v in tree if tree.degree(v) == 1)
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> rw, tree = g.rank_decomposition()>>> all(len(v)==Integer(1) for v in tree if tree.degree(v) == Integer(1))
True

The internal nodes are sets of the decomposition. This way, it is easy to deduce the bipartition associated to an edge
from the tree. Indeed, two adjacent vertices of the tree are comparable sets : they yield the bipartition obtained from thesmaller of the two and its complement.

1728

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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(sort=False)) - m)sage: bipartition({8, 9}, {0, 1, 2, 3, 4, 5, 6, 7})>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> rw, tree = g.rank_decomposition()>>> u = Set([Integer(8), Integer(9), Integer(3), Integer(7)])>>> v = Set([Integer(8), Integer(9)])>>> tree.has_edge(u,v)
True>>> m = min(u,v)>>> bipartition = (m, Set(g.vertices(sort=False)) - m)>>> 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)>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.rank_decomposition()(3, Graph on 19 vertices)

AUTHORS:• Philipp Klaus Krause : Implementation of the C algorithm• Nathann Cohen : Interface with Sage and documentation

5.22. Rank Decompositions of graphs

1729Graph Theory, Release 10.4

5.22.1 Methods
sage.graphs.graph_decompositions.rankwidth.mkgraph(num_vertices)
Return the graph corresponding to the current rank-decomposition.
(This function is for internal use)
EXAMPLES:
sage: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition
sage: g = graphs.PetersenGraph()
sage: rank_decomposition(g)(3, Graph on 19 vertices)>>> from sage.all import *>>> from sage.graphs.graph_decompositions.rankwidth import rank_decomposition>>> g = graphs.PetersenGraph()>>> rank_decomposition(g)(3, Graph on 19 vertices)sage.graphs.graph_decompositions.rankwidth.rank_decomposition(G, verbose=False)
Compute an optimal rank-decomposition of the given graph.
This function is available as a method of the Graph class. See rank_decomposition.
INPUT:• verbose – boolean (default: False); whether to display progress information while computing the 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)>>> from sage.all import *>>> from sage.graphs.graph_decompositions.rankwidth import rank_decomposition>>> g = graphs.PetersenGraph()>>> 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

1730

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(40), RealNumber( .5 ))>>> 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)>>> from sage.all import *>>> g = Graph()>>> rank_decomposition(g)(0, Graph on 0 vertices)

5.23 Bandwidth of undirected graphs
5.23.1 Definition
The bandwidth 𝑏𝑤(𝑀 ) of a matrix 𝑀 is the smallest integer 𝑘 such that all non-zero entries of 𝑀 are at distance 𝑘 fromthe 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 adjacentvertices 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.23.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 ?
Because of the previous definition, 𝑝𝑖+1 must be at distance at most 𝑘 × 𝑑𝐺 (𝑣1 , 𝑣𝑖+1 ) from 𝑝1 , and in general at distanceat 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 toan 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 [𝑝𝑗 , 𝑝𝑗 ].
5.23. Bandwidth of undirected graphs

1731

Graph Theory, Release 10.4

This problem is not always satisfiable, e.g. 5 vertices cannot all be assigned to the elements of [10, 13]. This is a matchingproblem which, because all admissible sets are intervals, can be solved quickly.

5.23.3 Solving the matching problem
Let 𝑛 points 𝑣1 , ..., 𝑣𝑛 be given, along with two functions 𝑚, 𝑀 : [𝑛] ↦→ [𝑛]. Is there an ordering 𝑝1 , ..., 𝑝𝑛 of themsuch that 𝑚(𝑣𝑖 ) ≤ 𝑝𝑖 ≤ 𝑀 (𝑣𝑖 ) ? This is equivalent to Hall’s bipartite matching theorem, and can in this specific case besolved 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 isnone, the assignment problem is not satisfiable.
Note that the latest operation can be performed with very few bitset operations (provided that 𝑛 < 64).

5.23.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.23.5 This module contains the following methods
bandwidth()
bandwidth_heuristics()

Compute the bandwidth of an undirected graph
Use Boost heuristics to approximate the bandwidth of the input graph5.23.6 Functions
sage.graphs.graph_decompositions.bandwidth.bandwidth(G, k=None)
Compute the bandwidth of an undirected graph.
For a definition of the bandwidth of a graph, see the documentation of the bandwidth module.
INPUT:• G – a graph• k – integer (default: None); set to an integer value to test whether 𝑏𝑤(𝐺) ≤ 𝑘, or to None (default) tocompute 𝑏𝑤(𝐺)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).

1732

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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])
˓→needs sage.modules[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])
˓→needs sage.modules[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]#␣#␣>>> from sage.all import *>>> from sage.graphs.graph_decompositions.bandwidth import bandwidth>>> G = graphs.PetersenGraph()>>> bandwidth(G,Integer(3))
False>>> bandwidth(G)(5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2])>>> G.adjacency_matrix(vertices=[Integer(0), Integer(4), Integer(5), Integer(8),␣
˓→Integer(1), Integer(9), Integer(3), Integer(7), Integer(6), Integer(2)])␣˓→# needs sage.modules[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](continues on next page)

5.23. Bandwidth of undirected graphs1733

Graph Theory, Release 10.4

(continued from previous page)[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]>>> G = graphs.ChvatalGraph()>>> bandwidth(G)(6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2])>>> G.adjacency_matrix(vertices=[Integer(0), Integer(5), Integer(9), Integer(4),␣
˓→Integer(10), Integer(1), Integer(6), Integer(11), Integer(3), Integer(8),␣
˓→Integer(7), Integer(2)])# needs sage.modules[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.24 CutwidthThis module implements several algorithms to compute the cutwidth of a graph and the corresponding ordering of thevertices. It also implements tests functions for evaluation the width of a linear ordering (or layout).
Given an ordering 𝑣1 , · · · , 𝑣𝑛 of the vertices of 𝑉 (𝐺), its cost is defined as:𝑐(𝑣1 , ..., 𝑣𝑛 ) =max

1≤𝑖≤𝑛−1𝑐′ ({𝑣1 , ..., 𝑣𝑖 })Where𝑐′ (𝑆) = |{(𝑢, 𝑤) ∈ 𝐸(𝐺) | 𝑢 ∈ 𝑆 and 𝑤 ∈ 𝑉 (𝐺)∖𝑆}|
The cutwidth of a graph 𝐺 is equal to the minimum cost of an ordering of its vertices.
This module contains the following methods
cutwidth()
cutwidth_dyn()cutwidth_MILP()
width_of_cut_decomposition()

1734

Return the cutwidth of the graph and the corresponding vertex ordering.
Compute the cutwidth of 𝐺 using an exponential time and space algorithm basedon dynamic programming
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 thevertices of 𝐺

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.24.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 asequence), 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 thatthe value 𝑐′ (𝑆) for a set 𝑆 is less than 𝑘 if all the paths leading to 𝑆 have a cost greater than 𝑘. For this reason, the valueof 𝑐′ (𝑆) 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 𝑘, thedepth-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 ofcomputational time is saved this way.
Besides, some improvement is also made by “improving” the values found by 𝑐′ . Indeed, 𝑐′ (𝑆) is a lower bound on thecost 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 𝑐′ (𝑆), andreplace it by max(𝑐′ (𝑆), minnext ) (where minnext is the minimum of the costs of the out-neighbors of 𝑆) once the costs ofthese 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. Thiscan be changed to 64 if necessary, but 32 vertices already require 4GB of memory.

5.24.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 theof edges with one∑︀ number𝑘
extremity at position at most 𝑘 and the other at position strictly more than 𝑘, that is 𝑢𝑣∈𝐸 𝑦𝑢,𝑣.
MILP formulation:

5.24. Cutwidth1735

Graph Theory, Release 10.4

Minimize:𝑧
Subject to:𝑘−1∑︁𝑥𝑖𝑣 ≤ 𝑘 * 𝑥𝑘𝑣∀𝑣 ∈ 𝑉, 𝑘 ∈ [1, 𝑛 − 1](1)∀𝑣 ∈ 𝑉(2)∀𝑘 ∈ [0, 𝑛 − 1](3)

∀𝑢𝑣 ∈ 𝐸, ∀𝑘 ∈ [0, 𝑛 − 1](4)

∀𝑢𝑣 ∈ 𝐸, ∀𝑘 ∈ [0, 𝑛 − 1](5)∀𝑘 ∈ [0, 𝑛 − 1]

(6)

𝑖=0

𝑥𝑛𝑣 = 1∑︁

𝑥𝑘𝑣 = 𝑘 + 1𝑣∈𝑉𝑘𝑥𝑘𝑢 − 𝑥𝑘𝑣 ≤ 𝑦𝑢,𝑣𝑘𝑥𝑘𝑣 − 𝑥𝑘𝑢 ≤ 𝑦𝑢,𝑣

∑︁

𝑘
𝑦𝑢,𝑣
≤𝑧

𝑢𝑣∈𝐸

0 ≤ 𝑧 ≤ |𝐸|𝑘Constraints (1)-(3) ensure that all vertices have a distinct position. Constraints (4)-(5) force variable 𝑦𝑢,𝑣
to 1 if the edge
is in the cut. Constraint (6) count the number of edges starting at position at most 𝑘 and ending at a position strictly larger
than 𝑘.

This formulation corresponds to method cutwidth_MILP().

5.24.3 Authors• David Coudert (2015-06): Initial version

5.24.4 Methods
sage.graphs.graph_decompositions.cutwidth.cutwidth(G, algorithm='exponential', cut_off=0,
solver=None, verbose=False,
integrality_tolerance=0.001)
Return the cutwidth of the graph and the corresponding vertex ordering.
INPUT:• G – a Graph or a DiGraph• algorithm – string (default: "exponential"); algorithm to use among:– exponential – Use an exponential time and space algorithm based on dynamic programming. Thisalgorithm 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 – integer (default: 0); 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – boolean (default: False); whether to display information on the computations.
1736

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Cutwidth of a 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>>> from sage.all import *>>> from sage.graphs.graph_decompositions.cutwidth import cutwidth>>> G = graphs.CompleteGraph(Integer(5))>>> cw,L = cutwidth(G); cw
6>>> K = graphs.CompleteGraph(Integer(6))>>> cw,L = cutwidth(K); cw
9>>> cw,L = cutwidth(K+K); cw
9The 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>>> from sage.all import *>>> from sage.graphs.graph_decompositions.cutwidth import cutwidth>>> G = graphs.Grid2dGraph(Integer(3),Integer(3))>>> cw,L = cutwidth(G); cw
4>>> G = graphs.Grid2dGraph(Integer(3),Integer(5))>>> cw,L = cutwidth(G); cw
4sage.graphs.graph_decompositions.cutwidth.cutwidth_MILP(G, lower_bound=0, solver=None,verbose=0,
integrality_tolerance=0.001)
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.

5.24. Cutwidth1737

Graph Theory, Release 10.4

INPUT:• G – a Graph• lower_bound – integer (default: 0); the algorithm searches for a solution with cost larger or equal tolower_bound. If the given bound is larger than the optimal solution the returned solution might not be
optimal. If the given bound is too high, the algorithm might not be able to find a feasible solution.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
EXAMPLES:
Cutwidth of a Cycle graph:
sage: from sage.graphs.graph_decompositions import cutwidth
sage: G = graphs.CycleGraph(5)sage: cw, L = cutwidth.cutwidth_MILP(G); cw
˓→needs sage.numerical.mip
2
sage: cw == cutwidth.width_of_cut_decomposition(G, L)
˓→needs sage.numerical.mip
True
sage: cwe, Le = cutwidth.cutwidth_dyn(G); cwe
2>>> from sage.all import *>>> from sage.graphs.graph_decompositions import cutwidth>>> G = graphs.CycleGraph(Integer(5))>>> cw, L = cutwidth.cutwidth_MILP(G); cw
˓→needs sage.numerical.mip
2>>> cw == cutwidth.width_of_cut_decomposition(G, L)
˓→needs sage.numerical.mip
True>>> 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
˓→needs sage.numerical.mip
4
sage: cw == cutwidth.width_of_cut_decomposition(G, L)
˓→needs sage.numerical.mip
True

1738

#␣

#␣

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_decompositions import cutwidth>>> G = graphs.CompleteGraph(Integer(4))>>> cw, L = cutwidth.cutwidth_MILP(G); cw
˓→needs sage.numerical.mip
4>>> cw == cutwidth.width_of_cut_decomposition(G, L)
˓→needs sage.numerical.mip
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
˓→needs sage.numerical.mip
1
sage: cw == cutwidth.width_of_cut_decomposition(G, L)
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions import cutwidth>>> G = graphs.PathGraph(Integer(3))>>> cw, L = cutwidth.cutwidth_MILP(G); cw
˓→needs sage.numerical.mip
1>>> cw == cutwidth.width_of_cut_decomposition(G, L)
˓→needs sage.numerical.mip
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 – integer (default: 0); the algorithm returns immediately if it finds a solution lower or equal
to lower_bound (in which case it may not be optimal).
OUTPUT:
A pair (cost, ordering) representing the optimal ordering of the vertices and its cost.
Note: Because of its current implementation, this algorithm only works on graphs on strictly less than 32 vertices.
This can be changed to 63 if necessary, but 32 vertices already require 4GB of memory.
sage.graphs.graph_decompositions.cutwidth.width_of_cut_decomposition(G, L)
Return the width of the cut decomposition induced by the linear ordering 𝐿 of the vertices of 𝐺.
If 𝐺 is an instance of Graph, this function returns the width 𝑐𝑤𝐿 (𝐺) of the cut decomposition induced by thelinear ordering 𝐿 of the vertices of 𝐺.
𝑐𝑤𝐿 (𝐺) =5.24. Cutwidthmax

0≤𝑖<|𝑉 |−1|{(𝑢, 𝑤) ∈ 𝐸(𝐺) | 𝑢 ∈ 𝐿[: 𝑖] and 𝑤 ∈ 𝑉 (𝐺) ∖ 𝐿[: 𝑖]}|1739

Graph Theory, Release 10.4

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(sort=False)
sage: cutwidth.width_of_cut_decomposition(G, L)
2>>> from sage.all import *>>> from sage.graphs.graph_decompositions import cutwidth>>> G = graphs.CycleGraph(Integer(6))>>> L = G.vertices(sort=False)>>> 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])2sage: cutwidth.width_of_cut_decomposition(P, [0, 2, 4, 1, 3, 5])5>>> from sage.all import *>>> from sage.graphs.graph_decompositions import cutwidth>>> P = graphs.PathGraph(Integer(6))>>> cutwidth.width_of_cut_decomposition(P, [Integer(0), Integer(1), Integer(2),␣
˓→Integer(3), Integer(4), Integer(5)])
1>>> cutwidth.width_of_cut_decomposition(P, [Integer(5), Integer(0), Integer(1),␣
˓→Integer(2), Integer(3), Integer(4)])
2>>> cutwidth.width_of_cut_decomposition(P, [Integer(0), Integer(2), Integer(4),␣
˓→Integer(1), Integer(3), Integer(5)])
55.25 Products of graphs
This module gathers everything related to graph products. At the moment it contains an implementation of a recognition
algorithm for graphs that can be written as a Cartesian product of smaller ones.
Author:• Nathann Cohen (May 2012 – coded while watching the election of Francois Hollande on TV)

1740

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.25.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• ℎ = ℎ′ and 𝑔𝑔 ′ ∈ 𝐺
Two remarks follow :1. The Cartesian product is commutative
2. Any edge 𝑢𝑣 of a graph 𝐺1  · · · 𝐺𝑘 can be given a color 𝑖 corresponding to the unique index 𝑖 such that 𝑢𝑖 and𝑣𝑖 differ.
The problem that is of interest to us in the present module is the following:
Recognition problem Given a graph 𝐺, can we guess whether there exist graphs 𝐺1 , ..., 𝐺𝑘 such that 𝐺 =𝐺1  · · · 𝐺𝑘 ?
This problem can actually be solved, and the resulting factorization is unique. What is explained below can be found in
the book Handbook of Product Graphs [HIK2011].
Everything is actually based on simple observations. Given a graph 𝐺, finding out whether 𝐺 can be written as the productof several graphs can be attempted by trying to color its edges according to some rules. Indeed, if we are to color theedges 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 uniquevertex 𝑢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.

5.25. Products of graphs

1741

Graph Theory, Release 10.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 𝑥𝑖 andthe 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 twoedges whenever they are found to be equivalent according to the previous remarks.
All that is left to do is to compute the connected components of this new graph, as each of them representing the edges
of a factor. Of course, only one connected component indicates that the graph has no factorization.
Then again, please refer to [HIK2011] for any technical question.
To Do
This implementation is made at Python level, and some parts of the algorithm could be rewritten in Cython to save time.
Especially when enumerating all pairs of edges and computing their distances. This can easily be done in C with thefunctions from the sage.graphs.distances_all_pairs module.

1742

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.25.2 Methods
sage.graphs.graph_decompositions.graph_products.is_cartesian_product(g, certificate=False,
relabeling=False)
Test whether the graph is a Cartesian product.
INPUT:• certificate – boolean (default: False); if certificate = False (default) the method only
returns True or False answers. If certificate = True, the True answers are replaced by the listof the factors of the graph.
• relabeling – boolean (default: False); if relabeling = True (implies certificate =True), the method also returns a dictionary associating to each vertex its natural coordinates as a vertex ofa product graph. If 𝑔 is not a Cartesian product, None is returned instead.
See also:• sage.graphs.generic_graph.GenericGraph.cartesian_product()• graph_products – a module on graph products.

Note: This algorithm may run faster whenever the graph’s vertices are integers (see relabel()). Give it a try
if it is too slow !
EXAMPLES:
The Petersen graph is prime:
sage: from sage.graphs.graph_decompositions.graph_products import is_cartesian_
˓→product
sage: g = graphs.PetersenGraph()
sage: is_cartesian_product(g)False>>> from sage.all import *>>> from sage.graphs.graph_decompositions.graph_products import is_cartesian_
˓→product>>> g = graphs.PetersenGraph()>>> 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))
Truesage: p2.is_isomorphic(graphs.PathGraph(5))
True>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5),Integer(5))>>> p1, p2 = is_cartesian_product(g, certificate = True)(continues on next page)

5.25. Products of graphs

1743

Graph Theory, Release 10.4

(continued from previous page)>>> p1.is_isomorphic(graphs.PathGraph(Integer(5)))
True>>> p2.is_isomorphic(graphs.PathGraph(Integer(5)))
True

Forgetting the graph’s labels, then finding them back:sage: g.relabel()
sage: b,D = g.is_cartesian_product(g, relabeling=True)
sage: bTrue
sage: D # random isomorphism{0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
15: (5, 0), 16: (5, 1), 17: (5, 2), 18: (5, 3), 19: (5, 4),
20: (0, 0), 21: (0, 1), 22: (0, 2), 23: (0, 3), 24: (0, 4)}>>> from sage.all import *>>> g.relabel()>>> b,D = g.is_cartesian_product(g, relabeling=True)
>>> b
True
>>> D # random isomorphism{0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
15: (5, 0), 16: (5, 1), 17: (5, 2), 18: (5, 3), 19: (5, 4),
20: (0, 0), 21: (0, 1), 22: (0, 2), 23: (0, 3), 24: (0, 4)}

And of course, we find the factors back when we build a graph from a product:
sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
sage: g1, g2 = is_cartesian_product(g, certificate = True)
sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
True
sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
True>>> from sage.all import *>>> g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(Integer(3)))>>> g1, g2 = is_cartesian_product(g, certificate = True)>>> any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
True>>> any( x.is_isomorphic(graphs.CycleGraph(Integer(3))) for x in [g1,g2])
Truesage.graphs.graph_decompositions.graph_products.rooted_product(G, H, root=None)
Return the rooted product of 𝐺 and 𝐻.
The rooted product of two graphs 𝐺 and 𝐻 is the graph 𝑅 defined as follows: take a copy of 𝐺 and |𝑉 (𝐺)| copiesof 𝐻, and for every vertex 𝑔𝑖 of 𝐺, identify 𝑔𝑖 with the root of the 𝑖-th copy of 𝐻. Mode formally, let 𝑉 (𝐺) ={𝑔1 , 𝑔2 , . . . , 𝑔𝑛 }, 𝑉 (𝐻) = {ℎ1 , ℎ2 , . . . , ℎ𝑚 }, and let ℎ1 be the root vertex of 𝐻. The vertex set 𝑉 (𝑅) is equal tothe cartesian product of the sets of vertices 𝑉 (𝐺) and 𝑉 (𝐻), that is 𝑉 (𝑅) = {(𝑔𝑖 , ℎ𝑗 ) : 𝑔𝑖 ∈ 𝑉 (𝐺), ℎ𝑗 ∈ 𝑉 (𝐻)}.
The edge set 𝐸(𝑅) is the union of the edges of a copy of 𝐺, that is {((𝑔𝑖 , ℎ1 ), (𝑔𝑗 , ℎ1 )) : (𝑔𝑖 , 𝑔𝑗 ) ∈ 𝐸(𝐺)}, andthe edges of the copies of 𝐻 for every 𝑔𝑖 ∈ 𝑉 (𝐺), that is {((𝑔𝑖 , ℎ𝑗 ), (𝑔𝑖 , ℎ𝑘 )) : (ℎ𝑗 , ℎ𝑘 ) ∈ 𝑉 (𝐻)}.
1744

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

See Wikipedia article Rooted_product_of_graphs for more details.
See also:• cartesian_product() – return the cartesian product of two graphs• graph_products – a module on graph products
EXAMPLES:
The rooted product of two trees is a tree:
sage: T1 = graphs.RandomTree(7)sage: T2 = graphs.RandomTree(8)sage: T = T1.rooted_product(T2)sage: T.is_tree()True>>> from sage.all import *>>> T1 = graphs.RandomTree(Integer(7))>>> T2 = graphs.RandomTree(Integer(8))>>> T = T1.rooted_product(T2)>>> T.is_tree()True

The rooted product of 𝐺 and 𝐻 depends on the selected root in 𝐻:
sage: G = graphs.CycleGraph(4)sage: H = graphs.PathGraph(3)sage: R1 = G.rooted_product(H, root=0)
sage: R2 = G.rooted_product(H, root=1)
sage: R1.is_isomorphic(R2)
False
sage: sorted(R1.degree())[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
sage: sorted(R2.degree())[1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(4))>>> H = graphs.PathGraph(Integer(3))>>> R1 = G.rooted_product(H, root=Integer(0))>>> R2 = G.rooted_product(H, root=Integer(1))>>> R1.is_isomorphic(R2)
False>>> sorted(R1.degree())[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]>>> sorted(R2.degree())[1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]

The domination number of the rooted product of any graph 𝐺 and a path of order 2 is the order of 𝐺:
sage: G = graphs.RandomGNP(20, .3)
sage: P = graphs.PathGraph(2)sage: R = G.rooted_product(P)sage: len(R.dominating_set()) == G.order()˓→needs sage.numerical.mip
True

#␣

(continues on next page)

5.25. Products of graphs

1745Graph Theory, Release 10.4

(continued from previous page)

sage: G = digraphs.RandomDirectedGNP(20, .3)
sage: P = digraphs.Path(2)sage: R = G.rooted_product(P)sage: len(R.dominating_set()) == G.order()˓→needs sage.numerical.mip
True

#␣

>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(20), RealNumber( .3 ))>>> P = graphs.PathGraph(Integer(2))>>> R = G.rooted_product(P)>>> len(R.dominating_set()) == G.order()˓→needs sage.numerical.mip
True>>> G = digraphs.RandomDirectedGNP(Integer(20), RealNumber( .3 ))>>> P = digraphs.Path(Integer(2))>>> R = G.rooted_product(P)>>> len(R.dominating_set()) == G.order()˓→needs sage.numerical.mip
True

#␣

#␣

The rooted product of two graphs is a subgraph of the cartesian product of the same two graphs:
sage: G = graphs.RandomGNP(6, .4)
sage: H = graphs.RandomGNP(7, .4)
sage: R = G.rooted_product(H)sage: C = G.cartesian_product(H)sage: R.is_subgraph(C, induced=False)
True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(6), RealNumber( .4 ))>>> H = graphs.RandomGNP(Integer(7), RealNumber( .4 ))>>> R = G.rooted_product(H)>>> C = G.cartesian_product(H)>>> R.is_subgraph(C, induced=False)
True

Corner cases:
sage: Graph().rooted_product(Graph())
Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0 vertices
sage: Graph(1).rooted_product(Graph())
Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0 vertices
sage: Graph().rooted_product(Graph(1))
Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0 vertices
sage: Graph(1).rooted_product(Graph(1))
Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex>>> from sage.all import *>>> Graph().rooted_product(Graph())
Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0 vertices>>> Graph(Integer(1)).rooted_product(Graph())
Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0 vertices>>> Graph().rooted_product(Graph(Integer(1)))(continues on next page)

1746

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0 vertices>>> Graph(Integer(1)).rooted_product(Graph(Integer(1)))
Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex

5.26 Modular Decomposition
This module implements the function for computing the modular decomposition of undirected graphs.
class sage.graphs.graph_decompositions.modular_decomposition.Node(node_type)
Bases: object
Node class stores information about the node type, node split and index of the node in the parent tree.
Node type can be PRIME, SERIES, PARALLEL, NORMAL or FOREST. Node split can be NO_SPLIT,
LEFT_SPLIT, RIGHT_SPLIT or BOTH_SPLIT. A node is split in the refinement phase and the split used
is propagated to the ancestors.
• node_type – is of type NodeType and specifies the type of node
• node_split – is of type NodeSplit and specifies the type of splits which have occurred in the node and its
descendants• index_in_root – specifies the index of the node in the forest obtained after promotion phase• comp_num – specifies the number given to nodes in a (co)component before refinement• is_separated – specifies whether a split has occurred with the node as the root
has_left_split()
Check whether self has LEFT_SPLIT.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: node = Node(NodeType.PRIME)
sage: node.set_node_split(NodeSplit.LEFT_SPLIT)
sage: node.has_left_split()
True
sage: node = Node(NodeType.PRIME)
sage: node.set_node_split(NodeSplit.BOTH_SPLIT)
sage: node.has_left_split()
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> node = Node(NodeType.PRIME)>>> node.set_node_split(NodeSplit.LEFT_SPLIT)>>> node.has_left_split()
True>>> node = Node(NodeType.PRIME)>>> node.set_node_split(NodeSplit.BOTH_SPLIT)>>> node.has_left_split()
True

has_right_split()
Check whether self has RIGHT_SPLIT.

5.26. Modular Decomposition

1747

Graph Theory, Release 10.4

EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: node = Node(NodeType.PRIME)
sage: node.set_node_split(NodeSplit.RIGHT_SPLIT)
sage: node.has_right_split()
True
sage: node = Node(NodeType.PRIME)
sage: node.set_node_split(NodeSplit.BOTH_SPLIT)
sage: node.has_right_split()
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> node = Node(NodeType.PRIME)>>> node.set_node_split(NodeSplit.RIGHT_SPLIT)>>> node.has_right_split()
True>>> node = Node(NodeType.PRIME)>>> node.set_node_split(NodeSplit.BOTH_SPLIT)>>> node.has_right_split()
True

set_node_split(node_split)
Add node_split to the node split of self.
LEFT_SPLIT and RIGHT_SPLIT can exist together in self as BOTH_SPLIT.
INPUT:• node_split – node_split to be added to self
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: node = Node(NodeType.PRIME)
sage: node.set_node_split(NodeSplit.LEFT_SPLIT)
sage: node.node_split == NodeSplit.LEFT_SPLIT
True
sage: node.set_node_split(NodeSplit.RIGHT_SPLIT)
sage: node.node_split == NodeSplit.BOTH_SPLIT
True
sage: node = Node(NodeType.PRIME)
sage: node.set_node_split(NodeSplit.BOTH_SPLIT)
sage: node.node_split == NodeSplit.BOTH_SPLIT
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> node = Node(NodeType.PRIME)>>> node.set_node_split(NodeSplit.LEFT_SPLIT)>>> node.node_split == NodeSplit.LEFT_SPLIT
True>>> node.set_node_split(NodeSplit.RIGHT_SPLIT)>>> node.node_split == NodeSplit.BOTH_SPLIT
True>>> node = Node(NodeType.PRIME)>>> node.set_node_split(NodeSplit.BOTH_SPLIT)(continues on next page)

1748

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> node.node_split == NodeSplit.BOTH_SPLIT
Trueclass sage.graphs.graph_decompositions.modular_decomposition.NodeSplit(value)
Bases: Enum
Enumeration class used to specify the split that has occurred at the node or at any of its descendants.
NodeSplit is defined for every node in modular decomposition tree and is required during the refinement andpromotion phase of modular decomposition tree computation. Various node splits defined are• LEFT_SPLIT – indicates a left split has occurred• RIGHT_SPLIT – indicates a right split has occurred• BOTH_SPLIT – indicates both left and right split have occurred• NO_SPLIT – indicates no split has occurred
BOTH_SPLIT = 3
LEFT_SPLIT = 1
NO_SPLIT = 0
RIGHT_SPLIT = 2
class sage.graphs.graph_decompositions.modular_decomposition.NodeType(value)
Bases: IntEnum
NodeType is an enumeration class used to define the various types of nodes in modular decomposition tree.
The various node types defined are• PARALLEL – indicates the node is a parallel module• SERIES – indicates the node is a series module• PRIME – indicates the node is a prime module• FOREST – indicates a forest containing trees• NORMAL – indicates the node is normal containing a vertex
FOREST = -1
NORMAL = 3
PARALLEL = 2
PRIME = 0
SERIES = 1
class sage.graphs.graph_decompositions.modular_decomposition.VertexPosition(value)
Bases: Enum
Enumeration class used to define position of a vertex w.r.t source in modular decomposition.
For computing modular decomposition of connected graphs a source vertex is chosen. The position of vertex is
w.r.t this source vertex. The various positions defined are• LEFT_OF_SOURCE – indicates vertex is to left of source and is a neighbour of source vertex

5.26. Modular Decomposition

1749

Graph Theory, Release 10.4

• RIGHT_OF_SOURCE – indicates vertex is to right of source and is connected to but not a neighbour ofsource vertex• SOURCE – indicates vertex is source vertex
LEFT_OF_SOURCE = -1
RIGHT_OF_SOURCE = 1
SOURCE = 0
sage.graphs.graph_decompositions.modular_decomposition.children_node_type(module,
node_type)
Check whether the node type of the children of module is node_type.
INPUT:• module – module which is tested• node_type – input node_type
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: g = graphs.OctahedralGraph()
sage: tree_root = modular_decomposition(g)sage: print_md_tree(modular_decomposition(g))
SERIESPARALLEL
0
5
PARALLEL
1
4
PARALLEL
2
3
sage: children_node_type(tree_root, NodeType.SERIES)
False
sage: children_node_type(tree_root, NodeType.PARALLEL)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> g = graphs.OctahedralGraph()>>> tree_root = modular_decomposition(g)>>> print_md_tree(modular_decomposition(g))
SERIESPARALLEL
0
5
PARALLEL
1
4
PARALLEL23>>> children_node_type(tree_root, NodeType.SERIES)(continues on next page)

1750

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

False>>> children_node_type(tree_root, NodeType.PARALLEL)
Truesage.graphs.graph_decompositions.modular_decomposition.create_normal_node(vertex)
Return a normal node with no children
INPUT:• vertex – vertex number
OUTPUT:
A node object representing the vertex with node_type set as NodeType.NORMAL
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→normal_node
sage: node = create_normal_node(2)sage: node
NORMAL [2]>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→normal_node>>> node = create_normal_node(Integer(2))>>> node
NORMAL [2]sage.graphs.graph_decompositions.modular_decomposition.create_parallel_node()
Return a parallel node with no children
OUTPUT:
A node object with node_type set as NodeType.PARALLEL
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→parallel_node
sage: node = create_parallel_node()sage: node
PARALLEL []>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→parallel_node>>> node = create_parallel_node()>>> node
PARALLEL []sage.graphs.graph_decompositions.modular_decomposition.create_prime_node()
Return a prime node with no children
OUTPUT:
A node object with node_type set as NodeType.PRIME
5.26. Modular Decomposition

1751

Graph Theory, Release 10.4

EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→prime_node
sage: node = create_prime_node()sage: node
PRIME []>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→prime_node>>> node = create_prime_node()>>> node
PRIME []

sage.graphs.graph_decompositions.modular_decomposition.create_series_node()
Return a series node with no children
OUTPUT:
A node object with node_type set as NodeType.SERIES
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→series_node
sage: node = create_series_node()sage: node
SERIES []>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import create_
˓→series_node>>> node = create_series_node()>>> node
SERIES []sage.graphs.graph_decompositions.modular_decomposition.either_connected_or_not_connected(v,
ve
tic
ule
gra
Check whether v is connected or disconnected to all vertices in the module.
INPUT:• v – vertex tested• vertices_in_module – list containing vertices in the module• graph – graph to which the vertices belong
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: g = graphs.OctahedralGraph()
sage: print_md_tree(modular_decomposition(g))
SERIESPARALLEL(continues on next page)

1752

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

0
5
PARALLEL
1
4
PARALLEL
2
3
sage: either_connected_or_not_connected(2, [1, 4], g)True
sage: either_connected_or_not_connected(2, [3, 4], g)
False>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> g = graphs.OctahedralGraph()>>> print_md_tree(modular_decomposition(g))
SERIESPARALLEL
0
5
PARALLEL
1
4
PARALLEL23>>> either_connected_or_not_connected(Integer(2), [Integer(1), Integer(4)], g)
True>>> either_connected_or_not_connected(Integer(2), [Integer(3), Integer(4)], g)
False

sage.graphs.graph_decompositions.modular_decomposition.equivalent_trees(root1,
root2)
Check that two modular decomposition trees are the same.
Verify that the structure of the trees is the same. Two leaves are equivalent if they represent the same vertex, twointernal nodes are equivalent if they have the same nodes type and the same number of children and there is amatching between the children such that each pair of children is a pair of equivalent subtrees.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: t1 = nested_tuple_to_tree((NodeType.SERIES, 1, 2,....:(NodeType.PARALLEL, 3, 4)))sage: t2 = nested_tuple_to_tree((NodeType.SERIES,....:(NodeType.PARALLEL, 4, 3), 2, 1))
sage: equivalent_trees(t1, t2)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> t1 = nested_tuple_to_tree((NodeType.SERIES, Integer(1), Integer(2),...
(NodeType.PARALLEL, Integer(3), Integer(4))))>>> t2 = nested_tuple_to_tree((NodeType.SERIES,...
(NodeType.PARALLEL, Integer(4), Integer(3)), Integer(2),␣
(continues on next page)

5.26. Modular Decomposition

1753

Graph Theory, Release 10.4

(continued from previous page)

Integer(1)))>>> equivalent_trees(t1, t2)
True˓→

sage.graphs.graph_decompositions.modular_decomposition.form_module(index,
other_index,
tree_root,
graph)
Forms a module out of the modules in the module pair.
Let 𝑀1 and 𝑀2 be the input modules. Let 𝑉 be the set of vertices in these modules. Suppose 𝑥 is a neighbor ofsubset of the vertices in 𝑉 but not all the vertices and 𝑥 does not belong to 𝑉 . Then the set of modules also include
the module which contains 𝑥. This process is repeated until a module is formed and the formed module if subsetof 𝑉 is returned.
INPUT:• index – first module in the module pair• other_index – second module in the module pair• tree_root – modular decomposition tree which contains the modules in the module pair
• graph – graph whose modular decomposition tree is created
OUTPUT:[module_formed, vertices] where module_formed is True if module is formed else False andvertices is a list of vertices included in the formed module
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: g = graphs.HexahedralGraph()
sage: tree_root = modular_decomposition(g)sage: form_module(0, 2, tree_root, g)[False, {0, 1, 2, 3, 4, 5, 6, 7}]>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> g = graphs.HexahedralGraph()>>> tree_root = modular_decomposition(g)>>> form_module(Integer(0), Integer(2), tree_root, g)[False, {0, 1, 2, 3, 4, 5, 6, 7}]

sage.graphs.graph_decompositions.modular_decomposition.gamma_classes(graph)
Partition the edges of the graph into Gamma classes.
Two distinct edges are Gamma related if they share a vertex but are not part of a triangle. A Gamma class of edges
is a collection of edges such that any edge in the class can be reached from any other by a chain of Gamma relatededges (that are also in the class).
The two important properties of the Gamma class• The vertex set corresponding to a Gamma class is a module• If the graph is not fragile (neither it or its complement is disconnected) then there is exactly one class that
visits all the vertices of the graph, and this class consists of just the edges that connect the maximal strong
modules of that graph.

1754

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

EXAMPLES:
The gamma_classes of the octahedral graph are the three 4-cycles corresponding to the slices through the centerof the octahedron:sage: from sage.graphs.graph_decompositions.modular_decomposition import gamma_
˓→classes
sage: g = graphs.OctahedralGraph()
sage: sorted(gamma_classes(g), key=str)[frozenset({0, 1, 4, 5}), frozenset({0, 2, 3, 5}), frozenset({1, 2, 3, 4})]>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import gamma_
˓→classes>>> g = graphs.OctahedralGraph()>>> sorted(gamma_classes(g), key=str)[frozenset({0, 1, 4, 5}), frozenset({0, 2, 3, 5}), frozenset({1, 2, 3, 4})]sage.graphs.graph_decompositions.modular_decomposition.get_module_type(graph)
Return the module type of the root of the modular decomposition tree of graph.
INPUT:• graph – input sage graph
OUTPUT:
PRIME if graph is PRIME, PARALLEL if graph is PARALLEL and SERIES if graph is of type SERIES
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import get_˓→module_type
sage: g = graphs.HexahedralGraph()
sage: get_module_type(g)PRIME>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import get_module_
˓→type>>> g = graphs.HexahedralGraph()>>> get_module_type(g)PRIMEsage.graphs.graph_decompositions.modular_decomposition.get_vertices(component_root)
Compute the list of vertices in the (co)component
INPUT:• component_root – root of the (co)component whose vertices need to be returned as a list
OUTPUT:
list of vertices in the (co)component
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: forest = Node(NodeType.FOREST)(continues on next page)

5.26. Modular Decomposition

1755

Graph Theory, Release 10.4

(continued from previous page)

sage: forest.children = [create_normal_node(2),....:create_normal_node(3), create_normal_node(1)]sage: series_node = Node(NodeType.SERIES)
sage: series_node.children = [create_normal_node(4),....:create_normal_node(5)]sage: parallel_node = Node(NodeType.PARALLEL)
sage: parallel_node.children = [create_normal_node(6),....:create_normal_node(7)]sage: forest.children.insert(1, series_node)sage: forest.children.insert(3, parallel_node)sage: get_vertices(forest)[2, 4, 5, 3, 6, 7, 1]>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> forest = Node(NodeType.FOREST)>>> forest.children = [create_normal_node(Integer(2)),...
create_normal_node(Integer(3)), create_normal_
˓→node(Integer(1))]>>> series_node = Node(NodeType.SERIES)>>> series_node.children = [create_normal_node(Integer(4)),...
create_normal_node(Integer(5))]>>> parallel_node = Node(NodeType.PARALLEL)>>> parallel_node.children = [create_normal_node(Integer(6)),...
create_normal_node(Integer(7))]>>> forest.children.insert(Integer(1), series_node)>>> forest.children.insert(Integer(3), parallel_node)>>> get_vertices(forest)[2, 4, 5, 3, 6, 7, 1]

sage.graphs.graph_decompositions.modular_decomposition.habib_maurer_algorithm(graph,g_classes=None)
Compute the modular decomposition by the algorithm of Habib and Maurer
Compute the modular decomposition of the given graph by the algorithm of Habib and Maurer [HM1979] . If thegraph is disconnected or its complement is disconnected return a tree with a PARALLEL or SERIES node at theroot and children being the modular decomposition of the subgraphs induced by the components. Otherwise, theroot is PRIME and the modules are identified by having identical neighborhoods in the gamma class that spans thevertices of the subgraph (exactly one is guaranteed to exist). The gamma classes only need to be computed once,as the algorithm computes the the classes for the current root and each of the submodules. See also [BM1983] foran equivalent algorithm described in greater detail.
INPUT:• graph – the graph for which modular decomposition tree needs to be computed• g_classes – dictionary (default: None); a dictionary whose values are the gamma classes of the graph,and whose keys are a frozenset of the vertices corresponding to the class. Used internally.
OUTPUT:
The modular decomposition tree of the graph.
EXAMPLES:
The Icosahedral graph is Prime:

1756

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: print_md_tree(habib_maurer_algorithm(graphs.IcosahedralGraph()))
PRIME
3
4
7
9
11
1
5
8
0
2
6
10
>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> print_md_tree(habib_maurer_algorithm(graphs.IcosahedralGraph()))
PRIME
3
4
7
9
11
1
5
8
0
2
6
10

The Octahedral graph is not Prime:
sage: print_md_tree(habib_maurer_algorithm(graphs.OctahedralGraph()))
SERIESPARALLEL
0
5
PARALLEL
1
4
PARALLEL
2
3>>> from sage.all import *>>> print_md_tree(habib_maurer_algorithm(graphs.OctahedralGraph()))
SERIESPARALLEL
0
5
PARALLEL
1
4
PARALLEL(continues on next page)

5.26. Modular Decomposition

1757

Graph Theory, Release 10.4

(continued from previous page)2
3

Tetrahedral Graph is Series:
sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES0
1
2
3>>> from sage.all import *>>> print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES0123Modular Decomposition tree containing both parallel and series modules:
sage: d = {2:[4,3,5], 1:[4,3,5], 5:[3,2,1,4], 3:[1,2,5], 4:[1,2,5]}
sage: g = Graph(d)sage: print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5>>> from sage.all import *>>> d = {Integer(2):[Integer(4),Integer(3),Integer(5)], Integer(1):[Integer(4),˓→Integer(3),Integer(5)], Integer(5):[Integer(3),Integer(2),Integer(1),˓→Integer(4)], Integer(3):[Integer(1),Integer(2),Integer(5)],␣
˓→Integer(4):[Integer(1),Integer(2),Integer(5)]}>>> g = Graph(d)>>> print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5

Graph from Marc Tedder implementation of modular decomposition:
sage: d = {1:[5,4,3,24,6,7,8,9,2,10,11,12,13,14,16,17], 2:[1],....:3:[24,9,1], 4:[5,24,9,1], 5:[4,24,9,1], 6:[7,8,9,1],....:
7:[6,8,9,1], 8:[6,7,9,1], 9:[6,7,8,5,4,3,1], 10:[1],....:11:[12,1], 12:[11,1], 13:[14,16,17,1], 14:[13,17,1],(continues on next page)

1758

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)....:
16:[13,17,1], 17:[13,14,16,18,1], 18:[17], 24:[5,4,3,1]}
sage: g = Graph(d)sage: test_modular_decomposition(habib_maurer_algorithm(g), g)
True>>> from sage.all import *>>> d = {Integer(1):[Integer(5),Integer(4),Integer(3),Integer(24),Integer(6),˓→Integer(7),Integer(8),Integer(9),Integer(2),Integer(10),Integer(11),Integer(12),
˓→Integer(13),Integer(14),Integer(16),Integer(17)], Integer(2):[Integer(1)],...
Integer(3):[Integer(24),Integer(9),Integer(1)], Integer(4):[Integer(5),˓→Integer(24),Integer(9),Integer(1)], Integer(5):[Integer(4),Integer(24),
˓→Integer(9),Integer(1)], Integer(6):[Integer(7),Integer(8),Integer(9),˓→Integer(1)],...
Integer(7):[Integer(6),Integer(8),Integer(9),Integer(1)],␣
˓→Integer(8):[Integer(6),Integer(7),Integer(9),Integer(1)],␣
˓→Integer(9):[Integer(6),Integer(7),Integer(8),Integer(5),Integer(4),Integer(3),˓→Integer(1)], Integer(10):[Integer(1)],...
Integer(11):[Integer(12),Integer(1)], Integer(12):[Integer(11),
˓→Integer(1)], Integer(13):[Integer(14),Integer(16),Integer(17),Integer(1)],␣
˓→Integer(14):[Integer(13),Integer(17),Integer(1)],...
Integer(16):[Integer(13),Integer(17),Integer(1)],␣
˓→Integer(17):[Integer(13),Integer(14),Integer(16),Integer(18),Integer(1)],␣
˓→Integer(18):[Integer(17)], Integer(24):[Integer(5),Integer(4),Integer(3),˓→Integer(1)]}>>> g = Graph(d)>>> test_modular_decomposition(habib_maurer_algorithm(g), g)
True

Graph from the Wikipedia article Modular_decomposition:
sage: d2 = {1:[2,3,4], 2:[1,4,5,6,7], 3:[1,4,5,6,7], 4:[1,2,3,5,6,7],....:
5:[2,3,4,6,7], 6:[2,3,4,5,8,9,10,11],....:
7:[2,3,4,5,8,9,10,11], 8:[6,7,9,10,11], 9:[6,7,8,10,11],....:
10:[6,7,8,9], 11:[6,7,8,9]}
sage: g = Graph(d2)sage: test_modular_decomposition(habib_maurer_algorithm(g), g)
True>>> from sage.all import *>>> d2 = {Integer(1):[Integer(2),Integer(3),Integer(4)], Integer(2):[Integer(1),˓→Integer(4),Integer(5),Integer(6),Integer(7)], Integer(3):[Integer(1),Integer(4),˓→Integer(5),Integer(6),Integer(7)], Integer(4):[Integer(1),Integer(2),Integer(3),˓→Integer(5),Integer(6),Integer(7)],...
Integer(5):[Integer(2),Integer(3),Integer(4),Integer(6),Integer(7)],␣
˓→Integer(6):[Integer(2),Integer(3),Integer(4),Integer(5),Integer(8),Integer(9),˓→Integer(10),Integer(11)],...
Integer(7):[Integer(2),Integer(3),Integer(4),Integer(5),Integer(8),˓→Integer(9),Integer(10),Integer(11)], Integer(8):[Integer(6),Integer(7),˓→Integer(9),Integer(10),Integer(11)], Integer(9):[Integer(6),Integer(7),˓→Integer(8),Integer(10),Integer(11)],...
Integer(10):[Integer(6),Integer(7),Integer(8),Integer(9)],␣
˓→Integer(11):[Integer(6),Integer(7),Integer(8),Integer(9)]}>>> g = Graph(d2)>>> test_modular_decomposition(habib_maurer_algorithm(g), g)
True

Tetrahedral Graph is Series:
5.26. Modular Decomposition1759

Graph Theory, Release 10.4

sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES0
1
2
3>>> from sage.all import *>>> print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES0123Modular Decomposition tree containing both parallel and series modules:
sage: d = {2:[4,3,5], 1:[4,3,5], 5:[3,2,1,4], 3:[1,2,5], 4:[1,2,5]}
sage: g = Graph(d)sage: print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5>>> from sage.all import *>>> d = {Integer(2):[Integer(4),Integer(3),Integer(5)], Integer(1):[Integer(4),˓→Integer(3),Integer(5)], Integer(5):[Integer(3),Integer(2),Integer(1),˓→Integer(4)], Integer(3):[Integer(1),Integer(2),Integer(5)],␣
˓→Integer(4):[Integer(1),Integer(2),Integer(5)]}>>> g = Graph(d)>>> print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5

sage.graphs.graph_decompositions.modular_decomposition.md_tree_to_graph(root)
Create a graph having the given MD tree.
For the prime nodes we use that every path of length 4 or more is prime.
TODO: accept a function that generates prime graphs as a parameter and use that in the prime nodes.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: tup1 = (NodeType.PRIME, 1, (NodeType.SERIES, 2, 3),....:(NodeType.PARALLEL, 4, 5), 6)(continues on next page)

1760

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: tree1 = nested_tuple_to_tree(tup1)
sage: g1 = md_tree_to_graph(tree1)
sage: g2 = Graph({1: [2, 3], 2: [1, 3, 4, 5], 3: [1, 2, 4, 5],....:
4: [2, 3, 6], 5: [2, 3, 6], 6: [4, 5]})sage: g1.is_isomorphic(g2)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> tup1 = (NodeType.PRIME, Integer(1), (NodeType.SERIES, Integer(2), Integer(3)),...
(NodeType.PARALLEL, Integer(4), Integer(5)), Integer(6))>>> tree1 = nested_tuple_to_tree(tup1)>>> g1 = md_tree_to_graph(tree1)>>> g2 = Graph({Integer(1): [Integer(2), Integer(3)], Integer(2): [Integer(1),␣
˓→Integer(3), Integer(4), Integer(5)], Integer(3): [Integer(1), Integer(2),␣
˓→Integer(4), Integer(5)],...
Integer(4): [Integer(2), Integer(3), Integer(6)], Integer(5):␣
˓→[Integer(2), Integer(3), Integer(6)], Integer(6): [Integer(4), Integer(5)]})>>> g1.is_isomorphic(g2)True

sage.graphs.graph_decompositions.modular_decomposition.modular_decomposition(graph,g_classes=None)
Compute the modular decomposition by the algorithm of Habib and Maurer
Compute the modular decomposition of the given graph by the algorithm of Habib and Maurer [HM1979] . If thegraph is disconnected or its complement is disconnected return a tree with a PARALLEL or SERIES node at theroot and children being the modular decomposition of the subgraphs induced by the components. Otherwise, theroot is PRIME and the modules are identified by having identical neighborhoods in the gamma class that spans thevertices of the subgraph (exactly one is guaranteed to exist). The gamma classes only need to be computed once,as the algorithm computes the the classes for the current root and each of the submodules. See also [BM1983] foran equivalent algorithm described in greater detail.
INPUT:• graph – the graph for which modular decomposition tree needs to be computed• g_classes – dictionary (default: None); a dictionary whose values are the gamma classes of the graph,and whose keys are a frozenset of the vertices corresponding to the class. Used internally.
OUTPUT:
The modular decomposition tree of the graph.
EXAMPLES:
The Icosahedral graph is Prime:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: print_md_tree(habib_maurer_algorithm(graphs.IcosahedralGraph()))
PRIME
3
4
7
9
11
1
5
(continues on next page)

5.26. Modular Decomposition1761

Graph Theory, Release 10.4

(continued from previous page)

8
0
2
6
10
>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> print_md_tree(habib_maurer_algorithm(graphs.IcosahedralGraph()))
PRIME
3
4
7
9
11
1
5
8
0
2
6
10

The Octahedral graph is not Prime:
sage: print_md_tree(habib_maurer_algorithm(graphs.OctahedralGraph()))
SERIESPARALLEL
0
5
PARALLEL
1
4
PARALLEL
2
3>>> from sage.all import *>>> print_md_tree(habib_maurer_algorithm(graphs.OctahedralGraph()))
SERIESPARALLEL
0
5
PARALLEL
1
4
PARALLEL
2
3

Tetrahedral Graph is Series:
sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES
0
1(continues on next page)

1762

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)2
3>>> from sage.all import *>>> print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES0123Modular Decomposition tree containing both parallel and series modules:
sage: d = {2:[4,3,5], 1:[4,3,5], 5:[3,2,1,4], 3:[1,2,5], 4:[1,2,5]}
sage: g = Graph(d)sage: print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5>>> from sage.all import *>>> d = {Integer(2):[Integer(4),Integer(3),Integer(5)], Integer(1):[Integer(4),˓→Integer(3),Integer(5)], Integer(5):[Integer(3),Integer(2),Integer(1),˓→Integer(4)], Integer(3):[Integer(1),Integer(2),Integer(5)],␣
˓→Integer(4):[Integer(1),Integer(2),Integer(5)]}>>> g = Graph(d)>>> print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5

Graph from Marc Tedder implementation of modular decomposition:
sage: d = {1:[5,4,3,24,6,7,8,9,2,10,11,12,13,14,16,17], 2:[1],....:3:[24,9,1], 4:[5,24,9,1], 5:[4,24,9,1], 6:[7,8,9,1],....:
7:[6,8,9,1], 8:[6,7,9,1], 9:[6,7,8,5,4,3,1], 10:[1],....:11:[12,1], 12:[11,1], 13:[14,16,17,1], 14:[13,17,1],....:
16:[13,17,1], 17:[13,14,16,18,1], 18:[17], 24:[5,4,3,1]}
sage: g = Graph(d)sage: test_modular_decomposition(habib_maurer_algorithm(g), g)
True>>> from sage.all import *>>> d = {Integer(1):[Integer(5),Integer(4),Integer(3),Integer(24),Integer(6),˓→Integer(7),Integer(8),Integer(9),Integer(2),Integer(10),Integer(11),Integer(12),(continues on next page)

5.26. Modular Decomposition

1763

Graph Theory, Release 10.4

(continued from previous page)

Integer(13),Integer(14),Integer(16),Integer(17)], Integer(2):[Integer(1)],...
Integer(3):[Integer(24),Integer(9),Integer(1)], Integer(4):[Integer(5),˓→Integer(24),Integer(9),Integer(1)], Integer(5):[Integer(4),Integer(24),
˓→Integer(9),Integer(1)], Integer(6):[Integer(7),Integer(8),Integer(9),˓→Integer(1)],...
Integer(7):[Integer(6),Integer(8),Integer(9),Integer(1)],␣
˓→Integer(8):[Integer(6),Integer(7),Integer(9),Integer(1)],␣
˓→Integer(9):[Integer(6),Integer(7),Integer(8),Integer(5),Integer(4),Integer(3),˓→Integer(1)], Integer(10):[Integer(1)],...
Integer(11):[Integer(12),Integer(1)], Integer(12):[Integer(11),
˓→Integer(1)], Integer(13):[Integer(14),Integer(16),Integer(17),Integer(1)],␣
˓→Integer(14):[Integer(13),Integer(17),Integer(1)],...
Integer(16):[Integer(13),Integer(17),Integer(1)],␣
˓→Integer(17):[Integer(13),Integer(14),Integer(16),Integer(18),Integer(1)],␣
˓→Integer(18):[Integer(17)], Integer(24):[Integer(5),Integer(4),Integer(3),˓→Integer(1)]}>>> g = Graph(d)>>> test_modular_decomposition(habib_maurer_algorithm(g), g)
True˓→Graph from the Wikipedia article Modular_decomposition:
sage: d2 = {1:[2,3,4], 2:[1,4,5,6,7], 3:[1,4,5,6,7], 4:[1,2,3,5,6,7],....:
5:[2,3,4,6,7], 6:[2,3,4,5,8,9,10,11],....:
7:[2,3,4,5,8,9,10,11], 8:[6,7,9,10,11], 9:[6,7,8,10,11],....:
10:[6,7,8,9], 11:[6,7,8,9]}
sage: g = Graph(d2)sage: test_modular_decomposition(habib_maurer_algorithm(g), g)
True>>> from sage.all import *>>> d2 = {Integer(1):[Integer(2),Integer(3),Integer(4)], Integer(2):[Integer(1),˓→Integer(4),Integer(5),Integer(6),Integer(7)], Integer(3):[Integer(1),Integer(4),˓→Integer(5),Integer(6),Integer(7)], Integer(4):[Integer(1),Integer(2),Integer(3),˓→Integer(5),Integer(6),Integer(7)],...
Integer(5):[Integer(2),Integer(3),Integer(4),Integer(6),Integer(7)],␣
˓→Integer(6):[Integer(2),Integer(3),Integer(4),Integer(5),Integer(8),Integer(9),˓→Integer(10),Integer(11)],...
Integer(7):[Integer(2),Integer(3),Integer(4),Integer(5),Integer(8),˓→Integer(9),Integer(10),Integer(11)], Integer(8):[Integer(6),Integer(7),˓→Integer(9),Integer(10),Integer(11)], Integer(9):[Integer(6),Integer(7),˓→Integer(8),Integer(10),Integer(11)],...
Integer(10):[Integer(6),Integer(7),Integer(8),Integer(9)],␣
˓→Integer(11):[Integer(6),Integer(7),Integer(8),Integer(9)]}>>> g = Graph(d2)>>> test_modular_decomposition(habib_maurer_algorithm(g), g)
True

Tetrahedral Graph is Series:
sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES
0
1
2
3

1764

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph()))
SERIES0123Modular Decomposition tree containing both parallel and series modules:
sage: d = {2:[4,3,5], 1:[4,3,5], 5:[3,2,1,4], 3:[1,2,5], 4:[1,2,5]}
sage: g = Graph(d)sage: print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5>>> from sage.all import *>>> d = {Integer(2):[Integer(4),Integer(3),Integer(5)], Integer(1):[Integer(4),˓→Integer(3),Integer(5)], Integer(5):[Integer(3),Integer(2),Integer(1),˓→Integer(4)], Integer(3):[Integer(1),Integer(2),Integer(5)],␣
˓→Integer(4):[Integer(1),Integer(2),Integer(5)]}>>> g = Graph(d)>>> print_md_tree(habib_maurer_algorithm(g))
SERIESPARALLEL
1
2
PARALLEL
3
4
5

sage.graphs.graph_decompositions.modular_decomposition.nested_tuple_to_tree(nest)
Turn a tuple representing the modular decomposition into a tree.
INPUT:• nest – a nested tuple of the form returned by tree_to_nested_tuple()
OUTPUT:The root node of a modular decomposition tree.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: tree = (NodeType.SERIES, 1, 2, (NodeType.PARALLEL, 3, 4))
sage: print_md_tree(nested_tuple_to_tree(tree))
SERIES
1
2
PARALLEL(continues on next page)

5.26. Modular Decomposition

1765

Graph Theory, Release 10.4

(continued from previous page)3
4>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> tree = (NodeType.SERIES, Integer(1), Integer(2), (NodeType.PARALLEL,␣
˓→Integer(3), Integer(4)))>>> print_md_tree(nested_tuple_to_tree(tree))
SERIES
1
2
PARALLEL
3
4

sage.graphs.graph_decompositions.modular_decomposition.permute_decomposition(*args,**kwargs)
Check that a graph and its permuted relabeling have the same modular decomposition.
We generate a trials random graphs and then generate an isomorphic graph by relabeling the original graph.
We then verify
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: permute_decomposition(30, habib_maurer_algorithm, 10, 0.5)>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> permute_decomposition(Integer(30), habib_maurer_algorithm, Integer(10),␣
˓→RealNumber( 0.5 ))sage.graphs.graph_decompositions.modular_decomposition.print_md_tree(root)
Print the modular decomposition tree
INPUT:• root – root of the modular decomposition tree
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: print_md_tree(modular_decomposition(graphs.IcosahedralGraph()))
PRIME
3
4
7
9
11
1
5
8
0
2
6
10

1766

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> print_md_tree(modular_decomposition(graphs.IcosahedralGraph()))
PRIME
3
4
7
9
11
1
5
8
0
2
6
10

sage.graphs.graph_decompositions.modular_decomposition.random_md_tree(max_depth,
max_fan_out,
leaf_probability)
Create a random MD tree.
INPUT:• max_depth – the maximum depth of the tree.
• max_fan_out – the maximum number of children a node can have (must be >=4 as a prime node musthave at least 4 vertices).
• leaf_probability – the probability that a subtree is a leaf
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: set_random_seed(0)sage: tree_to_nested_tuple(random_md_tree(2, 5, 0.5))(PRIME, [0, 1, (PRIME, [2, 3, 4, 5, 6]), 7, (PARALLEL, [8, 9, 10])])>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> set_random_seed(Integer(0))>>> tree_to_nested_tuple(random_md_tree(Integer(2), Integer(5), RealNumber( 0.5
˓→ )))(PRIME, [0, 1, (PRIME, [2, 3, 4, 5, 6]), 7, (PARALLEL, [8, 9, 10])])sage.graphs.graph_decompositions.modular_decomposition.recreate_decomposition(*args,**kwargs)
Verify that we can recreate a random MD tree.
We create a random MD tree, then create a graph having that decomposition, then find a modular decomposition
for that graph, and verify that the two modular decomposition trees are equivalent.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: recreate_decomposition(3, habib_maurer_algorithm, 4, 6, 0.5,....:
verbose=False)

5.26. Modular Decomposition

1767

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> recreate_decomposition(Integer(3), habib_maurer_algorithm, Integer(4),␣
˓→Integer(6), RealNumber( 0.5 ),...
verbose=False)

sage.graphs.graph_decompositions.modular_decomposition.relabel_tree(root, perm)
Relabel the leaves of a tree according to a dictionary
INPUT:• root – the root of the tree
• perm – a function, dictionary, list, permutation, or None representing the relabeling. See relabel() for
description of the permutation input.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: tuple_tree = (NodeType.SERIES, 1, 2, (NodeType.PARALLEL, 3, 4))
sage: tree = nested_tuple_to_tree(tuple_tree)
sage: print_md_tree(relabel_tree(tree, (4,3,2,1)))
SERIES
4
3
PARALLEL
2
1>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> tuple_tree = (NodeType.SERIES, Integer(1), Integer(2), (NodeType.PARALLEL,␣
˓→Integer(3), Integer(4)))>>> tree = nested_tuple_to_tree(tuple_tree)>>> print_md_tree(relabel_tree(tree, (Integer(4),Integer(3),Integer(2),˓→Integer(1))))SERIES
4
3
PARALLEL
2
1

sage.graphs.graph_decompositions.modular_decomposition.test_gamma_modules(*args,**kwargs)
Verify that the vertices of each gamma class of a random graph are modules of that graph.
INPUT:• trials – the number of trials to run• vertices – the size of the graph to use• prob – the probability that any given edge is in the graph. See RandomGNP() for more details.
• verbose – print information on each trial.
EXAMPLES:

1768

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: test_gamma_modules(3, 7, 0.5)>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> test_gamma_modules(Integer(3), Integer(7), RealNumber( 0.5 ))sage.graphs.graph_decompositions.modular_decomposition.test_maximal_modules(tree_root,
graph)
Test the maximal nature of modules in a modular decomposition tree.
Suppose the module 𝑀 = [𝑀1 , 𝑀2 , · · · , 𝑛] is the input modular decomposition tree. Algorithm forms pairs
like (𝑀1 , 𝑀2 ), (𝑀1 , 𝑀3 ), · · · , (𝑀1 , 𝑀𝑛 ); (𝑀2 , 𝑀3 ), (𝑀2 , 𝑀4 ), · · · , (𝑀2 , 𝑀𝑛 ); · · · and so on and tries to forma module using the pair. If the module formed has same type as 𝑀 and is of type SERIES or PARALLEL
then the formed module is not considered maximal. Otherwise it is considered maximal and 𝑀 is not a modular
decomposition tree.
INPUT:• tree_root – modular decomposition tree whose modules are tested for maximal nature• graph – graph whose modular decomposition tree is tested
OUTPUT:
True if all modules at first level in the modular decomposition tree are maximal in nature
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: g = graphs.HexahedralGraph()
sage: test_maximal_modules(modular_decomposition(g), g)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> g = graphs.HexahedralGraph()>>> test_maximal_modules(modular_decomposition(g), g)
Truesage.graphs.graph_decompositions.modular_decomposition.test_modular_decomposition(tree_root,
graph)
Test the input modular decomposition tree using recursion.
INPUT:• tree_root – root of the modular decomposition tree to be tested• graph – graph whose modular decomposition tree needs to be tested
OUTPUT:
True if input tree is a modular decomposition else False
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: g = graphs.HexahedralGraph()
sage: test_modular_decomposition(modular_decomposition(g), g)
True

5.26. Modular Decomposition

1769

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> g = graphs.HexahedralGraph()>>> test_modular_decomposition(modular_decomposition(g), g)
Truesage.graphs.graph_decompositions.modular_decomposition.test_module(module, graph)
Test whether input module is actually a module
INPUT:• module – module which needs to be tested• graph – input sage graph which contains the module
OUTPUT:
True if input module is a module by definition else False
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: g = graphs.HexahedralGraph()
sage: tree_root = modular_decomposition(g)sage: test_module(tree_root, g)True
sage: test_module(tree_root.children[0], g)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> g = graphs.HexahedralGraph()>>> tree_root = modular_decomposition(g)>>> test_module(tree_root, g)
True>>> test_module(tree_root.children[Integer(0)], g)Truesage.graphs.graph_decompositions.modular_decomposition.tree_to_nested_tuple(root)
Convert a modular decomposition tree to a nested tuple.
INPUT:• root – the root of the modular decomposition tree
OUTPUT:
A tuple whose first element is the type of the root of the tree and whose subsequent nodes are either vertex labelsin the case of leaves or tuples representing the child subtrees.
EXAMPLES:
sage: from sage.graphs.graph_decompositions.modular_decomposition import *sage: g = graphs.OctahedralGraph()
sage: tree_to_nested_tuple(modular_decomposition(g))(SERIES, [(PARALLEL, [0, 5]), (PARALLEL, [1, 4]), (PARALLEL, [2, 3])])>>> from sage.all import *>>> from sage.graphs.graph_decompositions.modular_decomposition import *>>> g = graphs.OctahedralGraph()(continues on next page)

1770

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> tree_to_nested_tuple(modular_decomposition(g))(SERIES, [(PARALLEL, [0, 5]), (PARALLEL, [1, 4]), (PARALLEL, [2, 3])])5.27 Decomposition by clique minimal separators
This module implements methods related to the decomposition of a graph by clique minimal separators. See [TY1984]
and [BPS2010] for more details on the algorithms.

5.27.1 Methods

sage.graphs.graph_decompositions.clique_separators.atoms_and_clique_separators(G,tree=False,rooted_tree=False
separators=False)
Return the atoms of the decomposition of 𝐺 by clique minimal separators.
Let 𝐺 = (𝑉, 𝐸) be a graph. A set 𝑆 ⊂ 𝑉 is a clique separator if 𝐺[𝑆] is a clique and the graph 𝐺 ∖ 𝑆 has at least
2 connected components. Let 𝐶 ⊂ 𝑉 be the vertices of a connected component of 𝐺 ∖ 𝑆. The graph 𝐺[𝐶 + 𝑆] isan atom if it has no clique separator.
This method implements the algorithm proposed in [BPS2010], that improves upon the algorithm proposed in[TY1984], for computing the atoms and the clique minimal separators of a graph. This algorithm is based on the
maximum_cardinality_search_M() graph traversal and has time complexity in 𝑂(|𝑉 | · |𝐸|).
Note: As the graph is converted to a short_digraph (with sort_neighbors=True), the complexity has an
extra 𝑂(|𝑉 | + |𝐸| log |𝐸|) for SparseGraph and 𝑂(|𝑉 |2 log |𝐸|) for DenseGraph.
If the graph is not connected, we insert empty separators between the lists of separators of each connected components. See the examples below for more details.
INPUT:• G – a Sage graph• tree – boolean (default: False); whether to return the result as a directed tree in which internal nodes are
clique separators and leaves are the atoms of the decomposition. Since a clique separator is repeated when its
removal partition the graph into 3 or more connected components, vertices are labels by tuples (𝑖, 𝑆), where
𝑆 is the set of vertices of the atom or the clique separator, and 0 ≤ 𝑖 ≤ |𝑇 |.
• rooted_tree – boolean (default: False); whether to return the result as a LabelledRootedTree.
When tree is True, this parameter is ignored.
• separators – boolean (default: False); whether to also return the complete list of separators consideredduring the execution of the algorithm. When tree or rooted_tree is True, this parameter is ignored.
OUTPUT:• By default, return a tuple (𝐴, 𝑆𝑐 ), where 𝐴 is the list of atoms of the graph in the order of discovery, and
𝑆𝑐 is the list of clique separators, with possible repetitions, in the order the separator has been considered. If

5.27. Decomposition by clique minimal separators

1771

Graph Theory, Release 10.4

furthermore separators is True, return a tuple (𝐴, 𝑆ℎ , 𝑆𝑐 ), where 𝑆𝑐 is the list of considered separatorsof the graph in the order they have been considered.
• When tree is True, format the result as a directed tree
• When rooted_tree is True and tree is False, format the output as a LabelledRootedTree
EXAMPLES:
Example of [BPS2010]:
sage: G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],....:d : [ e , f , j , k ], e : [ g ],....:f : [ g , j , k ], g : [ j , k ], h : [ i , j ],....:i : [ k ], j : [ k ]})sage: atoms, cliques = G.atoms_and_clique_separators()
sage: sorted(sorted(a) for a in atoms)[[ a , b , c , k ],[ c , d , j , k ],[ d , e , f , g , j , k ],[ h , i , j , k ]]sage: sorted(sorted(c) for c in cliques)[[ c , k ], [ d , j , k ], [ j , k ]]sage: T = G.atoms_and_clique_separators(tree=True)
sage: T.is_tree()True
sage: T.diameter() == len(atoms)Truesage: all(u[1] in atoms for u in T if T.degree(u) == 1)
True
sage: all(u[1] in cliques for u in T if T.degree(u) != 1)
True>>> from sage.all import *>>> G = Graph({ a : [ b , k ], b : [ c ], c : [ d , j , k ],...
d : [ e , f , j , k ], e : [ g ],...
f : [ g , j , k ], g : [ j , k ], h : [ i , j ],...
i : [ k ], j : [ k ]})>>> atoms, cliques = G.atoms_and_clique_separators()>>> sorted(sorted(a) for a in atoms)[[ a , b , c , k ],[ c , d , j , k ],[ d , e , f , g , j , k ],[ h , i , j , k ]]>>> sorted(sorted(c) for c in cliques)[[ c , k ], [ d , j , k ], [ j , k ]]>>> T = G.atoms_and_clique_separators(tree=True)>>> T.is_tree()True>>> T.diameter() == len(atoms)
True>>> all(u[Integer(1)] in atoms for u in T if T.degree(u) == Integer(1))
True>>> all(u[Integer(1)] in cliques for u in T if T.degree(u) != Integer(1))
True

A graph without clique separator:

1772

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: G = graphs.CompleteGraph(5)sage: G.atoms_and_clique_separators()([{0, 1, 2, 3, 4}], [])sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True)){0, 1, 2, 3, 4}>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(5))>>> G.atoms_and_clique_separators()([{0, 1, 2, 3, 4}], [])>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True)){0, 1, 2, 3, 4}

Graphs with several biconnected components:
sage: G = graphs.PathGraph(4)sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))____{2}____//{2, 3}__{1}__//{1, 2} {0, 1}
sage: G = graphs.WindmillGraph(3, 4)
sage: G.atoms_and_clique_separators()([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))________{0}________//{0, 1, 2}_______{0}______//{0, 3, 4}____{0}___//{0, 8, 7} {0, 5, 6}>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))____{2}____//{2, 3}__{1}__//{1, 2} {0, 1}>>> G = graphs.WindmillGraph(Integer(3), Integer(4))>>> G.atoms_and_clique_separators()([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))________{0}________//{0, 1, 2}_______{0}______//{0, 3, 4}____{0}___//{0, 8, 7} {0, 5, 6}

When the removal of a clique separator results in 𝑘 > 2 connected components, this separator is repeated 𝑘 − 1

5.27. Decomposition by clique minimal separators

1773

Graph Theory, Release 10.4

times, but the repetitions are not necessarily contiguous:
sage: G = Graph(2)sage: for i in range(5):....:G.add_cycle([0, 1, G.add_vertex()])
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))_________{0, 1}_____//{0, 1, 4}________{0, 1}_____//{0, 1, 2}_______{0, 1}___//{0, 1, 3}____{0, 1}//{0, 1, 5} {0, 1, 6}
sage: G = graphs.StarGraph(3)sage: G.subdivide_edges(G.edges(sort=False), 2)
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{5}______//{1, 5}______{7}______//{2, 7}______{9}______//{9, 3}______{6}______//{6, 7}______{4}_____//{4, 5}_____{0}_____//{0, 6}____{8}____//{8, 9}__{0}__//{0, 8} {0, 4}>>> from sage.all import *>>> G = Graph(Integer(2))>>> for i in range(Integer(5)):...
G.add_cycle([Integer(0), Integer(1), G.add_vertex()])>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))_________{0, 1}_____//{0, 1, 4}________{0, 1}_____//{0, 1, 2}_______{0, 1}___//{0, 1, 3}____{0, 1}//{0, 1, 5} {0, 1, 6}>>> G = graphs.StarGraph(Integer(3))>>> G.subdivide_edges(G.edges(sort=False), Integer(2))>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{5}______//{1, 5}______{7}______(continues on next page)

1774

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)/{2, 7}/______{9}______//{9, 3}______{6}______//{6, 7}______{4}_____//{4, 5}_____{0}_____//{0, 6}____{8}____//{8, 9}__{0}__//{0, 8} {0, 4}

If the graph is not connected, we insert empty separators between the lists of separators of each connectedcomponents. For instance, let 𝐺 be a graph with 3 connected components. The method returns the list 𝑆𝑐 =[𝑆0 , · · · , 𝑆𝑖 , . . . , 𝑆𝑗 , . . . , 𝑆𝑘−1 ] of 𝑘 clique separators, where 𝑖 and 𝑗 are the indexes of the inserted empty separators and 0 ≤ 𝑖 < 𝑗 < 𝑘 −1. The method also returns the list 𝐴 = [𝐴0 , . . . , 𝑆𝑘 ] of the 𝑘 +1 atoms, with 𝑘 +1 ≥ 3.
The lists of atoms and clique separators of each of the connected components are respectively [𝐴0 , . . . , 𝐴𝑖 ] and[𝑆0 , . . . , 𝑆𝑖−1 ], [𝐴𝑖+1 , . . . , 𝐴𝑗 ] and [𝑆𝑖+1 , . . . , 𝑆𝑗−1 ], and [𝐴𝑗+1 , . . . , 𝐴𝑘 ] and [𝑆𝑗+1 , . . . , 𝑆𝑘−1 ]. One can checkthat for each connected component, we get one atom more than clique separators:
sage: G = graphs.PathGraph(3) * 3
sage: A, Sc = G.atoms_and_clique_separators()
sage: A[{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]
sage: Sc[{1}, {}, {4}, {}, {7}]sage: i , j = [i for i, s in enumerate(Sc) if not s]sage: i, j
(1, 3)
sage: A[:i+1], Sc[:i]([{1, 2}, {0, 1}], [{1}])sage: A[i+1:j+1], Sc[i+1:j]([{4, 5}, {3, 4}], [{4}])sage: A[j+1:], Sc[j+1:]([{8, 7}, {6, 7}], [{7}])sage: I = [-1, i, j, len(Sc)]sage: for i, j in zip(I[:-1], I[1:]):....:
print(A[i+1:j+1], Sc[i+1:j])[{1, 2}, {0, 1}] [{1}][{4, 5}, {3, 4}] [{4}][{8, 7}, {6, 7}] [{7}]sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}

5.27. Decomposition by clique minimal separators

1775

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.PathGraph(Integer(3)) * Integer(3)>>> A, Sc = G.atoms_and_clique_separators()>>> A[{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]>>> Sc[{1}, {}, {4}, {}, {7}]>>> i , j = [i for i, s in enumerate(Sc) if not s]>>> i, j(1, 3)>>> A[:i+Integer(1)], Sc[:i]([{1, 2}, {0, 1}], [{1}])>>> A[i+Integer(1):j+Integer(1)], Sc[i+Integer(1):j]([{4, 5}, {3, 4}], [{4}])>>> A[j+Integer(1):], Sc[j+Integer(1):]([{8, 7}, {6, 7}], [{7}])>>> I = [-Integer(1), i, j, len(Sc)]>>> for i, j in zip(I[:-Integer(1)], I[Integer(1):]):...
print(A[i+Integer(1):j+Integer(1)], Sc[i+Integer(1):j])[{1, 2}, {0, 1}] [{1}][{4, 5}, {3, 4}] [{4}][{8, 7}, {6, 7}] [{7}]>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}

Loops and multiple edges are ignored:sage: G.allow_loops(True)
sage: G.add_edges([(u, u) for u in G])
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edges(sort=False))
sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}>>> from sage.all import *>>> G.allow_loops(True)>>> G.add_edges([(u, u) for u in G])(continues on next page)

1776

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edges(sort=False))>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))______{1}______//{1, 2}______{}______//{0, 1}_____{4}_____//{4, 5}____{}_____//{3, 4}__{7}__//{6, 7} {8, 7}

We can check that the returned list of separators is valid:
sage: G = graphs.RandomGNP(50, .1)
sage: while not G.is_connected():....:G = graphs.RandomGNP(50, .1)
sage: _, separators, _ = G.atoms_and_clique_separators(separators=True)
sage: for S in separators:....:
H = G.copy()....:
H.delete_vertices(S)....:if H.is_connected():....:raise ValueError("something goes wrong")>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(50), RealNumber( .1 ))>>> while not G.is_connected():...
G = graphs.RandomGNP(Integer(50), RealNumber( .1 ))>>> _, separators, _ = G.atoms_and_clique_separators(separators=True)>>> for S in separators:...
H = G.copy()...
H.delete_vertices(S)...
if H.is_connected():...
raise ValueError("something goes wrong")

sage.graphs.graph_decompositions.clique_separators.make_labelled_rooted_tree(atoms,
cliques)
Return a LabelledRootedTree of atoms and cliques.
The atoms are the leaves of the tree and the cliques are the internal vertices. The number of atoms is the numberof cliques plus one.
EXAMPLES:
sage: G = graphs.PathGraph(5)sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))_____{3}_____//{3, 4}____{2}____//{2, 3}__{1}__//{0, 1} {1, 2}

5.27. Decomposition by clique minimal separators

1777

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.PathGraph(Integer(5))>>> ascii_art(G.atoms_and_clique_separators(rooted_tree=True))_____{3}_____//{3, 4}____{2}____//{2, 3}__{1}__//{0, 1} {1, 2}

sage.graphs.graph_decompositions.clique_separators.make_tree(atoms, cliques)
Return a tree of atoms and cliques.
The atoms are the leaves of the tree and the cliques are the internal vertices. The number of atoms is the numberof cliques plus one.
As a clique may appear several times in the list cliques, vertices are numbered by pairs (𝑖, 𝑆), where 0 ≤ 𝑖 <|𝑎𝑡𝑜𝑚𝑠| + |𝑐𝑙𝑖𝑞𝑢𝑒𝑠| and 𝑆 is either an atom or a clique.
The root of the tree is the only vertex with even or null degree, i.e., 0 if cliques is empty and 2 otherwise. Whencliques is not empty, other internal vertices (each of which is a clique) have degree 3, and the leaves (verticesof degree 1) are the atoms.
INPUT:• atoms – list of atoms• cliques – list of cliques
EXAMPLES:
sage: from sage.graphs.graph_decompositions.clique_separators import make_tree
sage: G = graphs.Grid2dGraph(2, 4)
sage: A, Sc = G.atoms_and_clique_separators()
sage: T = make_tree(A, Sc)
sage: all(u[1] in A for u in T if T.degree(u) == 1)
True
sage: all(u[1] in Sc for u in T if T.degree(u) != 1)
True>>> from sage.all import *>>> from sage.graphs.graph_decompositions.clique_separators import make_tree>>> G = graphs.Grid2dGraph(Integer(2), Integer(4))>>> A, Sc = G.atoms_and_clique_separators()>>> T = make_tree(A, Sc)>>> all(u[Integer(1)] in A for u in T if T.degree(u) == Integer(1))
True>>> all(u[Integer(1)] in Sc for u in T if T.degree(u) != Integer(1))
True

1778

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.28 Convexity properties of graphs
This class gathers the algorithms related to convexity in a graph. It implements the following methods:
ConvexityProperties.
hull()
ConvexityProperties.
hull_number()geodetic_closure()
is_geodetic()

Return the convex hull of a set of vertices
Compute the hull number of a graph and a corresponding generating set
Return the geodetic closure of a set of vertices
Check whether the input (di)graph is geodetic

Some of these methods can be used through the ConvexityProperties object returned by Graph.
convexity_properties().

5.28.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 ashortest path between 𝑢 and 𝑣. Alternatively, a set 𝑆 is said to be convex if the distances satisfy ∀𝑢, 𝑣 ∈ 𝑆, ∀𝑤 ∈𝑉 ∖𝑆 : 𝑑𝐺 (𝑢, 𝑤) + 𝑑𝐺 (𝑤, 𝑣) > 𝑑𝐺 (𝑢, 𝑣).
The convex hull ℎ(𝑆) of a set 𝑆 of vertices is defined as the smallest convex set containing 𝑆.
It is a closure operator, as trivially 𝑆 ⊆ ℎ(𝑆) and ℎ(ℎ(𝑆)) = ℎ(𝑆).
What this class contains
As operations on convex sets generally involve the computation of distances between vertices, this class’ purpose
is to cache that information so that computing the convex hulls of several different sets of vertices does not imply
recomputing several times the distances between the vertices.
In order to compute the convex hull of a set 𝑆 it is possible to write the following algorithm:
For any pair 𝑢, 𝑣 of elements in the set 𝑆, and for any vertex 𝑤 outside of it, add 𝑤 to 𝑆 if 𝑑𝐺 (𝑢, 𝑤) +𝑑𝐺 (𝑤, 𝑣) = 𝑑𝐺 (𝑢, 𝑣). When no vertex can be added anymore, the set 𝑆 is convex
The distances are not actually that relevant. The same algorithm can be implemented by remembering for eachpair 𝑢, 𝑣 of vertices the list of elements 𝑤 satisfying the condition, and this is precisely what this class remembers,
encoded as bitsets to make storage and union operations more efficient.
Note:• This class is useful if you compute the convex hulls of many sets in the same graph, or if you want to computethe 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.
5.28. Convexity properties of graphs

1779

Graph Theory, Release 10.4

• 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 thepairs 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()˓→needs sage.numerical.mip
3>>> from sage.all import *>>> from sage.graphs.convexity_properties import ConvexityProperties>>> g = graphs.PetersenGraph()>>> CP = ConvexityProperties(g)>>> CP.hull([Integer(1), Integer(3)])[1, 2, 3]>>> CP.hull_number()˓→needs sage.numerical.mip
3

#␣

#␣

hull(vertices)
Return 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]>>> from sage.all import *>>> from sage.graphs.convexity_properties import ConvexityProperties>>> g = graphs.PetersenGraph()>>> CP = ConvexityProperties(g)>>> CP.hull([Integer(1), Integer(3)])[1, 2, 3]1780

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

hull_number(value_only=True, verbose=False)
Compute the hull number and a corresponding generating set.
The hull number ℎ𝑛(𝐺) of a graph 𝐺 is the cardinality of a smallest set of vertices 𝑆 such that ℎ(𝑆) = 𝑉 (𝐺).
INPUT:• value_only – boolean (default: True); whether to return only the hull number (default) or a minimum set whose convex hull is the whole graph• verbose – boolean (default: False); whether to display information on the LPCOMPLEXITY:This problem is NP-Hard [HLT1993], but seems to be of the “nice” kind. Update this comment if you fallon 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 anothersolution 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()˓→needs sage.numerical.mip
3
sage: generating_set = CP.hull_number(value_only=False)
˓→needs sage.numerical.mip
sage: CP.hull(generating_set)
˓→needs sage.numerical.mip[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

5.28. Convexity properties of graphs

#␣

#␣
#␣

1781

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.convexity_properties import ConvexityProperties>>> g = graphs.PetersenGraph()>>> CP = ConvexityProperties(g)>>> CP.hull_number()˓→needs sage.numerical.mip
3>>> generating_set = CP.hull_number(value_only=False)
˓→needs sage.numerical.mip>>> CP.hull(generating_set)
˓→needs sage.numerical.mip[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

#␣

#␣
#␣

sage.graphs.convexity_properties.geodetic_closure(G, S)
Return the geodetic closure of the set of vertices 𝑆 in 𝐺.
The geodetic closure 𝑔(𝑆) of a subset of vertices 𝑆 of a graph 𝐺 is in [HLT1993] as the set of all vertices that lie
on a shortest 𝑢 − 𝑣 path for any pair of vertices 𝑢, 𝑣 ∈ 𝑆. We assume that 𝑔(∅) = ∅ and that 𝑔({𝑢}) = {𝑢} for
any 𝑢 in 𝐺.
Warning: This operation is not a closure function. Indeed, a closure function must satisfy the property that𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋), which is not always the case here. The term closure is used here tofollow the terminology of the domain. See for instance [HLT1993].
Here, we implement a simple algorithm to determine this set. Roughly, for each vertex 𝑢 ∈ 𝑆, the algorithm
first performs a breadth first search from 𝑢 to get distances, and then identifies the vertices of 𝐺 lying on a shortest path from 𝑢 to any 𝑣 ∈ 𝑆 using a reversal traversal from vertices in 𝑆. This algorithm has time complexity in 𝑂(|𝑆|(𝑛 + 𝑚) + (𝑛 + 𝑚 log 𝑚)) for SparseGraph, 𝑂(|𝑆|(𝑛 + 𝑚) + 𝑛2 log 𝑚) for DenseGraphand space complexity in 𝑂(𝑛 + 𝑚) (the extra log factor is due to init_short_digraph being called with
sort_neighbors=True).
INPUT:• G – a Sage graph• S – a subset of vertices of 𝐺
EXAMPLES:
The vertices of the Petersen graph can be obtained by a geodetic closure of four of its vertices:sage: from sage.graphs.convexity_properties import geodetic_closure
sage: G = graphs.PetersenGraph()
sage: geodetic_closure(G, [0, 2, 8, 9])[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> from sage.all import *>>> from sage.graphs.convexity_properties import geodetic_closure>>> G = graphs.PetersenGraph()>>> geodetic_closure(G, [Integer(0), Integer(2), Integer(8), Integer(9)])[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The vertices of a 2D grid can be obtained by a geodetic closure of two vertices:sage: G = graphs.Grid2dGraph(4, 4)
sage: c = G.geodetic_closure([(0, 0), (3, 3)])
(continues on next page)

1782

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: len(c) == G.order()True>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(4), Integer(4))>>> c = G.geodetic_closure([(Integer(0), Integer(0)), (Integer(3), Integer(3))])>>> len(c) == G.order()True

If two vertices belong to different connected components of a graph, their geodetic closure is trivial:sage: G = Graph([(0, 1), (2, 3)])sage: geodetic_closure(G, [0, 2])[0, 2]>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1)), (Integer(2), Integer(3))])>>> geodetic_closure(G, [Integer(0), Integer(2)])[0, 2]The geodetic closure does not satisfy the closure function property that 𝑓 (𝑓 (𝑋)) should be equal to 𝑓 (𝑋):sage: G = graphs.DiamondGraph()
sage: G.subdivide_edge((1, 2), 1)
sage: geodetic_closure(G, [0, 3])[0, 1, 2, 3]
sage: geodetic_closure(G, geodetic_closure(G, [0, 3]))[0, 1, 2, 3, 4]>>> from sage.all import *>>> G = graphs.DiamondGraph()>>> G.subdivide_edge((Integer(1), Integer(2)), Integer(1))>>> geodetic_closure(G, [Integer(0), Integer(3)])[0, 1, 2, 3]>>> geodetic_closure(G, geodetic_closure(G, [Integer(0), Integer(3)]))[0, 1, 2, 3, 4]

sage.graphs.convexity_properties.is_geodetic(G)Check whether the input (di)graph is geodetic.
A graph 𝐺 is geodetic if there exists only one shortest path between every pair of its vertices. This can be checked intime 𝑂(𝑛𝑚) for SparseGraph and 𝑂(𝑛𝑚 + 𝑛2 ) for DenseGraph in unweighted (di)graphs with 𝑛 nodes and𝑚 edges. Examples of geodetic graphs are trees, cliques and odd cycles. See the Wikipedia article Geodetic_graphfor more details.
(Di)graphs with multiple edges are not considered geodetic.
INPUT:• G – a graph or a digraph
EXAMPLES:
Trees, cliques and odd cycles are geodetic:sage: T = graphs.RandomTree(20)sage: T.is_geodetic()(continues on next page)

5.28. Convexity properties of graphs

1783

Graph Theory, Release 10.4

(continued from previous page)True
sage: all(graphs.CompleteGraph(n).is_geodetic() for n in range(8))
Truesage: all(graphs.CycleGraph(n).is_geodetic() for n in range(3, 16, 2))
True>>> from sage.all import *>>> T = graphs.RandomTree(Integer(20))>>> T.is_geodetic()
True>>> all(graphs.CompleteGraph(n).is_geodetic() for n in range(Integer(8)))
True>>> all(graphs.CycleGraph(n).is_geodetic() for n in range(Integer(3), Integer(16),
˓→ Integer(2)))
True

Even cycles of order at least 4 are not geodetic:sage: all(graphs.CycleGraph(n).is_geodetic() for n in range(4, 17, 2))
False>>> from sage.all import *>>> all(graphs.CycleGraph(n).is_geodetic() for n in range(Integer(4), Integer(17),˓→ Integer(2)))
False

The Petersen graph is geodetic:sage: P = graphs.PetersenGraph()
sage: P.is_geodetic()
True>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.is_geodetic()
True

Grid graphs are not geodetic:sage: G = graphs.Grid2dGraph(2, 3)
sage: G.is_geodetic()
False>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(2), Integer(3))>>> G.is_geodetic()
False

This method is also valid for digraphs:
sage: G = DiGraph(graphs.PetersenGraph())
sage: G.is_geodetic()Truesage: G = digraphs.Path(5)sage: G.add_path([0, a , b , c , 4])(continues on next page)

1784

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: G.is_geodetic()
False>>> from sage.all import *>>> G = DiGraph(graphs.PetersenGraph())>>> G.is_geodetic()
True>>> G = digraphs.Path(Integer(5))>>> G.add_path([Integer(0), a , b , c , Integer(4)])>>> G.is_geodetic()
False

5.29 Weakly chordal graphs
This module deals with everything related to weakly chordal graphs. It currently contains the following functions:is_long_hole_free()is_long_antihole_free()is_weakly_chordal()Tests whether g contains an induced cycle of length at least 5.
Tests whether g contains an induced anticycle of length at least 5.
Tests whether g is weakly chordal.

Author:• Birk Eisermann (initial implementation)• Nathann Cohen (some doc and optimization)• David Coudert (remove recursion)

5.29.1 Methods
sage.graphs.weakly_chordal.is_long_antihole_free(g, certificate=False)
Tests whether the given graph contains an induced subgraph that is isomorphic to the complement of a cycle oflength 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 areadjacent 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 .
5.29. Weakly chordal graphs

1785

Graph Theory, Release 10.4

This is done through a depth-first-search. For efficiency, the auxiliary graph is constructed on-the-fly and neverstored in memory.
The run time of this algorithm is 𝑂(𝑛 + 𝑚2 ) for SparseGraph and 𝑂(𝑛2 log 𝑚 + 𝑚2 ) for DenseGraph[NP2007] (where 𝑛 is the number of vertices and 𝑚 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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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: rFalse
sage: a.complement().is_isomorphic(graphs.CycleGraph(6))
True>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(6)).complement()>>> r,a = g.is_long_antihole_free(certificate=True)
>>> r
False
>>> a.complement().is_isomorphic(graphs.CycleGraph(Integer(6)))
Truesage.graphs.weakly_chordal.is_long_hole_free(g, certificate=False)
Tests whether g contains an induced cycle of length at least 5.
INPUT:• certificate – boolean (default: False)
Whether to return a certificate. When certificate = True, then the function returns– (True, []) if g does not contain such a cycle. For this case, it is not known how to provide a
certificate.
– (False, Hole) if g contains an induced cycle of length at least 5. Hole returns this cycle.
If certificate = False, the function returns just True or False accordingly.
ALGORITHM:
This algorithm tries to find a cycle in the graph of all induced 𝑃4 of 𝑔, where two copies 𝑃 and 𝑃 ′ of 𝑃4 areadjacent 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 neverstored in memory.

1786

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

The run time of this algorithm is 𝑂(𝑛 + 𝑚2 ) for SparseGraph and 𝑂(𝑛2 + 𝑚2 ) for DenseGraph [NP2007](where 𝑛 is the number of vertices and 𝑚 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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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: rFalse
sage: Graph(h).is_isomorphic(graphs.CycleGraph(h.order()))
True>>> from sage.all import *>>> g = graphs.FlowerSnark()>>> r,h = g.is_long_hole_free(certificate=True)
>>> r
False
>>> Graph(h).is_isomorphic(graphs.CycleGraph(h.order()))
True

sage.graphs.weakly_chordal.is_weakly_chordal(g, certificate=False)
Tests whether the given graph is weakly chordal, i.e., the graph and its complement have no induced cycle of length
at least 5.
INPUT:• certificate – Boolean value (default: False) whether to return a certificate. If certificate =False, return True or False according to the graph. If certificate = True, return– (False, forbidden_subgraph) when the graph contains a forbidden subgraph H, this graph isreturned.
– (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 ) for SparseGraph and𝑂(𝑛2 log 𝑚 + 𝑚2 ) for DenseGraph (where 𝑛 is the number of vertices and 𝑚 is the number of edges of thegraph).
EXAMPLES:
The Petersen Graph is not weakly chordal and contains a hole:

5.29. Weakly chordal graphs

1787

Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: r,s = g.is_weakly_chordal(certificate=True)
sage: rFalse
sage: l = s.order()sage: s.is_isomorphic(graphs.CycleGraph(l))
True>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> r,s = g.is_weakly_chordal(certificate=True)
>>> r
False
>>> l = s.order()>>> s.is_isomorphic(graphs.CycleGraph(l))
True

5.30 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 pairsof vertices.
Efficiency : Because these functions involve listing many times the (out)-neighborhoods of (di)-graphs, it is useful interms 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 notnecessary.
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.30.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.

1788

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

This vector of size 𝑛 encodes for each vertex 𝑣 the distance to vertex which is furthest from 𝑣 in the graph. In
particular, the diameter of the graph is the maximum of these values.
What does it take as input ?
• gg a (Di)Graph.
• unsigned short * predecessors – a pointer toward an array of size 𝑛2 · sizeof(unsigned short). Set to
NULL if you do not want to compute the predecessors.
• unsigned short * distances – a pointer toward an array of size 𝑛2 · sizeof(unsigned short). The
computation of the distances is necessary for the algorithm, so this value can not be set to NULL.
• int * eccentricity – a pointer toward an array of size 𝑛 · sizeof(int). Set to NULL if you do not want tocompute the eccentricity.
Technical details• The vertices are encoded as 1, ..., 𝑛 as they appear in the ordering of G.vertices(sort=True), unless another ordering is specified by the user.
• Because this function works on matrices whose size is quadratic compared to the number of vertices when computing all distances or predecessors, it uses short variables to store the vertices’ names instead of long ones to divide by
2 the size in memory. This means that only the diameter/eccentricities can be computed on a graph of more than65536 nodes. For information, the current version of the algorithm on a graph with 65536 = 216 nodes creates inmemory 2 tables on 232 short elements (2bytes each), for a total of 233 bytes or 8 gigabytes. In order to support
larger sizes, we would have to replace shorts by 32-bits int or 64-bits int, which would then require respectively
16GB or 32GB.
• In the C version of these functions, infinite distances are represented with <unsigned short> -1 = 65535
for unsigned short variables, and by INT32_MAX otherwise. These case happens when the input is a
disconnected graph, or a non-strongly-connected digraph.
• A memory error is raised when data structures allocation failed. This could happen with large graphs on computerswith 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 thatfeed it with the good parameters. As the function is inlined, using those wrappers actually saves time as it should
avoid testing the parameters again and again in the main function’s body.
AUTHOR:• Nathann Cohen (2011)• David Coudert (2014) – 2sweep, multi-sweep and iFUB for diameter computation

5.30.2 Functions
sage.graphs.distances_all_pairs.antipodal_graph(G)Return the antipodal graph of 𝐺.
The antipodal graph of a graph 𝐺 has the same vertex set of 𝐺 and two vertices are adjacent if their distance in 𝐺
is equal to the diameter of 𝐺.
This method first computes the eccentricity of all vertices and determines the diameter of the graph. Then, it foreach vertex 𝑢 with eccentricity the diameter, it computes BFS distances from 𝑢 and add an edge in the antipodal
graph for each vertex 𝑣 at diamter distance from 𝑢 (i.e., for each antipodal vertex).

5.30. Distances/shortest paths between all pairs of vertices

1789

Graph Theory, Release 10.4

The drawback of this method is that some BFS distances may be computed twice, one time to determine theeccentricities and another time is the vertex has eccentricity equal to the diameter. However, in practive, this ismuch more efficient. See the documentation of method c_eccentricity_DHV().
EXAMPLES:
The antipodal graph of a grid graph has only 2 edges:
sage: from sage.graphs.distances_all_pairs import antipodal_graphsage: G = graphs.Grid2dGraph(5, 5)
sage: A = antipodal_graph(G)sage: A.order(), A.size()(25, 2)>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import antipodal_graph>>> G = graphs.Grid2dGraph(Integer(5), Integer(5))>>> A = antipodal_graph(G)>>> A.order(), A.size()(25, 2)

The antipodal graph of a disjoint union of cliques is its complement:
sage: from sage.graphs.distances_all_pairs import antipodal_graphsage: G = graphs.CompleteGraph(3) * 3
sage: A = antipodal_graph(G)sage: A.is_isomorphic(G.complement())
True>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import antipodal_graph>>> G = graphs.CompleteGraph(Integer(3)) * Integer(3)>>> A = antipodal_graph(G)>>> A.is_isomorphic(G.complement())
True

The antipodal graph can also be constructeddistance_graph() for diameter distance:

as

the

sage.graphs.generic_graph.

sage: from sage.graphs.distances_all_pairs import antipodal_graphsage: G = graphs.RandomGNP(10, .2)
sage: A = antipodal_graph(G)sage: B = G.distance_graph(G.diameter())
sage: A.is_isomorphic(B)True>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import antipodal_graph>>> G = graphs.RandomGNP(Integer(10), RealNumber( .2 ))>>> A = antipodal_graph(G)>>> B = G.distance_graph(G.diameter())>>> A.is_isomorphic(B)Truesage.graphs.distances_all_pairs.diameter(G, algorithm=None, source=None)
Return the diameter of 𝐺.

1790

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

This method returns Infinity if the (di)graph is not connected. It can also quickly return a lower bound on the
diameter using the 2sweep, 2Dsweep and multi-sweep schemes.
INPUT:• algorithm – string (default: None); specifies the algorithm to use among:–standard – Computes the diameter of the input (di)graph as the largest eccentricity of its vertices.
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 [MLH2008]. It first selects a vertex 𝑣 that is at largest distance from an initialvertex 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 𝐺.

–

2Dsweep – Computes lower bound on the diameter of an unweighted directed graph using directedversion of 2sweep as proposed in [Broder2000]. If the digraph is not strongly connected, the returned
value is infinity.

–

DHV – Computes diameter of unweighted undirected graph using the algorithm proposed in[Dragan2018].

–

multi-sweep – Computes a lower bound on the diameter of an unweighted undirected graph using
several iterations of the 2sweep algorithms [CGHLM2013]. 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 boundon the diameter is improved.

–

iFUB – The iFUB (iterative Fringe Upper Bound) algorithm, proposed in [CGILM2010], 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 algorithm
used in [CGHLM2013]), we compute the diameter by computing the eccentricity of all vertices sorted
decreasingly according to their distance to 𝑣, and stop as allowed by the remark above. The worst casetime complexity of the iFUB algorithm is 𝑂(𝑛𝑚), but it can be very fast in practice.

–

DiFUB – The directed version of iFUB (iterative Fringe Upper Bound) algorithm. See the code’s
documentation and [CGLM2012] for more details. If the digraph is not strongly connected, the returned
value is infinity.

• source – (default: None) vertex from which to start the first BFS. If source==None, an arbitrary vertexof the graph is chosen. Raise an error if the initial vertex is not in 𝐺. This parameter is not used whenalgorithm== standard .
Note: As the graph is first converted to a short_digraph, all complexity have an extra 𝑂(𝑚 + 𝑛) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph.

5.30. Distances/shortest paths between all pairs of vertices

1791

Graph Theory, Release 10.4

EXAMPLES:
sage: from sage.graphs.distances_all_pairs import diametersage: G = graphs.PetersenGraph()
sage: diameter(G, algorithm= iFUB )2
sage: G = Graph({0: [], 1: [], 2: [1]})sage: diameter(G, algorithm= iFUB )+Infinity
sage: G = digraphs.Circuit(6)sage: diameter(G, algorithm= 2Dsweep )5sage: G = graphs.PathGraph(7).to_directed()sage: diameter(G, algorithm= DiFUB )6>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import diameter>>> G = graphs.PetersenGraph()>>> diameter(G, algorithm= iFUB )2>>> G = Graph({Integer(0): [], Integer(1): [], Integer(2): [Integer(1)]})>>> diameter(G, algorithm= iFUB )+Infinity>>> G = digraphs.Circuit(Integer(6))>>> diameter(G, algorithm= 2Dsweep )5>>> G = graphs.PathGraph(Integer(7)).to_directed()>>> diameter(G, algorithm= DiFUB )6

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>>> from sage.all import *>>> G = graphs.EmptyGraph()>>> diameter(G, algorithm= iFUB )0

Comparison of exact algorithms for graphs:
sage: # needs networkx
sage: G = graphs.RandomBarabasiAlbert(100, 2)
sage: d1 = diameter(G, algorithm= standard )sage: d2 = diameter(G, algorithm= iFUB )sage: d3 = diameter(G, algorithm= iFUB , source=G.random_vertex())
sage: d4 = diameter(G, algorithm= DHV )sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!")>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomBarabasiAlbert(Integer(100), Integer(2))>>> d1 = diameter(G, algorithm= standard )>>> d2 = diameter(G, algorithm= iFUB )(continues on next page)

1792

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> d3 = diameter(G, algorithm= iFUB , source=G.random_vertex())>>> d4 = diameter(G, algorithm= DHV )>>> if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!")Comparison of lower bound algorithms:
sage: lb2 = diameter(G, algorithm= 2sweep )˓→needs networkx
sage: lbm = diameter(G, algorithm= multi-sweep )˓→needs networkx
sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!")
˓→needs networkx>>> from sage.all import *>>> lb2 = diameter(G, algorithm= 2sweep )˓→needs networkx>>> lbm = diameter(G, algorithm= multi-sweep )˓→needs networkx>>> if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!")
˓→needs networkx

#␣
#␣
#␣

#␣
#␣
#␣

Comparison of exact algorithms for digraphs:
sage: # needs networkx
sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2))
sage: d1 = diameter(D, algorithm= standard )sage: d2 = diameter(D, algorithm= DiFUB )sage: d3 = diameter(D, algorithm= DiFUB , source=D.random_vertex())
sage: d1 == d2 and d1 == d3
True>>> from sage.all import *>>> # needs networkx>>> D = DiGraph(graphs.RandomBarabasiAlbert(Integer(50), Integer(2)))>>> d1 = diameter(D, algorithm= standard )>>> d2 = diameter(D, algorithm= DiFUB )>>> d3 = diameter(D, algorithm= DiFUB , source=D.random_vertex())>>> d1 == d2 and d1 == d3
Truesage.graphs.distances_all_pairs.distances_all_pairs(G)Return the matrix of distances in G.
This function returns a double dictionary D of vertices, in which the distance between vertices u and v is D[u][v].
EXAMPLES:
sage: 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},(continues on next page)

5.30. Distances/shortest paths between all pairs of vertices

1793

Graph Theory, Release 10.4

(continued from previous page)

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}}>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import distances_all_pairs>>> g = graphs.PetersenGraph()>>> 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(G)Return the matrix of distances in G and the matrix of predecessors.
Distances : the matrix 𝑀 returned is of length 𝑛2 , and the distance between vertices 𝑢 and 𝑣 is 𝑀 [𝑢, 𝑣]. The
integer corresponding to a vertex is its index in the list G.vertices(sort=True).
Predecessors : the matrix 𝑃 returned has size 𝑛2 , and is such that vertex 𝑃 [𝑢, 𝑣] is a predecessor of 𝑣 on a shortest
𝑢𝑣-path. Hence, this matrix efficiently encodes the information of a shortest 𝑢𝑣-path for any 𝑢, 𝑣 ∈ 𝐺 : indeed,
to go from 𝑢 to 𝑣 you should first find a shortest 𝑢𝑃 [𝑢, 𝑣]-path, then jump from 𝑃 [𝑢, 𝑣] to 𝑣 as it is one of its
outneighbors.
EXAMPLES:
sage: 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},
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}})

1794

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import distances_and_predecessors_all_
˓→pairs>>> g = graphs.PetersenGraph()>>> 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},
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(G)Return the distances distribution of the (di)graph in a dictionary.
This method ignores all edge labels, so that the distance considered is the topological distance.
OUTPUT:
A dictionary d such that the number of pairs of vertices at distance k (if any) is equal to 𝑑[𝑘] · |𝑉 (𝐺)| ·(|𝑉 (𝐺)| − 1).
Note: We consider that two vertices that do not belong to the same connected component are at infinite distance,
and we do not take the trivial pairs of vertices (𝑣, 𝑣) at distance 0 into account. Empty (di)graphs and (di)graphsof order 1 have no paths and so we return the empty dictionary {}.
EXAMPLES:
An empty Graph:
sage: g = Graph()
sage: g.distances_distribution(){}>>> from sage.all import *>>> g = Graph()>>> g.distances_distribution(){}

A Graph of order 1:

5.30. Distances/shortest paths between all pairs of vertices

1795

Graph Theory, Release 10.4

sage: g = Graph()
sage: g.add_vertex(1)sage: g.distances_distribution(){}>>> from sage.all import *>>> g = Graph()>>> g.add_vertex(Integer(1))>>> 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}>>> from sage.all import *>>> g = Graph()>>> g.add_vertices([Integer(1),Integer(2)])>>> g.distances_distribution(){+Infinity: 1}

The Petersen Graph:
sage: g = graphs.PetersenGraph()
sage: g.distances_distribution(){1: 1/3, 2: 2/3}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.add_edge( good , wine )>>> 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)˓→needs sage.combinat
sage: D.distances_distribution()
˓→needs sage.combinat{1: 1/4, 2: 11/28, 3: 5/14}

1796

#␣
#␣

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> D = digraphs.DeBruijn(Integer(2),Integer(3))˓→# needs sage.combinat>>> D.distances_distribution()
˓→needs sage.combinat{1: 1/4, 2: 11/28, 3: 5/14}

␣#␣

sage.graphs.distances_all_pairs.eccentricity(G, algorithm='standard', vertex_list=None)
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(sort=True).
INPUT:• G – a Graph or a DiGraph.
• algorithm – string (default: standard ); name of the method used to compute the eccentricity of thevertices.
–standard – Computes eccentricity by performing a BFS from each vertex.

–

bounds – Computes eccentricity using the fast algorithm proposed in [TK2013] for undirected
graphs.

–

DHV – Computes all eccentricities of undirected graph using the algorithm proposed in [Dragan2018].

• vertex_list – list (default: None); a list of 𝑛 vertices specifying a mapping from (0, . . . , 𝑛−1) to vertex
labels in 𝐺. When set, ecc[i] is the eccentricity of vertex vertex_list[i]. When vertex_list
is None, ecc[i] is the eccentricity of vertex G.vertices(sort=True)[i].
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: g.add_edge(0, g.add_vertex())
sage: V = list(g)sage: eccentricity(g, vertex_list=V)[2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3]
sage: eccentricity(g, vertex_list=V[::-1])[3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 2]>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import eccentricity>>> g = graphs.PetersenGraph()>>> eccentricity(g)[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]>>> g.add_edge(Integer(0), g.add_vertex())>>> V = list(g)>>> eccentricity(g, vertex_list=V)[2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3]>>> eccentricity(g, vertex_list=V[::-Integer(1)])[3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 2]

sage.graphs.distances_all_pairs.floyd_warshall(gg, paths=True, distances=False)
Compute the shortest path/distances between all pairs of vertices.
For more information on the Floyd-Warshall algorithm, see the Wikipedia article Floyd-Warshall_algorithm.
5.30. Distances/shortest paths between all pairs of vertices

1797

Graph Theory, Release 10.4

INPUT:• gg – the graph on which to work.
• paths – boolean (default: True); whether to return the dictionary of shortest paths• distances – boolean (default: False); whether to return the dictionary of distances
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, butwould require much more memory. It may be worth writing two versions). For information, the current versionof 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, thealgorithm runs in cubic time.

Note: When paths = False the algorithm saves roughly half of the memory as it does not have to maintainthe matrix of predecessors. However, setting distances=False produces no such effect as the algorithm can
not run without computing them. They will not be returned, but they will be stored while the method is running.
EXAMPLES:
Shortest paths in a small grid
sage: g = graphs.Grid2dGraph(2,2)
sage: from sage.graphs.distances_all_pairs import floyd_warshallsage: print(floyd_warshall(g)){(0, 0): {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 1)},(0, 1): {(0, 1): None, (0, 0): (0, 1), (1, 0): (0, 0), (1, 1): (0, 1)},
(1, 0): {(1, 0): None, (0, 0): (1, 0), (0, 1): (0, 0), (1, 1): (1, 0)},(1, 1): {(1, 1): None, (0, 0): (0, 1), (0, 1): (1, 1), (1, 0): (1, 1)}}>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(2),Integer(2))>>> from sage.graphs.distances_all_pairs import floyd_warshall>>> print(floyd_warshall(g)){(0, 0): {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 1)},(0, 1): {(0, 1): None, (0, 0): (0, 1), (1, 0): (0, 0), (1, 1): (0, 1)},
(1, 0): {(1, 0): None, (0, 0): (1, 0), (0, 1): (0, 0), (1, 1): (1, 0)},(1, 1): {(1, 1): None, (0, 0): (0, 1), (0, 1): (1, 1), (1, 0): (1, 1)}}

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

1798

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.Grid2dGraph(Integer(5),Integer(5))>>> dist,path = floyd_warshall(g, distances=True)>>> 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>>> from sage.all import *>>> u,v = g.random_vertex(), g.random_vertex()>>> p = [v]>>> while p[Integer(0)] is not None:...
p.insert(Integer(0),path[u][p[Integer(0)]])>>> len(p) == dist[u][v] + Integer(2)TrueDistances 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}}>>> from sage.all import *>>> g = graphs.DiamondGraph()>>> 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(G, parameters=False)
Test if the graph is distance-regularA 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:

5.30. Distances/shortest paths between all pairs of vertices

1799

Graph Theory, Release 10.4

• parameters – boolean (default: False); if set to True, the function returns the pair (b, c) of lists ofintegers instead of a boolean answer (see the definition above)
See also:• is_regular()• is_strongly_regular()
EXAMPLES:
sage: g = graphs.PetersenGraph()
sage: g.is_distance_regular()True
sage: g.is_distance_regular(parameters = True)([3, 2, None], [None, 1, 1])>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.is_distance_regular()True>>> 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>>> from sage.all import *>>> graphs.CubeGraph(Integer(4)).is_distance_regular()True>>> graphs.OddGraph(Integer(5)).is_distance_regular()
True

Disconnected graph:
sage: (2*graphs.CubeGraph(4)).is_distance_regular()True>>> from sage.all import *>>> (Integer(2)*graphs.CubeGraph(Integer(4))).is_distance_regular()Truesage.graphs.distances_all_pairs.radius_DHV(G)Return the radius of unweighted graph 𝐺.
This method computes the radius of unweighted undirected graph using the algorithm given in [Dragan2018].
This method returns Infinity if graph is not connected.
EXAMPLES:
sage: from sage.graphs.distances_all_pairs import radius_DHV
sage: G = graphs.PetersenGraph()
sage: radius_DHV(G)(continues on next page)

1800

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)2
sage: G = graphs.RandomGNP(20,0.3)
sage: from sage.graphs.distances_all_pairs import eccentricity
sage: radius_DHV(G) == min(eccentricity(G, algorithm= bounds ))True>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import radius_DHV>>> G = graphs.PetersenGraph()>>> radius_DHV(G)2>>> G = graphs.RandomGNP(Integer(20),RealNumber( 0.3 ))>>> from sage.graphs.distances_all_pairs import eccentricity>>> radius_DHV(G) == min(eccentricity(G, algorithm= bounds ))Truesage.graphs.distances_all_pairs.shortest_path_all_pairs(G)Return the matrix of predecessors in G.
The matrix 𝑃 returned has size 𝑛2 , and is such that vertex 𝑃 [𝑢, 𝑣] is a predecessor of 𝑣 on a shortest 𝑢𝑣-path.
Hence, this matrix efficiently encodes the information of a shortest 𝑢𝑣-path for any 𝑢, 𝑣 ∈ 𝐺 : indeed, to go from𝑢 to 𝑣 you should first find a shortest 𝑢𝑃 [𝑢, 𝑣]-path, then jump from 𝑃 [𝑢, 𝑣] to 𝑣 as it is one of its outneighbors.
EXAMPLES:
sage: 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}}>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import shortest_path_all_pairs>>> g = graphs.PetersenGraph()>>> 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.szeged_index(G, algorithm=None)
Return the Szeged index of the graph 𝐺.

5.30. Distances/shortest paths between all pairs of vertices

1801

Graph Theory, Release 10.4

Let 𝐺 = (𝑉, 𝐸) be a connected graph, and for any 𝑢𝑣 ∈ 𝐸, let 𝑁𝑢 (𝑢𝑣) = {𝑤 ∈ 𝑉 : 𝑑(𝑢, 𝑤) < 𝑑(𝑣, 𝑤)} and𝑛𝑢 (𝑢𝑣) = |𝑁𝑢 (𝑢𝑣)|. The Szeged index of 𝐺 is then defined as [KRG1996]∑︁`𝑛𝑢 (𝑢𝑣) × 𝑛𝑣 (𝑢𝑣)`𝑢𝑣∈𝐸(𝐺)See the Wikipedia article Szeged_index for more details.
INPUT:• G – a Sage graph• algorithm – string (default: None); algorithm to use among:– "low" – algorithm with time complexity in 𝑂(𝑛𝑚) and space complexity in 𝑂(𝑚). This implementation is currently valid only for simple (without loops or multiple edges) connected graphs.
– "high" – algorithm with time complexity in 𝑂(𝑛𝑚) and space complexity in 𝑂(𝑛2 ). It cannot be usedon graphs with more than 65536 = 216 vertices.
By default (None), the "low" algorithm is used for graphs and the "high" algorithm for digraphs.
Note: As the graph is converted to a short_digraph, the complexity for the case algorithm == "high" has an
extra 𝑂(𝑚 + 𝑛) for SparseGraph and 𝑂(𝑛2 ) for DenseGraph. If algorithm == "low", the extra complexity is 𝑂(𝑛+𝑚 log 𝑚) for SparseGraph and 𝑂(𝑛2 log 𝑚) for DenseGraph (because init_short_digraph is called with sort_neighbors=True).
EXAMPLES:
True for any connected graph [KRG1996]:
sage: from sage.graphs.distances_all_pairs import szeged_index
sage: g = graphs.PetersenGraph()
sage: g.wiener_index() <= szeged_index(g)True>>> from sage.all import *>>> from sage.graphs.distances_all_pairs import szeged_index>>> g = graphs.PetersenGraph()>>> g.wiener_index() <= szeged_index(g)True

True for all trees [KRG1996]:
sage: g = Graph()
sage: g.add_edges(graphs.CubeGraph(5).min_spanning_tree())
sage: g.wiener_index() == szeged_index(g)True>>> from sage.all import *>>> g = Graph()>>> g.add_edges(graphs.CubeGraph(Integer(5)).min_spanning_tree())>>> g.wiener_index() == szeged_index(g)TrueCheck that both algorithms return same value:

1802

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: # long time, needs networkx
sage: G = graphs.RandomBarabasiAlbert(100, 2)
sage: a = szeged_index(G, algorithm= low )sage: b = szeged_index(G, algorithm= high )sage: a == b
True>>> from sage.all import *>>> # long time, needs networkx>>> G = graphs.RandomBarabasiAlbert(Integer(100), Integer(2))>>> a = szeged_index(G, algorithm= low )>>> b = szeged_index(G, algorithm= high )>>> a == b
True

The Szeged index of a directed circuit of order 𝑛 is (𝑛 − 1)2 :sage: [digraphs.Circuit(n).szeged_index() for n in range(1, 8)][0, 1, 4, 9, 16, 25, 36]>>> from sage.all import *>>> [digraphs.Circuit(n).szeged_index() for n in range(Integer(1), Integer(8))][0, 1, 4, 9, 16, 25, 36]

sage.graphs.distances_all_pairs.wiener_index(G)Return the Wiener index of the graph.
The Wiener index of an undirected graph 𝐺 is defined as 𝑊 (𝐺) = 12
distance between vertices 𝑢 and 𝑣 (see [KRG1996]).

∑︀

𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣) where 𝑑(𝑢, 𝑣) denotes the

The Wiener∑︀ index of a directed graph 𝐺 is defined as the sum of the distances between each pairs of vertices,
𝑊 (𝐺) = 𝑢,𝑣∈𝐺 𝑑(𝑢, 𝑣).
EXAMPLES:
From [GYLL1993], cited in [KRG1996]:
sage: g=graphs.PathGraph(10)sage: w=lambda x: (x*(x*x -1)/6)
sage: g.wiener_index()==w(10)True>>> from sage.all import *>>> g=graphs.PathGraph(Integer(10))>>> w=lambda x: (x*(x*x -Integer(1))/Integer(6))>>> g.wiener_index()==w(Integer(10))
True

Wiener index of complete (di)graphs:
sage: n = 5
sage: g = graphs.CompleteGraph(n)sage: g.wiener_index() == (n * (n - 1)) / 2
True
sage: g = digraphs.Complete(n)sage: g.wiener_index() == n * (n - 1)
True

5.30. Distances/shortest paths between all pairs of vertices

1803

Graph Theory, Release 10.4>>> from sage.all import *>>> n = Integer(5)>>> g = graphs.CompleteGraph(n)>>> g.wiener_index() == (n * (n - Integer(1))) / Integer(2)True>>> g = digraphs.Complete(n)>>> g.wiener_index() == n * (n - Integer(1))
True

Wiener index of a graph of order 1:
sage: Graph(1).wiener_index()
0>>> from sage.all import *>>> Graph(Integer(1)).wiener_index()
0

The Wiener index is not defined on the empty graph:
sage: Graph().wiener_index()
Traceback (most recent call last):...
ValueError: Wiener index is not defined for the empty graph>>> from sage.all import *>>> Graph().wiener_index()
Traceback (most recent call last):...
ValueError: Wiener index is not defined for the empty graph5.31 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

1804

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.31.1 LaTeX Versions of Graphs

Many mathematical objects in Sage have LaTeX representations, and graphs are no exception. For a graph g, the commandview(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 foundat https://www.ctan.org/pkg/tkz-graph.
The range of possible options for customizing the appearance of a graph are carefully documented at sage.graphs.
graph_latex.GraphLatex.set_option(). As a broad overview, the following options are supported:• Pre-built Styles: the pre-built styles of the tkz-graph package provide nice drawings quickly• Dimensions: can be specified in natural units, then uniformly scaled after design work
• Vertex Colors: the perimeter and fill color for vertices can be specified, including on a per-vertex basis• Vertex Shapes: may be circles, shaded spheres, rectangles or diamonds, including on a per-vertex basis• Vertex Sizes: may be specified as minimums, and will automatically sized to contain vertex labels, including on a
per-vertex basis• Vertex Labels: can use latex formatting, and may have their colors specified, including on a per-vertex basis• Vertex Label Placement: can be interior to the vertex, or external at a configurable location• Edge Colors: a solid color with or without a second color down the middle, on a per-edge basis• Edge Thickness: can be set, including on a per-edge basis• Edge Labels: can use latex formatting, and may have their colors specified, including on a per-edge basis• Edge Label Placement: can be to the left, right, above, below, inline, and then sloped or horizontal• Digraph Edges: are slightly curved, with arrowheads

5.31. LaTeX options for graphs

1805

Graph Theory, Release 10.4

• 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 magick utilities. For graphs you need the tkz-graph.sty and tkz-berge.sty style files of the tkz-graphpackage. 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/• magick: http://www.imagemagick.org (the ImageMagick suite)• tkz-graph: https://www.ctan.org/pkg/tkz-graph
Customizing the output is accomplished in several ways. Suppose g is a graph, then g.set_latex_options() canbe used to efficiently set or modify various options. Setting individual options, or querying options, can be accomplishedby 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 orat 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....: )>>> from sage.all import *>>> H = graphs.HeawoodGraph()>>> H.set_latex_options(...
graphic_size=(Integer(5),Integer(5)),...
vertex_size=RealNumber( 0.2 ),...
edge_thickness=RealNumber( 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, thelatex() 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_graphsage: 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}(continues on next page)

1806

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)\definecolor{cv1}{rgb}{0.0,0.502,0.0}\definecolor{cfv1}{rgb}{1.0,1.0,1.0}\definecolor{clv1}{rgb}{1.0,0.0,0.0}\definecolor{cv2}{rgb}{0.0,0.502,0.0}\definecolor{cfv2}{rgb}{1.0,1.0,1.0}\definecolor{clv2}{rgb}{1.0,0.0,0.0}\definecolor{cv3}{rgb}{0.0,0.502,0.0}\definecolor{cfv3}{rgb}{1.0,1.0,1.0}\definecolor{clv3}{rgb}{1.0,0.0,0.0}\definecolor{cv4}{rgb}{0.0,0.502,0.0}\definecolor{cfv4}{rgb}{1.0,1.0,1.0}\definecolor{clv4}{rgb}{1.0,0.0,0.0}\definecolor{cv5}{rgb}{0.0,0.502,0.0}\definecolor{cfv5}{rgb}{1.0,1.0,1.0}\definecolor{clv5}{rgb}{1.0,0.0,0.0}\definecolor{cv6}{rgb}{0.0,0.502,0.0}\definecolor{cfv6}{rgb}{1.0,1.0,1.0}\definecolor{clv6}{rgb}{1.0,0.0,0.0}\definecolor{cv7}{rgb}{0.0,0.502,0.0}\definecolor{cfv7}{rgb}{1.0,1.0,1.0}\definecolor{clv7}{rgb}{1.0,0.0,0.0}\definecolor{cv8}{rgb}{0.0,0.502,0.0}\definecolor{cfv8}{rgb}{1.0,1.0,1.0}\definecolor{clv8}{rgb}{1.0,0.0,0.0}\definecolor{cv9}{rgb}{0.0,0.502,0.0}\definecolor{cfv9}{rgb}{1.0,1.0,1.0}\definecolor{clv9}{rgb}{1.0,0.0,0.0}\definecolor{cv10}{rgb}{0.0,0.502,0.0}\definecolor{cfv10}{rgb}{1.0,1.0,1.0}\definecolor{clv10}{rgb}{1.0,0.0,0.0}\definecolor{cv11}{rgb}{0.0,0.502,0.0}\definecolor{cfv11}{rgb}{1.0,1.0,1.0}\definecolor{clv11}{rgb}{1.0,0.0,0.0}\definecolor{cv12}{rgb}{0.0,0.502,0.0}\definecolor{cfv12}{rgb}{1.0,1.0,1.0}\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}(continues on next page)

5.31. LaTeX options for graphs

1807

Graph Theory, Release 10.4

(continued from previous page)\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}%\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}

1808

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> latex(H)\begin{tikzpicture}\definecolor{cv0}{rgb}{0.0,0.502,0.0}\definecolor{cfv0}{rgb}{1.0,1.0,1.0}\definecolor{clv0}{rgb}{1.0,0.0,0.0}\definecolor{cv1}{rgb}{0.0,0.502,0.0}\definecolor{cfv1}{rgb}{1.0,1.0,1.0}\definecolor{clv1}{rgb}{1.0,0.0,0.0}\definecolor{cv2}{rgb}{0.0,0.502,0.0}\definecolor{cfv2}{rgb}{1.0,1.0,1.0}\definecolor{clv2}{rgb}{1.0,0.0,0.0}\definecolor{cv3}{rgb}{0.0,0.502,0.0}\definecolor{cfv3}{rgb}{1.0,1.0,1.0}\definecolor{clv3}{rgb}{1.0,0.0,0.0}\definecolor{cv4}{rgb}{0.0,0.502,0.0}\definecolor{cfv4}{rgb}{1.0,1.0,1.0}\definecolor{clv4}{rgb}{1.0,0.0,0.0}\definecolor{cv5}{rgb}{0.0,0.502,0.0}\definecolor{cfv5}{rgb}{1.0,1.0,1.0}\definecolor{clv5}{rgb}{1.0,0.0,0.0}\definecolor{cv6}{rgb}{0.0,0.502,0.0}\definecolor{cfv6}{rgb}{1.0,1.0,1.0}\definecolor{clv6}{rgb}{1.0,0.0,0.0}\definecolor{cv7}{rgb}{0.0,0.502,0.0}\definecolor{cfv7}{rgb}{1.0,1.0,1.0}\definecolor{clv7}{rgb}{1.0,0.0,0.0}\definecolor{cv8}{rgb}{0.0,0.502,0.0}\definecolor{cfv8}{rgb}{1.0,1.0,1.0}\definecolor{clv8}{rgb}{1.0,0.0,0.0}\definecolor{cv9}{rgb}{0.0,0.502,0.0}\definecolor{cfv9}{rgb}{1.0,1.0,1.0}\definecolor{clv9}{rgb}{1.0,0.0,0.0}\definecolor{cv10}{rgb}{0.0,0.502,0.0}\definecolor{cfv10}{rgb}{1.0,1.0,1.0}\definecolor{clv10}{rgb}{1.0,0.0,0.0}\definecolor{cv11}{rgb}{0.0,0.502,0.0}\definecolor{cfv11}{rgb}{1.0,1.0,1.0}\definecolor{clv11}{rgb}{1.0,0.0,0.0}\definecolor{cv12}{rgb}{0.0,0.502,0.0}\definecolor{cfv12}{rgb}{1.0,1.0,1.0}\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}(continues on next page)

5.31. LaTeX options for graphs

1809

Graph Theory, Release 10.4

(continued from previous page)\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}%\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)(continues on next page)

1810

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)\Edge[lw=0.04cm,style={color=cv8v13,},](v8)(v13)\Edge[lw=0.04cm,style={color=cv9v10,},](v9)(v10)\Edge[lw=0.04cm,style={color=cv10v11,},](v10)(v11)\Edge[lw=0.04cm,style={color=cv11v12,},](v11)(v12)\Edge[lw=0.04cm,style={color=cv12v13,},](v12)(v13)%\end{tikzpicture}

EXAMPLES:This example illustrates switching between the built-in styles when using the tkz_graph format.:sage: g = graphs.PetersenGraph()
sage: g.set_latex_options(tkz_style= Classic )sage: from sage.graphs.graph_latex import check_tkz_graphsage: 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}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.set_latex_options(tkz_style= Classic )>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> latex(g)\begin{tikzpicture}\GraphInit[vstyle=Classic]...
\end{tikzpicture}>>> opts = g.latex_options()>>> opts
LaTeX options for Petersen graph: { tkz_style : Classic }>>> g.set_latex_options(tkz_style = Art )>>> opts.get_option( tkz_style )Art>>> opts
LaTeX options for Petersen graph: { tkz_style : Art }>>> latex(g)\begin{tikzpicture}\GraphInit[vstyle=Art]...
(continues on next page)

5.31. LaTeX options for graphs

1811

Graph Theory, Release 10.4

(continued from previous page)\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_graphsage: check_tkz_graph() # random - depends on TeX installation
sage: latex(g) # optional - dot2tex graphviz\begin{tikzpicture}[>=latex,line join=bevel,]...
\end{tikzpicture}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.set_latex_options(format= dot2tex , prog= neato )>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> 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}>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.set_latex_options(format="dot2tex", edge_options=lambda u_v_label: {"color":
˓→"red"} if u_v_label[Integer(0)] == Integer(0) else {})>>> latex(g) # optional - dot2tex graphviz\begin{tikzpicture}[>=latex,line join=bevel,]...
\end{tikzpicture}

5.31.2 GraphLatex class and functionsclass sage.graphs.graph_latex.GraphLatex(graph, **options)
Bases: 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 reference to it. Second, thisclass contains the code to convert a graph into the corresponding LaTeX constructs, returning a string.
EXAMPLES:
1812

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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>>> from sage.all import *>>> from sage.graphs.graph_latex import GraphLatex>>> opts = GraphLatex(graphs.PetersenGraph())>>> opts
LaTeX options for Petersen graph: {}>>> g = graphs.PetersenGraph()>>> opts = g.latex_options()>>> g == loads(dumps(g))
True

dot2tex_picture()
Call dot2tex to construct a string of LaTeX commands representing a graph as a tikzpicture.
EXAMPLES:
sage: g = digraphs.ButterflyGraph(1)sage: from sage.graphs.graph_latex import check_tkz_graphsage: 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_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) ..␣
˓→(node_...);\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) ..␣
˓→(node_...);\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) ..␣
˓→(node_...);\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) ..␣
˓→(node_...);%\end{tikzpicture}>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(1))>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> print(g.latex_options().dot2tex_picture()) # optional - dot2tex graphviz\begin{tikzpicture}[>=latex,line join=bevel,]%%\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$};(continues on next page)

5.31. LaTeX options for graphs

1813

Graph Theory, Release 10.4

(continued from previous page)\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp)˓→(node_...);\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp)˓→(node_...);\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp)˓→(node_...);\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp)˓→(node_...);%\end{tikzpicture}

..␣
..␣
..␣
..␣

We make sure Issue #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_...) at (...bp,...bp) [draw,draw=none] {$...$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$...$};\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp)˓→(node_...);\definecolor{strokecol}{rgb}{0.0,0.0,0.0};\pgfsetstrokecolor{strokecol}\draw (...bp,...bp) node {$\text{\texttt{my{\char \_}label}}$};%\end{tikzpicture}..␣>>> from sage.all import *>>> G = DiGraph()>>> G.add_edge(Integer(3333), Integer(88), my_label )>>> G.set_latex_options(edge_labels=True)>>> print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz\begin{tikzpicture}[>=latex,line join=bevel,]%%\node (node_...) at (...bp,...bp) [draw,draw=none] {$...$};\node (node_...) at (...bp,...bp) [draw,draw=none] {$...$};\draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) ..␣
˓→(node_...);\definecolor{strokecol}{rgb}{0.0,0.0,0.0};\pgfsetstrokecolor{strokecol}\draw (...bp,...bp) node {$\text{\texttt{my{\char \_}label}}$};%\end{tikzpicture}

Check that Issue #25120 is fixed:
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);(continues on next page)

1814

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)...
\end{tikzpicture}>>> from sage.all import *>>> G = Graph([(Integer(0),Integer(1))])>>> G.set_latex_options(edge_colors = {(Integer(0),Integer(1)): red })>>> print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz\begin{tikzpicture}[>=latex,line join=bevel,]...
\draw [red,] (node_0) ... (node_1);...
\end{tikzpicture}

Note: There is a lot of overlap between what tkz_picture and dot2tex do. It would be best to merge
them! dot2tex probably can work without graphviz if layout information is provided.
get_option(option_name)Return the current value of the named option.
INPUT:• 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 notbeen 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"Truesage: opts.get_option( bad_name )Traceback (most recent call last):...
ValueError: bad_name is not a Latex option for a graph.
>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> opts = g.latex_options()>>> opts.set_option( tkz_style , Art )>>> opts.get_option( tkz_style )Art>>> opts.set_option( tkz_style )>>> opts.get_option( tkz_style ) == "Custom"True>>> opts.get_option( bad_name )Traceback (most recent call last):...
ValueError: bad_name is not a Latex option for a graph.

5.31. LaTeX options for graphs

1815

Graph Theory, Release 10.4

latex()
Return a string in LaTeX representing a graph.
This is the command that is invoked by sage.graphs.generic_graph.GenericGraph.
_latex_ for a graph, so it returns a string of LaTeX commands that can be incorporated into a
LaTeX document 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_graphsage: check_tkz_graph() # random - depends on TeX installation
sage: g = graphs.CompleteGraph(2)sage: opts = g.latex_options()
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}>>> from sage.all import *>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> g = graphs.CompleteGraph(Integer(2))>>> opts = g.latex_options()>>> 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)(continues on next page)

1816

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)%\end{tikzpicture}

We check that Issue #22070 is fixed:
sage: edges = [(i,(i+1)%3,a) for i,a in enumerate( abc )]sage: G_with_labels = DiGraph(edges)
sage: C = [[0,1], [2]]sage: kwds = dict(subgraph_clusters=C,color_by_label=True,prog= dot ,format=
˓→ dot2tex )sage: opts = G_with_labels.latex_options()
sage: opts.set_options(edge_labels=True, **kwds) # optional - dot2tex␣
˓→graphviz
sage: latex(G_with_labels)# optional - dot2tex␣
˓→graphviz\begin{tikzpicture}[>=latex,line join=bevel,]%%\begin{scope}\pgfsetstrokecolor{black}\definecolor{strokecol}{rgb}{...};\pgfsetstrokecolor{strokecol}\definecolor{fillcol}{rgb}{...};\pgfsetfillcolor{fillcol}\filldraw ... cycle;\end{scope}\begin{scope}\pgfsetstrokecolor{black}\definecolor{strokecol}{rgb}{...};\pgfsetstrokecolor{strokecol}\definecolor{fillcol}{rgb}{...};\pgfsetfillcolor{fillcol}\filldraw ... cycle;\end{scope}...
\end{tikzpicture}>>> from sage.all import *>>> edges = [(i,(i+Integer(1))%Integer(3),a) for i,a in enumerate( abc )]>>> G_with_labels = DiGraph(edges)>>> C = [[Integer(0),Integer(1)], [Integer(2)]]>>> kwds = dict(subgraph_clusters=C,color_by_label=True,prog= dot ,format=
˓→ dot2tex )>>> opts = G_with_labels.latex_options()>>> opts.set_options(edge_labels=True, **kwds) # optional - dot2tex graphviz>>> latex(G_with_labels)# optional - dot2tex graphviz\begin{tikzpicture}[>=latex,line join=bevel,]%%\begin{scope}\pgfsetstrokecolor{black}\definecolor{strokecol}{rgb}{...};\pgfsetstrokecolor{strokecol}\definecolor{fillcol}{rgb}{...};\pgfsetfillcolor{fillcol}\filldraw ... cycle;\end{scope}\begin{scope}(continues on next page)

5.31. LaTeX options for graphs

1817

Graph Theory, Release 10.4

(continued from previous page)\pgfsetstrokecolor{black}\definecolor{strokecol}{rgb}{...};\pgfsetstrokecolor{strokecol}\definecolor{fillcol}{rgb}{...};\pgfsetfillcolor{fillcol}\filldraw ... cycle;\end{scope}...
\end{tikzpicture}

set_option(option_name, option_value=None)
Set, modify, clear a LaTeX option for controlling the rendering of a graph.
The possible options are documented here, because ultimately it is this routine that sets the values. However,the sage.graphs.generic_graph.GenericGraph.set_latex_options() method is theeasiest 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 andgraphviz. This is controlled by the option format:• format – string (default: tkz_graph ); either dot2tex or tkz_graph .
If format is dot2tex , then all the LaTeX generation will be delegated to dot2tex (which must be
installed).
For tkz_graph, the possible option names, and associated values are given below. This first group allows
you to set a style for a graph and specify some sizes related to the eventual image. (For more information
consult the documentation for the tkz-graph package.)• tkz_style – string (default: Custom ); the name of a pre-defined tkz-graph style such as
Shade , Art , Normal , Dijkstra , Welsh , Classic , and Simple , or thestring Custom . Using one of these styles alone will often give a reasonably good drawing withminimal effort. For a custom appearance set this to Custom and use the options described below tooverride the default values.
• units – string (default: cm ) – a natural unit of measurement used for all dimensions. Possible values
are: in , mm , cm , pt , em , ex .
• scale – float (default: 1.0); a dimensionless number that multiplies every linear dimension. So you
can design at sizes you are accustomed to, then shrink or expand to meet other needs. Though fonts do
not scale.
• graphic_size – tuple (default: (5, 5)); overall dimensions (width, length) of the bounding box
around the entire graphic image.
• margins – 4-tuple (default: (0, 0, 0, 0)); portion of graphic given over to a plain border as
a tuple of four numbers: (left, right, top, bottom). These are subtracted from the graphic_size tocreate 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.

1818

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

If not using a pre-built style the following options are used, so the following defaults will apply. It is notpossible to begin with a pre-built style and modify it (other than editing the latex string by hand after thefact).
• 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 mustbe 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 theoptions for a tikzpicture.
• vertex_colors – a dictionary whose keys are vertices of the graph and whose values are colors.
These will be used to color the outline of vertices. See the explanation above for the vertex_color
option to see possible values. These values need only be specified for a proper subset of the vertices.
Specified values will supersede a default value.
• vertex_fill_color – (default: white ); a single color to use as the default for the fill color ofvertices. See the explanation above for the vertex_color option to see possible values. This color
is ignored for the sphere vertex shape.
• vertex_fill_colors – a dictionary whose keys are vertices of the graph and whose values are colors. These will be used to fill the interior of vertices. See the explanation above for the vertex_color
option to see possible values. These values need only be specified for a proper subset of the vertices.
Specified values will supersede a default value.
• vertex_shape – string (default: circle ); specifies the shape of the vertices. Allowable values
are circle , sphere , rectangle , diamond . The sphere shape has a 3D look to its
coloring and is uses only one color, that specified by vertex_color and vertex_colors, which
are normally used for the outline of the vertex.
• vertex_shapes – a dictionary whose keys are vertices of the graph and whose values are shapes.
See vertex_shape for the allowable possibilities.
• vertex_size – float (default: 1.0); the minimum size of a vertex as a number. Vertices will expand tocontain 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 – boolean (default: True); determine whether or not to display the vertex labels. If
False subsequent options about vertex labels are ignored.
• vertex_labels_math – boolean (default: True); when True, if a label is a string that begins andends with dollar signs, then the string will be rendered as a latex string. Otherwise, the label will be
automatically 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-complicatedmathematics is not especially robust.
• vertex_label_color – (default: black ); a single color to use as the default for labels ofvertices. 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 arecolors. These will be used for the text of the labels of vertices. See the explanation above for thevertex_color option to see possible values. These values need only be specified for a proper subsetof the vertices. Specified values will supersede a default value.
• vertex_label_placement – (default: center ); if center the label is centered in theinterior of the vertex and the vertex will expand to contain the label. Giving instead a pair of numbers

5.31. LaTeX options for graphs

1819

Graph Theory, Release 10.4

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 explanation 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 willsupersede a default value.
• edge_fills – boolean (default: False); whether 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 ofan edge. The boolean switch edge_fills must be set to True for this to have an effect. See theexplanation 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 – float (default: 0.1); specifies the width of the edges. Note that tkz-graphdoes 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 – boolean (default: False); determine if edge labels are shown. If False subsequent
options about edge labels are ignored.
• edge_labels_math – boolean (default: True); control how edge labels are rendered. Readthe explanation for the vertex_labels_math option, which behaves identically. Support forarbitrarily-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 – boolean (default: True); specifies how edge labels are place. False results
in a horizontal label, while True means the label is rotated to follow the direction of the edge it labels.
• edge_label_slopes – a dictionary of booleans, indexed by some subset of the edges. See theedge_label_sloped option for a description of sloped edge labels.
• edge_label_placement – (default: 0.50); either a number between 0.0 and 1.0, or one of:above , below , left , right . These adjust the location of an edge label along an edge. A
number specifies how far along the edge the label is located. left and right are conveniences.
above and below move the label off the edge itself while leaving it near the midpoint of theedge. 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 theedge_label_placement option for a description of the allowable values.

1820

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• loop_placement – (default: (3.0, NO )); determine how loops are rendered. the first elementof 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 theallowable values. While loops are technically edges, this dictionary is indexed by vertices.
For the dot2tex format, the possible option names and associated values are given below:• prog – string; the program used for the layout. It must be a string corresponding to one of the softwareof the graphviz suite: dot , neato , twopi , circo or fdp .
• edge_labels – boolean (default: False); whether to display the labels on edges.
• edge_colors – a color; can be used to set a global color to the edge of the graph.
• color_by_label – boolean (default: False); colors the edges according to their labels• subgraph_clusters – (default: []) a list of lists of vertices, if supported by the layout engine,nodes belonging to the same cluster subgraph are drawn together, with the entire drawing of the cluster
contained within a bounding rectangle.
OUTPUT:
There are none. Success happens silently.
EXAMPLES:
Set, then modify, then clear the tkz_style option, and finally show an error for an unrecognized option
name:sage: g = graphs.PetersenGraph()
sage: opts = g.latex_options()
sage: opts
LaTeX options for Petersen graph: {}sage: opts.set_option( tkz_style , Art )sage: opts
LaTeX options for Petersen graph: { tkz_style : Art }sage: opts.set_option( tkz_style , Simple )sage: opts
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.
>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> opts = g.latex_options()>>> opts
LaTeX options for Petersen graph: {}>>> opts.set_option( tkz_style , Art )>>> opts
LaTeX options for Petersen graph: { tkz_style :>>> opts.set_option( tkz_style , Simple )>>> opts
LaTeX options for Petersen graph: { tkz_style :>>> opts.set_option( tkz_style )Art }Simple }(continues on next page)

5.31. LaTeX options for graphs

1821

Graph Theory, Release 10.4

(continued from previous page)>>> opts
LaTeX options for Petersen graph: {}>>> 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. Furthermore, pgf >= 2.00 should be available inside LaTeX’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/• 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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> opts = g.latex_options()>>> opts.set_options(tkz_style= Welsh )>>> opts.get_option( tkz_style )Welshtkz_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 alsoneed a current version of the pgf package. If the tkz-graph and tkz-berge packages are present in
the system’s TeX installation, the appropriate \\usepackage{} commands will be added to the LaTeX
preamble as part of the initialization of the graph. If these two packages are not present, then this command
will return a warning on its first use, but will return a string that could be used elsewhere, such as a LaTeX
document.
For more information about tkz-graph you can visit https://www.ctan.org/pkg/tkz-graph.
EXAMPLES:
1822

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

With a pre-built tkz-graph style specified, the latex representation will be relatively simple.
sage: from sage.graphs.graph_latex import check_tkz_graphsage: 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}>>> from sage.all import *>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> g = graphs.CompleteGraph(Integer(3))>>> opts = g.latex_options()>>> g.set_latex_options(tkz_style= Art )>>> 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}

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_graphsage: 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}(continues on next page)

5.31. LaTeX options for graphs

1823

Graph Theory, Release 10.4

(continued from previous page)\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}>>> from sage.all import *>>> from sage.graphs.graph_latex import check_tkz_graph>>> check_tkz_graph() # random - depends on TeX installation>>> g = graphs.CompleteGraph(Integer(3))>>> opts = g.latex_options()>>> g.set_latex_options(tkz_style= Custom )>>> 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()
Check if the proper LaTeX packages for the tikzpicture environment are installed in the user’s environment,
1824

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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-graphpackages should call this once as having random output to exhaust the warnings before testing output.
See also sage.misc.latex.Latex.check_file()
sage.graphs.graph_latex.have_tkz_graph()
Return True if the proper LaTeX packages for the tikzpicture environment are installed in the user’s 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()
Add appropriate \usepackage{...}, and other instructions to the latex preamble for the packages that areneeded for processing graphs(tikz, tkz-graph, tkz-berge), if available in the LaTeX installation.
See also sage.misc.latex.Latex.add_package_to_preamble_if_available().
EXAMPLES:
sage: sage.graphs.graph_latex.setup_latex_preamble()>>> from sage.all import *>>> sage.graphs.graph_latex.setup_latex_preamble()

5.32 Graph editor widget
This module adds an interface to phitigra, a graph editor widget for Jupyter and JupyterLab. The phitigra optional
package should be installed on your Sage installation.
AUTHORS:• Radoslav Kirov (2009): initial editor for use with the old sage notebook• Jean-Florent Raymond (2022-04-12): replacement with the phitigra package
sage.graphs.graph_editor.graph_editor(graph=None, **display_options)
Return a graph editor widget.
The graph editor widget can be displayed with Jupyter or JupyterLab. It is provided by the phitigra optional package, see https://github.com/jfraymond/phitigra for details about the possible options (changing thewidth/height of the canvas, the default size and color of vertices, etc.).
INPUT:• graph – a graph to edit (default: None)• display_options – options for the widget
EXAMPLES:
sage: e = graph_editor()sage: e.show()>>> from sage.all import *>>> e = graph_editor()>>> e.show()

5.32. Graph editor widget# optional - phitigra# not tested# optional - phitigra# not tested

1825

Graph Theory, Release 10.4

Opening an existing graph:
sage: G = graphs.RandomGNP(10, 0.5)
sage: e = graph_editor(G)# optional - phitigra
sage: e.show()# not tested>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(10), RealNumber( 0.5 ))>>> e = graph_editor(G)# optional - phitigra>>> e.show()# not tested

Retrieving a copy of the drawn graph:
sage: G = graphs.RandomGNP(10, 0.5)
sage: e = graph_editor(G)# optional - phitigra
sage: H = e.get_graph()# optional - phitigra
sage: H == G and not H is G
# optional - phitigra
True>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(10), RealNumber( 0.5 ))>>> e = graph_editor(G)# optional - phitigra>>> H = e.get_graph()# optional - phitigra>>> H == G and not H is G
# optional - phitigra
True

Using different display options:sage: e = graph_editor(graphs.PetersenGraph(), width=300, height=300,#␣˓→optional - phitigra....:
default_radius=12, default_vertex_color= orange ,....:default_edge_color= #666 , show_vertex_labels=False)
sage: e.show()# not␣
˓→tested>>> from sage.all import *>>> e = graph_editor(graphs.PetersenGraph(), width=Integer(300),␣
˓→height=Integer(300),# optional - phitigra...
default_radius=Integer(12), default_vertex_color= orange ,...
default_edge_color= #666 , show_vertex_labels=False)>>> e.show()# not␣
˓→tested

Note: The editor does not support multigraphs.

1826

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.33 Lists of graphs
AUTHORS:• Robert L. Miller (2007-02-10): initial version• Emily A. Kirkman (2007-02-13): added show functions (to_graphics_array and show_graphs)
sage.graphs.graph_list.from_graph6(data)
Return a list of Sage Graphs, given a list of graph6 data.
INPUT:• data – can be a string, a list of strings, or a file stream
EXAMPLES:
sage: 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]>>> from sage.all import *>>> l = [ N@@?N@UGAGG?gGlKCMO , XsGGWOW?CC?C@HQKHqOjYKC_uHWGX?P?~
˓→TqIKA OA@SAOEcEA?? ]>>> graphs_list.from_graph6(l)[Graph on 15 vertices, Graph on 25 vertices]sage.graphs.graph_list.from_sparse6(data)
Return a list of Sage Graphs, given a list of sparse6 data.
INPUT:• data – can be a string, a list of strings, or a file stream
EXAMPLES:
sage: g1 = :P_ cBaC_ACd C_@BC ABDHaEH_@BF_@CHIK_@BCEHKL_BIKM_BFGHI
sage: g2 = :f ??KO?B_OOSCGE_?OWONDBO?GOJBDO?_SSJdApcOIG ?og_UKEbg?_SKF
sage: g2 += q@[CCBA p?oYMFp@gw]Qaa@xEMHDb@hMCBCbQ@ECHEcAKKQKFPOwo[PIDQ
sage: g2 += {KIHEcQPOkVKEW_WMNKqPWwcRKOOWSKIGCqhWt??___WMJFCahWzEBa xO
sage: g2 += u[MpPPKqYNoOOOKHHDBPs|??__gWMKEcAHKgTLErqA?A@a@G{kVLErs?GD
sage: g2 += BA@XCs\NggWSOJIDbHh@?A@aF
sage: graphs_list.from_sparse6([g1, g2])
[Looped multi-graph on 17 vertices, Looped multi-graph on 39 vertices]>>> from sage.all import *>>> g1 = :P_ cBaC_ACd C_@BC ABDHaEH_@BF_@CHIK_@BCEHKL_BIKM_BFGHI>>> g2 = :f ??KO?B_OOSCGE_?OWONDBO?GOJBDO?_SSJdApcOIG ?og_UKEbg?_SKF>>> g2 += q@[CCBA p?oYMFp@gw]Qaa@xEMHDb@hMCBCbQ@ECHEcAKKQKFPOwo[PIDQ>>> g2 += {KIHEcQPOkVKEW_WMNKqPWwcRKOOWSKIGCqhWt??___WMJFCahWzEBa xO>>> g2 += u[MpPPKqYNoOOOKHHDBPs|??__gWMKEcAHKgTLErqA?A@a@G{kVLErs?GD>>> g2 += BA@XCs\NggWSOJIDbHh@?A@aF>>> graphs_list.from_sparse6([g1, g2])
[Looped multi-graph on 17 vertices, Looped multi-graph on 39 vertices]sage.graphs.graph_list.from_whatever(data)
Return a list of Sage Graphs, given a list of whatever kind of data.
INPUT:
5.33. Lists of graphs

1827

Graph Theory, Release 10.4

• 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]>>> from sage.all import *>>> l = [ N@@?N@UGAGG?gGlKCMO , :P_ cBaC_ACd C_@BC ABDHaEH_@BF_@CHIK_@BCEHKL_
˓→BIKM_BFGHI ]>>> graphs_list.from_whatever(l)[Graph on 15 vertices, Looped multi-graph on 17 vertices]>>> 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]>>> from sage.all import *>>> filename = tmp_filename()>>> with open(filename, w ) as fobj:...
_ = fobj.write( \n .join(l))>>> with open(filename) as fobj:...
graphs_list.from_whatever(fobj)[Graph on 15 vertices, Looped multi-graph on 17 vertices]sage.graphs.graph_list.show_graphs(graph_list, **kwds)
Show a maximum of 20 graphs from graph_list in a sage graphics array.
If more than 20 graphs are given in the list argument, then it will display one graphics array after another with eachcontaining at most 20 graphs.
Note that to save the image output from the notebook, you must save each graphics array individually. (There will
be a small space between graphics arrays).
INPUT:• graph_list – a Python list of Sage Graphs
GRAPH PLOTTING: Defaults to circular layout for graphs. This allows for a nicer display in a small area andtakes 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))(continues on next page)

1828

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: glist.append(graphs.CycleGraph(15))
sage: glist.append(graphs.DiamondGraph())
sage: glist.append(graphs.GemGraph())
sage: glist.append(graphs.DartGraph())
sage: glist.append(graphs.ForkGraph())
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))>>> from sage.all import *>>> glist = []>>> glist.append(graphs.CompleteGraph(Integer(6)))>>> glist.append(graphs.CompleteBipartiteGraph(Integer(4), Integer(5)))>>> glist.append(graphs.BarbellGraph(Integer(7), Integer(4)))>>> glist.append(graphs.CycleGraph(Integer(15)))>>> glist.append(graphs.DiamondGraph())>>> glist.append(graphs.GemGraph())>>> glist.append(graphs.DartGraph())>>> glist.append(graphs.ForkGraph())>>> glist.append(graphs.HouseGraph())>>> glist.append(graphs.HouseXGraph())>>> glist.append(graphs.KrackhardtKiteGraph())>>> glist.append(graphs.LadderGraph(Integer(5)))>>> glist.append(graphs.LollipopGraph(Integer(5), Integer(6)))>>> glist.append(graphs.PathGraph(Integer(15)))>>> glist.append(graphs.PetersenGraph())>>> glist.append(graphs.StarGraph(Integer(17)))>>> glist.append(graphs.WheelGraph(Integer(9)))

Check that length is <= 20:
sage: len(glist)17>>> from sage.all import *>>> len(glist)
17

Show the graphs in a graphics array:sage: graphs_list.show_graphs(glist)
˓→needs sage.plot>>> from sage.all import *>>> graphs_list.show_graphs(glist)
˓→needs sage.plot#␣#␣

Example where more than one graphics array is used:

5.33. Lists of graphs

1829

Graph Theory, Release 10.4

sage: gq = GraphQuery(display_cols=[ graph6 ], num_vertices=5)
sage: g = gq.get_graphs_list()
sage: len(g)34sage: graphs_list.show_graphs(g)˓→needs sage.plot#␣>>> from sage.all import *>>> gq = GraphQuery(display_cols=[ graph6 ], num_vertices=Integer(5))>>> g = gq.get_graphs_list()>>> len(g)34>>> graphs_list.show_graphs(g)˓→needs sage.plot#␣

See the .plot() or .show() documentation for an individual graph for options, all of which are available fromto_graphics_array():
sage: glist = []sage: for _ in range(10):˓→needs networkx....:
glist.append(graphs.RandomLobster(41, .3, .4))
sage: graphs_list.show_graphs(glist, layout= spring , vertex_size=20)
˓→needs sage.plot>>> from sage.all import *>>> glist = []>>> for _ in range(Integer(10)):˓→# needs networkx...
glist.append(graphs.RandomLobster(Integer(41), RealNumber( .3 ),␣
˓→RealNumber( .4 )))>>> graphs_list.show_graphs(glist, layout= spring , vertex_size=Integer(20))˓→# needs sage.plot

#␣

#␣

␣

␣

sage.graphs.graph_list.to_graph6(graphs, file=None, output_list=False)
Convert 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• file – (optional) a file stream to write to (must be in ‘w’ mode)• output_list – boolean (default: False); whether to return a string (when set to True) or a list of
strings. This parameter is 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>>> from sage.all import *>>> l = [graphs.DodecahedralGraph(), graphs.PetersenGraph()](continues on next page)

1830

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> graphs_list.to_graph6(l)ShCHGD@?K?_@?@?C_GGG@??cG?G?GK_?C\nIheA@GUAo\nsage.graphs.graph_list.to_graphics_array(graph_list, **kwds)
Draw all graphs in a graphics array
INPUT:• graph_list – a Python list of Sage Graphs
GRAPH PLOTTING:
Defaults to circular layout for graphs. This allows for a nicer display in a small area and takes much less time tocompute 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)
˓→needs sage.plot
sage: garray.nrows(), garray.ncols()
˓→needs sage.plot(250, 4)>>> from sage.all import *>>> glist = []>>> for i in range(Integer(999)):...
glist.append(graphs.RandomGNP(Integer(6), RealNumber( .45 )))>>> garray = graphs_list.to_graphics_array(glist)
˓→needs sage.plot>>> garray.nrows(), garray.ncols()
˓→needs sage.plot(250, 4)

#␣
#␣

#␣
#␣

See the .plot() or .show() documentation for an individual graph for options, all of which are available fromto_graphics_array():
sage: glist = []sage: for _ in range(10):˓→needs networkx....:
glist.append(graphs.RandomLobster(41, .3, .4))
sage: graphs_list.to_graphics_array(glist, layout= spring , vertex_size=20)
˓→needs networkx sage.plot
Graphics Array of size 3 x 4>>> from sage.all import *>>> glist = []>>> for _ in range(Integer(10)):˓→# needs networkx...
glist.append(graphs.RandomLobster(Integer(41), RealNumber( .3 ),␣
˓→RealNumber( .4 )))>>> graphs_list.to_graphics_array(glist, layout= spring , vertex_
˓→size=Integer(20))# needs networkx sage.plot
Graphics Array of size 3 x 4

5.33. Lists of graphs

#␣

#␣

␣

1831

Graph Theory, Release 10.4

sage.graphs.graph_list.to_sparse6(graphs, file=None, output_list=False)
Convert 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:• graphs – a Python list of Sage Graphs• file – (optional) a file stream to write to (must be in ‘w’ mode)• output_list – boolean (default: False); whether to return a string (when set to True) or a list of
strings. This parameter is 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>>> from sage.all import *>>> l = [graphs.DodecahedralGraph(), graphs.PetersenGraph()]>>> graphs_list.to_sparse6(l):S_ abcaDe Fg_HijhKfLdMkNcOjP_BQ\n:I ES@obGkqegW~\n5.34 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 theconstructors of Graph and DiGraph.
Note that because they are called by the constructors of Graph and DiGraph, most of these functions modify a graphinplace.
from_adjacency_matrix()from_dict_of_dicts()
from_dict_of_lists()
from_dig6()
from_graph6()
from_incidence_matrix()from_networkx_graph()from_oriented_incidence_matrix()from_seidel_adjacency_matrix()from_sparse6()

1832

Fill G with the data of an adjacency matrix.
Fill G with the data of a dictionary of dictionaries.
Fill G with the data of a dictionary of lists.
Fill G with the data of a dig6 string.
Fill G with the data of a graph6 string.
Fill G with the data of an incidence matrix.
Fill 𝐺 with the data of a NetworkX (di)graph.
Fill G with the data of an oriented incidence matrix.
Fill G with the data of a Seidel adjacency matrix.
Fill G with the data of a sparse6 string.

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

5.34.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 (default: False); whether to consider the graph as havingloops, multiple edges, or weights
EXAMPLES:
sage: from sage.graphs.graph_input import from_adjacency_matrix
sage: g = Graph()
sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix())
˓→needs sage.modules
sage: g.is_isomorphic(graphs.PetersenGraph())˓→needs sage.modules
True>>> from sage.all import *>>> from sage.graphs.graph_input import from_adjacency_matrix>>> g = Graph()>>> from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix())
˓→needs sage.modules>>> g.is_isomorphic(graphs.PetersenGraph())˓→needs sage.modules
True

#␣
#␣

#␣
#␣

sage.graphs.graph_input.from_dict_of_dicts(G, M, loops=False, multiedges=False,
weighted=False,
convert_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 (default: False); whether to consider the graph as havingloops, multiple edges, or weights• convert_empty_dict_labels_to_None – booleans (default: False); 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

5.34. Functions for reading/building graphs/digraphs

1833

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_input import from_dict_of_dicts>>> g = Graph()>>> from_dict_of_dicts(g, graphs.PetersenGraph().to_dictionary(edge_labels=True))>>> g.is_isomorphic(graphs.PetersenGraph())
True

The resulting order of vertices is unspecified but deterministic:
sage: from sage.graphs.graph_input import from_dict_of_dicts
sage: g = Graph()
sage: from_dict_of_dicts(g, {i: {} for i in range(99, 90, -1)})
sage: g.vertices(sort=False)[99, 98, 97, 96, 95, 94, 93, 92, 91]>>> from sage.all import *>>> from sage.graphs.graph_input import from_dict_of_dicts>>> g = Graph()>>> from_dict_of_dicts(g, {i: {} for i in range(Integer(99), Integer(90), ˓→Integer(1))})>>> g.vertices(sort=False)[99, 98, 97, 96, 95, 94, 93, 92, 91]

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 (default: False); whether to consider the graph as havingloops, multiple edges, or weights
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>>> from sage.all import *>>> from sage.graphs.graph_input import from_dict_of_lists>>> g = Graph()>>> from_dict_of_lists(g, graphs.PetersenGraph().to_dictionary())>>> g.is_isomorphic(graphs.PetersenGraph())
True

The resulting order of vertices is unspecified but deterministic:
sage: from sage.graphs.graph_input import from_dict_of_lists
sage: g = Graph()
sage: from_dict_of_lists(g, {i: [] for i in range(99, 90, -1)})
sage: g.vertices(sort=False)[99, 98, 97, 96, 95, 94, 93, 92, 91]

1834

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.graph_input import from_dict_of_lists>>> g = Graph()>>> from_dict_of_lists(g, {i: [] for i in range(Integer(99), Integer(90), ˓→Integer(1))})>>> g.vertices(sort=False)[99, 98, 97, 96, 95, 94, 93, 92, 91]

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>>> from sage.all import *>>> from sage.graphs.graph_input import from_dig6>>> g = DiGraph()>>> from_dig6(g, digraphs.Circuit(Integer(10)).dig6_string())>>> g.is_isomorphic(digraphs.Circuit(Integer(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:
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>>> from sage.all import *>>> from sage.graphs.graph_input import from_graph6>>> g = Graph()>>> from_graph6(g, IheA@GUAo )>>> 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.
5.34. Functions for reading/building graphs/digraphs

1835

Graph Theory, Release 10.4

INPUT:• G – a graph• M – an incidence matrix• loops, multiedges, weighted – booleans (default: False); whether to consider the graph as havingloops, multiple edges, or weights
EXAMPLES:
sage: from sage.graphs.graph_input import from_incidence_matrix
sage: g = Graph()
sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix())
˓→needs sage.modules
sage: g.is_isomorphic(graphs.PetersenGraph())˓→needs sage.modules
True>>> from sage.all import *>>> from sage.graphs.graph_input import from_incidence_matrix>>> g = Graph()>>> from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix())
˓→needs sage.modules>>> g.is_isomorphic(graphs.PetersenGraph())˓→needs sage.modules
True

#␣
#␣

#␣
#␣

sage.graphs.graph_input.from_networkx_graph(G, gnx, weighted=None, loops=None,
multiedges=None,convert_empty_dict_labels_to_None=None)
Fill 𝐺 with the data of a NetworkX (di)graph.
INPUT:• G – a Graph or DiGraph• gnx – a NetworkX Graph, MultiGraph, DiGraph or MultiDiGraph• weighted – boolean (default: None); whether graph thinks of itself as weighted or not.
weighted().

See• loops – boolean (default: None); whether to allow loops• multiedges – boolean (default: None); whether to allow multiple edges• convert_empty_dict_labels_to_None – boolean (default: None); whether to replace the default
edge labels used by NetworkX (empty dictionaries) by None, the default Sage edge label. When set to
False, empty dictionaries are not converted to None.
EXAMPLES:
Feeding a Graph with a NetworkX Graph:
sage: # needs networkx
sage: from sage.graphs.graph_input import from_networkx_graphsage: import networkx
sage: G = Graph()
sage: _ = gnx = networkx.Graph()
sage: _ = gnx.add_edge(0, 1)
sage: _ = gnx.add_edge(1, 2)(continues on next page)

1836

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: from_networkx_graph(G, gnx)
sage: G.edges(sort=True, labels=False)[(0, 1), (1, 2)]>>> from sage.all import *>>> # needs networkx>>> from sage.graphs.graph_input import from_networkx_graph>>> import networkx>>> G = Graph()>>> _ = gnx = networkx.Graph()>>> _ = gnx.add_edge(Integer(0), Integer(1))>>> _ = gnx.add_edge(Integer(1), Integer(2))>>> from_networkx_graph(G, gnx)>>> G.edges(sort=True, labels=False)[(0, 1), (1, 2)]

Feeding a Graph with a NetworkX MultiGraph:
sage: # needs networkx
sage: G = Graph()
sage: gnx = networkx.MultiGraph()
sage: _ = gnx.add_edge(0, 1)
sage: _ = gnx.add_edge(0, 1)
sage: from_networkx_graph(G, gnx)
sage: G.edges(sort=True, labels=False)[(0, 1), (0, 1)]
sage: G = Graph()
sage: from_networkx_graph(G, gnx, multiedges=False)
sage: G.edges(sort=True, labels=False)[(0, 1)]>>> from sage.all import *>>> # needs networkx>>> G = Graph()>>> gnx = networkx.MultiGraph()>>> _ = gnx.add_edge(Integer(0), Integer(1))>>> _ = gnx.add_edge(Integer(0), Integer(1))>>> from_networkx_graph(G, gnx)>>> G.edges(sort=True, labels=False)[(0, 1), (0, 1)]>>> G = Graph()>>> from_networkx_graph(G, gnx, multiedges=False)>>> G.edges(sort=True, labels=False)[(0, 1)]

When feeding a Graph 𝐺 with a NetworkX DiGraph 𝐷, 𝐺 has one edge (𝑢, 𝑣) whenever 𝐷 has arc (𝑢, 𝑣) or(𝑣, 𝑢) or both:
sage: # needs networkx
sage: G = Graph()
sage: D = networkx.DiGraph()
sage: _ = D.add_edge(0, 1)
sage: from_networkx_graph(G, D)
sage: G.edges(sort=True, labels=False)[(0, 1)]
sage: G = Graph()(continues on next page)

5.34. Functions for reading/building graphs/digraphs

1837

Graph Theory, Release 10.4

(continued from previous page)

sage: _ = D.add_edge(1, 0)
sage: from_networkx_graph(G, D)
sage: G.edges(sort=True, labels=False)[(0, 1)]>>> from sage.all import *>>> # needs networkx>>> G = Graph()>>> D = networkx.DiGraph()>>> _ = D.add_edge(Integer(0), Integer(1))>>> from_networkx_graph(G, D)>>> G.edges(sort=True, labels=False)[(0, 1)]>>> G = Graph()>>> _ = D.add_edge(Integer(1), Integer(0))>>> from_networkx_graph(G, D)>>> G.edges(sort=True, labels=False)[(0, 1)]

When feeding a Graph 𝐺 with a NetworkX MultiDiGraph 𝐷, the number of edges between 𝑢 and 𝑣 in 𝐺 is
the maximum between the number of arcs (𝑢, 𝑣) and the number of arcs (𝑣, 𝑢) in D`:
sage: # needs networkx
sage: G = Graph()
sage: D = networkx.MultiDiGraph()
sage: _ = D.add_edge(0, 1)
sage: _ = D.add_edge(1, 0)
sage: _ = D.add_edge(1, 0)
sage: D.edges()
OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)])sage: from_networkx_graph(G, D)
sage: G.edges(sort=True, labels=False)[(0, 1), (0, 1)]>>> from sage.all import *>>> # needs networkx>>> G = Graph()>>> D = networkx.MultiDiGraph()>>> _ = D.add_edge(Integer(0), Integer(1))>>> _ = D.add_edge(Integer(1), Integer(0))>>> _ = D.add_edge(Integer(1), Integer(0))>>> D.edges()
OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)])>>> from_networkx_graph(G, D)>>> G.edges(sort=True, labels=False)[(0, 1), (0, 1)]

Feeding a DiGraph with a NetworkX DiGraph:
sage: # needs networkx
sage: from sage.graphs.graph_input import from_networkx_graphsage: import networkx
sage: G = DiGraph()
sage: _ = gnx = networkx.DiGraph()
sage: _ = gnx.add_edge(0, 1)
sage: _ = gnx.add_edge(1, 2)(continues on next page)

1838

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: from_networkx_graph(G, gnx)
sage: G.edges(sort=True, labels=False)[(0, 1), (1, 2)]>>> from sage.all import *>>> # needs networkx>>> from sage.graphs.graph_input import from_networkx_graph>>> import networkx>>> G = DiGraph()>>> _ = gnx = networkx.DiGraph()>>> _ = gnx.add_edge(Integer(0), Integer(1))>>> _ = gnx.add_edge(Integer(1), Integer(2))>>> from_networkx_graph(G, gnx)>>> G.edges(sort=True, labels=False)[(0, 1), (1, 2)]

Feeding a DiGraph with a NetworkX MultiDiGraph:
sage: # needs networkx
sage: G = DiGraph()
sage: gnx = networkx.MultiDiGraph()
sage: _ = gnx.add_edge(0, 1)
sage: _ = gnx.add_edge(0, 1)
sage: from_networkx_graph(G, gnx)
sage: G.edges(sort=True, labels=False)[(0, 1), (0, 1)]
sage: G = DiGraph()
sage: from_networkx_graph(G, gnx, multiedges=False)
sage: G.edges(sort=True, labels=False)[(0, 1)]>>> from sage.all import *>>> # needs networkx>>> G = DiGraph()>>> gnx = networkx.MultiDiGraph()>>> _ = gnx.add_edge(Integer(0), Integer(1))>>> _ = gnx.add_edge(Integer(0), Integer(1))>>> from_networkx_graph(G, gnx)>>> G.edges(sort=True, labels=False)[(0, 1), (0, 1)]>>> G = DiGraph()>>> from_networkx_graph(G, gnx, multiedges=False)>>> G.edges(sort=True, labels=False)[(0, 1)]

When feeding a DiGraph 𝐺 with a NetworkX Graph 𝐻, 𝐺 has both arcs (𝑢, 𝑣) and (𝑣, 𝑢) if 𝐺 has edge (𝑢, 𝑣):
sage: # needs networkx
sage: G = DiGraph()
sage: H = networkx.Graph()
sage: _ = H.add_edge(0, 1)
sage: from_networkx_graph(G, H)
sage: G.edges(labels=False, sort=True)[(0, 1), (1, 0)]5.34. Functions for reading/building graphs/digraphs

1839

Graph Theory, Release 10.4>>> from sage.all import *>>> # needs networkx>>> G = DiGraph()>>> H = networkx.Graph()>>> _ = H.add_edge(Integer(0), Integer(1))>>> from_networkx_graph(G, H)>>> G.edges(labels=False, sort=True)[(0, 1), (1, 0)]

When feeding a DiGraph 𝐺 with a NetworkX MultiGraph 𝐻, 𝐺 has 𝑘 arcs (𝑢, 𝑣) and 𝑘 arcs (𝑣, 𝑢) if 𝐻 has𝑘 edges (𝑢, 𝑣), unless parameter multiedges is set to False:
sage: # needs networkx
sage: G = DiGraph()
sage: H = networkx.MultiGraph()
sage: _ = H.add_edge(0, 1)
sage: _ = H.add_edge(0, 1)
sage: _ = H.add_edge(0, 1)
sage: H.edges()
MultiEdgeDataView([(0, 1), (0, 1), (0, 1)])
sage: from_networkx_graph(G, H)
sage: G.edges(labels=False, sort=True)[(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)]
sage: G = DiGraph()
sage: from_networkx_graph(G, H, multiedges=False)
sage: G.edges(labels=False, sort=True)[(0, 1), (1, 0)]>>> from sage.all import *>>> # needs networkx>>> G = DiGraph()>>> H = networkx.MultiGraph()>>> _ = H.add_edge(Integer(0), Integer(1))>>> _ = H.add_edge(Integer(0), Integer(1))>>> _ = H.add_edge(Integer(0), Integer(1))>>> H.edges()
MultiEdgeDataView([(0, 1), (0, 1), (0, 1)])>>> from_networkx_graph(G, H)>>> G.edges(labels=False, sort=True)[(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)]>>> G = DiGraph()>>> from_networkx_graph(G, H, multiedges=False)>>> G.edges(labels=False, sort=True)[(0, 1), (1, 0)]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 corresponds
to a +1 and a −1, indicating its source and destination.
INPUT:• G – a DiGraph• M – an incidence matrix

1840

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• loops, multiedges, weighted – booleans (default: False); whether to consider the graph as havingloops, multiple edges, or weights
Note: weighted is currently ignored.
EXAMPLES:
sage: from sage.graphs.graph_input import from_oriented_incidence_matrix
sage: g = DiGraph()
sage: im = digraphs.Circuit(10).incidence_matrix()
˓→needs sage.modules
sage: from_oriented_incidence_matrix(g, im)˓→needs sage.modules
sage: g.is_isomorphic(digraphs.Circuit(10))˓→needs sage.modules
True>>> from sage.all import *>>> from sage.graphs.graph_input import from_oriented_incidence_matrix>>> g = DiGraph()>>> im = digraphs.Circuit(Integer(10)).incidence_matrix()˓→# needs sage.modules>>> from_oriented_incidence_matrix(g, im)˓→needs sage.modules>>> g.is_isomorphic(digraphs.Circuit(Integer(10)))˓→# needs sage.modules
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:
sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix
sage: g = Graph()
sage: sam = graphs.PetersenGraph().seidel_adjacency_matrix()
˓→needs sage.modules
sage: from_seidel_adjacency_matrix(g, sam)
˓→needs sage.modules
sage: g.is_isomorphic(graphs.PetersenGraph())˓→needs sage.modules
True>>> from sage.all import *>>> from sage.graphs.graph_input import from_seidel_adjacency_matrix>>> g = Graph()>>> sam = graphs.PetersenGraph().seidel_adjacency_matrix()
˓→needs sage.modules>>> from_seidel_adjacency_matrix(g, sam)
˓→needs sage.modules>>> g.is_isomorphic(graphs.PetersenGraph())

#␣
#␣
#␣

#␣
#␣
#␣
(continues on next page)

5.34. Functions for reading/building graphs/digraphs

1841

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules
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>>> from sage.all import *>>> from sage.graphs.graph_input import from_sparse6>>> g = Graph()>>> from_sparse6(g, :I ES@obGkqegW~ )>>> g.is_isomorphic(graphs.PetersenGraph())
True

5.35 Hyperbolicity
Definition :The hyperbolicity 𝛿 of a graph 𝐺 has been defined by Gromov [Gro1987] as follows (we give here theso-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𝛿(𝐺) =

1maxℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑)
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

1842

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• Chordal graphs are ≤ 1-hyperbolic
Besides, the hyperbolicity of a graph is the maximum over all its biconnected components.
Algorithms and complexity :The time complexity of the naive implementation (i.e. testing all 4-tuples) is 𝑂(𝑛4 ), and an algorithm withtime complexity 𝑂(𝑛3.69 ) has been proposed in [FIV2012]. This remains very long for large-scale graphs,
and much harder to implement.
Several improvements over the naive algorithm have been proposed and are implemented in the current
module.
• Another upper bound on ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑) has been proved in [CCL2015]. It is used to design an algorithm 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 asa multiplicative approximation factor or an additive one is proven.
• The notion of ‘’far-apart pairs’’ has been introduced in [Sot2011] to further reduce the number of
4-tuples to consider. We say that the pair (𝑎, 𝑏) is far-apart if for every 𝑤 in 𝑉 ∖ {𝑎, 𝑏} we have𝑑𝑖𝑠𝑡(𝑤, 𝑎) + 𝑑𝑖𝑠𝑡(𝑎, 𝑏) > 𝑑𝑖𝑠𝑡(𝑤, 𝑏) and 𝑑𝑖𝑠𝑡(𝑤, 𝑏) + 𝑑𝑖𝑠𝑡(𝑎, 𝑏) > 𝑑𝑖𝑠𝑡(𝑤, 𝑎)
Determining the set of far-apart pairs can be done in time 𝑂(𝑛𝑚) using BFS. Now, it is proved in[Sot2011] that there exists two far-apart pairs (𝑎, 𝑏) and (𝑐, 𝑑) satisfying 𝛿(𝐺) = ℎ𝑦𝑝(𝑎, 𝑏, 𝑐, 𝑑)/2. For
instance, the 𝑛 × 𝑚-grid has only two far-apart pairs, and so computing its hyperbolicity is immediate
once the far-apart pairs are found. The ‘CCL+FA’ or ‘CCL+’ algorithm improves the ‘CCL’ algorithm
since it uses far-apart pairs.
• This algorithm was further improved in [BCCM2015]: instead of iterating twice over all pairs of vertices, in the “inner” loop, we cut several pairs by exploiting properties of the underlying graph.
Todo:• Add exact methods for the hyperbolicity of chordal graphs• Add method for partitioning the graph with clique separators
5.35. Hyperbolicity

1843

Graph Theory, Release 10.4

This module contains the following functions
At Python level :hyperbolicity()
hyperbolicity_distribution()

Return the hyperbolicity of the graph or an approximation of this value.
Return the hyperbolicity distribution of the graph or a sampling of it.

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.35.1 Methods
sage.graphs.hyperbolicity.hyperbolicity(G, algorithm='BCCM', approximation_factor=None,
additive_gap=None, verbose=False)
Return the hyperbolicity of the graph or an approximation of this value.
The hyperbolicity of a graph has been defined by Gromov [Gro1987] as follows: Let 𝑎, 𝑏, 𝑐, 𝑑 be vertices of thegraph, 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 thehyperbolicity of the graph is the maximum over all possible 4-tuples (𝑎, 𝑏, 𝑐, 𝑑) divided by 2. The worst case timecomplexity 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:

1844

–

basic is an exhaustive algorithm considering all possible 4-tuples and so have time complexity in𝑂(𝑛4 ).

–CCL is an exact algorithm proposed in [CCL2015]. It considers the 4-tuples in an ordering allowing
to cut the search space as soon as a new lower bound is found (see the module’s documentation). Thisalgorithm can be turned into a approximation algorithm.

–

CCL+FA or CCL+ uses the notion of far-apart pairs as proposed in [Sot2011] to significantly
reduce the overall computation time of the CCL algorithm.

–

BCCM is an exact algorithm proposed in [BCCM2015]. It improves CCL+FA by cutting several
4-tuples (for more information, see the module’s documentation).

–

dom is an approximation with additive constant four. It computes the hyperbolicity of the vertices ofa dominating set of the graph. This is sometimes slower than CCL and sometimes faster. Try it toknow 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.

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• 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 foundsolution is less than the approximation factor. When the approximation factor is 1.0, the problem is solved
optimally. This parameter is used only when the chosen algorithm is CCL , CCL+FA , or BCCM .
• additive_gap – (default: None) When sets to a positive number, the function stop computations as soon
as the difference between the upper bound and the best found solution is less than additive gap. When the gap
is 0.0, the problem is solved optimally. This parameter is used only when the chosen algorithm is CCL or
CCL+FA , or BCCM .
• verbose – (default: False) is a boolean set to True to display some information during execution: newupper 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 thehyperbolicity 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.Grid2dGraph(3, 3)
sage: L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)
sage: L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.Grid2dGraph(Integer(3), Integer(3))>>> L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)>>> L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2)>>> L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(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: L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+ ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+FA ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
(continues on next page)

5.35. Hyperbolicity

1845

Graph Theory, Release 10.4

(continued from previous page)

sage: L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)
sage: L,C,U = hyperbolicity(G, algorithm= dom ); L,U(0, 1)
sage: sorted(C) # random[0, 1, 2, 6]>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.PetersenGraph()>>> L,C,U = hyperbolicity(G, algorithm= BCCM ); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+ ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+FA ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= basic ); L,sorted(C),U(1/2, [0, 1, 2, 3], 1/2)>>> L,C,U = hyperbolicity(G, algorithm= dom ); L,U(0, 1)>>> sorted(C) # random[0, 1, 2, 6]

Asking for an approximation in a grid graph:
sage: from sage.graphs.hyperbolicity import hyperbolicity
sage: G = graphs.Grid2dGraph(2, 10)
sage: L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=1.5); L,U(1, 3/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+ , approximation_factor=1.5); L,U(1, 1)
sage: L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=4); L,U(1, 4)
sage: L,C,U = hyperbolicity(G, algorithm= CCL , additive_gap=2); L,U(1, 3)
sage: L,C,U = hyperbolicity(G, algorithm= dom ); L,U(1, 5)>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.Grid2dGraph(Integer(2), Integer(10))>>> L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=RealNumber( 1.5
˓→ )); L,U(1, 3/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+ , approximation_factor=RealNumber( 1.
˓→5 )); L,U(1, 1)>>> L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=Integer(4)); L,˓→U(1, 4)>>> L,C,U = hyperbolicity(G, algorithm= CCL , additive_gap=Integer(2)); L,U(1, 3)>>> L,C,U = hyperbolicity(G, algorithm= dom ); L,U(1, 5)

1846

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

Asking for an approximation in a cycle graph:
sage: from sage.graphs.hyperbolicity import hyperbolicity
sage: G = graphs.CycleGraph(10)sage: L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=1.5); L,U(2, 5/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+FA , approximation_factor=1.5); L,U(2, 5/2)
sage: L,C,U = hyperbolicity(G, algorithm= CCL+FA , additive_gap=1); L,U(2, 5/2)>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.CycleGraph(Integer(10))>>> L,C,U = hyperbolicity(G, algorithm= CCL , approximation_factor=RealNumber( 1.5
˓→ )); L,U(2, 5/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+FA , approximation_factor=RealNumber(
˓→ 1.5 )); L,U(2, 5/2)>>> L,C,U = hyperbolicity(G, algorithm= CCL+FA , additive_gap=Integer(1)); L,U(2, 5/2)

Comparison of results:
sage: from sage.graphs.hyperbolicity import hyperbolicity
sage: for i in range(10):# long time
˓→needs networkx....:
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
˓→needs networkx....:
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(sort=True))#␣#␣>>> from sage.all import *(continues on next page)

5.35. Hyperbolicity

1847

Graph Theory, Release 10.4

(continued from previous page)>>> from sage.graphs.hyperbolicity import hyperbolicity>>> for i in range(Integer(10)):# long time˓→# needs networkx...
G = graphs.RandomBarabasiAlbert(Integer(100),Integer(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=Integer(2))...
if (not d1==d2==d3==d4==d5) or l3>d1 or u3<d1:...
print("That s not good!")>>> from sage.graphs.hyperbolicity import hyperbolicity>>> import random>>> random.seed()>>> for i in range(Integer(10)):# long time˓→# needs networkx...
n = random.randint(Integer(2), Integer(20))...
m = random.randint(Integer(0), n*(n-Integer(1)) / Integer(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=Integer(2))...
if (not d1==d2==d3==d4==d5) or l3>d1 or u3<d1:...
print("Error in graph ", cc.edges(sort=True))␣␣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: L,C,U = hyperbolicity(G); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity>>> G = graphs.PetersenGraph() * Integer(2)>>> G.add_edge(Integer(0), Integer(11))>>> L,C,U = hyperbolicity(G); L,sorted(C),U(1/2, [6, 7, 8, 9], 1/2)

sage.graphs.hyperbolicity.hyperbolicity_distribution(G, algorithm='sampling',
sampling_size=1000000)
Return the hyperbolicity distribution of the graph or a sampling of it.
The hyperbolicity of a graph has been defined by Gromov [Gro1987] as follows: Let 𝑎, 𝑏, 𝑐, 𝑑 be vertices of thegraph, 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 thehyperbolicity 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 ).

1848

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

INPUT:• G – a Graph.
• algorithm – (default: ‘sampling’) When algorithm is ‘sampling’, it returns the distribution of the hyperbolicity over a sample of sampling_size 4-tuples. When algorithm is ‘exact’, it computes the distributionof 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}>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity_distribution>>> G = graphs.PetersenGraph()>>> 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}>>> from sage.all import *>>> from sage.graphs.hyperbolicity import hyperbolicity_distribution>>> G = graphs.GridGraph([Integer(3),Integer(3)])>>> hyperbolicity_distribution(G,algorithm= exact ){0: 11/18, 1: 8/21, 2: 1/126}

5.36 Tutte polynomial
This module implements a deletion-contraction algorithm for computing the Tutte polynomial as described in the paper[HPR2010].
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

5.36. Tutte polynomial

1849

Graph Theory, Release 10.4

5.36.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 𝐺.

5.36.2 Functionsclass 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 [HPR2010]:
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.s3sage: E.unlabeled_edges[(0, 1), (1, 2), (2, 3)]
sage: E.vertices[0, 1, 2, 3]>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.add_edges([(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(3),˓→Integer(6)),(Integer(3),Integer(7))])>>> from sage.graphs.tutte_polynomial import Ear>>> E = Ear.find_ear(G)>>> E.s3>>> E.unlabeled_edges[(0, 1), (1, 2), (2, 3)]>>> E.vertices[0, 1, 2, 3]

removed_from(*args, **kwds)
A context manager which removes the ear from the graph 𝐺.
EXAMPLES:

1850

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: G = graphs.PathGraph(4)sage: G.add_edges([(0,4),(0,5),(3,6),(3,7)])
sage: len(G.edges(sort=True))7
sage: from sage.graphs.tutte_polynomial import Ear
sage: E = Ear.find_ear(G)sage: with E.removed_from(G) as Y:....:
G.edges(sort=True)[(0, 4, None), (0, 5, None), (3, 6, None), (3, 7, None)]sage: len(G.edges(sort=True))
7>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.add_edges([(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(3),˓→Integer(6)),(Integer(3),Integer(7))])>>> len(G.edges(sort=True))
7>>> from sage.graphs.tutte_polynomial import Ear>>> E = Ear.find_ear(G)>>> with E.removed_from(G) as Y:...
G.edges(sort=True)[(0, 4, None), (0, 5, None), (3, 6, None), (3, 7, None)]>>> len(G.edges(sort=True))
7

property 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>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.add_edges([(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(3),˓→Integer(6)),(Integer(3),Integer(7))])>>> from sage.graphs.tutte_polynomial import Ear>>> E = Ear(G,[Integer(0),Integer(3)],[Integer(1),Integer(2)],False)>>> E.s3

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

5.36. Tutte polynomial

1851

Graph Theory, Release 10.4

(continued from previous page)

sage: E.unlabeled_edges[(0, 1), (1, 2), (2, 3)]>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.add_edges([(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(3),˓→Integer(6)),(Integer(3),Integer(7))])>>> from sage.graphs.tutte_polynomial import Ear>>> E = Ear(G,[Integer(0),Integer(3)],[Integer(1),Integer(2)],False)>>> E.unlabeled_edges[(0, 1), (1, 2), (2, 3)]property 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]>>> from sage.all import *>>> G = graphs.PathGraph(Integer(4))>>> G.add_edges([(Integer(0),Integer(4)),(Integer(0),Integer(5)),(Integer(3),˓→Integer(6)),(Integer(3),Integer(7))])>>> from sage.graphs.tutte_polynomial import Ear>>> E = Ear(G,[Integer(0),Integer(3)],[Integer(1),Integer(2)],False)>>> E.vertices[0, 1, 2, 3]class sage.graphs.tutte_polynomial.EdgeSelection
Bases: object
class sage.graphs.tutte_polynomial.MaximizeDegree
Bases: EdgeSelection
class sage.graphs.tutte_polynomial.MinimizeDegree
Bases: EdgeSelection
class sage.graphs.tutte_polynomial.MinimizeSingleDegree
Bases: EdgeSelection
class sage.graphs.tutte_polynomial.VertexOrder(order)
Bases: EdgeSelection
EXAMPLES:
sage: from sage.graphs.tutte_polynomial import VertexOrdersage: 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}

1852

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.tutte_polynomial import VertexOrder>>> A = VertexOrder([Integer(4),Integer(6),Integer(3),Integer(2),Integer(1),˓→Integer(7)])>>> A.order[4, 6, 3, 2, 1, 7]>>> A.inverse_order{1: 4, 2: 3, 3: 2, 4: 0, 6: 1, 7: 5}

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(sort=True)[(0, 1, a ), (0, 3, c ), (1, 2, b )]sage: with contracted_edge(G,(0,1)) as Y:....:
G.edges(sort=True); G.vertices(sort=True)[(1, 2, b ), (1, 3, c )][1, 2, 3]
sage: G.edges(sort=True)[(0, 1, a ), (0, 3, c ), (1, 2, b )]>>> from sage.all import *>>> from sage.graphs.tutte_polynomial import contracted_edge>>> G = Graph(multiedges=True)>>> G.add_edges([(Integer(0),Integer(1), a ),(Integer(1),Integer(2), b ),˓→(Integer(0),Integer(3), c )])>>> G.edges(sort=True)[(0, 1, a ), (0, 3, c ), (1, 2, b )]>>> with contracted_edge(G,(Integer(0),Integer(1))) as Y:...
G.edges(sort=True); G.vertices(sort=True)[(1, 2, b ), (1, 3, c )][1, 2, 3]>>> G.edges(sort=True)[(0, 1, a ), (0, 3, c ), (1, 2, b )]sage.graphs.tutte_polynomial.edge_multiplicities(G)Return the 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)]>>> from sage.all import *>>> from sage.graphs.tutte_polynomial import edge_multiplicities>>> G = Graph({Integer(1): [Integer(2),Integer(2),Integer(3)], Integer(2):␣
˓→[Integer(2)], Integer(3): [Integer(4),Integer(4)], Integer(4): [Integer(2),˓→Integer(2),Integer(2)]})>>> sorted(edge_multiplicities(G).items())[((1, 2), 2), ((1, 3), 1), ((2, 2), 1), ((2, 4), 3), ((3, 4), 2)]

5.36. Tutte polynomial

1853

Graph Theory, Release 10.4

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(sort=True)[(0, 1, None)]sage: with removed_edge(G,(0,1)) as Y:....:
G.edges(sort=True); G.vertices(sort=True)[][0, 1]
sage: G.edges(sort=True)[(0, 1, None)]>>> from sage.all import *>>> from sage.graphs.tutte_polynomial import removed_edge>>> G = Graph()>>> G.add_edge(Integer(0),Integer(1))>>> G.edges(sort=True)[(0, 1, None)]>>> with removed_edge(G,(Integer(0),Integer(1))) as Y:...
G.edges(sort=True); G.vertices(sort=True)[][0, 1]>>> G.edges(sort=True)[(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(sort=True)[(0, 0, c ), (0, 1, a ), (1, 2, b )]sage: with removed_loops(G) as Y:....:
G.edges(sort=True); G.vertices(sort=True); Y[(0, 1, a ), (1, 2, b )][0, 1, 2][(0, 0, c )]sage: G.edges(sort=True)[(0, 0, c ), (0, 1, a ), (1, 2, b )]>>> from sage.all import *>>> from sage.graphs.tutte_polynomial import removed_loops>>> G = Graph(multiedges=True, loops=True)>>> G.add_edges([(Integer(0),Integer(1), a ),(Integer(1),Integer(2), b ),˓→(Integer(0),Integer(0), c )])>>> G.edges(sort=True)[(0, 0, c ), (0, 1, a ), (1, 2, b )]>>> with removed_loops(G) as Y:(continues on next page)

1854

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)...
G.edges(sort=True); G.vertices(sort=True); Y[(0, 1, a ), (1, 2, b )][0, 1, 2][(0, 0, c )]>>> G.edges(sort=True)[(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(sort=True)[(0, 1, a ), (0, 1, b )]sage: with removed_multiedge(G,(0,1)) as Y:....:
G.edges(sort=True)[]
sage: G.edges(sort=True)[(0, 1, a ), (0, 1, b )]>>> from sage.all import *>>> from sage.graphs.tutte_polynomial import removed_multiedge>>> G = Graph(multiedges=True)>>> G.add_edges([(Integer(0),Integer(1), a ),(Integer(0),Integer(1), b )])>>> G.edges(sort=True)[(0, 1, a ), (0, 1, b )]>>> with removed_multiedge(G,(Integer(0),Integer(1))) as Y:...
G.edges(sort=True)[]>>> G.edges(sort=True)[(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 selectingedges 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))˓→needs sage.symbolic
True

#␣

>>> from sage.all import *>>> all(T.tutte_polynomial() == x**Integer(9) for T in graphs.trees(Integer(10)))␣
˓→# needs sage.symbolicTrue

5.36. Tutte polynomial

1855Graph Theory, Release 10.4

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>>> from sage.all import *>>> P = graphs.PetersenGraph()>>> P.tutte_polynomial()x^9 + 6*x^8 + 21*x^7 + 56*x^6 + 12*x^5*y + y^6 + 114*x^5 + 70*x^4*y+ 30*x^3*y^2 + 15*x^2*y^3 + 10*x*y^4 + 9*y^5 + 170*x^4 + 170*x^3*y+ 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2+ 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y

The Tutte polynomial of a connected graph 𝐺 evaluated at (1,1) is the number of spanning trees of 𝐺:
sage: G = graphs.RandomGNP(10,0.6)
sage: while not G.is_connected():....:G = graphs.RandomGNP(10,0.6)
sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count()
˓→needs sage.modules
True

#␣

>>> from sage.all import *>>> G = graphs.RandomGNP(Integer(10),RealNumber( 0.6 ))>>> while not G.is_connected():...
G = graphs.RandomGNP(Integer(10),RealNumber( 0.6 ))>>> G.tutte_polynomial()(Integer(1),Integer(1)) == G.spanning_trees_count()˓→# needs sage.modules
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()˓→needs sage.symbolic(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage: G.chromatic_polynomial().factor()˓→needs sage.libs.flint(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)#␣#␣>>> from sage.all import *>>> G = graphs.OctahedralGraph()>>> T = G.tutte_polynomial()>>> R = PolynomialRing(ZZ, x )>>> R((-Integer(1))**Integer(5)*x*T(Integer(1)-x,Integer(0))).factor()˓→# needs sage.symbolic(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)>>> G.chromatic_polynomial().factor()˓→needs sage.libs.flint(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)

1856

␣

#␣

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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_graphsage: G = Graph(multiedges=True)
sage: G.add_edges([(0,1, a ),(0,1, b )])sage: G.edges(sort=True)[(0, 1, a ), (0, 1, b )]sage: underlying_graph(G).edges(sort=True)[(0, 1, None)]>>> from sage.all import *>>> from sage.graphs.tutte_polynomial import underlying_graph>>> G = Graph(multiedges=True)>>> G.add_edges([(Integer(0),Integer(1), a ),(Integer(0),Integer(1), b )])>>> G.edges(sort=True)[(0, 1, a ), (0, 1, b )]>>> underlying_graph(G).edges(sort=True)[(0, 1, None)]

5.37 Partial cubes
The code in this module that recognizes partial cubes is originally from the PADS library by David Eppstein, which isavailable at http://www.ics.uci.edu/ eppstein/PADS/ under the MIT license. It has a quadratic runtime and has been
described in [Epp2008].
For more information on partial cubes, see the Wikipedia article Partial cube.

5.37.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 [Epp2008], a token represents a transition of the form:
switch the k-th bit of the binary string from 0 to 1
Each token can be matched with a ‘reversed’ token that performs the same switch in the opposite direction. Alternatively,
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 𝑣.

5.37. Partial cubes

1857

Graph Theory, Release 10.4

Observations
Shortest paths: in a hypercube, a shortest path between two vertices uses each token at most once. Furthermore, itcannot use both a token and it reverse.
Cycles: a cycle in a partial cube is necessarily even, as hypercubes are bipartite. If an edge 𝑒 of a cycle 𝐶 belongs to a
token 𝑇 , then the edge opposite to 𝑒 in 𝐶 belongs to the reverse of 𝑇 .
Incident edges: all 2𝑑𝐺 (𝑣) arcs incident to a given vertex belong to as many different tokens.
Algorithm
Labeling: Iteratively, the algorithm selects a vertex 𝑣 ∈ 𝐺, which is naturally associated to 2𝑑(𝑣) tokens. It then performs
a breadth-first search from 𝑣, applying the previous observation on cycles to attribute a token to some of the edges it meets.
None of the edges whose token remains undecided after this step can belong to one of those 2𝑑(𝑣) tokens, by virtue ofthe 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 theHamming 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 theyshould be. In the implementation, the sequence of the sources (𝑣, 𝑣 ′ , ...) is given by a depth-first search.

5.37.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 theirneighbours 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)˓→needs sage.combinat
sage: list(sage.graphs.partial_cube.breadth_first_level_search(H,˓→needs sage.combinat[{ 00 : { 01 , 02 }},

#␣
00 ))

#␣

(continues on next page)

1858

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page){ 01 : { 10 , 11 ,{ 10 : set(),11 : set(),12 : set(),20 : set(),21 : set(),22 : set()}]12 },02 : { 20 ,21 ,22 }},>>> from sage.all import *>>> H = digraphs.DeBruijn(Integer(3),Integer(2))˓→# needs sage.combinat>>> list(sage.graphs.partial_cube.breadth_first_level_search(H,˓→needs sage.combinat[{ 00 : { 01 , 02 }},{ 01 : { 10 , 11 , 12 }, 02 : { 20 , 21 , 22 }},{ 10 : set(),11 : set(),12 : set(),20 : set(),21 : set(),22 : set()}]

␣
00 ))

#␣

sage.graphs.partial_cube.depth_first_traversal(G, start)
Generate a sequence of triples (v,w,edgetype) for DFS of graph G.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/ eppstein/PADS/).
INPUT:• G – a graph to perform the search on.
• start – vertex or list of vertices from which to start the traversal.
OUTPUT:• a generator of triples (v,w,edgetype), where edgetype is True if the algorithm is progressing via
the edge vw, or False if the algorithm is backtracking via the edge wv.
EXAMPLES:
sage: H = digraphs.DeBruijn(3,2)˓→needs sage.combinat
sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H,˓→needs sage.combinat
sage: len(t)˓→needs sage.combinat
16>>> from sage.all import *>>> H = digraphs.DeBruijn(Integer(3),Integer(2))˓→# needs sage.combinat>>> t = list(sage.graphs.partial_cube.depth_first_traversal(H,˓→needs sage.combinat>>> len(t)˓→needs sage.combinat
16

5.37. Partial cubes

#␣
00 ))

#␣
#␣

␣
00 ))

#␣
#␣

1859

Graph Theory, Release 10.4

sage.graphs.partial_cube.is_partial_cube(G, certificate=False)
Test whether the given graph is a partial cube.
A partial cube is a graph that can be isometrically embedded into a hypercube, i.e., its vertices can be labelled with(0,1)-vectors of some fixed length such that the distance between any two vertices in the graph equals the Hamming
distance of their labels.
Originally written by D. Eppstein for the PADS library (http://www.ics.uci.edu/ eppstein/PADS/), see also
[Epp2008]. The algorithm runs in 𝑂(𝑛2 ) time, where 𝑛 is the number of vertices. See the documentation ofpartial_cube for an overview of the algorithm.
INPUT:• certificate – boolean (default: False); this function returns True or False according to the graph,when certificate = False. When certificate = True and the graph is a partial cube, thefunction returns (True, mapping), where mapping is an isometric mapping of the vertices of the graphto the vertices of a hypercube ((0, 1)-strings of a fixed length). When certificate = True and thegraph 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>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> 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>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(10)).cartesian_product(graphs.
˓→CompleteGraph(Integer(2)))>>> g.is_partial_cube()True

5.38 Path enumeration
This module is meant for all functions related to path enumeration in graphs.

1860

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

all_paths()
yen_k_shortest_simple_paths()feng_k_shortest_simple_paths()
all_paths_iterator()
all_simple_paths()
shortest_simple_paths()

Return the list of all paths between a pair of vertices.
Return an iterator over the simple paths between a pair of vertices in increasingorder of weights.
Return an iterator over the simple paths between a pair of vertices in increasingorder of weights.
Return an iterator over the paths of self.
Return a list of all the simple paths of self starting with one of the given vertices.
Return an iterator over the simple paths between a pair of vertices.

5.38.1 Functions
sage.graphs.path_enumeration.all_paths(G, start, end, use_multiedges=False, report_edges=False,labels=False)
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”.
If G has multiple edges, a path will be returned as many times as the product of the multiplicity of the edges alongthat path depending on the value of the flag use_multiedges.
INPUT:• start – a vertex of a graph, where to start• end – a vertex of a graph, where to end• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as
in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges isTrue– If True, a path will be reported as many times as the edges multiplicities along that path (when report_edges = False or labels = False), or with all possible combinations of edge labels(when report_edges = True and labels = True)• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list ofedges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise
a list of edges along with its edge labels are used to represent the path.
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],[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],(continues on next page)

5.38. Path enumeration

1861

Graph Theory, Release 10.4

(continued from previous page)[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]]
sage: g = Graph([(0, 1), (0, 1), (1, 2), (1, 2)], multiedges=True)
sage: g.all_paths(0, 2, use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: dg = DiGraph({0:[1, 2, 1], 3:[0, 0]}, multiedges=True)
sage: dg.all_paths(3, 1, use_multiedges=True)[[3, 0, 1], [3, 0, 1], [3, 0, 1], [3, 0, 1]]
sage: g = Graph([(0, 1, a ), (0, 1, b ), (1, 2, c ), (1, 2, d )],␣˓→multiedges=True)
sage: g.all_paths(0, 2, use_multiedges=False)[[0, 1, 2]]
sage: g.all_paths(0, 2, use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: g.all_paths(0, 2, use_multiedges=True, report_edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]sage: g.all_paths(0, 2, use_multiedges=True, report_edges=True, labels=True)[((0, 1, b ), (1, 2, d )),((0, 1, b ), (1, 2, c )),((0, 1, a ), (1, 2, d )),((0, 1, a ), (1, 2, c ))]sage: g.all_paths(0, 2, use_multiedges=False, report_edges=True, labels=True)[((0, 1, b ), (1, 2, d ))]sage: g.all_paths(0, 2, use_multiedges=False, report_edges=False, labels=True)[[0, 1, 2]](continues on next page)

1862

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: g.all_paths(0, 2, use_multiedges=True, report_edges=False, labels=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> from sage.all import *>>> eg1 = Graph({Integer(0):[Integer(1), Integer(2)], Integer(1):[Integer(4)],␣
˓→Integer(2):[Integer(3), Integer(4)], Integer(4):[Integer(5)],␣
˓→Integer(5):[Integer(6)]})>>> eg1.all_paths(Integer(0), Integer(6))[[0, 1, 4, 5, 6], [0, 2, 4, 5, 6]]>>> eg2 = graphs.PetersenGraph()>>> sorted(eg2.all_paths(Integer(1), Integer(4)))[[1, 0, 4],[1, 0, 5, 7, 2, 3, 4],[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]]>>> dg = DiGraph({Integer(0):[Integer(1), Integer(3)], Integer(1):[Integer(3)],␣
˓→Integer(2):[Integer(0), Integer(3)]})>>> sorted(dg.all_paths(Integer(0), Integer(3)))[[0, 1, 3], [0, 3]]>>> ug = dg.to_undirected()>>> sorted(ug.all_paths(Integer(0), Integer(3)))[[0, 1, 3], [0, 2, 3], [0, 3]]>>> g = Graph([(Integer(0), Integer(1)), (Integer(0), Integer(1)), (Integer(1),␣
˓→Integer(2)), (Integer(1), Integer(2))], multiedges=True)>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> dg = DiGraph({Integer(0):[Integer(1), Integer(2), Integer(1)],␣
(continues on next page)

5.38. Path enumeration

1863

Graph Theory, Release 10.4

(continued from previous page)

Integer(3):[Integer(0), Integer(0)]}, multiedges=True)>>> dg.all_paths(Integer(3), Integer(1), use_multiedges=True)[[3, 0, 1], [3, 0, 1], [3, 0, 1], [3, 0, 1]]˓→>>> g = Graph([(Integer(0), Integer(1), a ), (Integer(0), Integer(1), b ),␣
˓→(Integer(1), Integer(2),c ), (Integer(1), Integer(2), d )], multiedges=True)>>> g.all_paths(Integer(0), Integer(2), use_multiedges=False)[[0, 1, 2]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_edges=True,␣
˓→labels=True)[((0, 1, b ), (1, 2, d )),((0, 1, b ), (1, 2, c )),((0, 1, a ), (1, 2, d )),((0, 1, a ), (1, 2, c ))]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=False, report_edges=True,␣
˓→labels=True)[((0, 1, b ), (1, 2, d ))]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=False, report_edges=False,␣
˓→labels=True)[[0, 1, 2]]>>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_edges=False,␣
˓→labels=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]

sage.graphs.path_enumeration.all_paths_iterator(self, starting_vertices=None,
ending_vertices=None, simple=False,
max_length=None, trivial=False,
use_multiedges=False, report_edges=False,labels=False)
Return an iterator over the paths of self.
The paths are enumerated in increasing length order.
INPUT:• starting_vertices – iterable (default: None); vertices from which the paths must start. If None,then all vertices of the graph can be starting points.
• ending_vertices – iterable (default: None); allowed ending vertices of the paths. If None, then allvertices are allowed.
• simple – boolean (default: False); if set to True, then only simple paths are considered. 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 onceand 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.
• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as
in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges is
True

1864

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

– If True, a path will be reported as many times as the edges multiplicities along that path (when report_edges = False or labels = False), or with all possible combinations of edge labels(when report_edges = True and labels = True)• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list ofedges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise
a list of edges along with its edge labels are used to represent the path.
OUTPUT:
iterator
AUTHOR:
Alexandre Blondin Masse
EXAMPLES:
sage: G = graphs.CompleteGraph(4)sage: list(G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3],␣
˓→simple=True))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]
sage: list(G.shortest_simple_paths(1, 3))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]
sage: pi = G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3])sage: for _ in range(6):....:print(next(pi))[1, 3][1, 0, 3][1, 2, 3][1, 0, 1, 3][1, 0, 2, 3][1, 2, 0, 3]
sage: g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)
sage: pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ d ],␣
˓→report_edges=True, simple=True)
sage: list(pi)[[( a , b ), ( b , c ), ( c , d )]]sage: g = DiGraph([(0, 1, a ), (0, 1, b ), (1, 2, c ), (1, 2, d )],␣˓→multiedges=True)
sage: pi = g.all_paths_iterator(starting_vertices=[0], use_multiedges=True)
sage: for _ in range(6):....:print(next(pi))[0, 1][0, 1][0, 1, 2][0, 1, 2][0, 1, 2][0, 1, 2]
sage: pi = g.all_paths_iterator(starting_vertices=[0], use_multiedges=True,␣
˓→report_edges=True, labels=True)
sage: for _ in range(6):....:print(next(pi))[(0, 1, b )][(0, 1, a )](continues on next page)

5.38. Path enumeration

1865

Graph Theory, Release 10.4

(continued from previous page)[(0, 1, b ), (1, 2, d )][(0, 1, b ), (1, 2, c )][(0, 1, a ), (1, 2, d )][(0, 1, a ), (1, 2, c )]sage: list(g.all_paths_iterator(starting_vertices=[0, 1], ending_vertices=[2],␣
˓→use_multiedges=False, report_edges=True, labels=True, simple=True))[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]sage: list(g.all_paths_iterator(starting_vertices=[0, 1], ending_vertices=[2],␣
˓→use_multiedges=False, report_edges=False, labels=True))[[1, 2], [0, 1, 2]]
sage: list(g.all_paths_iterator(use_multiedges=True, report_edges=False,␣
˓→labels=True, max_length=1))[[1, 2], [1, 2], [0, 1], [0, 1]]
sage: list(g.all_paths_iterator(use_multiedges=True, report_edges=True,␣
˓→labels=True, max_length=1))[[(1, 2, d )], [(1, 2, c )], [(0, 1, b )], [(0, 1, a )]]sage: g = DiGraph({ a : [ a , b ], b : [ c ],˓→loops=True)
sage: pi = g.all_paths_iterator()sage: [len(next(pi)) - 1 for _ in range(7)][1, 1, 1, 1, 1, 2, 2]

c : [ d ],d : [ c ]},␣>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> list(G.all_paths_iterator(starting_vertices=[Integer(1)], ending_˓→vertices=[Integer(3)], simple=True))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]>>> list(G.shortest_simple_paths(Integer(1), Integer(3)))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]>>> pi = G.all_paths_iterator(starting_vertices=[Integer(1)], ending_˓→vertices=[Integer(3)])>>> for _ in range(Integer(6)):...
print(next(pi))[1, 3][1, 0, 3][1, 2, 3][1, 0, 1, 3][1, 0, 2, 3][1, 2, 0, 3]>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]}, loops=True)>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ d ],␣
˓→report_edges=True, simple=True)>>> list(pi)[[( a , b ), ( b , c ), ( c , d )]]>>> g = DiGraph([(Integer(0), Integer(1), a ), (Integer(0), Integer(1), b ),␣
˓→(Integer(1), Integer(2), c ), (Integer(1), Integer(2), d )], multiedges=True)>>> pi = g.all_paths_iterator(starting_vertices=[Integer(0)], use_
˓→multiedges=True)>>> for _ in range(Integer(6)):...
print(next(pi))[0, 1][0, 1][0, 1, 2](continues on next page)

1866

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)[0, 1, 2][0, 1, 2][0, 1, 2]>>> pi = g.all_paths_iterator(starting_vertices=[Integer(0)], use_
˓→multiedges=True, report_edges=True, labels=True)>>> for _ in range(Integer(6)):...
print(next(pi))[(0, 1, b )][(0, 1, a )][(0, 1, b ), (1, 2, d )][(0, 1, b ), (1, 2, c )][(0, 1, a ), (1, 2, d )][(0, 1, a ), (1, 2, c )]>>> list(g.all_paths_iterator(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True,␣
˓→simple=True))[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]>>> list(g.all_paths_iterator(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=False, labels=True))[[1, 2], [0, 1, 2]]>>> list(g.all_paths_iterator(use_multiedges=True, report_edges=False,␣
˓→labels=True, max_length=Integer(1)))[[1, 2], [1, 2], [0, 1], [0, 1]]>>> list(g.all_paths_iterator(use_multiedges=True, report_edges=True, labels=True,
˓→ max_length=Integer(1)))[[(1, 2, d )], [(1, 2, c )], [(0, 1, b )], [(0, 1, a )]]>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]}, loops=True)>>> pi = g.all_paths_iterator()>>> [len(next(pi)) - Integer(1) for _ in range(Integer(7))][1, 1, 1, 1, 1, 2, 2]

It is possible to precise the allowed starting and/or ending vertices:sage: pi = g.all_paths_iterator(starting_vertices=[ a ])sage: [len(next(pi)) - 1 for _ in range(5)][1, 1, 2, 2, 2]
sage: pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ])sage: for _ in range(5):....:print(next(pi))[ a , b ][ a , a , b ][ a , a , a , b ][ a , a , a , a , b ][ a , a , a , a , a , b ]>>> from sage.all import *>>> pi = g.all_paths_iterator(starting_vertices=[ a ])>>> [len(next(pi)) - Integer(1) for _ in range(Integer(5))][1, 1, 2, 2, 2]>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ])>>> for _ in range(Integer(5)):...
print(next(pi))[ a , b ][ a , a , b ][ a , a , a , b ](continues on next page)

5.38. Path enumeration

1867

Graph Theory, Release 10.4

(continued from previous page)

[ a ,
[ a ,

a ,
a ,

a ,
a ,

a ,
a ,

b ]
a ,

b ]

One may prefer to enumerate only simple paths (see all_simple_paths()):
sage: pi = g.all_paths_iterator(simple=True)
sage: sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d ,[ a , b , c , d ]]sage: pi = g.all_paths_iterator(simple=True)
sage: [len(p) - 1 for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]>>> from sage.all import *>>> pi = g.all_paths_iterator(simple=True)>>> sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d ,[ a , b , c , d ]]>>> pi = g.all_paths_iterator(simple=True)>>> [len(p) - Integer(1) for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]

c ,

d ],

c ,

d ],

Or simply bound the length of the enumerated paths:
sage: pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ,˓→ ], max_length=6)
sage: sorted(list(pi), key=lambda x:(len(x), x))[[ 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 ]]sage: pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ,˓→ ], max_length=6)
sage: [len(p) - 1 for p in pi][1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6]>>> from sage.all import *>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ,˓→ max_length=Integer(6))>>> sorted(list(pi), key=lambda x:(len(x), x))[[ 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 ]]

c

c

c ],

(continues on next page)

1868

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> pi = g.all_paths_iterator(starting_vertices=[ a ], ending_vertices=[ b ,˓→ max_length=Integer(6))>>> [len(p) - Integer(1) for p in pi][1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6]

c ],By default, empty paths are not enumerated, but it may be parametrized:
sage: pi = g.all_paths_iterator(simple=True, trivial=True)
sage: sorted(list(pi), key=lambda x:(len(x), x))[[ 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=True)
sage: [len(p) - 1 for p in pi][0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3]
sage: pi = g.all_paths_iterator(simple=True, trivial=False)
sage: sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d , c ,[ a , b , c , d ]]sage: pi = g.all_paths_iterator(simple=True, trivial=False)
sage: [len(p) - 1 for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]>>> from sage.all import *>>> pi = g.all_paths_iterator(simple=True, trivial=True)>>> sorted(list(pi), key=lambda x:(len(x), x))[[ 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 ]]>>> pi = g.all_paths_iterator(simple=True, trivial=True)>>> [len(p) - Integer(1) for p in pi][0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3]>>> pi = g.all_paths_iterator(simple=True, trivial=False)>>> sorted(list(pi), key=lambda x:(len(x), x))[[ a , a ], [ a , b ], [ b , c ], [ c , d ], [ d , c ],[ a , b , c ], [ b , c , d ], [ c , d , c ], [ d , c ,[ a , b , c , d ]]>>> pi = g.all_paths_iterator(simple=True, trivial=False)>>> [len(p) - Integer(1) for p in pi][1, 1, 1, 1, 1, 2, 2, 2, 2, 3]

d ],

d ],

sage.graphs.path_enumeration.all_simple_paths(self, starting_vertices=None,
ending_vertices=None, max_length=None,trivial=False, use_multiedges=False,
report_edges=False, labels=False)
Return 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 atmost once and exited at most once.
INPUT:• starting_vertices – list (default: None); vertices from which the paths must start. If None, then allvertices of the graph can be starting points.
• ending_vertices – iterable (default: None); allowed ending vertices of the paths. If None, then allvertices are allowed.
5.38. Path enumeration

1869

Graph Theory, Release 10.4

• 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.
• use_multiedges – boolean (default: False); this parameter is used only if the graph has multiple edges.
– If False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as
in sage.graphs.generic_graph.GenericGraph.to_simple() if report_edges isTrue– If True, a path will be reported as many times as the edges multiplicities along that path (when report_edges = False or labels = False), or with all possible combinations of edge labels(when report_edges = True and labels = True)• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list ofedges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise
a list of edges along with its edge labels are used to represent the path.
OUTPUT:
list
Note: Although the number of simple paths of a finite graph is always finite, computing all its paths may take avery long time.
EXAMPLES:
sage: G = graphs.CompleteGraph(4)sage: G.all_simple_paths([1], [3])[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]
sage: list(G.shortest_simple_paths(1, 3))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]
sage: G.all_simple_paths([0, 1], [2, 3])[[1, 2],[1, 3],[0, 2],[0, 3],[0, 1, 2],[0, 1, 3],[0, 2, 3],[0, 3, 2],[1, 0, 2],[1, 0, 3],[1, 2, 3],[1, 3, 2],[1, 0, 2, 3],[1, 0, 3, 2],[1, 2, 0, 3],[1, 3, 0, 2],[0, 1, 2, 3],[0, 1, 3, 2],[0, 2, 1, 3],[0, 3, 1, 2]]
sage: g = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True)
sage: g.all_simple_paths()(continues on next page)

1870

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3],[0, 1, 2, 3]]
sage: g = DiGraph([(0, 1, a ), (0, 1, b ), (1, 2, c ), (1, 2, d )],␣˓→multiedges=True)
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=False)[[0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True, report_edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_
˓→multiedges=True, report_edges=True, labels=True)[[(0, 1, b ), (1, 2, d )],[(0, 1, b ), (1, 2, c )],[(0, 1, a ), (1, 2, d )],[(0, 1, a ), (1, 2, c )]]sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_
˓→multiedges=False, report_edges=True, labels=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_
˓→multiedges=False, report_edges=False, labels=True)[[1, 2], [0, 1, 2]]
sage: g.all_simple_paths(use_multiedges=True, report_edges=False, labels=True)[[1, 2], [1, 2], [0, 1], [0, 1], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_
˓→multiedges=False, report_edges=True, labels=True, trivial=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> G.all_simple_paths([Integer(1)], [Integer(3)])[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]>>> list(G.shortest_simple_paths(Integer(1), Integer(3)))[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]>>> G.all_simple_paths([Integer(0), Integer(1)], [Integer(2), Integer(3)])[[1, 2],[1, 3],[0, 2],[0, 3],[0, 1, 2],[0, 1, 3],[0, 2, 3],[0, 3, 2],[1, 0, 2],(continues on next page)

5.38. Path enumeration

1871

Graph Theory, Release 10.4

(continued from previous page)[1, 0, 3],[1, 2, 3],[1, 3, 2],[1, 0, 2, 3],[1, 0, 3, 2],[1, 2, 0, 3],[1, 3, 0, 2],[0, 1, 2, 3],[0, 1, 3, 2],[0, 2, 1, 3],[0, 3, 1, 2]]>>> g = DiGraph({Integer(0): [Integer(0), Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(3): [Integer(2)]}, loops=True)>>> g.all_simple_paths()[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3],[0, 1, 2, 3]]>>> g = DiGraph([(Integer(0), Integer(1), a ), (Integer(0), Integer(1), b ),␣
˓→(Integer(1), Integer(2), c ), (Integer(1), Integer(2), d )], multiedges=True)>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=False)[[0, 1, 2]]>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=True)[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=True, report_edges=True)[[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]]>>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_˓→vertices=[Integer(2)], use_multiedges=True, report_edges=True, labels=True)[[(0, 1, b ), (1, 2, d )],[(0, 1, b ), (1, 2, c )],[(0, 1, a ), (1, 2, d )],[(0, 1, a ), (1, 2, c )]]>>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]>>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=False, labels=True)[[1, 2], [0, 1, 2]]>>> g.all_simple_paths(use_multiedges=True, report_edges=False, labels=True)[[1, 2], [1, 2], [0, 1], [0, 1], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]>>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_˓→vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True,␣
˓→trivial=True)[[(1, 2, d )], [(0, 1, b ), (1, 2, d )]]One may compute all paths having specific starting and/or ending vertices:

1872

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)
sage: g.all_simple_paths(starting_vertices=[ a ])[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]sage: g.all_simple_paths(starting_vertices=[ a ], ending_vertices=[ c ])[[ a , b , c ]]sage: g.all_simple_paths(starting_vertices=[ a ], ending_vertices=[ b , c ])[[ a , b ], [ a , b , c ]]>>> from sage.all import *>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]}, loops=True)>>> g.all_simple_paths(starting_vertices=[ a ])[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]>>> g.all_simple_paths(starting_vertices=[ a ], ending_vertices=[ c ])[[ a , b , c ]]>>> 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 = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True)
sage: g.all_simple_paths(max_length=2)[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3]]>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(0), Integer(1)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(3): [Integer(2)]}, loops=True)>>> g.all_simple_paths(max_length=Integer(2))[[3, 2],[2, 3],[1, 2],[0, 0],[0, 1],[0, 1, 2],[1, 2, 3],[2, 3, 2],[3, 2, 3]]

By default, empty paths are not enumerated, but this can be parametrized:
sage: g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]},␣˓→loops=True)
sage: g.all_simple_paths(starting_vertices=[ a ], trivial=True)[[ a ], [ a , a ], [ a , b ], [ a , b , c ],[ a , b , c , d ]]sage: g.all_simple_paths(starting_vertices=[ a ], trivial=False)[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]5.38. Path enumeration

1873

Graph Theory, Release 10.4>>> from sage.all import *>>> g = DiGraph({ a : [ a , b ], b : [ c ], c : [ d ], d : [ c ]}, loops=True)>>> g.all_simple_paths(starting_vertices=[ a ], trivial=True)[[ a ], [ a , a ], [ a , b ], [ a , b , c ],[ a , b , c , d ]]>>> g.all_simple_paths(starting_vertices=[ a ], trivial=False)[[ a , a ], [ a , b ], [ a , b , c ], [ a , b , c , d ]]sage.graphs.path_enumeration.feng_k_shortest_simple_paths(self, source, target,
weight_function=None,by_weight=False,
check_weight=True,
report_edges=False,labels=False,
report_weight=False)
Return an iterator over the simple paths between a pair of vertices in increasing order of weights.
Works only for directed graphs.
For unweighted graphs, paths are returned in order of increasing number of edges.
In case of weighted graphs, negative weights are not allowed.
If source is the same vertex as target, then [[source]] is returned – a list containing the 1-vertex, 0-edge
path source.
The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels is kept
in case of multiedges.
INPUT:• source – a vertex of the graph, where to start• target – a vertex of the graph, where to end• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l as a weight.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1• check_weight – boolean (default: True); whether to check that the weight_function outputs anumber for each edge
• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list ofedges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise
a list of edges along with its edge labels are used to represent the path.
• report_weight – boolean (default: False); if False, just the path between source and target isreturned. Otherwise a tuple of path length and path is returned.
ALGORITHM:
This algorithm can be divided into two parts. Firstly, it determines the shortest path from source to target.
Then, it determines all the other 𝑘-shortest paths. This algorithm finds the deviations of previous shortest paths
to determine the next shortest paths. This algorithm finds the candidate paths more efficiently using a node classification technique. At first the candidate path is separated by its deviation node as prefix and suffix. Then thealgorithm classify the nodes as red, yellow and green. A node on the prefix is assigned a red color, a node thatcan reach t (the destination node) through a shortest path without visiting a red node is assigned a green color, and1874

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

all other nodes are assigned a yellow color. When searching for the suffix of a candidate path, all green nodes are
bypassed, and Dijkstra’s algorithm is applied to find an all-yellow-node subpath. Since on average thenumber of yellow nodes is much smaller than n, this algorithm has a much lower average-case running time.
Time complexity is 𝑂(𝑘𝑛(𝑚 + 𝑛 log 𝑛)) where 𝑛 is the number of vertices and 𝑚 is the number of edges and 𝑘is the number of shortest paths needed to find. Its average running time is much smaller as compared to 𝑌 𝑒𝑛′ 𝑠algorithm.
See [Feng2014] for more details on this algorithm.
EXAMPLES:
sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4,˓→ 5, 30)])
sage: list(feng_k_shortest_simple_paths(g, 1, 5, by_weight=True))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]
sage: list(feng_k_shortest_simple_paths(g, 1, 5))[[1, 4, 5], [1, 3, 5], [1, 2, 5]]
sage: list(feng_k_shortest_simple_paths(g, 1, 1))[[1]]
sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True))[[(1, 4, 30), (4, 5, 30)], [(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)]]
sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True,␣
˓→by_weight=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True,␣
˓→by_weight=True, report_weight=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4,˓→ 5, 30), (1, 6, 100), (5, 6, 5)])sage: list(feng_k_shortest_simple_paths(g, 1, 6, by_weight = True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]
sage: list(feng_k_shortest_simple_paths(g, 1, 6))[[1, 6], [1, 4, 5, 6], [1, 3, 5, 6], [1, 2, 5, 6]]
sage: list(feng_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True,␣
˓→by_weight=True, report_weight=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]sage: list(feng_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True,␣
˓→report_weight=True))[(1, [(1, 6, 100)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)])]sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths
sage: g = DiGraph([(1, 2, 5), (2, 3, 0), (1, 4, 2), (4, 5, 1), (5, 3, 0)])sage: list(feng_k_shortest_simple_paths(g, 1, 3, by_weight=True))[[1, 4, 5, 3], [1, 2, 3]]
sage: list(feng_k_shortest_simple_paths(g, 1, 3))[[1, 2, 3], [1, 4, 5, 3]]
sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True))[(2, [1, 2, 3]), (3, [1, 4, 5, 3])]
(continues on next page)

5.38. Path enumeration

1875

Graph Theory, Release 10.4

(continued from previous page)

sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_
˓→edges=True))[(2, [(1, 2), (2, 3)]), (3, [(1, 4), (4, 5), (5, 3)])]sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_
˓→edges=True, by_weight=True))[(3, [(1, 4), (4, 5), (5, 3)]), (5, [(1, 2), (2, 3)])]sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_
˓→edges=True, by_weight=True, labels=True))[(3, [(1, 4, 2), (4, 5, 1), (5, 3, 0)]), (5, [(1, 2, 5), (2, 3, 0)])]>>> from sage.all import *>>> from sage.graphs.path_enumeration import feng_k_shortest_simple_paths>>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3),␣
˓→Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5),␣
˓→Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5),␣
˓→Integer(30))])>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5)))[[1, 4, 5], [1, 3, 5], [1, 2, 5]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(1)))[[1]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), report_
˓→edges=True, labels=True))[[(1, 4, 30), (4, 5, 30)], [(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), report_
˓→edges=True, labels=True, by_weight=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), report_
˓→edges=True, labels=True, by_weight=True, report_weight=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]>>> from sage.graphs.path_enumeration import feng_k_shortest_simple_paths>>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3),␣
˓→Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5),␣
˓→Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5),␣
˓→Integer(30)), (Integer(1), Integer(6), Integer(100)), (Integer(5), Integer(6),␣
˓→Integer(5))])>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6), by_weight =␣˓→True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6)))[[1, 6], [1, 4, 5, 6], [1, 3, 5, 6], [1, 2, 5, 6]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6), report_
˓→edges=True, labels=True, by_weight=True, report_weight=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6), report_
˓→edges=True, labels=True, report_weight=True))[(1, [(1, 6, 100)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(continues on next page)

1876

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)])]>>> from sage.graphs.path_enumeration import feng_k_shortest_simple_paths>>> g = DiGraph([(Integer(1), Integer(2), Integer(5)), (Integer(2), Integer(3),␣
˓→Integer(0)), (Integer(1), Integer(4), Integer(2)), (Integer(4), Integer(5),␣
˓→Integer(1)), (Integer(5), Integer(3), Integer(0))])>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), by_weight=True))[[1, 4, 5, 3], [1, 2, 3]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3)))[[1, 2, 3], [1, 4, 5, 3]]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_
˓→weight=True))[(2, [1, 2, 3]), (3, [1, 4, 5, 3])]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_
˓→weight=True, report_edges=True))[(2, [(1, 2), (2, 3)]), (3, [(1, 4), (4, 5), (5, 3)])]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_
˓→weight=True, report_edges=True, by_weight=True))[(3, [(1, 4), (4, 5), (5, 3)]), (5, [(1, 2), (2, 3)])]>>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_
˓→weight=True, report_edges=True, by_weight=True, labels=True))[(3, [(1, 4, 2), (4, 5, 1), (5, 3, 0)]), (5, [(1, 2, 5), (2, 3, 0)])]sage.graphs.path_enumeration.shortest_simple_paths(self, source, target,
weight_function=None, by_weight=False,
check_weight=True, algorithm=None,
report_edges=False, labels=False,
report_weight=False)
Return an iterator over the simple paths between a pair of vertices.
This method returns an iterator over the simple paths (i.e., without repetition) from source to target. By
default (by_weight is False), the paths are reported by increasing number of edges. When by_weight isTrue, the paths are reported by increasing weights.
In case of weighted graphs negative weights are not allowed.
If source is the same vertex as target, then [[source]] is returned – a list containing the 1-vertex, 0-edge
path source.
By default Yen s algorithm [Yen1970] is used for undirected graphs and Feng s algorithm is used for directed
graphs [Feng2014].
The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels is kept
in case of multiedges.
INPUT:• source – a vertex of the graph, where to start• target – a vertex of the graph, where to end• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l as a weight.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1• check_weight – boolean (default: True); whether to check that the weight_function outputs anumber for each edge.

5.38. Path enumeration

1877

Graph Theory, Release 10.4

• algorithm – string (default: None); the algorithm to use in computing k shortest paths of self. The
following algorithms are supported:– "Yen" – Yen’s algorithm [Yen1970]– "Feng" – an improved version of Yen’s algorithm but that works only for directed graphs [Feng2014]• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list ofedges. When set to False, the labels parameter is ignored.
• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise
a list of edges along with its edge labels are used to represent the path.
• report_weight – boolean (default: False); if False, just the path between source and target isreturned. Otherwise a tuple of path length and path is returned.
EXAMPLES:
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30),....:
(2, 5, 20), (3, 5, 10), (4, 5, 30)])
sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Yen"))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]
sage: list(g.shortest_simple_paths(1, 5, algorithm="Yen"))[[1, 2, 5], [1, 3, 5], [1, 4, 5]]
sage: list(g.shortest_simple_paths(1, 1))[[1]]
sage: list(g.shortest_simple_paths(1, 5, by_weight=True,....:
report_edges=True, report_weight=True,␣
˓→labels=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng",....:
report_edges=True, report_weight=True))[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True))[(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])]sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True))[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng",....:
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20),....:
(3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)])sage: list(g.shortest_simple_paths(1, 6, by_weight = True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]
sage: list(g.shortest_simple_paths(1, 6, algorithm="Yen"))[[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]]
sage: list(g.shortest_simple_paths(1, 6,....:
report_edges=True, report_weight=True,␣
˓→labels=True))[(1, [(1, 6, 100)]),(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])]sage: list(g.shortest_simple_paths(1, 6, by_weight=True,....:
report_edges=True, report_weight=True,␣
˓→labels=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(continues on next page)

1878

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]sage: list(g.shortest_simple_paths(1, 6, by_weight=True,....:
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)],[(1, 6, 100)]]
sage: list(g.shortest_simple_paths(1, 6, report_edges=True, labels=True))[[(1, 6, 100)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)]]>>> from sage.all import *>>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3),␣
˓→Integer(10)), (Integer(1), Integer(4), Integer(30)),...
(Integer(2), Integer(5), Integer(20)), (Integer(3), Integer(5),␣
˓→Integer(10)), (Integer(4), Integer(5), Integer(30))])>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,␣
˓→algorithm="Yen"))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), algorithm="Yen"))[[1, 2, 5], [1, 3, 5], [1, 4, 5]]>>> list(g.shortest_simple_paths(Integer(1), Integer(1)))[[1]]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,...
report_edges=True, report_weight=True,␣
˓→labels=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,␣
˓→algorithm="Feng",...
report_edges=True, report_weight=True))[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), report_edges=True,␣
˓→report_weight=True))[(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True, report_
˓→edges=True))[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]>>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True,␣
˓→algorithm="Feng",...
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]>>> g = Graph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3),␣
˓→Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5),␣
˓→Integer(20)),...
(Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5),␣
˓→Integer(30)), (Integer(1), Integer(6), Integer(100)), (Integer(5), Integer(6),␣
˓→Integer(5))])>>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight = True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), algorithm="Yen"))[[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]](continues on next page)

5.38. Path enumeration

1879

Graph Theory, Release 10.4

(continued from previous page)>>> list(g.shortest_simple_paths(Integer(1), Integer(6),...
report_edges=True, report_weight=True,␣
˓→labels=True))[(1, [(1, 6, 100)]),(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight=True,...
report_edges=True, report_weight=True,␣
˓→labels=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight=True,...
report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)],[(1, 6, 100)]]>>> list(g.shortest_simple_paths(Integer(1), Integer(6), report_edges=True,␣
˓→labels=True))[[(1, 6, 100)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)]]sage.graphs.path_enumeration.yen_k_shortest_simple_paths(self, source, target,
weight_function=None,by_weight=False,
check_weight=True,
report_edges=False,labels=False,
report_weight=False)
Return an iterator over the simple paths between a pair of vertices in increasing order of weights.
For unweighted graphs paths are returned in order of increasing number of edges.
In case of weighted graphs negative weights are not allowed.
If source is the same vertex as target, then [[source]] is returned – a list containing the 1-vertex, 0-edge
path source.
The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels is kept
in case of multiedges.
INPUT:• source – a vertex of the graph, where to start• target – a vertex of the graph, where to end• weight_function – function (default: None); a function that takes as input an edge (u, v, l) andoutputs its weight. If not None, by_weight is automatically set to True. If None and by_weight isTrue, we use the edge label l as a weight.
• by_weight – boolean (default: False); if True, the edges in the graph are weighted, otherwise all edges
have weight 1

1880

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• check_weight – boolean (default: True); whether to check that the weight_function outputs anumber for each edge
• report_edges – boolean (default: False); whether to report paths as list of vertices (default) or list ofedges, if False then labels parameter is ignored• labels – boolean (default: False); if False, each edge is simply a pair (u, v) of vertices. Otherwise
a list of edges along with its edge labels are used to represent the path.
• report_weight – boolean (default: False); if False, just the path between source and target isreturned. Otherwise a tuple of path length and path is returned.
ALGORITHM:
This algorithm can be divided into two parts. Firstly, it determines a shortest path from source to target.
Then, it determines all the other 𝑘-shortest paths. This algorithm finds the deviations of previous shortest paths todetermine the next shortest paths.
Time complexity is 𝑂(𝑘𝑛(𝑚 + 𝑛 log 𝑛)) where 𝑛 is the number of vertices and 𝑚 is the number of edges and 𝑘 is
the number of shortest paths needed to find.
See [Yen1970] and the Wikipedia article Yen%27s_algorithm for more details on the algorithm.
EXAMPLES:
sage: from sage.graphs.path_enumeration import yen_k_shortest_simple_paths
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4,˓→ 5, 30)])
sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]
sage: list(yen_k_shortest_simple_paths(g, 1, 5))[[1, 2, 5], [1, 3, 5], [1, 4, 5]]
sage: list(yen_k_shortest_simple_paths(g, 1, 1))[[1]]
sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True,
˓→ report_weight=True, labels=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True,
˓→ report_weight=True))[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]sage: list(yen_k_shortest_simple_paths(g, 1, 5, report_edges=True, report_
˓→weight=True))[(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])]sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_
˓→edges=True))[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True,
˓→ labels=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]
sage: from sage.graphs.path_enumeration import yen_k_shortest_simple_paths
sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4,␣
˓→5, 30), (1, 6, 100), (5, 6, 5)])sage: list(yen_k_shortest_simple_paths(g, 1, 6, by_weight = True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]
sage: list(yen_k_shortest_simple_paths(g, 1, 6))[[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]]
sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, report_
˓→weight=True, labels=True))(continues on next page)

5.38. Path enumeration

1881

Graph Theory, Release 10.4

(continued from previous page)[(1, [(1, 6, 100)]),(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])]sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, report_
˓→weight=True, labels=True, by_weight=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True,␣
˓→by_weight=True))[[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)],[(1, 6, 100)]]
sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True))[[(1, 6, 100)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)]]>>> from sage.all import *>>> from sage.graphs.path_enumeration import yen_k_shortest_simple_paths>>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3),␣
˓→Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5),␣
˓→Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5),␣
˓→Integer(30))])>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True))[[1, 3, 5], [1, 2, 5], [1, 4, 5]]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5)))[[1, 2, 5], [1, 3, 5], [1, 4, 5]]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(1)))[[1]]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True,␣
˓→report_edges=True, report_weight=True, labels=True))[(20, [(1, 3, 10), (3, 5, 10)]),(40, [(1, 2, 20), (2, 5, 20)]),(60, [(1, 4, 30), (4, 5, 30)])]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True,␣
˓→report_edges=True, report_weight=True))[(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), report_edges=True,
˓→ report_weight=True))[(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True,␣
˓→report_edges=True))[[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True,␣
˓→report_edges=True, labels=True))[[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]]>>> from sage.graphs.path_enumeration import yen_k_shortest_simple_paths>>> g = Graph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3),␣
˓→Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5),␣
˓→Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5),␣
˓→Integer(30)), (Integer(1), Integer(6), Integer(100)), (Integer(5), Integer(6),␣
(continues on next page)

1882

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

Integer(5))])>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), by_weight = True))[[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6)))[[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True,
˓→ report_weight=True, labels=True))[(1, [(1, 6, 100)]),(3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True,
˓→ report_weight=True, labels=True, by_weight=True))[(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]),(45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]),(65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]),(100, [(1, 6, 100)])]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True,
˓→ labels=True, by_weight=True))[[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)],[(1, 6, 100)]]>>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True,
˓→ labels=True))[[(1, 6, 100)],[(1, 2, 20), (2, 5, 20), (5, 6, 5)],[(1, 3, 10), (3, 5, 10), (5, 6, 5)],[(1, 4, 30), (4, 5, 30), (5, 6, 5)]]˓→

5.39 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 searchclass sage.graphs.generic_graph_pyx.GenericGraph_pyx
Bases: 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 representativeof ℎ1 , then a representative of ℎ2 compatible with ℎ1 , then a representative of ℎ3 compatible with the first two,
etc.
(︀
)︀
This way, most of the time we need to test far less than 𝑘! |𝑉 (𝐺)|subsets, and hope this brute-force technique can𝑘sometimes be useful.
5.39. GenericGraph Cython functions

1883

Graph Theory, Release 10.4

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 tocount 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)˓→needs sage.modules
sage: S.cardinality()
˓→needs sage.modules
6>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import SubgraphSearch>>> g = graphs.PathGraph(Integer(5))>>> h = graphs.PathGraph(Integer(3))>>> S = SubgraphSearch(g, h)˓→needs sage.modules>>> S.cardinality()
˓→needs sage.modules
6

#␣
#␣

#␣
#␣

Check that the method is working even when vertices or edges are of incomparable types (see Issue #35904):
sage: from sage.graphs.generic_graph_pyx import SubgraphSearch
sage: G = Graph()
sage: G.add_cycle([ A , 1, 2, 3, ( a , 1)])
sage: H = Graph()
sage: H.add_path("xyz")
sage: S = SubgraphSearch(G, H)
˓→needs sage.modules
sage: S.cardinality()
˓→needs sage.modules
10

#␣
#␣

>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import SubgraphSearch>>> G = Graph()>>> G.add_cycle([ A , Integer(1), Integer(2), Integer(3), ( a , Integer(1))])>>> H = Graph()>>> H.add_path("xyz")>>> S = SubgraphSearch(G, H)#␣˓→needs sage.modules>>> S.cardinality()#␣(continues on next page)

1884

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)needs sage.modules˓→

10

sage.graphs.generic_graph_pyx.binary_string_from_dig6(s, n)
A helper function for the dig6 format.
INPUT:• s – a graph6 string• n – the length of the binary string encoded by s.
EXAMPLES:
sage: from sage.graphs.generic_graph_pyx import binary_string_from_dig6
sage: d6 = ?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O?????
sage: d6 += ?G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?
sage: d6 += CAOGO??????A??G?GR?C?_o ???g???A_C?OG??O?G_IA????_QO@EG???
sage: d6 += O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_
sage: d6 += C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G
sage: d6 += @A??O??_?A?????O@Z?_@M????GQ@_G@?C?
sage: binary_string_from_dig6(d6, 63)

000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000..
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000
˓→
˓→

˓→

sage: d6 = ???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG??
sage: d6 += ??I?J??Q??O?_@@??@??????
sage: binary_string_from_dig6(d6, 32)0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000
˓→
˓→

˓→

>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import binary_string_from_dig6>>> d6 = ?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O?????
>>> d6 += ?G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?
>>> d6 += CAOGO??????A??G?GR?C?_o ???g???A_C?OG??O?G_IA????_QO@EG???
>>> d6 += O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_>>> d6 += C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G>>> d6 += @A??O??_?A?????O@Z?_@M????GQ@_G@?C?
>>> binary_string_from_dig6(d6, Integer(63))

000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000..
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000
˓→
˓→

˓→

>>> d6 = ???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG??
>>> d6 += ??I?J??Q??O?_@@??@??????
>>> binary_string_from_dig6(d6, Integer(32))

0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000
˓→
˓→

˓→

5.39. GenericGraph Cython functions

1885

Graph Theory, Release 10.4

sage.graphs.generic_graph_pyx.binary_string_from_graph6(s, n)
Decode a binary string from its graph6 representation
This helper function is the inverse of 𝑅 from [McK2015].
INPUT:• s – a graph6 string• n – the length of the binary string encoded by s.
EXAMPLES:
sage: from sage.graphs.generic_graph_pyx import binary_string_from_graph6
sage: g6 = ?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O?????
sage: g6 += ?G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?
sage: g6 += CAOGO??????A??G?GR?C?_o ???g???A_C?OG??O?G_IA????_QO@EG???
sage: g6 += O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_
sage: g6 += C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G
sage: g6 += @A??O??_?A?????O@Z?_@M????GQ@_G@?C?
sage: binary_string_from_graph6(g6, 63)

000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000..
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000
˓→
˓→

˓→

sage: g6 = ???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG??
sage: g6 += ??I?J??Q??O?_@@??@??????
sage: binary_string_from_graph6(g6, 32)0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000
˓→
˓→

˓→

>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import binary_string_from_graph6>>> g6 = ?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O?????
>>> g6 += ?G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?
>>> g6 += CAOGO??????A??G?GR?C?_o ???g???A_C?OG??O?G_IA????_QO@EG???
>>> g6 += O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_>>> g6 += C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G>>> g6 += @A??O??_?A?????O@Z?_@M????GQ@_G@?C?
>>> binary_string_from_graph6(g6, Integer(63))

000000000000000000000000000000100000000001000000000100001000000000000000000011000000000000000..
˓→1000000000000000000000000000000001000000000101101100000010000000000100111000000000000000000000
˓→
˓→

˓→

>>> g6 = ???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG??
>>> g6 += ??I?J??Q??O?_@@??@??????
>>> binary_string_from_graph6(g6, Integer(32))

0000000000000000000001000000000000010000100000100000001000000000000000100000000100000.
..
˓→0100000000000001000100000010000000000000000000000000000010100000000010110000000000000100100000
˓→
˓→

˓→

sage.graphs.generic_graph_pyx.binary_string_to_graph6(x)Transform a binary string into its graph6 representation.
1886

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

This helper function is named 𝑅 in [McK2015].
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>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import binary_string_to_graph6>>> binary_string_to_graph6( 110111010110110010111000001100000001000000001 )vUqwK@?G

sage.graphs.generic_graph_pyx.find_hamiltonian(G, max_iter=100000, reset_bound=30000,
backtrack_bound=1000, find_path=False)
Randomized backtracking for finding Hamiltonian cycles and paths.
ALGORITHM:
A path P is maintained during the execution of the algorithm. Initially the path will contain an edge of the graph.
Every 10 iterations the path is reversed. Every reset_bound iterations the path will be cleared and the procedure
is restarted. Every backtrack_bound steps we discard the last five vertices and continue with the procedure.
The total number of steps in the algorithm is controlled by max_iter. If a Hamiltonian cycle or Hamiltonian path
is found it is returned. If the number of steps reaches max_iter then a longest path is returned. See OUTPUT
for more details.
INPUT:• G – graph• max_iter – maximum number of iterations• reset_bound – number of iterations before restarting theprocedure• 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:
For demonstration purposes we fix a random seed:

5.39. GenericGraph Cython functions

1887

Graph Theory, Release 10.4

sage: set_random_seed(0)>>> from sage.all import *>>> set_random_seed(Integer(0))

First we try the algorithm in the Dodecahedral graph, which is Hamiltonian, so we are able to find a Hamiltonian
cycle and a Hamiltonian path:sage: from sage.graphs.generic_graph_pyx import find_hamiltonian as fhsage: 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])>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import find_hamiltonian as fh>>> G=graphs.DodecahedralGraph()>>> fh(G)(True, [12, 11, 10, 9, 13, 14, 15, 5, 4, 3, 2, 6, 7, 8, 1, 0, 19, 18, 17, 16])>>> 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])>>> from sage.all import *>>> G=graphs.MoebiusKantorGraph()>>> fh(G)(True, [15, 10, 2, 3, 4, 5, 13, 8, 11, 14, 6, 7, 0, 1, 9, 12])>>> 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 hypohamiltonian, so a Hamiltonian path can be found:sage: G=graphs.PetersenGraph()
sage: fh(G)(False, [9, 4, 0, 1, 6, 8, 5, 7, 2, 3])
sage: fh(G,find_path=True)(True, [7, 2, 1, 0, 5, 8, 6, 9, 4, 3])>>> from sage.all import *>>> G=graphs.PetersenGraph()>>> fh(G)(False, [9, 4, 0, 1, 6, 8, 5, 7, 2, 3])>>> 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
1888

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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])>>> from sage.all import *>>> G=graphs.GeneralizedPetersenGraph(Integer(11),Integer(2))>>> 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])>>> 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: G.order()10sage: b, P = fh(G,find_path=False)
sage: b, len(P)(False, 9)
sage: b, P = fh(G,find_path=True)
sage: b, len(P)(False, 9)>>> from sage.all import *>>> G = graphs.HyperStarGraph(Integer(5), Integer(2))>>> G.order()10>>> b, P = fh(G,find_path=False)>>> b, len(P)(False, 9)>>> b, P = fh(G,find_path=True)>>> b, len(P)(False, 9)

The method can also be used for directed graphs:
sage: G = DiGraph([(0, 1), (1, 2), (2, 3)])sage: fh(G)(False, [0, 1, 2, 3])
sage: G = G.reverse()
sage: fh(G)(False, [3, 2, 1, 0])
sage: G = DiGraph()
sage: G.add_cycle([0, 1, 2, 3, 4, 5])
sage: b, P = fh(G)sage: b, len(P)(True, 6)

5.39. GenericGraph Cython functions

1889

Graph Theory, Release 10.4>>> from sage.all import *>>> G = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(2)), (Integer(2),␣
˓→Integer(3))])>>> fh(G)(False, [0, 1, 2, 3])>>> G = G.reverse()>>> fh(G)(False, [3, 2, 1, 0])>>> G = DiGraph()>>> G.add_cycle([Integer(0), Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5)])>>> b, P = fh(G)>>> b, len(P)(True, 6)

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>>> from sage.all import *>>> sage.graphs.generic_graph_pyx.int_to_binary_string(Integer(389))
110000101>>> Integer(Integer(389)).binary()
110000101>>> sage.graphs.generic_graph_pyx.int_to_binary_string(Integer(2007))
11111010111

sage.graphs.generic_graph_pyx.layout_split(layout_function, G, **options)
Graph each component of G separately with layout_function, placing them adjacent to each other.
This is done because several layout methods need the input graph to be connected. For instance, on a disconnected
graph, the spring layout will push components further and further from each other without bound, resulting in very
tight clumps for each component.
Note: If the axis are scaled to fit the plot in a square, the horizontal distance may end up being “squished” due tothe several adjacent components.
EXAMPLES:
sage: G = graphs.DodecahedralGraph()
sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3)))
sage: from sage.graphs.generic_graph_pyx import layout_split, spring_layout_fast
sage: D = layout_split(spring_layout_fast, G); D # random{0: [0.77..., 0.06...],(continues on next page)

1890

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)...
902: [3.13..., 0.22...]}>>> from sage.all import *>>> G = graphs.DodecahedralGraph()>>> for i in range(Integer(10)): G.add_cycle(list(range(Integer(100)*i,␣
˓→Integer(100)*i+Integer(3))))>>> from sage.graphs.generic_graph_pyx import layout_split, spring_layout_fast>>> D = layout_split(spring_layout_fast, G); D # random{0: [0.77..., 0.06...],...
902: [3.13..., 0.22...]}AUTHOR:
Robert Bradshaw
sage.graphs.generic_graph_pyx.length_and_string_from_graph6(s)Return a pair (length, graph6_string) from a graph6 string of unknown length.
This helper function is the inverse of 𝑁 from [McK2015].
INPUT:• s – a graph6 string describing a binary vector (and encoding its length).
EXAMPLES:
sage: from sage.graphs.generic_graph_pyx import length_and_string_from_graph6
sage: g6 = ~??~?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O?
sage: g6 += ?????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?C
sage: g6 += C?A?CAOGO??????A??G?GR?C?_o ???g???A_C?OG??O?G_IA????_QO@E
sage: g6 += G???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAA
sage: g6 += Cd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?
sage: g6 += aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?
sage: length_and_string_from_graph6(g6)(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: g6 = _???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG?
sage: g6 += ???I?J??Q??O?_@@??@??????
sage: length_and_string_from_graph6(g6)(32, ???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??
˓→@?????? )>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import length_and_string_from_graph6>>> g6 = ~??~?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O?
>>> g6 += ?????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?C>>> g6 += C?A?CAOGO??????A??G?GR?C?_o ???g???A_C?OG??O?G_IA????_QO@E>>> g6 += G???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAA>>> g6 += Cd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?
>>> g6 += aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?
>>> length_and_string_from_graph6(g6)(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??
(continues on next page)

5.39. GenericGraph Cython functions

1891

Graph Theory, Release 10.4

(continued from previous page)

O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??
˓→G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M???
˓→?GQ@_G@?C? )>>> g6 = _???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG?
>>> g6 += ???I?J??Q??O?_@@??@??????
>>> length_and_string_from_graph6(g6)(32, ???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??
˓→@?????? )˓→

sage.graphs.generic_graph_pyx.small_integer_to_graph6(n)Encode a small integer (i.e. a number of vertices) as a graph6 string.
This helper function is named 𝑁 [McK2015].
INPUT:• n (integer)
EXAMPLES:
sage: 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>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import small_integer_to_graph6>>> small_integer_to_graph6(Integer(13))
L>>> small_integer_to_graph6(Integer(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 afunction 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] # random[0.00..., 0.03...]sage: sorted(pos.keys()) == sorted(G)
True

1892

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.DodecahedralGraph()>>> for i in range(Integer(10)): G.add_cycle(list(range(Integer(100)*i,␣
˓→Integer(100)*i+Integer(3))))>>> from sage.graphs.generic_graph_pyx import spring_layout_fast>>> pos = spring_layout_fast(G)>>> pos[Integer(0)] # random[0.00..., 0.03...]>>> sorted(pos.keys()) == sorted(G)TrueWith split=True, each component of G is laid out separately, placing them adjacent to each other. This isdone because on a disconnected graph, the spring layout will push components further and further from each otherwithout bound, resulting in very tight clumps for each component.
If the axis are scaled to fit the plot in a square, the horizontal distance may end up being “squished” due to theseveral adjacent components.
sage: G = graphs.DodecahedralGraph()
sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3)))
sage: from sage.graphs.generic_graph_pyx import spring_layout_fast
sage: pos = spring_layout_fast(G, by_component = True)
sage: pos[0] # random[2.21..., -0.00...]sage: len(pos) == G.order()True>>> from sage.all import *>>> G = graphs.DodecahedralGraph()>>> for i in range(Integer(10)): G.add_cycle(list(range(Integer(100)*i,␣
˓→Integer(100)*i+Integer(3))))>>> from sage.graphs.generic_graph_pyx import spring_layout_fast>>> pos = spring_layout_fast(G, by_component = True)>>> pos[Integer(0)] # random[2.21..., -0.00...]>>> len(pos) == G.order()Truesage.graphs.generic_graph_pyx.transitive_reduction_acyclic(G)Return 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>>> from sage.all import *>>> from sage.graphs.generic_graph_pyx import transitive_reduction_acyclic>>> G = posets.BooleanLattice(Integer(4)).hasse_diagram()>>> G == transitive_reduction_acyclic(G.transitive_closure())
True

5.39. GenericGraph Cython functions

1893

Graph Theory, Release 10.4

5.40 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
strong_orientations_iterator()
random_orientation()

Return an iterator over all strong orientations of a graph 𝐺
Return a random orientation of a graph 𝐺

5.40.1 Authors• Kolja Knauer, Petru Valicov (2017-01-10) – initial version

5.40.2 Methods
sage.graphs.orientations.acyclic_orientations(G)Return an iterator over all acyclic orientations of an undirected graph 𝐺.
ALGORITHM:
The algorithm is based on [Sq1998]. It presents an efficient algorithm for listing the acyclic orientations of a graph.
The algorithm is shown to require O(n) time per acyclic orientation generated, making it the most efficient known
algorithm for generating acyclic orientations.
The function uses a recursive approach to generate acyclic orientations of the graph. It reorders the vertices andedges of the graph, creating a new graph with updated labels. Then, it iteratively generates acyclic orientations byconsidering subsets of edges and checking whether they form upsets in a corresponding poset.
INPUT:• G – an undirected graph.
OUTPUT:• An iterator over all acyclic orientations of the input graph.
Note: The function assumes that the input graph is undirected and the edges are unlabelled.
EXAMPLES:
To count number acyclic orientations for a graph:
sage: g = Graph([(0, 3), (0, 4), (3, 4), (1, 3), (1, 2), (2, 3), (2, 4)])sage: it = g.acyclic_orientations()
sage: len(list(it))
54>>> from sage.all import *>>> g = Graph([(Integer(0), Integer(3)), (Integer(0), Integer(4)), (Integer(3),␣
˓→Integer(4)), (Integer(1), Integer(3)), (Integer(1), Integer(2)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(4))])(continues on next page)

1894

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> it = g.acyclic_orientations()>>> len(list(it))
54

Test for arbitary vertex labels:
sage: g_str = Graph([( abc , def ), ( ghi ,˓→ ), ( uvw ,abc ), ( uvw , ghi )])sage: it = g_str.acyclic_orientations()
sage: len(list(it))
42>>> from sage.all import *>>> g_str = Graph([( abc , def ), ( ghi ,˓→ ( uvw ,abc ), ( uvw , ghi )])>>> it = g_str.acyclic_orientations()>>> len(list(it))
42

def ), ( xyz ,def ), ( xyz ,abc ), ( xyz ,abc ), ( xyz ,uvwuvw ),

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)>>> from sage.all import *>>> from sage.graphs.orientations import random_orientation>>> G = graphs.PetersenGraph()>>> D = random_orientation(G)>>> D.order() == G.order(), D.size() == G.size()(True, True)

See also:• orientations()• strong_orientation()• strong_orientations_iterator()• nauty_directg()
sage.graphs.orientations.strong_orientations_iterator(G)Return an iterator over all strong orientations of a graph 𝐺.

5.40. Orientations

1895

Graph Theory, Release 10.4

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). According to Robbins’ theorem (see the Wikipedia
article Robbins_theorem), the graphs that have strong orientations are exactly the 2-edge-connected graphs (i.e.,the bridgeless graphs).
ALGORITHM:
It is an adaptation of the algorithm published in [CGMRV16]. It runs in 𝑂(𝑚𝑛) amortized time, where 𝑚 is thenumber 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 symmetries, the orientation of an arbitrary edge isfixed before the start of the enumeration process.
INPUT:• G – an undirected graph.
OUTPUT:• an iterator which will produce all strong orientations of this graph.
Note: Works only for simple graphs (no multiple edges). To avoid symmetries an orientation of an arbitrary edge
is fixed.
See also:• orientations()• strong_orientation()• nauty_directg()• random_orientation()
EXAMPLES:
A cycle has one possible (non-symmetric) strong orientation:
sage: g = graphs.CycleGraph(4)sage: it = g.strong_orientations_iterator()sage: len(list(it))
1>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(4))>>> it = g.strong_orientations_iterator()>>> len(list(it))
1

A tree cannot be strongly oriented:
sage: g = graphs.RandomTree(10)sage: len(list(g.strong_orientations_iterator()))
0

1896

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.RandomTree(Integer(10))>>> 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>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(6))>>> g.add_vertex(Integer(7))>>> len(list(g.strong_orientations_iterator()))
05.41 Connectivity related functions
This module implements the connectivity based functions for graphs and digraphs. The methods in this module are alsoavailable as part of GenericGraph, DiGraph or Graph classes as aliases, and these methods can be accessed through thismodule or as class methods. Here is what the module can do:
For both directed and undirected graphs:
is_connected()connected_components()
connected_components_number()connected_components_subgraphs()
connected_component_containing_vertex()
connected_components_sizes()
blocks_and_cut_vertices()
blocks_and_cuts_tree()is_cut_edge()
is_cut_vertex()
edge_connectivity()vertex_connectivity()

Check whether the (di)graph is connected.
Return the list of connected components
Return the number of connected components.
Return a list of connected components as graph objects.
Return a list of the vertices connected to vertex.
Return the sizes of the connected components as a list.
Return the blocks and cut vertices of the graph.
Return the blocks-and-cuts tree of the graph.
Return True if the input edge is a cut-edge or a bridge.
Check whether the input vertex is a cut-vertex.
Return the edge connectivity of the graph.
Return the vertex connectivity of the graph.

For DiGraph:5.41. Connectivity related functions

1897

Graph Theory, Release 10.4

is_strongly_connected()strongly_connected_components_digraph()strongly_connected_components_subgraphs()
strongly_connected_component_containing_vertex()strong_articulation_points()

Check whether the current DiGraph is strongly connected.
Return the digraph of the strongly connected components
Return the strongly connected components as a list of subgraphs.

Return the strongly connected component containing a given vertex.
Return the strong articulation points of this digraph.

For undirected graphs:
bridges()cleave()is_triconnected()
spqr_tree()
spqr_tree_to_graph()

Returns an iterator over the bridges (or cut edges) of given undirected graph.
Return the connected subgraphs separated by the input vertex cut.
Check whether the graph is triconnected.
Return a SPQR-tree representing the triconnected components of the graph.
Return the graph represented by the SPQR-tree 𝑇 .

5.41.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 thenorganizes 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)graphand the 2-vertex cuts separating them. A node of a SPQR-tree, and the graph associated with it, can be one of thefollowing four types:• "S" – the associated graph is a cycle with at least three vertices. "S" stands for series and is also calleda 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
1898

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

See also:• sage.graphs.connectivity.spqr_tree()• is_biconnected()• Wikipedia article SPQR_tree
EXAMPLES:
Example from the Wikipedia article SPQR_tree:
sage: from sage.graphs.connectivity import TriconnectivitySPQR
sage: from sage.graphs.connectivity import spqr_tree_to_graphsage: 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>>> from sage.all import *>>> from sage.graphs.connectivity import TriconnectivitySPQR>>> from sage.graphs.connectivity import spqr_tree_to_graph>>> G = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(4)), (Integer(1),␣
˓→Integer(8)), (Integer(1), Integer(12)), (Integer(3), Integer(4)), (Integer(2),␣
˓→Integer(3)),... (Integer(2), Integer(13)), (Integer(3), Integer(13)), (Integer(4),␣
˓→Integer(5)), (Integer(4), Integer(7)), (Integer(5), Integer(6)), (Integer(5),␣
˓→Integer(8)), (Integer(5), Integer(7)), (Integer(6), Integer(7)),... (Integer(8), Integer(11)), (Integer(8), Integer(9)), (Integer(8),␣
˓→Integer(12)), (Integer(9), Integer(10)), (Integer(9), Integer(11)), (Integer(9),˓→ Integer(12)), (Integer(10), Integer(12))])>>> tric = TriconnectivitySPQR(G)>>> T = tric.get_spqr_tree()>>> 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: T = tric.get_spqr_tree()sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: tric.print_triconnected_components()
Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10, 11,
˓→ None), (9, 10, None), (10, 12, None), (8, 12,
newVEdge0 )]Bond: [(8, 12, None), (8, 12, newVEdge0 ), (8, 12, newVEdge1 )]Polygon: [(6, 7, None), (5, 6, None), (7, 5, newVEdge2 )]Bond: [(7, 5, newVEdge2 ), (5, 7, newVEdge3 ), (5, 7, None)]
Polygon: [(5, 7, newVEdge3 ), (4, 7, None), (5, 4, newVEdge4 )]Bond: [(5, 4, newVEdge4 ), (4, 5, newVEdge5 ), (4, 5, None)]
Polygon: [(4, 5, newVEdge5 ), (5, 8, None), (1, 4, newVEdge9 ), (1, 8,(continues on next page)

5.41. Connectivity related functions

1899

Graph Theory, Release 10.4

(continued from previous page)

newVEdge10 )]Triconnected: [(1, 2, None), (2, 13, None), (1, 13, None), (3, 13, None), (2, 3,␣
˓→None), (1, 3,
newVEdge7 )]Polygon: [(1, 3, newVEdge7 ), (3, 4, None), (1, 4, newVEdge8 )]Bond: [(1, 4, None), (1, 4, newVEdge8 ), (1, 4, newVEdge9 )]Bond: [(1, 8, None), (1, 8, newVEdge10 ), (1, 8, newVEdge11 )]Polygon: [(8, 12, newVEdge1 ), (1, 8, newVEdge11 ), (1, 12, None)]˓→>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(4)), (Integer(1),␣
˓→Integer(8)), (Integer(1), Integer(12)), (Integer(1), Integer(13)), (Integer(2),␣
˓→Integer(3)),... (Integer(2), Integer(13)), (Integer(3), Integer(4)), (Integer(3),␣
˓→Integer(13)), (Integer(4), Integer(5)), (Integer(4), Integer(7)), (Integer(5),␣
˓→Integer(6)), (Integer(5), Integer(7)), (Integer(5), Integer(8)),... (Integer(6), Integer(7)), (Integer(8), Integer(9)), (Integer(8), Integer(11)),
˓→ (Integer(8), Integer(12)), (Integer(9), Integer(10)), (Integer(9),␣
˓→Integer(11)), (Integer(9), Integer(12)),... (Integer(10), Integer(11)), (Integer(10), Integer(12))])>>> tric = TriconnectivitySPQR(G)>>> T = tric.get_spqr_tree()>>> G.is_isomorphic(spqr_tree_to_graph(T))
True>>> tric.print_triconnected_components()
Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10, 11,
˓→ None), (9, 10, None), (10, 12, None), (8, 12,
newVEdge0 )]Bond: [(8, 12, None), (8, 12, newVEdge0 ), (8, 12, newVEdge1 )]Polygon: [(6, 7, None), (5, 6, None), (7, 5, newVEdge2 )]Bond: [(7, 5, newVEdge2 ), (5, 7, newVEdge3 ), (5, 7, None)]
Polygon: [(5, 7, newVEdge3 ), (4, 7, None), (5, 4, newVEdge4 )]Bond: [(5, 4, newVEdge4 ), (4, 5, newVEdge5 ), (4, 5, None)]
Polygon: [(4, 5, newVEdge5 ), (5, 8, None), (1, 4, newVEdge9 ), (1, 8,
˓→ newVEdge10 )]Triconnected: [(1, 2, None), (2, 13, None), (1, 13, None), (3, 13, None), (2, 3,␣
˓→None), (1, 3,
newVEdge7 )]Polygon: [(1, 3, newVEdge7 ), (3, 4, None), (1, 4, newVEdge8 )]Bond: [(1, 4, None), (1, 4, newVEdge8 ), (1, 4, newVEdge9 )]Bond: [(1, 8, None), (1, 8, newVEdge10 ), (1, 8, newVEdge11 )]Polygon: [(8, 12, newVEdge1 ), (1, 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>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(4)), (Integer(2),␣
˓→Integer(3)), (Integer(2), Integer(5)), (Integer(3), Integer(4)), (Integer(3),␣
˓→Integer(5)), (Integer(4), Integer(5)),... (Integer(4), Integer(6)), (Integer(5), Integer(7)), (Integer(5), Integer(8)),␣
˓→(Integer(5), Integer(14)), (Integer(6), Integer(8)), (Integer(7), Integer(14)),␣
(continues on next page)

1900

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)(Integer(8), Integer(9)), (Integer(8), Integer(10)),... (Integer(8), Integer(11)), (Integer(8), Integer(12)), (Integer(9),␣
˓→Integer(10)), (Integer(10), Integer(13)), (Integer(10), Integer(14)),␣
˓→(Integer(10), Integer(15)), (Integer(10), Integer(16)),... (Integer(11), Integer(12)), (Integer(11), Integer(13)), (Integer(12),␣
˓→Integer(13)), (Integer(14), Integer(15)), (Integer(14), Integer(16)),␣
˓→(Integer(15), Integer(16))])>>> T = TriconnectivitySPQR(G).get_spqr_tree()>>> 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: T = tric.get_spqr_tree()sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
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)]>>> from sage.all import *>>> G = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(5)), (Integer(1),␣
˓→Integer(5)), (Integer(2), Integer(3)), (Integer(2), Integer(3)), (Integer(3),␣
˓→Integer(4)), (Integer(4), Integer(5))], multiedges=True)>>> tric = TriconnectivitySPQR(G)>>> T = tric.get_spqr_tree()>>> G.is_isomorphic(spqr_tree_to_graph(T))
True>>> 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)]

An example of a triconnected graph:
sage: G = Graph([( a , b ), ( a , c ), ( a , d ), ( b ,˓→d )])sage: T = TriconnectivitySPQR(G).get_spqr_tree()sage: print(T.vertices(sort=True))[( R , Multi-graph on 4 vertices)]sage: G.is_isomorphic(spqr_tree_to_graph(T))
True>>> from sage.all import *>>> G = Graph([( a , b ), ( a , c ), ( a , d ), ( b ,˓→ d )])>>> T = TriconnectivitySPQR(G).get_spqr_tree()>>> print(T.vertices(sort=True))[( R , Multi-graph on 4 vertices)]>>> G.is_isomorphic(spqr_tree_to_graph(T))

c ), ( b ,c ), ( b ,d ), ( c ,d ), ( c ,(continues on next page)

5.41. Connectivity related functions

1901

Graph Theory, Release 10.4

(continued from previous page)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)]>>> from sage.all import *>>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(3),␣
˓→Integer(4)), (Integer(4), Integer(5)), (Integer(1), Integer(5)), (Integer(5),␣
˓→Integer(1))])>>> tric = TriconnectivitySPQR(G)>>> 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,....: (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: all(G.has_edge(e) for e in H.edge_iterator())
True
sage: all(H.has_edge(e) for e in G.edge_iterator())
True

15 ),

>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(1), 01 ), (Integer(0), Integer(4), 04 ),␣
˓→(Integer(1), Integer(2),12 ), (Integer(1), Integer(5), 15 ),... (Integer(2), Integer(3), 23 ), (Integer(2), Integer(6), 26 ), (Integer(3),␣
˓→Integer(7),37 ), (Integer(4), Integer(5), 45 ),... (Integer(5), Integer(6), 56 ), (Integer(6), Integer(7), Integer(67))])>>> T = TriconnectivitySPQR(G).get_spqr_tree()>>> H = spqr_tree_to_graph(T)>>> all(G.has_edge(e) for e in H.edge_iterator())
True>>> all(H.has_edge(e) for e in G.edge_iterator())
True

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 withit, 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.
1902

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• "Q" – the associated graph has a single real edge. This trivial case is necessary to handle the graph thathas 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 thedecomposition.
EXAMPLES:
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 if u[0] == R )True
sage: from sage.graphs.connectivity import spqr_tree_to_graphsage: 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 if u[0] == S )True
sage: G.is_isomorphic(spqr_tree_to_graph(Tree))True
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edge_iterator())
sage: tric = TriconnectivitySPQR(G)sage: Tree = tric.get_spqr_tree()sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] ==Truesage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True

S )

sage: G = graphs.CycleGraph(6)sage: tric = TriconnectivitySPQR(G)sage: Tree = tric.get_spqr_tree()sage: Tree.order()1sage: 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()3sage: G.is_isomorphic(spqr_tree_to_graph(Tree))(continues on next page)

5.41. Connectivity related functions

1903

Graph Theory, Release 10.4

(continued from previous page)True
sage: G = Graph([(0, 1)], multiedges=True)
sage: tric = TriconnectivitySPQR(G)sage: Tree = tric.get_spqr_tree()sage: Tree.vertices(sort=True)[( Q , Multi-graph on 2 vertices)]sage: G.add_edge(0, 1)
sage: Tree = TriconnectivitySPQR(G).get_spqr_tree()sage: Tree.vertices(sort=True)[( P , Multi-graph on 2 vertices)]>>> from sage.all import *>>> from sage.graphs.connectivity import TriconnectivitySPQR>>> G = Graph(Integer(2))>>> for i in range(Integer(3)):...
G.add_clique([Integer(0), Integer(1), G.add_vertex(), G.add_vertex()])>>> tric = TriconnectivitySPQR(G)>>> Tree = tric.get_spqr_tree()>>> K4 = graphs.CompleteGraph(Integer(4))>>> all(u[Integer(1)].is_isomorphic(K4) for u in Tree if u[Integer(0)] == R )True>>> from sage.graphs.connectivity import spqr_tree_to_graph>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G = Graph(Integer(2))>>> for i in range(Integer(3)):...
G.add_path([Integer(0), G.add_vertex(), G.add_vertex(), Integer(1)])>>> tric = TriconnectivitySPQR(G)>>> Tree = tric.get_spqr_tree()>>> C4 = graphs.CycleGraph(Integer(4))>>> all(u[Integer(1)].is_isomorphic(C4) for u in Tree if u[Integer(0)] == S )True>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edge_iterator())>>> tric = TriconnectivitySPQR(G)>>> Tree = tric.get_spqr_tree()>>> all(u[Integer(1)].is_isomorphic(C4) for u in Tree if u[Integer(0)] ==True>>> G.is_isomorphic(spqr_tree_to_graph(Tree))
True

S )

>>> G = graphs.CycleGraph(Integer(6))>>> tric = TriconnectivitySPQR(G)>>> Tree = tric.get_spqr_tree()>>> Tree.order()1>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G.add_edge(Integer(0), Integer(3))>>> tric = TriconnectivitySPQR(G)>>> Tree = tric.get_spqr_tree()(continues on next page)

1904

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> Tree.order()3>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G = Graph([(Integer(0), Integer(1))], multiedges=True)>>> tric = TriconnectivitySPQR(G)>>> Tree = tric.get_spqr_tree()>>> Tree.vertices(sort=True)[( Q , Multi-graph on 2 vertices)]>>> G.add_edge(Integer(0), Integer(1))>>> Tree = TriconnectivitySPQR(G).get_spqr_tree()>>> Tree.vertices(sort=True)[( P , Multi-graph on 2 vertices)]

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 component.
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)])]>>> from sage.all import *>>> from sage.graphs.connectivity import TriconnectivitySPQR>>> G = Graph(Integer(2))>>> for i in range(Integer(3)):...
G.add_path([Integer(0), G.add_vertex(), G.add_vertex(), Integer(1)])>>> tric = TriconnectivitySPQR(G)>>> 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: from sage.graphs.connectivity import spqr_tree_to_graphsage: 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),
(continues on next page)

5.41. Connectivity related functions

1905

Graph Theory, Release 10.4

(continued from previous page)....: (10, 11), (10, 12)])sage: tric = TriconnectivitySPQR(G)sage: T = tric.get_spqr_tree()sage: G.is_isomorphic(spqr_tree_to_graph(T))
True
sage: tric.print_triconnected_components()
Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10,˓→ 11, None), (9, 10, None), (10, 12, None), (8, 12,
newVEdge0 )]Bond: [(8, 12, None), (8, 12, newVEdge0 ), (8, 12, newVEdge1 )]Polygon: [(6, 7, None), (5, 6, None), (7, 5, newVEdge2 )]Bond: [(7, 5, newVEdge2 ), (5, 7, newVEdge3 ), (5, 7, None)]
Polygon: [(5, 7, newVEdge3 ), (4, 7, None), (5, 4, newVEdge4 )]Bond: [(5, 4, newVEdge4 ), (4, 5, newVEdge5 ), (4, 5, None)]
Polygon: [(4, 5, newVEdge5 ), (5, 8, None), (1, 4, newVEdge9 ), (1, 8,
˓→ newVEdge10 )]Triconnected: [(1, 2, None), (2, 13, None), (1, 13, None), (3, 13, None), (2,␣
˓→3, None), (1, 3,
newVEdge7 )]Polygon: [(1, 3, newVEdge7 ), (3, 4, None), (1, 4, newVEdge8 )]Bond: [(1, 4, None), (1, 4, newVEdge8 ), (1, 4, newVEdge9 )]Bond: [(1, 8, None), (1, 8, newVEdge10 ), (1, 8, newVEdge11 )]Polygon: [(8, 12, newVEdge1 ), (1, 8, newVEdge11 ), (1, 12, None)]>>> from sage.all import *>>> from sage.graphs.connectivity import TriconnectivitySPQR>>> from sage.graphs.connectivity import spqr_tree_to_graph>>> G = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(4)),␣
˓→(Integer(1), Integer(8)), (Integer(1), Integer(12)), (Integer(1),␣
˓→Integer(13)), (Integer(2), Integer(3)),... (Integer(2), Integer(13)), (Integer(3), Integer(4)), (Integer(3),␣
˓→Integer(13)), (Integer(4), Integer(5)), (Integer(4), Integer(7)),␣
˓→(Integer(5), Integer(6)), (Integer(5), Integer(7)), (Integer(5),␣
˓→Integer(8)),... (Integer(6), Integer(7)), (Integer(8), Integer(9)), (Integer(8),␣
˓→Integer(11)), (Integer(8), Integer(12)), (Integer(9), Integer(10)),␣
˓→(Integer(9), Integer(11)), (Integer(9), Integer(12)),... (Integer(10), Integer(11)), (Integer(10), Integer(12))])>>> tric = TriconnectivitySPQR(G)>>> T = tric.get_spqr_tree()>>> G.is_isomorphic(spqr_tree_to_graph(T))
True>>> tric.print_triconnected_components()
Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10,˓→ 11, None), (9, 10, None), (10, 12, None), (8, 12,
newVEdge0 )]Bond: [(8, 12, None), (8, 12, newVEdge0 ), (8, 12, newVEdge1 )]Polygon: [(6, 7, None), (5, 6, None), (7, 5, newVEdge2 )]Bond: [(7, 5, newVEdge2 ), (5, 7, newVEdge3 ), (5, 7, None)]
Polygon: [(5, 7, newVEdge3 ), (4, 7, None), (5, 4, newVEdge4 )]Bond: [(5, 4, newVEdge4 ), (4, 5, newVEdge5 ), (4, 5, None)]
Polygon: [(4, 5, newVEdge5 ), (5, 8, None), (1, 4, newVEdge9 ), (1, 8,
˓→ newVEdge10 )]Triconnected: [(1, 2, None), (2, 13, None), (1, 13, None), (3, 13, None), (2,␣
˓→3, None), (1, 3,
newVEdge7 )]Polygon: [(1, 3, newVEdge7 ), (3, 4, None), (1, 4, newVEdge8 )]Bond: [(1, 4, None), (1, 4, newVEdge8 ), (1, 4, newVEdge9 )]Bond: [(1, 8, None), (1, 8, newVEdge10 ), (1, 8, newVEdge11 )]Polygon: [(8, 12, newVEdge1 ), (1, 8, newVEdge11 ), (1, 12, None)]

1906

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage.graphs.connectivity.blocks_and_cut_vertices(G, algorithm='Tarjan_Boost', sort=False,
key=None)
Return 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 – string (default: "Tarjan_Boost"); the algorithm to use among:– "Tarjan_Boost" (default) – Tarjan’s algorithm (Boost implementation)– "Tarjan_Sage" – Tarjan’s algorithm (Sage implementation)• sort – boolean (default: False); whether to sort vertices inside the components and the list of cut vertices
currently only available for ``”Tarjan_Sage”``• key – a function (default: None); a function that takes a vertex as its one argument and returns a value thatcan be used for comparisons in the sorting algorithm (we must have sort=True)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: B, C = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=True)
sage: B, C([[0, 1, 2, 3, 4], [0, 6, 7, 8, 9]], [0])sage: B2, C2 = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=False)
sage: Set(map(Set, B)) == Set(map(Set, B2)) and set(C) == set(C2)True>>> from sage.all import *>>> from sage.graphs.connectivity import blocks_and_cut_vertices>>> rings = graphs.CycleGraph(Integer(10))(continues on next page)

5.41. Connectivity related functions

1907

Graph Theory, Release 10.4

(continued from previous page)>>> rings.merge_vertices([Integer(0), Integer(5)])>>> blocks_and_cut_vertices(rings)([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])>>> rings.blocks_and_cut_vertices()([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0])>>> B, C = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=True)>>> B, C([[0, 1, 2, 3, 4], [0, 6, 7, 8, 9]], [0])>>> B2, C2 = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=False)>>> Set(map(Set, B)) == Set(map(Set, B2)) and set(C) == set(C2)True

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]], [])>>> from sage.all import *>>> 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])>>> from sage.all import *>>> g = graphs.PathGraph(Integer(4)) + graphs.PathGraph(Integer(5))>>> 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])>>> from sage.all import *>>> g = Graph({Integer(1): {Integer(2): Integer(28), Integer(3): Integer(10)},␣
˓→Integer(2): {Integer(1): Integer(10), Integer(3): Integer(16)}, Integer(4): {},␣
˓→Integer(5): {Integer(6): Integer(3), Integer(7): Integer(10), Integer(8):␣
˓→Integer(4)}})>>> blocks_and_cut_vertices(g)([[1, 2, 3], [5, 6], [5, 7], [5, 8], [4]], [5])A directed graph with Boost’s algorithm (Issue #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])1908

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> rings = graphs.CycleGraph(Integer(10))>>> rings.merge_vertices([Integer(0), Integer(5)])>>> rings = rings.to_directed()>>> 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(G)Return the blocks-and-cuts tree of self.
This new graph has two different kinds of vertices, some representing the blocks (type B) and some other the cut
vertices of the graph (type C).
There is an edge between a vertex 𝑢 of type B and a vertex 𝑣 of type C if the cut-vertex corresponding to 𝑣 is in
the block corresponding to 𝑢.
The resulting graph is a tree, with the additional characteristic property that the distance between two leaves is even.
When self is not connected, the resulting graph is a forest.
When self is biconnected, the tree is reduced to a single node of type 𝐵.
We referred to [HarPri] and [Gallai] for blocks and cuts tree.
See also:• blocks_and_cut_vertices()• is_biconnected()
EXAMPLES:
sage: 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))
Truesage: from sage.graphs.connectivity import blocks_and_cuts_tree
sage: T = graphs.KrackhardtKiteGraph().blocks_and_cuts_tree(); T
Graph on 5 vertices>>> from sage.all import *>>> from sage.graphs.connectivity import blocks_and_cuts_tree>>> T = blocks_and_cuts_tree(graphs.KrackhardtKiteGraph()); T
Graph on 5 vertices>>> T.is_isomorphic(graphs.PathGraph(Integer(5)))
True>>> from sage.graphs.connectivity import blocks_and_cuts_tree>>> 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

5.41. Connectivity related functions

1909

Graph Theory, Release 10.4>>> from sage.all import *>>> T = blocks_and_cuts_tree(graphs.RandomTree(Integer(40)))>>> T.is_tree()True>>> leaves = [v for v in T if T.degree(v) == Integer(1)]>>> all(T.distance(u,v) % Integer(2) == Integer(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(sort=True)[( B , (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]>>> from sage.all import *>>> T = blocks_and_cuts_tree(graphs.PetersenGraph())>>> T.vertices(sort=True)[( B , (0, 1, 4, 5, 2, 6, 3, 7, 8, 9))]sage.graphs.connectivity.bridges(G, labels=True)
Return an iterator over the bridges (or cut edges).
A bridge is an edge whose deletion disconnects the undirected graph. A disconnected graph has no bridge.
INPUT:• labels – boolean (default: True); if False, each bridge is a tuple (𝑢, 𝑣) of vertices
EXAMPLES:
sage: 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)Truesage: list(bridges(g))[(1, 10, None)]sage: list(g.bridges())[(1, 10, None)]>>> from sage.all import *>>> from sage.graphs.connectivity import bridges>>> from sage.graphs.connectivity import is_connected>>> g = Integer(2) * graphs.PetersenGraph()>>> g.add_edge(Integer(1), Integer(10))>>> is_connected(g)True>>> list(bridges(g))[(1, 10, None)]>>> list(g.bridges())[(1, 10, None)]

Every edge of a tree is a bridge:

1910

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g = graphs.RandomTree(100)sage: sum(1 for _ in g.bridges()) == 99
True>>> from sage.all import *>>> g = graphs.RandomTree(Integer(100))>>> sum(Integer(1) for _ in g.bridges()) == Integer(99)True

sage.graphs.connectivity.cleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0,
integrality_tolerance=0.001)
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 𝐺 inducedby each connected component 𝑐 of 𝐺 ∖ 𝑋 plus 𝑋, i.e., 𝐺[𝑐 ∪ 𝑋].
INPUT:• G – a Graph.
• cut_vertices – iterable container of vertices (default: None); a set of vertices representing a vertex cutof 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT: A 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, whenvirtual_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, andits edge set is the set of virtual edges (i.e., edges between pairs of vertices of the cut that are not connectedby 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()(continues on next page)

5.41. Connectivity related functions

1911

Graph Theory, Release 10.4

(continued from previous page)(2, 4)
sage: f1.vertices(sort=True), f1.edges(sort=True)([0, 1], [])>>> from sage.all import *>>> from sage.graphs.connectivity import cleave>>> G = Graph(Integer(2))>>> for _ in range(Integer(3)):...
G.add_clique([Integer(0), Integer(1), G.add_vertex(), G.add_vertex()])>>> S1,C1,f1 = cleave(G, cut_vertices=[Integer(0), Integer(1)])>>> [g.order() for g in S1][4, 4, 4]>>> C1.order(), C1.size()(2, 4)>>> f1.vertices(sort=True), f1.edges(sort=True)([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)>>> from sage.all import *>>> G.subgraph([Integer(0), Integer(1)]).complement() == Graph([[Integer(0),␣
˓→Integer(1)], []])
True>>> S2,C2,f2 = cleave(G, cut_vertices=[Integer(0), Integer(1)], virtual_
˓→edges=False)>>> (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(sort=True), f1.edges(sort=True)([0, 1], [(0, 1, None)])>>> from sage.all import *>>> G.delete_edge(Integer(0), Integer(1))>>> S1,C1,f1 = cleave(G, cut_vertices=[Integer(0), Integer(1)])>>> [g.order() for g in S1][4, 4, 4]>>> C1.order(), C1.size()(2, 3)>>> f1.vertices(sort=True), f1.edges(sort=True)([0, 1], [(0, 1, None)])If virtual_edges == False and the cut vertices are not connected by an edge:
1912

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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(sort=True), f2.edges(sort=True)([0, 1], [])sage: (S1 == S2, C1 == C2, f1 == f2)(False, False, False)>>> from sage.all import *>>> G.subgraph([Integer(0), Integer(1)]).complement() == Graph([[Integer(0),␣
˓→Integer(1)], []])
False>>> S2,C2,f2 = cleave(G, cut_vertices=[Integer(0), Integer(1)], virtual_
˓→edges=False)>>> [g.order() for g in S2][4, 4, 4]>>> C2.order(), C2.size()(2, 0)>>> f2.vertices(sort=True), f2.edges(sort=True)([0, 1], [])>>> (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.edge_iterator())
sage: G.add_edges([(0, 1), (0, 1), (0, 1)])
sage: S,C,f = cleave(G, cut_vertices=[0, 1])
sage: for g in S:....:
print(g.edges(sort=True, labels=0))[(0, 1), (0, 1), (0, 1), (0, 2), (0, 2), (0, 3), (0, 3), (1, 2), (1, 2), (1, 3),␣
˓→(1, 3), (2, 3), (2, 3)][(0, 1), (0, 1), (0, 1), (0, 4), (0, 4), (1, 4), (1, 4)]>>> from sage.all import *>>> G = graphs.CompleteBipartiteGraph(Integer(2), Integer(3))>>> G.add_edge(Integer(2), Integer(3))>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edge_iterator())>>> G.add_edges([(Integer(0), Integer(1)), (Integer(0), Integer(1)), (Integer(0),␣
˓→Integer(1))])>>> S,C,f = cleave(G, cut_vertices=[Integer(0), Integer(1)])>>> for g in S:...
print(g.edges(sort=True, labels=Integer(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(G, vertex, sort=None,
key=None)
5.41. Connectivity related functions

1913

Graph Theory, Release 10.4

Return a list of the vertices connected to vertex.
INPUT:• G – the input graph• v – the vertex to search for• sort – boolean (default: None); if True, vertices inside the component are sorted according to the default
ordering
As of Issue #35889, this argument must be explicitly specified (unless a key is given); otherwise a warning
is printed and sort=True is used. The default will eventually be changed to False.
• key – a function (default: None); a function that takes a vertex as its one argument and returns a value thatcan be used for comparisons in the sorting algorithm (we must have sort=True)
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, sort=True)[0, 1, 2, 3]
sage: G.connected_component_containing_vertex(0, sort=True)[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, sort=True)[0, 1, 2, 3]
sage: connected_component_containing_vertex(D, 0, sort=True, key=lambda x: -x)[3, 2, 1, 0]>>> from sage.all import *>>> from sage.graphs.connectivity import connected_component_containing_vertex>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> connected_component_containing_vertex(G, Integer(0), sort=True)[0, 1, 2, 3]>>> G.connected_component_containing_vertex(Integer(0), sort=True)[0, 1, 2, 3]>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> connected_component_containing_vertex(D, Integer(0), sort=True)[0, 1, 2, 3]>>> connected_component_containing_vertex(D, Integer(0), sort=True, key=lambda x:␣
˓→-x)[3, 2, 1, 0]

sage.graphs.connectivity.connected_components(G, sort=None, key=None)
Return the list of connected components.
This returns a list of lists of vertices, each list representing a connected component. The list is ordered from largest
to smallest component.
INPUT:• G – the input graph• sort – boolean (default: None); if True, vertices inside each component are sorted according to the default
ordering

1914

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

As of Issue #35889, this argument must be explicitly specified (unless a key is given); otherwise a warning
is printed and sort=True is used. The default will eventually be changed to False.
• key – a function (default: None); a function that takes a vertex as its one argument and returns a value thatcan be used for comparisons in the sorting algorithm (we must have sort=True)
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, sort=True)[[0, 1, 2, 3], [4, 5, 6]]
sage: G.connected_components(sort=True)[[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, sort=True)[[0, 1, 2, 3], [4, 5, 6]]
sage: connected_components(D, sort=True, key=lambda x: -x)[[3, 2, 1, 0], [6, 5, 4]]>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> connected_components(G, sort=True)[[0, 1, 2, 3], [4, 5, 6]]>>> G.connected_components(sort=True)[[0, 1, 2, 3], [4, 5, 6]]>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> connected_components(D, sort=True)[[0, 1, 2, 3], [4, 5, 6]]>>> connected_components(D, sort=True, key=lambda x: -x)[[3, 2, 1, 0], [6, 5, 4]]

sage.graphs.connectivity.connected_components_number(G)Return the number of connected components.
INPUT:• G – 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)2sage: 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>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components_number(continues on next page)

5.41. Connectivity related functions

1915

Graph Theory, Release 10.4

(continued from previous page)>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> connected_components_number(G)2>>> G.connected_components_number()2>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> connected_components_number(D)2sage.graphs.connectivity.connected_components_sizes(G)Return the sizes of the connected components as a list.
The list is sorted from largest to lower values.
EXAMPLES:
sage: 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]>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components_sizes>>> for x in graphs(Integer(3)):...
print(connected_components_sizes(x))[1, 1, 1][2, 1][3][3]>>> for x in graphs(Integer(3)):...
print(x.connected_components_sizes())[1, 1, 1][2, 1][3][3]

sage.graphs.connectivity.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)(continues on next page)

1916

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: graphs_list.show_graphs(L)˓→needs sage.plot
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)˓→needs sage.plot
sage: L = D.connected_components_subgraphs()sage: graphs_list.show_graphs(L)˓→needs sage.plot

#␣

#␣

#␣

>>> from sage.all import *>>> from sage.graphs.connectivity import connected_components_subgraphs>>> G = Graph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> L = connected_components_subgraphs(G)>>> graphs_list.show_graphs(L)#␣˓→needs sage.plot>>> D = DiGraph({Integer(0): [Integer(1), Integer(3)], Integer(1): [Integer(2)],␣
˓→Integer(2): [Integer(3)], Integer(4): [Integer(5), Integer(6)], Integer(5):␣
˓→[Integer(6)]})>>> L = connected_components_subgraphs(D)>>> graphs_list.show_graphs(L)#␣˓→needs sage.plot>>> L = D.connected_components_subgraphs()>>> graphs_list.show_graphs(L)#␣˓→needs sage.plot

sage.graphs.connectivity.edge_connectivity(G, value_only=True, implementation=None,
use_edge_labels=False, vertices=False, solver=None,verbose=0, integrality_tolerance=0.001)
Return 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 toconsider strong connectivity, the best is probably to convert your DiGraph object to a Graph object, and computethe connectivity of this other graph.
INPUT:• G – the input Sage (Di)Graph• value_only – boolean (default: True)– When set to True (default), only the value is returned.
– When set to False, both the value and a minimum vertex cut are returned.
• implementation – string (default: None); selects an implementation:– None (default) – selects the best implementation available– "boost" – use the Boost graph library (which is much more efficient). It is not available when
edge_labels=True, and it is unreliable for directed graphs (see Issue #18753).

5.41. Connectivity related functions

1917

Graph Theory, Release 10.4-"Sage" – use Sage’s implementation based on integer linear
programming• 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 – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic application on the PappusGraph:
sage: from sage.graphs.connectivity import edge_connectivity
sage: g = graphs.PappusGraph()
sage: edge_connectivity(g)3sage: g.edge_connectivity()3>>> from sage.all import *>>> from sage.graphs.connectivity import edge_connectivity>>> g = graphs.PappusGraph()>>> edge_connectivity(g)3>>> g.edge_connectivity()
3

The edge connectivity of a complete graph is its minimum degree, and one of the two parts of the bipartition is
reduced to only one vertex. The graph of the cut edges is isomorphic to a Star graph:
sage: g = graphs.CompleteGraph(5)sage: [ value, edges, [ setA, setB ]] = edge_connectivity(g,vertices=True)
sage: value
4
sage: len(setA) == 1 or len(setB) == 1
True
sage: cut = Graph()
sage: cut.add_edges(edges)
sage: cut.is_isomorphic(graphs.StarGraph(4))
True>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(5))>>> [ value, edges, [ setA, setB ]] = edge_connectivity(g,vertices=True)(continues on next page)

1918

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> value
4>>> len(setA) == Integer(1) or len(setB) == Integer(1)True>>> cut = Graph()>>> cut.add_edges(edges)>>> cut.is_isomorphic(graphs.StarGraph(Integer(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>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(10),RealNumber( .3 ))>>> 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: tree = graphs.RandomTree(10)sage: for u,v in tree.edge_iterator(labels=None):....:tree.set_edge_label(u, v, random())
sage: minimum = min(tree.edge_labels())
sage: [_, [(_, _, l)]] = edge_connectivity(tree, value_only=False,
˓→needs sage.numerical.mip....:
use_edge_labels=True)
sage: l == minimum
˓→needs sage.numerical.mip
True>>> from sage.all import *>>> tree = graphs.RandomTree(Integer(10))>>> for u,v in tree.edge_iterator(labels=None):...
tree.set_edge_label(u, v, random())>>> minimum = min(tree.edge_labels())>>> [_, [(_, _, l)]] = edge_connectivity(tree, value_only=False,
˓→needs sage.numerical.mip...
use_edge_labels=True)>>> l == minimum
˓→needs sage.numerical.mip
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>>> from sage.all import *>>> g = Integer(2) * graphs.PetersenGraph()(continues on next page)

5.41. Connectivity related functions

1919

Graph Theory, Release 10.4

(continued from previous page)>>> 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>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(3))>>> 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, implementation="boost")
˓→needs sage.numerical.mip....:== edge_connectivity(g, implementation="sage"))
True

#␣

>>> from sage.all import *>>> g = graphs.RandomGNP(Integer(15), RealNumber( .3 ))>>> (edge_connectivity(g, implementation="boost")
˓→needs sage.numerical.mip...
== 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}]]>>> from sage.all import *>>> edge_connectivity(digraphs.Circuit(Integer(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 Issue #18753):
sage: g = digraphs.Path(3)sage: edge_connectivity(g)0.0sage: edge_connectivity(g, implementation="boost")
1
sage: g.add_edge(1, 0)
sage: edge_connectivity(g)0.0sage: edge_connectivity(g, implementation="boost")0>>> from sage.all import *>>> g = digraphs.Path(Integer(3))(continues on next page)

1920

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> edge_connectivity(g)0.0>>> edge_connectivity(g, implementation="boost")
1>>> g.add_edge(Integer(1), Integer(0))>>> edge_connectivity(g)0.0>>> edge_connectivity(g, implementation="boost")
0sage.graphs.connectivity.is_connected(G)Check whether the (di)graph is connected.
Note that in a graph, path connected is equivalent to connected.
INPUT:• G – the input graphSee 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)Truesage: 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)Truesage: D = DiGraph({1: [0], 2: [0]})sage: is_connected(D)True>>> from sage.all import *>>> from sage.graphs.connectivity import is_connected>>> G = Graph({Integer(0): [Integer(1), Integer(2)], Integer(1): [Integer(2)],␣
˓→Integer(3): [Integer(4), Integer(5)], Integer(4): [Integer(5)]})>>> is_connected(G)False>>> G.is_connected()
False>>> G.add_edge(Integer(0),Integer(3))>>> is_connected(G)True>>> D = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1): [Integer(2)],␣
˓→Integer(3): [Integer(4), Integer(5)], Integer(4): [Integer(5)]})(continues on next page)

5.41. Connectivity related functions

1921

Graph Theory, Release 10.4

(continued from previous page)>>> is_connected(D)False>>> D.add_edge(Integer(0), Integer(3))>>> is_connected(D)True>>> D = DiGraph({Integer(1): [Integer(0)], Integer(2): [Integer(0)]})>>> is_connected(D)Truesage.graphs.connectivity.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 whenremoved 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 ))Truesage: 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):(continues on next page)

1922

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)...
ValueError: edge not in graph>>> from sage.all import *>>> from sage.graphs.connectivity import is_cut_edge>>> G = graphs.CompleteGraph(Integer(4))>>> is_cut_edge(G,Integer(0),Integer(2))
False>>> G.is_cut_edge(Integer(0),Integer(2))
False>>> G = graphs.CompleteGraph(Integer(4))>>> G.add_edge((Integer(0),Integer(5), silly ))>>> is_cut_edge(G,(Integer(0),Integer(5), silly ))True>>> G = Graph([[Integer(0),Integer(1)],[Integer(0),Integer(2)],[Integer(3),˓→Integer(4)],[Integer(4),Integer(5)],[Integer(3),Integer(5)]])>>> is_cut_edge(G,(Integer(0),Integer(1)))
True>>> G = Graph([[Integer(0),Integer(1)],[Integer(0),Integer(2)],[Integer(1),˓→Integer(1)]], loops = True)>>> is_cut_edge(G,(Integer(1),Integer(1)))
False>>> G = digraphs.Circuit(Integer(5))>>> is_cut_edge(G,(Integer(0),Integer(1)))
False>>> G = graphs.CompleteGraph(Integer(6))>>> is_cut_edge(G,(Integer(0),Integer(7)))
Traceback (most recent call last):...
ValueError: edge not in graphsage.graphs.connectivity.is_cut_vertex(G, u, weak=False)
Check whether the input vertex is a cut-vertex.
A vertex is a cut-vertex if its removal from the (di)graph increases the number of (strongly) connected components.
Isolated vertices or leafs are not cut-vertices. This function works with simple graphs as well as graphs with loops
and multiple edges.
INPUT:• G – a Sage (Di)Graph• u – a vertex• weak – boolean (default: False); whether the connectivity of directed graphs is to be taken in the weaksense, that is ignoring edges orientations
OUTPUT:
Return True if u is a cut-vertex, and False otherwise.
EXAMPLES:
Giving a LollipopGraph(4,2), that is a complete graph with 4 vertices with a pending edge:

5.41. Connectivity related functions

1923

Graph Theory, Release 10.4

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>>> from sage.all import *>>> from sage.graphs.connectivity import is_cut_vertex>>> G = graphs.LollipopGraph(Integer(4), Integer(2))>>> is_cut_vertex(G, Integer(0))
False>>> is_cut_vertex(G, Integer(3))
True>>> G.is_cut_vertex(Integer(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)Truesage: is_cut_vertex(D, 2)
True
sage: is_cut_vertex(D, 2, weak=True)
False>>> from sage.all import *>>> from sage.graphs.connectivity import is_strongly_connected>>> D = digraphs.Circuit(Integer(6))>>> is_strongly_connected(D)True>>> is_cut_vertex(D, Integer(2))
True>>> is_cut_vertex(D, Integer(2), weak=True)
False

Giving a vertex that is not in the graph:
sage: G = graphs.CompleteGraph(4)sage: is_cut_vertex(G, 7)
Traceback (most recent call last):...
ValueError: vertex (7) is not a vertex of the graph>>> from sage.all import *>>> G = graphs.CompleteGraph(Integer(4))>>> is_cut_vertex(G, Integer(7))
Traceback (most recent call last):...
ValueError: vertex (7) is not a vertex of the graphsage.graphs.connectivity.is_strongly_connected(G)Check whether the current DiGraph is strongly connected.
1924

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

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)Truesage: g.is_strongly_connected()True>>> from sage.all import *>>> from sage.graphs.connectivity import is_strongly_connected>>> g = digraphs.Circuit(Integer(5))>>> is_strongly_connected(g)True>>> 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>>> from sage.all import *>>> g = DiGraph({Integer(0): [Integer(1), Integer(2)], Integer(1): [Integer(2)]})>>> is_strongly_connected(g)Falsesage.graphs.connectivity.is_triconnected(G)Check whether the graph is triconnected.
A triconnected graph is a connected graph on 3 or more vertices that is not broken into disconnected pieces bydeleting any pair of vertices.
EXAMPLES:
The Petersen graph is triconnected:
sage: G = graphs.PetersenGraph()
sage: G.is_triconnected()True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.is_triconnected()
True

But a 2D grid is not:sage: G = graphs.Grid2dGraph(3, 3)
sage: G.is_triconnected()
False>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(3), Integer(3))(continues on next page)

5.41. Connectivity related functions

1925

Graph Theory, Release 10.4

(continued from previous page)>>> G.is_triconnected()
False

By convention, a cycle of order 3 is triconnected:
sage: G = graphs.CycleGraph(3)sage: G.is_triconnected()True>>> from sage.all import *>>> G = graphs.CycleGraph(Integer(3))>>> G.is_triconnected()True

But cycles of order 4 and more are not:sage: [graphs.CycleGraph(i).is_triconnected() for i in range(4, 8)][False, False, False, False]>>> from sage.all import *>>> [graphs.CycleGraph(i).is_triconnected() for i in range(Integer(4),␣
˓→Integer(8))][False, False, False, False]

Comparing different methods on random graphs that are not always triconnected:
sage: G = graphs.RandomBarabasiAlbert(50, 3)
˓→needs networkx
sage: G.is_triconnected() == G.vertex_connectivity(k=3)˓→needs networkx
True>>> from sage.all import *>>> G = graphs.RandomBarabasiAlbert(Integer(50), Integer(3))˓→# needs networkx>>> G.is_triconnected() == G.vertex_connectivity(k=Integer(3))˓→# needs networkx
True

#␣
#␣

␣
␣

See also:• is_connected()• is_biconnected()• spqr_tree()• Wikipedia article SPQR_tree
sage.graphs.connectivity.spqr_tree(G, algorithm='Hopcroft_Tarjan', solver=None, verbose=0,
integrality_tolerance=0.001)
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)graphand the 2-vertex cuts separating them. A node of a SPQR-tree, and the graph associated with it, can be one of thefollowing four types:

1926

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• "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 uniquedecomposition into 3-connected blocks, cycles and cocycles. The cocycles are dipole graphs with one edge perreal edge between the included vertices and one additional (virtual) edge per connected component resulting fromdeletion of the vertices in the cut. See the Wikipedia article SPQR_tree.
INPUT:• G – the input graph• algorithm – string (default: "Hopcroft_Tarjan"); the algorithm to use among:– "Hopcroft_Tarjan" (default) – use the algorithm proposed by Hopcroft and Tarjan in[Hopcroft1973] and later corrected by Gutwenger and Mutzel in [Gut2001]. See TriconnectivitySPQR.
– "cleave" – using method cleave()• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
OUTPUT: SPQR-tree a tree whose vertices are labeled with the block’s type and the subgraph of three-blocks
in the decomposition.
EXAMPLES:
sage: 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 if u[0] == R )True
sage: from sage.graphs.connectivity import spqr_tree_to_graphsage: 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(continues on next page)

5.41. Connectivity related functions

1927

Graph Theory, Release 10.4

(continued from previous page)

sage: C4 = graphs.CycleGraph(4)sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] ==Truesage: G.is_isomorphic(spqr_tree_to_graph(Tree))True
sage: G.allow_multiple_edges(True)
sage: G.add_edges(G.edge_iterator())
sage: Tree = spqr_tree(G)sage: Tree.order()13sage: all(u[1].is_isomorphic(C4) for u in Tree if u[0] ==Truesage: G.is_isomorphic(spqr_tree_to_graph(Tree))
True

S )

S )

sage: G = graphs.CycleGraph(6)sage: Tree = spqr_tree(G)sage: Tree.order()1sage: G.is_isomorphic(spqr_tree_to_graph(Tree))True
sage: G.add_edge(0, 3)
sage: Tree = spqr_tree(G)sage: Tree.order()3sage: 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 )˓→needs sage.numerical.mip
sage: G.is_isomorphic(spqr_tree_to_graph(T2))
˓→needs sage.numerical.mip
True

#␣
#␣

sage: G = Graph([(0, 1)], multiedges=True)
sage: T = spqr_tree(G, algorithm= cleave )˓→needs sage.numerical.mip
sage: T.vertices(sort=True)
˓→needs sage.numerical.mip[( Q , Multi-graph on 2 vertices)]sage: G.is_isomorphic(spqr_tree_to_graph(T))˓→needs sage.numerical.mip
True
sage: T = spqr_tree(G, algorithm= Hopcroft_Tarjan )sage: T.vertices(sort=True)[( Q , Multi-graph on 2 vertices)]sage: G.add_edge(0, 1)
sage: spqr_tree(G, algorithm= cleave ).vertices(sort=True)
˓→needs sage.numerical.mip[( P , Multi-graph on 2 vertices)]

#␣
#␣

#␣

#␣

sage: from collections import Counter(continues on next page)

1928

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

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")
˓→needs sage.numerical.mip
sage: Counter(u[0] for u in T)
˓→needs sage.numerical.mip
Counter({ R : 1})sage: for u,v in list(G.edges(labels=False, sort=False)):....:G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")sage: sorted(Counter(u[0] for u in T).items())[( P , 15), ( R , 1), ( S , 15)]
sage: T = G.spqr_tree(algorithm="cleave")
˓→needs sage.numerical.mip
sage: sorted(Counter(u[0] for u in T).items())
˓→needs sage.numerical.mip[( P , 15), ( R , 1), ( S , 15)]
sage: for u,v in list(G.edges(labels=False, sort=False)):....:G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")sage: sorted(Counter(u[0] for u in T).items())[( P , 60), ( R , 1), ( S , 75)]
sage: T = G.spqr_tree(algorithm="cleave")# long time
˓→needs sage.numerical.mip
sage: sorted(Counter(u[0] for u in T).items()) # long time
˓→needs sage.numerical.mip[( P , 60), ( R , 1), ( S , 75)]

#␣
#␣

#␣
#␣

#␣
#␣

>>> from sage.all import *>>> from sage.graphs.connectivity import spqr_tree>>> G = Graph(Integer(2))>>> for i in range(Integer(3)):...
G.add_clique([Integer(0), Integer(1), G.add_vertex(), G.add_vertex()])>>> Tree = spqr_tree(G)>>> Tree.order()4>>> K4 = graphs.CompleteGraph(Integer(4))>>> all(u[Integer(1)].is_isomorphic(K4) for u in Tree if u[Integer(0)] == R )True>>> from sage.graphs.connectivity import spqr_tree_to_graph>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G = Graph(Integer(2))>>> for i in range(Integer(3)):...
G.add_path([Integer(0), G.add_vertex(), G.add_vertex(), Integer(1)])>>> Tree = spqr_tree(G)>>> Tree.order()4>>> C4 = graphs.CycleGraph(Integer(4))>>> all(u[Integer(1)].is_isomorphic(C4) for u in Tree if u[Integer(0)] == S )True>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True(continues on next page)

5.41. Connectivity related functions

1929

Graph Theory, Release 10.4

(continued from previous page)>>> G.allow_multiple_edges(True)>>> G.add_edges(G.edge_iterator())>>> Tree = spqr_tree(G)>>> Tree.order()13>>> all(u[Integer(1)].is_isomorphic(C4) for u in Tree if u[Integer(0)] ==True>>> G.is_isomorphic(spqr_tree_to_graph(Tree))
True

S )

>>> G = graphs.CycleGraph(Integer(6))>>> Tree = spqr_tree(G)>>> Tree.order()1>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G.add_edge(Integer(0), Integer(3))>>> Tree = spqr_tree(G)>>> Tree.order()3>>> G.is_isomorphic(spqr_tree_to_graph(Tree))True>>> G = Graph( LlCG{O@?GBoMw? )>>> T = spqr_tree(G, algorithm="Hopcroft_Tarjan")>>> G.is_isomorphic(spqr_tree_to_graph(T))
True>>> T2 = spqr_tree(G, algorithm= cleave )˓→needs sage.numerical.mip>>> G.is_isomorphic(spqr_tree_to_graph(T2))
˓→needs sage.numerical.mip
True

#␣
#␣

>>> G = Graph([(Integer(0), Integer(1))], multiedges=True)>>> T = spqr_tree(G, algorithm= cleave )˓→needs sage.numerical.mip>>> T.vertices(sort=True)
˓→needs sage.numerical.mip[( Q , Multi-graph on 2 vertices)]>>> G.is_isomorphic(spqr_tree_to_graph(T))˓→needs sage.numerical.mip
True>>> T = spqr_tree(G, algorithm= Hopcroft_Tarjan )>>> T.vertices(sort=True)[( Q , Multi-graph on 2 vertices)]>>> G.add_edge(Integer(0), Integer(1))>>> spqr_tree(G, algorithm= cleave ).vertices(sort=True)
˓→needs sage.numerical.mip[( P , Multi-graph on 2 vertices)]>>> from collections import Counter>>> G = graphs.PetersenGraph()>>> T = G.spqr_tree(algorithm="Hopcroft_Tarjan")>>> Counter(u[Integer(0)] for u in T)
Counter({ R : 1})>>> T = G.spqr_tree(algorithm="cleave")

#␣
#␣

#␣

#␣

#␣
(continues on next page)

1930

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)needs sage.numerical.mip>>> Counter(u[Integer(0)] for u in T)˓→# needs sage.numerical.mip
Counter({ R : 1})>>> for u,v in list(G.edges(labels=False, sort=False)):...
G.add_path([u, G.add_vertex(), G.add_vertex(), v])>>> T = G.spqr_tree(algorithm="Hopcroft_Tarjan")>>> sorted(Counter(u[Integer(0)] for u in T).items())[( P , 15), ( R , 1), ( S , 15)]>>> T = G.spqr_tree(algorithm="cleave")
˓→needs sage.numerical.mip>>> sorted(Counter(u[Integer(0)] for u in T).items())˓→# needs sage.numerical.mip[( P , 15), ( R , 1), ( S , 15)]>>> for u,v in list(G.edges(labels=False, sort=False)):...
G.add_path([u, G.add_vertex(), G.add_vertex(), v])>>> T = G.spqr_tree(algorithm="Hopcroft_Tarjan")>>> sorted(Counter(u[Integer(0)] for u in T).items())[( P , 60), ( R , 1), ( S , 75)]>>> T = G.spqr_tree(algorithm="cleave")# long time
˓→needs sage.numerical.mip>>> sorted(Counter(u[Integer(0)] for u in T).items()) # long time˓→# needs sage.numerical.mip[( P , 60), ( R , 1), ( S , 75)]
˓→

␣

#␣
␣

#␣
␣

sage.graphs.connectivity.spqr_tree_to_graph(T)Return the graph represented by the SPQR-tree 𝑇 .
The main purpose of this method is to test spqr_tree().
INPUT:• T – a SPQR tree as returned by spqr_tree().
OUTPUT: a (multi) graph
EXAMPLES:
Wikipedia article SPQR_tree reference paper example:
sage: from sage.graphs.connectivity import spqr_tree
sage: from sage.graphs.connectivity import spqr_tree_to_graphsage: 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>>> from sage.all import *>>> from sage.graphs.connectivity import spqr_tree>>> from sage.graphs.connectivity import spqr_tree_to_graph>>> G = Graph([(Integer(1), Integer(2)), (Integer(1), Integer(4)), (Integer(1),␣
˓→Integer(8)), (Integer(1), Integer(12)), (Integer(3), Integer(4)), (Integer(2),␣
˓→Integer(3)),... (Integer(2), Integer(13)), (Integer(3), Integer(13)), (Integer(4),␣
˓→Integer(5)), (Integer(4), Integer(7)), (Integer(5), Integer(6)), (Integer(5),␣
(continues on next page)

5.41. Connectivity related functions

1931

Graph Theory, Release 10.4

(continued from previous page)

Integer(8)), (Integer(5), Integer(7)), (Integer(6), Integer(7)),... (Integer(8), Integer(11)), (Integer(8), Integer(9)), (Integer(8),␣
˓→Integer(12)), (Integer(9), Integer(10)), (Integer(9), Integer(11)), (Integer(9),˓→ Integer(12)), (Integer(10), Integer(12))])>>> T = spqr_tree(G)>>> H = spqr_tree_to_graph(T)>>> H.is_isomorphic(G)True˓→A small multigraphsage: 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>>> from sage.all import *>>> G = Graph([(Integer(0), Integer(2)), (Integer(0), Integer(2)), (Integer(1),␣
˓→Integer(3)), (Integer(2), Integer(3))], multiedges=True)>>> for i in range(Integer(3)):...
G.add_clique([Integer(0), Integer(1), G.add_vertex(), G.add_vertex()])>>> for i in range(Integer(3)):...
G.add_clique([Integer(2), Integer(3), G.add_vertex(), G.add_vertex()])>>> T = spqr_tree(G)>>> H = spqr_tree_to_graph(T)>>> H.is_isomorphic(G)Truesage.graphs.connectivity.strong_articulation_points(G)Return the strong articulation points of this digraph.
A vertex is a strong articulation point if its deletion increases the number of strongly connected components. Thismethod 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]>>> from sage.all import *>>> from sage.graphs.connectivity import strong_articulation_points>>> D = digraphs.Complete(Integer(4))(continues on next page)

1932

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> D.add_clique([Integer(3), Integer(4), Integer(5), Integer(6)])>>> strong_articulation_points(D)[3]>>> 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)[]>>> from sage.all import *>>> D = digraphs.Complete(Integer(4)) * Integer(2)>>> D.add_edges([(Integer(0), Integer(4)), (Integer(7), Integer(3))])>>> sorted(strong_articulation_points(D))[0, 3, 4, 7]>>> D.add_edge(Integer(1), Integer(5))>>> sorted(strong_articulation_points(D))[3, 7]>>> D.add_edge(Integer(6), Integer(2))>>> strong_articulation_points(D)[]See also:• strongly_connected_components()• dominator_tree()sage.graphs.connectivity.strongly_connected_component_containing_vertex(G, v)
Return the strongly connected component containing a given vertex
INPUT:• G – the input DiGraph• v – a vertex
EXAMPLES:In the symmetric digraph of a graph, the strongly connected components are the connected components:
sage: 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]

5.41. Connectivity related functions

1933

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.connectivity import strongly_connected_component_containing_˓→vertex>>> g = graphs.PetersenGraph()>>> d = DiGraph(g)>>> strongly_connected_component_containing_vertex(d, Integer(0))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> d.strongly_connected_component_containing_vertex(Integer(0))[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])sage: strongly_connected_component_containing_vertex(g, 0)[0, 1]>>> from sage.all import *>>> g = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(0)), (Integer(1),␣
˓→Integer(2)), (Integer(2), Integer(3)), (Integer(3), Integer(2))])>>> strongly_connected_component_containing_vertex(g, Integer(0))[0, 1]

sage.graphs.connectivity.strongly_connected_components_digraph(G, keep_labels=False)
Return the digraph of the strongly connected components
The digraph of the strongly connected components of a graph 𝐺 has a vertex per strongly connected component
included in 𝐺. There is an edge from a component 𝐶1 to a component 𝐶2 if there is an edge in 𝐺 from a vertex
𝑢1 ∈ 𝐶1 to a vertex 𝑢2 ∈ 𝐶2 .
INPUT:• G – the input DiGraph• keep_labels – boolean (default: False); when keep_labels=True, the resulting digraph has anedge from a component 𝐶𝑖 to a component 𝐶𝑗 for each edge in 𝐺 from a vertex 𝑢𝑖 ∈ 𝐶𝑖 to a vertex 𝑢𝑗 ∈ 𝐶𝑗 .
Hence the resulting digraph may have loops and multiple edges. However, edges in the result with same source,
target, and label are not duplicated (see examples below). When keep_labels=False, the return digraphis simple, so without loops nor multiple edges, and edges are unlabelled.
EXAMPLES:
Such a digraph is always acyclic:
sage: from sage.graphs.connectivity import strongly_connected_components_digraphsage: g = digraphs.RandomDirectedGNP(15, .1)
sage: scc_digraph = strongly_connected_components_digraph(g)sage: scc_digraph.is_directed_acyclic()Truesage: scc_digraph = g.strongly_connected_components_digraph()
sage: scc_digraph.is_directed_acyclic()True>>> from sage.all import *>>> from sage.graphs.connectivity import strongly_connected_components_digraph>>> g = digraphs.RandomDirectedGNP(Integer(15), RealNumber( .1 ))>>> scc_digraph = strongly_connected_components_digraph(g)>>> scc_digraph.is_directed_acyclic()True>>> scc_digraph = g.strongly_connected_components_digraph()(continues on next page)

1934

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> 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()Truesage: V_scc = list(scc_digraph)
sage: all(Set(scc) in V_scc for scc in g.strongly_connected_components())
True>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(2))>>> scc_digraph = strongly_connected_components_digraph(g)>>> g.is_directed_acyclic()
True>>> V_scc = list(scc_digraph)>>> all(Set(scc) in V_scc for scc in g.strongly_connected_components())
True

The following digraph has three strongly connected components, and the digraph of those is a TransitiveTournament():
sage: g = DiGraph({0: {1: "01", 2: "02", 3: "03"}, 1: {2: "12"}, 2:{1: "21", 3:
˓→"23"}})
sage: scc_digraph = strongly_connected_components_digraph(g)sage: scc_digraph.is_isomorphic(digraphs.TransitiveTournament(3))
True>>> from sage.all import *>>> g = DiGraph({Integer(0): {Integer(1): "01", Integer(2): "02", Integer(3): "03
˓→"}, Integer(1): {Integer(2): "12"}, Integer(2):{Integer(1): "21", Integer(3):˓→"23"}})>>> scc_digraph = strongly_connected_components_digraph(g)>>> scc_digraph.is_isomorphic(digraphs.TransitiveTournament(Integer(3)))
True

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 connectedcomponent {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: g.order(), g.size()(4, 7)
sage: scc_digraph = strongly_connected_components_digraph(g, keep_labels=True)
sage: (scc_digraph.order(), scc_digraph.size())(3, 6)
sage: set(g.edge_labels()) == set(scc_digraph.edge_labels())
True

5.41. Connectivity related functions

1935

Graph Theory, Release 10.4>>> from sage.all import *>>> g = DiGraph({Integer(0): {Integer(1): "0-12", Integer(2): "0-12", Integer(3):˓→"0-3"}, Integer(1): {Integer(2): "1-2", Integer(3): "1-3"}, Integer(2):˓→{Integer(1): "2-1", Integer(3): "2-3"}})>>> g.order(), g.size()(4, 7)>>> scc_digraph = strongly_connected_components_digraph(g, keep_labels=True)>>> (scc_digraph.order(), scc_digraph.size())(3, 6)>>> set(g.edge_labels()) == set(scc_digraph.edge_labels())
Truesage.graphs.connectivity.strongly_connected_components_subgraphs(G)Return the strongly connected components as a list of subgraphs.
EXAMPLES:In the symmetric digraph of a graph, the strongly connected components are the connected components:
sage: 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]>>> from sage.all import *>>> from sage.graphs.connectivity import strongly_connected_components_subgraphs>>> g = graphs.PetersenGraph()>>> d = DiGraph(g)>>> strongly_connected_components_subgraphs(d)[Subgraph of (Petersen graph): Digraph on 10 vertices]>>> d.strongly_connected_components_subgraphs()[Subgraph of (Petersen graph): Digraph on 10 vertices]sage: g = DiGraph([(0, 1), (1, 0), (1, 2), (2, 3), (3, 2)])sage: strongly_connected_components_subgraphs(g)[Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 2 vertices]>>> from sage.all import *>>> g = DiGraph([(Integer(0), Integer(1)), (Integer(1), Integer(0)), (Integer(1),␣
˓→Integer(2)), (Integer(2), Integer(3)), (Integer(3), Integer(2))])>>> strongly_connected_components_subgraphs(g)[Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 2 vertices]sage.graphs.connectivity.vertex_connectivity(G, value_only=True, sets=False, k=None,solver=None, verbose=0,
integrality_tolerance=0.001)
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:

1936

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• When the graph is directed, this method actually computes the strong connectivity, (i.e. a directed graph isstrongly 𝑘-connected if there are 𝑘 vertex disjoint paths between any two vertices 𝑢, 𝑣). If you do not want toconsider strong connectivity, the best is probably to convert your DiGraph object to a Graph object, andcompute 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 thissituation are empty.
INPUT:• G – the input Sage (Di)Graph• value_only – boolean (default: True)– When set to True (default), only the value is returned.
– When set to False, both the value and a minimum vertex cut are returned.
• sets – boolean (default: False); whether to also return the two
sets of vertices that are disconnected by the cut (implies value_only=False)• k – integer (default: None); when specified, check if the vertex connectivity of the (di)graph is larger or
equal to 𝑘. The method thus outputs a boolean only.
• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic application on a PappusGraph:
sage: from sage.graphs.connectivity import vertex_connectivity
sage: g = graphs.PappusGraph()
sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
3
sage: g.vertex_connectivity()
˓→# needs sage.numerical.mip
3>>> from sage.all import *>>> from sage.graphs.connectivity import vertex_connectivity>>> g = graphs.PappusGraph()>>> vertex_connectivity(g)˓→needs sage.numerical.mip
3>>> g.vertex_connectivity()
˓→needs sage.numerical.mip
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:

5.41. Connectivity related functions

1937

Graph Theory, Release 10.4

sage: g = graphs.GridGraph([ 3,3 ])sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True)
˓→# needs sage.numerical.mip
sage: len(setA) == 1 or len(setB) == 1
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> g = graphs.GridGraph([ Integer(3),Integer(3) ])>>> [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True)
˓→needs sage.numerical.mip>>> len(setA) == Integer(1) or len(setB) == Integer(1)˓→# needs sage.numerical.mip
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)
˓→# needs sage.numerical.mip
sage: tree.degree(cut_vertex) > 1
˓→# needs sage.numerical.mip
True>>> from sage.all import *>>> tree = graphs.RandomTree(Integer(15))>>> val, [cut_vertex] = vertex_connectivity(tree, value_only=False)
˓→needs sage.numerical.mip>>> tree.degree(cut_vertex) > Integer(1)˓→# needs sage.numerical.mip
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)˓→# needs sage.numerical.mip
0>>> from sage.all import *>>> g = Integer(2) * graphs.PetersenGraph()>>> vertex_connectivity(g)˓→needs sage.numerical.mip
0#␣

Or if they are just 1-connected:
sage: g = graphs.PathGraph(10)sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
1

1938

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PathGraph(Integer(10))>>> vertex_connectivity(g)˓→needs sage.numerical.mip
1#␣For directed graphs, the strong connectivity is tested through the dedicated function:
sage: g = digraphs.ButterflyGraph(3)sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
0>>> from sage.all import *>>> g = digraphs.ButterflyGraph(Integer(3))>>> vertex_connectivity(g)˓→needs sage.numerical.mip
0#␣

A complete graph on 10 vertices is 9-connected:
sage: g = graphs.CompleteGraph(10)sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
9>>> from sage.all import *>>> g = graphs.CompleteGraph(Integer(10))>>> vertex_connectivity(g)˓→needs sage.numerical.mip
9#␣

A complete digraph on 10 vertices is 9-connected:
sage: g = DiGraph(graphs.CompleteGraph(10))
sage: vertex_connectivity(g)˓→# needs sage.numerical.mip
9>>> from sage.all import *>>> g = DiGraph(graphs.CompleteGraph(Integer(10)))>>> vertex_connectivity(g)˓→needs sage.numerical.mip
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)
˓→# needs sage.numerical.mip
True
sage: vertex_connectivity(g, k=4)
˓→# needs sage.numerical.mip
False

5.41. Connectivity related functions

1939

Graph Theory, Release 10.4>>> from sage.all import *>>> g = graphs.PappusGraph()>>> vertex_connectivity(g, k=Integer(3))˓→# needs sage.numerical.mip
True>>> vertex_connectivity(g, k=Integer(4))˓→# needs sage.numerical.mip
False

␣

␣

5.42 Edge connectivity
This module implements methods for computing the edge-connectivity of graphs and digraphs. It also implements methods to extract 𝑘 edge-disjoint spanning trees from a 2𝑘 edge-connected graph or a 𝑘 edge-connected digraph.
Todo:• Implement the tree-packing algorithms proposed in [Gabow1995] and [BHKP2008]• Extend to digraphs with multiple edges• Extend to weighted digraphs
class sage.graphs.edge_connectivity.GabowEdgeConnectivity
Bases: object
Gabow’s algorithm for finding the edge connectivity of digraphs.
This class implements the algorithm proposed in [Gabow1995] for finding the edge connectivity of a directed graphand 𝑘 edge disjoint spanning trees if the digraph is 𝑘 edge connected.
Warning: Multiple edges are currently not supported. The current implementation act as if the digraph is
simple and so the return results might not be correct. We therefore raise an error if the digraph has multiple
edges.
INPUT:• D – a DiGraph
EXAMPLES:
A random 𝑑-regular digraph is 𝑑-edge-connected:
sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
sage: D = DiGraph(graphs.RandomRegular(6, 50))
˓→needs networkx
sage: while not D.is_strongly_connected():˓→needs networkx....:
D = DiGraph(graphs.RandomRegular(6, 50))
sage: GabowEdgeConnectivity(D).edge_connectivity()
˓→needs networkx
6

1940

#␣
#␣

#␣

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4>>> from sage.all import *>>> from sage.graphs.edge_connectivity import GabowEdgeConnectivity>>> D = DiGraph(graphs.RandomRegular(Integer(6), Integer(50)))˓→# needs networkx>>> while not D.is_strongly_connected():˓→needs networkx...
D = DiGraph(graphs.RandomRegular(Integer(6), Integer(50)))>>> GabowEdgeConnectivity(D).edge_connectivity()
˓→needs networkx
6

␣
#␣

#␣

A complete digraph with 𝑛 vertices is 𝑛 − 1-edge-connected:
sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
sage: D = DiGraph(digraphs.Complete(10))
sage: GabowEdgeConnectivity(D, use_rec=True).edge_connectivity()
9>>> from sage.all import *>>> from sage.graphs.edge_connectivity import GabowEdgeConnectivity>>> D = DiGraph(digraphs.Complete(Integer(10)))>>> GabowEdgeConnectivity(D, use_rec=True).edge_connectivity()
9

Check that we get the same result when with and without the DFS-based speed-up initialization proposed in[GKLP2021]:
sage: # needs networkx
sage: G = graphs.RandomBarabasiAlbert(100, 2)
sage: D = DiGraph(G)sage: ec1 = GabowEdgeConnectivity(D,....:dfs_preprocessing=False).edge_connectivity()
sage: ec2 = GabowEdgeConnectivity(D,....:dfs_preprocessing=True).edge_connectivity()
sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True,....:
use_rec=True).edge_connectivity()
sage: ec1 == ec2 and ec2 == ec3
True>>> from sage.all import *>>> # needs networkx>>> G = graphs.RandomBarabasiAlbert(Integer(100), Integer(2))>>> D = DiGraph(G)>>> ec1 = GabowEdgeConnectivity(D,...
dfs_preprocessing=False).edge_connectivity()>>> ec2 = GabowEdgeConnectivity(D,...
dfs_preprocessing=True).edge_connectivity()>>> ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True,...
use_rec=True).edge_connectivity()>>> ec1 == ec2 and ec2 == ec3
TrueG
edge_connectivity()
Return the edge connectivity of the digraph.
EXAMPLES:
5.42. Edge connectivity

1941

Graph Theory, Release 10.4

sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
sage: D = digraphs.Complete(5)sage: GabowEdgeConnectivity(D).edge_connectivity()4>>> from sage.all import *>>> from sage.graphs.edge_connectivity import GabowEdgeConnectivity>>> D = digraphs.Complete(Integer(5))>>> GabowEdgeConnectivity(D).edge_connectivity()4edge_disjoint_spanning_trees()
Iterator over the edge disjoint spanning trees.
EXAMPLES:
sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
sage: D = digraphs.Complete(5)sage: GabowEdgeConnectivity(D).edge_disjoint_spanning_trees()
Traceback (most recent call last):...
NotImplementedError: this method has not been implemented yet>>> from sage.all import *>>> from sage.graphs.edge_connectivity import GabowEdgeConnectivity>>> D = digraphs.Complete(Integer(5))>>> GabowEdgeConnectivity(D).edge_disjoint_spanning_trees()
Traceback (most recent call last):...
NotImplementedError: this method has not been implemented yet

5.43 Domination
This module implements methods related to the notion of domination in graphs, and more precisely:
dominating_set()
dominating_sets()
minimal_dominating_sets()
is_dominating()
is_redundant()
private_neighbors()
greedy_dominating_set()
maximum_leaf_number()

Return a minimum distance-𝑘 dominating set of the graph.
Return an iterator over the minimum distance-𝑘 dominating sets of the graph.
Return an iterator over the minimal dominating sets of a graph.
Check whether a set of vertices dominates a graph.
Check whether a set of vertices has redundant vertices (with respect to domination).
Return the private neighbors of a vertex with respect to other vertices.
Return a greedy distance-𝑘 dominating set of the graph.
Return the maximum leaf number of the graph.

EXAMPLES:
We compute the size of a minimum dominating set of the Petersen graph:

1942

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

sage: g = graphs.PetersenGraph()
sage: g.dominating_set(value_only=True)
˓→needs sage.numerical.mip
3>>> from sage.all import *>>> g = graphs.PetersenGraph()>>> g.dominating_set(value_only=True)
˓→needs sage.numerical.mip
3

#␣

#␣

We enumerate the minimal dominating sets of the 5-star graph:
sage: g = graphs.StarGraph(5)sage: list(g.minimal_dominating_sets())[{0}, {1, 2, 3, 4, 5}]>>> from sage.all import *>>> g = graphs.StarGraph(Integer(5))>>> list(g.minimal_dominating_sets())[{0}, {1, 2, 3, 4, 5}]

Now only those that dominate the middle vertex:
sage: list(g.minimal_dominating_sets([0]))[{0}, {1}, {2}, {3}, {4}, {5}]>>> from sage.all import *>>> list(g.minimal_dominating_sets([Integer(0)]))[{0}, {1}, {2}, {3}, {4}, {5}]Now the minimal dominating sets of the 5-path graph:
sage: g = graphs.PathGraph(5)sage: list(g.minimal_dominating_sets())[{0, 2, 4}, {1, 4}, {0, 3}, {1, 3}]>>> from sage.all import *>>> g = graphs.PathGraph(Integer(5))>>> list(g.minimal_dominating_sets())[{0, 2, 4}, {1, 4}, {0, 3}, {1, 3}]

We count the minimal dominating sets of the Petersen graph:
sage: sum(1 for _ in graphs.PetersenGraph().minimal_dominating_sets())
27>>> from sage.all import *>>> sum(Integer(1) for _ in graphs.PetersenGraph().minimal_dominating_sets())
27

5.43. Domination

1943

Graph Theory, Release 10.4

5.43.1 Methods
sage.graphs.domination.dominating_set(g, k, independent=1, total=False, connected=False,
value_only=False, solver=False, verbose=None,
integrality_tolerance=0)
Return a minimum distance-𝑘 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.
A minimum distance-𝑘 dominating set is a set 𝑆 of vertices of 𝐺 of minimal cardinality such that any vertex of
𝐺 is in 𝑆 or at distance at most 𝑘 from a vertex in 𝑆. A distance-0 dominating set is the set of vertices itself, andwhen 𝑘 is the radius of the graph, any vertex dominates all the other vertices.
As an optimization problem, it can be expressed as follows, where 𝑁 𝑘 (𝑢) denotes the set of vertices at distance at
most 𝑘 from 𝑢 (the set of neighbors when 𝑘 = 1):∑︁Minimize :𝑏𝑣𝑣∈𝐺Such that : ∀𝑣 ∈ 𝐺, 𝑏𝑣 +∑︁

𝑏𝑢 ≥ 1𝑢∈𝑁 𝑘 (𝑣)∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
INPUT:• k – a non-negative integer (default: 1); the domination distance• independent – boolean (default: False); when True, computes a minimum independent dominating
set, that is a minimum dominating set that is also an independent set (see also independent_set())• total – boolean (default: False); when True, computes a total dominating set (see the See the Wikipedia
article Dominating_set)• connected – boolean (default: False); when True, computes a connected dominating set (see Wikipedia
article Connected_dominating_set)• value_only – boolean (default: False); whether to only return the cardinality of the computed dominating set, or to return its list of vertices (default)• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
A basic illustration on a PappusGraph:
sage: g = graphs.PappusGraph()
sage: g.dominating_set(value_only=True)
˓→needs sage.numerical.mip
5#␣>>> from sage.all import *>>> g = graphs.PappusGraph()(continues on next page)

1944

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> g.dominating_set(value_only=True)
˓→needs sage.numerical.mip
5#␣

If we build a graph from two disjoint stars, then link their centers we will find a difference between the cardinalityof an independent set and a stable independent set:sage: g = 2 * graphs.StarGraph(5)sage: g.add_edge(0, 6)
sage: len(g.dominating_set())˓→needs sage.numerical.mip
2
sage: len(g.dominating_set(independent=True))
˓→needs sage.numerical.mip
6>>> from sage.all import *>>> g = Integer(2) * graphs.StarGraph(Integer(5))>>> g.add_edge(Integer(0), Integer(6))>>> len(g.dominating_set())˓→needs sage.numerical.mip
2>>> len(g.dominating_set(independent=True))
˓→needs sage.numerical.mip
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)
˓→needs sage.numerical.mip
4>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.dominating_set(total=True, value_only=True)
˓→needs sage.numerical.mip
4

#␣

#␣

The dominating set is calculated for both the directed and undirected graphs (modification introduced in Issue#17905):sage: g = digraphs.Path(3)sage: g.dominating_set(value_only=True)
˓→needs sage.numerical.mip
2
sage: g = graphs.PathGraph(3)sage: g.dominating_set(value_only=True)
˓→needs sage.numerical.mip
1>>> from sage.all import *>>> g = digraphs.Path(Integer(3))>>> g.dominating_set(value_only=True)
˓→needs sage.numerical.mip

#␣

#␣

#␣
(continues on next page)

5.43. Domination

1945

Graph Theory, Release 10.4

(continued from previous page)2>>> g = graphs.PathGraph(Integer(3))>>> g.dominating_set(value_only=True)
˓→needs sage.numerical.mip
1#␣

Cardinality of distance-𝑘 dominating sets:
sage: G = graphs.PetersenGraph()
sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
˓→needs sage.numerical.mip[10, 3, 1]
sage: G = graphs.PathGraph(5)sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)]
˓→needs sage.numerical.mip[5, 2, 1]#␣#␣>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> [G.dominating_set(k=k, value_only=True) for k in range(G.radius() +␣˓→Integer(1))]# needs sage.numerical.mip[10, 3, 1]>>> G = graphs.PathGraph(Integer(5))>>> [G.dominating_set(k=k, value_only=True) for k in range(G.radius() +␣˓→Integer(1))]# needs sage.numerical.mip[5, 2, 1]

sage.graphs.domination.dominating_sets(g, k, independent=1, total=False, connected=False,
solver=False, verbose=None, integrality_tolerance=0)
Return an iterator over the minimum distance-𝑘 dominating sets 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.
A minimum distance-𝑘 dominating set is a set 𝑆 of vertices of 𝐺 of minimal cardinality such that any vertex of
𝐺 is in 𝑆 or at distance at most 𝑘 from a vertex in 𝑆. A distance-0 dominating set is the set of vertices itself, andwhen 𝑘 is the radius of the graph, any vertex dominates all the other vertices.
As an optimization problem, it can be expressed as follows, where 𝑁 𝑘 (𝑢) denotes the set of vertices at distance at
most 𝑘 from 𝑢 (the set of neighbors when 𝑘 = 1):∑︁Minimize :𝑏𝑣𝑣∈𝐺Such that : ∀𝑣 ∈ 𝐺, 𝑏𝑣 +∑︁

𝑏𝑢 ≥ 1𝑢∈𝑁 𝑘 (𝑣)∀𝑥 ∈ 𝐺, 𝑏𝑥 is a binary variable
We use constraints generation to iterate over the minimum distance-𝑘 dominating sets. That is, after reporting asolution, we add a constraint to discard it and solve the problem again until no more solution can be found.
INPUT:• k – a non-negative integer (default: 1); the domination distance• independent – boolean (default: False); when True, computes minimum independent dominating
sets, that is minimum dominating sets that are also independent sets (see also independent_set())

1946

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• total – boolean (default: False); when True, computes total dominating sets (see the See the Wikipedia
article Dominating_set)• connected – boolean (default: False); when True, computes connected dominating sets (see Wikipedia
article Connected_dominating_set)• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
Number of distance-𝑘 dominating sets of a Path graph of order 10:
sage: g = graphs.PathGraph(10)sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)]˓→needs sage.numerical.mip[1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10]#␣>>> from sage.all import *>>> g = graphs.PathGraph(Integer(10))>>> [sum(Integer(1) for _ in g.dominating_sets(k=k)) for k in range(Integer(11))]␣
˓→# needs sage.numerical.mip[1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10]If we build a graph from two disjoint stars, then link their centers we will find a difference between the cardinalityof an independent set and a stable independent set:sage: g = 2 * graphs.StarGraph(5)sage: g.add_edge(0, 6)
sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)]˓→needs sage.numerical.mip[1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12]#␣>>> from sage.all import *>>> g = Integer(2) * graphs.StarGraph(Integer(5))>>> g.add_edge(Integer(0), Integer(6))>>> [sum(Integer(1) for _ in g.dominating_sets(k=k)) for k in range(Integer(11))]␣
˓→# needs sage.numerical.mip[1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12]

The total dominating set of the Petersen graph has cardinality 4:
sage: G = graphs.PetersenGraph()
sage: G.dominating_set(total=True, value_only=True)
˓→needs sage.numerical.mip
4
sage: sorted(G.dominating_sets(k=1))
˓→needs sage.numerical.mip[[0, 2, 6],[0, 3, 9],[0, 7, 8],[1, 3, 7],[1, 4, 5],#␣#␣(continues on next page)

5.43. Domination

1947

Graph Theory, Release 10.4

(continued from previous page)[1, 8, 9],[2, 4, 8],[2, 5, 9],[3, 5, 6],[4, 6, 7]]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.dominating_set(total=True, value_only=True)
˓→needs sage.numerical.mip
4>>> sorted(G.dominating_sets(k=Integer(1)))˓→# needs sage.numerical.mip[[0, 2, 6],[0, 3, 9],[0, 7, 8],[1, 3, 7],[1, 4, 5],[1, 8, 9],[2, 4, 8],[2, 5, 9],[3, 5, 6],[4, 6, 7]]#␣␣

Independent distance-𝑘 dominating sets of a Path graph:
sage: # needs sage.numerical.mip
sage: G = graphs.PathGraph(6)sage: sorted(G.dominating_sets(k=1, independent=True))[[1, 4]]sage: sorted(G.dominating_sets(k=2, independent=True))[[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5]]
sage: sorted(G.dominating_sets(k=3, independent=True))[[2], [3]]>>> from sage.all import *>>> # needs sage.numerical.mip>>> G = graphs.PathGraph(Integer(6))>>> sorted(G.dominating_sets(k=Integer(1), independent=True))[[1, 4]]>>> sorted(G.dominating_sets(k=Integer(2), independent=True))[[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5]]>>> sorted(G.dominating_sets(k=Integer(3), independent=True))[[2], [3]]The dominating set is calculated for both the directed and undirected graphs (modification introduced in Issue#17905):sage: # needs sage.numerical.mip
sage: g = digraphs.Path(3)sage: g.dominating_set(value_only=True)2
sage: list(g.dominating_sets())[[0, 1], [0, 2]]
sage: list(g.dominating_sets(k=2))[[0]](continues on next page)

1948

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)

sage: g = graphs.PathGraph(3)sage: g.dominating_set(value_only=True)1
sage: next(g.dominating_sets())[1]>>> from sage.all import *>>> # needs sage.numerical.mip>>> g = digraphs.Path(Integer(3))>>> g.dominating_set(value_only=True)2>>> list(g.dominating_sets())[[0, 1], [0, 2]]>>> list(g.dominating_sets(k=Integer(2)))[[0]]>>> g = graphs.PathGraph(Integer(3))>>> g.dominating_set(value_only=True)
1>>> next(g.dominating_sets())[1]

Minimum connected dominating sets of the Petersen graph:
sage: G = graphs.PetersenGraph()
sage: G.dominating_set(total=True, value_only=True)
˓→needs sage.numerical.mip
4
sage: sorted(G.dominating_sets(k=1, connected=True))
˓→needs sage.numerical.mip[[0, 1, 2, 6],[0, 1, 4, 5],[0, 3, 4, 9],[0, 5, 7, 8],[1, 2, 3, 7],[1, 6, 8, 9],[2, 3, 4, 8],[2, 5, 7, 9],[3, 5, 6, 8],[4, 6, 7, 9]]>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.dominating_set(total=True, value_only=True)
˓→needs sage.numerical.mip
4>>> sorted(G.dominating_sets(k=Integer(1), connected=True))˓→# needs sage.numerical.mip[[0, 1, 2, 6],[0, 1, 4, 5],[0, 3, 4, 9],[0, 5, 7, 8],[1, 2, 3, 7],[1, 6, 8, 9],[2, 3, 4, 8],[2, 5, 7, 9],[3, 5, 6, 8],

#␣

#␣

#␣

␣

(continues on next page)

5.43. Domination

1949

Graph Theory, Release 10.4

(continued from previous page)[4, 6, 7, 9]]

Subgraph induced by the dominating set is connected:
sage: G = graphs.PetersenGraph()
sage: all(G.subgraph(vertices=dom).is_connected()....:for dom in G.dominating_set(k=1, connected=True))
True>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> all(G.subgraph(vertices=dom).is_connected()...
for dom in G.dominating_set(k=Integer(1), connected=True))
True

Minimum distance-k connected dominating sets of the Tietze graph:
sage: G = graphs.TietzeGraph()
sage: sorted(G.dominating_sets(k=2, connected=True))[[0, 9], [1, 0], [2, 3], [4, 3], [5, 6], [7, 6], [8, 0], [10, 3], [11, 6]]
sage: sorted(G.dominating_sets(k=3, connected=True))[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]]>>> from sage.all import *>>> G = graphs.TietzeGraph()>>> sorted(G.dominating_sets(k=Integer(2), connected=True))[[0, 9], [1, 0], [2, 3], [4, 3], [5, 6], [7, 6], [8, 0], [10, 3], [11, 6]]>>> sorted(G.dominating_sets(k=Integer(3), connected=True))[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]]sage.graphs.domination.greedy_dominating_set(G, k=1, vertices=None, ordering=None,
return_sets=False, closest=False)
Return a greedy distance-𝑘 dominating set of the graph.
A distance-𝑘 dominating set 𝑆 of a graph 𝐺 is a set of its vertices of minimal cardinality such that any vertex of 𝐺
is in 𝑆 or is at distance at most 𝑘 from a vertex in 𝑆. See the Wikipedia article Dominating_set.
When 𝐺 is directed, vertex 𝑢 can be a dominator of vertex 𝑣 if there is a directed path of length at most 𝑘 from 𝑢
to 𝑣.
This method implements a greedy heuristic to find a minimal dominatic set.
INPUT:• G – a Graph• k – integer (default: 1); the domination distance to consider• vertices – iterable container of vertices (default: None); when specified, return a dominating set of thespecified vertices only
• ordering – string (default: None); specify the order in which to consider the vertices– None – if vertices is None, then consider the vertices in the order given by list(G). Otherwise,
consider the vertices in the order of iteration of vertices.
– "degree_min" – consider the vertices by increasing degree– "degree_max" – consider the vertices by decreasing degree

1950

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

• return_sets – boolean (default: False); whether to return the vertices of the dominating set only
(default), or a dictionary mapping each vertex of the dominating set to the set of vertices it dominates.
• closest – boolean (default: False); whether to attach a vertex to its closest dominator or not. Thisparameter is use only when return_sets is True.
EXAMPLES:
Dominating sets of a path:sage: from sage.graphs.domination import greedy_dominating_set
sage: G = graphs.PathGraph(5)sage: sorted(greedy_dominating_set(G, ordering=None))[0, 2, 4]
sage: sorted(greedy_dominating_set(G, ordering="degree_min"))[0, 2, 4]
sage: sorted(greedy_dominating_set(G, ordering="degree_max"))[1, 3]
sage: sorted(greedy_dominating_set(G, k=2, ordering=None))[0, 3]
sage: sorted(greedy_dominating_set(G, k=2, ordering="degree_min"))[0, 4]
sage: sorted(greedy_dominating_set(G, k=2, ordering="degree_max"))[1, 4]
sage: greedy_dominating_set(G, k=3, ordering="degree_min", return_sets=True,␣
˓→closest=False){0: {0, 1, 2, 3}, 4: {4}}sage: greedy_dominating_set(G, k=3, ordering="degree_min", return_sets=True,␣
˓→closest=True){0: {0, 2, 3}, 4: {1, 4}}>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set>>> G = graphs.PathGraph(Integer(5))>>> sorted(greedy_dominating_set(G, ordering=None))[0, 2, 4]>>> sorted(greedy_dominating_set(G, ordering="degree_min"))[0, 2, 4]>>> sorted(greedy_dominating_set(G, ordering="degree_max"))[1, 3]>>> sorted(greedy_dominating_set(G, k=Integer(2), ordering=None))[0, 3]>>> sorted(greedy_dominating_set(G, k=Integer(2), ordering="degree_min"))[0, 4]>>> sorted(greedy_dominating_set(G, k=Integer(2), ordering="degree_max"))[1, 4]>>> greedy_dominating_set(G, k=Integer(3), ordering="degree_min", return_˓→sets=True, closest=False){0: {0, 1, 2, 3}, 4: {4}}>>> greedy_dominating_set(G, k=Integer(3), ordering="degree_min", return_˓→sets=True, closest=True){0: {0, 2, 3}, 4: {1, 4}}

Asking for a dominating set of a subset of vertices:sage: from sage.graphs.domination import greedy_dominating_set
sage: from sage.graphs.domination import is_dominating
sage: G = graphs.PetersenGraph()
sage: vertices = {0, 1, 2, 3, 4, 5}(continues on next page)

5.43. Domination

1951

Graph Theory, Release 10.4

(continued from previous page)

sage: dom = greedy_dominating_set(G, vertices=vertices, return_sets=True)
sage: sorted(dom)[0, 2]
sage: is_dominating(G, dom, focus=vertices)
True
sage: is_dominating(G, dom)
False
sage: dominated = [u for v in dom for u in dom[v]]sage: sorted(dominated) == sorted(vertices)
True>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set>>> from sage.graphs.domination import is_dominating>>> G = graphs.PetersenGraph()>>> vertices = {Integer(0), Integer(1), Integer(2), Integer(3), Integer(4),␣
˓→Integer(5)}>>> dom = greedy_dominating_set(G, vertices=vertices, return_sets=True)>>> sorted(dom)[0, 2]>>> is_dominating(G, dom, focus=vertices)
True>>> is_dominating(G, dom)
False>>> dominated = [u for v in dom for u in dom[v]]>>> sorted(dominated) == sorted(vertices)
True

Influence of the ordering of the vertices on the result:
sage: from sage.graphs.domination import greedy_dominating_set
sage: G = graphs.StarGraph(4)sage: greedy_dominating_set(G, vertices=[0, 1, 2, 3, 4])[0]
sage: sorted(greedy_dominating_set(G, vertices=[1, 2, 3, 4, 0]))[1, 2, 3, 4]>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set>>> G = graphs.StarGraph(Integer(4))>>> greedy_dominating_set(G, vertices=[Integer(0), Integer(1), Integer(2),␣
˓→Integer(3), Integer(4)])[0]>>> sorted(greedy_dominating_set(G, vertices=[Integer(1), Integer(2), Integer(3),␣
˓→Integer(4), Integer(0)]))[1, 2, 3, 4]

Dominating set of a directed graph:
sage: from sage.graphs.domination import greedy_dominating_set
sage: D = digraphs.Path(3)sage: sorted(greedy_dominating_set(D, vertices=[0, 1, 2]))[0, 2]>>> from sage.all import *>>> from sage.graphs.domination import greedy_dominating_set

1952(continues on next page)

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> D = digraphs.Path(Integer(3))>>> sorted(greedy_dominating_set(D, vertices=[Integer(0), Integer(1),␣
˓→Integer(2)]))[0, 2]

sage.graphs.domination.is_dominating(G, dom, focus=None)
Check whether dom is a dominating set of G.
We say that a set 𝐷 of vertices of a graph 𝐺 dominates a set 𝑆 if every vertex of 𝑆 either belongs to 𝐷 or is adjacent
to a vertex of 𝐷. Also, 𝐷 is a dominating set of 𝐺 if it dominates 𝑉 (𝐺).
INPUT:• dom – iterable of vertices of G; the vertices of the supposed dominating set.
• focus – iterable of vertices of G (default: None); if specified, this method checks instead if dom dominates
the vertices in focus.
EXAMPLES:
sage: g = graphs.CycleGraph(5)sage: g.is_dominating([0,1], [4, 2])True
sage: g.is_dominating([0,1])
False>>> from sage.all import *>>> g = graphs.CycleGraph(Integer(5))>>> g.is_dominating([Integer(0),Integer(1)], [Integer(4), Integer(2)])
True>>> g.is_dominating([Integer(0),Integer(1)])
False

sage.graphs.domination.is_redundant(G, dom, focus=None)
Check whether dom has redundant vertices.
For a graph 𝐺 and sets 𝐷 and 𝑆 of vertices, we say that a vertex 𝑣 ∈ 𝐷 is redundant in 𝑆 if 𝑣 has no private
neighbor with respect to 𝐷 in 𝑆. In other words, there is no vertex in 𝑆 that is dominated by 𝑣 but not by 𝐷 ∖ {𝑣}.
INPUT:• dom – iterable of vertices of G; where we look for redundant vertices.
• focus – iterable of vertices of G (default: None); if specified, this method checks instead whether dom hasa redundant vertex in focus.
Warning: The assumption is made that focus (if provided) does not contain repeated vertices.
EXAMPLES:
sage: G = graphs.CubeGraph(3)sage: G.is_redundant([ 000 , 101 ], [ 011 ])Truesage: G.is_redundant([ 000 , 101 ])False

5.43. Domination

1953

Graph Theory, Release 10.4>>> from sage.all import *>>> G = graphs.CubeGraph(Integer(3))>>> G.is_redundant([ 000 , 101 ], [ 011 ])True>>> G.is_redundant([ 000 , 101 ])False

sage.graphs.domination.maximum_leaf_number(G, solver=None, verbose=0,
integrality_tolerance=0.001)
Return the maximum leaf number of the graph.
The maximum leaf number is the maximum possible number of leaves of a spanning tree of 𝐺. This is also thecardinality of the complement of a minimum connected dominating set. See the Wikipedia article Connected_dominating_set.
The MLN of a graph with less than 2 vertices is 0, while the MLN of a connected graph with 2 or 3 vertices is 1
or 2 respectively.
INPUT:• G – a Graph• solver – string (default: None); specify a Mixed Integer Linear Programming (MILP) solver to be used.
If set to None, the default one is used. For more information on MILP solvers and which default solver isused, see the method solve of the class MixedIntegerLinearProgram.
• verbose – integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
• integrality_tolerance – float; parameter for use with MILP solvers over an inexact base ring; see
MixedIntegerLinearProgram.get_values().
EXAMPLES:
Empty graph:
sage: G = Graph()
sage: G.maximum_leaf_number()0>>> from sage.all import *>>> G = Graph()>>> G.maximum_leaf_number()0Petersen graph:
sage: G = graphs.PetersenGraph()
sage: G.maximum_leaf_number()6>>> from sage.all import *>>> G = graphs.PetersenGraph()>>> G.maximum_leaf_number()6

sage.graphs.domination.minimal_dominating_sets(G, to_dominate=None, work_on_copy=True,
k=1)
Return an iterator over the minimal dominating sets of a graph.

1954

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

INPUT:• G – a graph.
• to_dominate – vertex iterable or None (default: None); the set of vertices to be dominated.
• work_on_copy – boolean (default: True); whether or not to work on a copy of the input graph; if set to
False, the input graph will be modified (relabeled).
• k – a non-negative integer (default: 1); the domination distance
OUTPUT:
An iterator over the inclusion-minimal sets of vertices of G. If to_dominate is provided, return an iterator overthe inclusion-minimal sets of vertices that dominate the vertices of to_dominate.
ALGORITHM: The algorithm described in [BDHPR2019].
AUTHOR: Jean-Florent Raymond (2019-03-04) – initial version.
EXAMPLES:
sage: G = graphs.ButterflyGraph()
sage: ll = list(G.minimal_dominating_sets())
sage: pp = [{0, 1}, {1, 3}, {0, 2}, {2, 3}, {4}]sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
sage: ll = list(G.minimal_dominating_sets([0,3]))
sage: pp = [{0}, {3}, {4}]sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
sage: ll = list(G.minimal_dominating_sets([4]))sage: pp = [{4}, {0}, {1}, {2}, {3}]sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True>>> from sage.all import *>>> G = graphs.ButterflyGraph()>>> ll = list(G.minimal_dominating_sets())>>> pp = [{Integer(0), Integer(1)}, {Integer(1), Integer(3)}, {Integer(0),␣
˓→Integer(2)}, {Integer(2), Integer(3)}, {Integer(4)}]>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True>>> ll = list(G.minimal_dominating_sets([Integer(0),Integer(3)]))>>> pp = [{Integer(0)}, {Integer(3)}, {Integer(4)}]>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True>>> ll = list(G.minimal_dominating_sets([Integer(4)]))>>> pp = [{Integer(4)}, {Integer(0)}, {Integer(1)}, {Integer(2)}, {Integer(3)}]>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True
sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets())
sage: pp = [{0, 2, 6},....:{0, 9, 3},....:{0, 8, 7},(continues on next page)

5.43. Domination

1955

Graph Theory, Release 10.4

(continued from previous page)....:{1, 3, 7},....:{1, 4, 5},....:{8, 1, 9},....:{8, 2, 4},....:{9, 2, 5},....:{3, 5, 6},....:{4, 6, 7},....:{0, 8, 2, 9},....:{0, 3, 6, 7},....:{1, 3, 5, 9},....:{8, 1, 4, 7},....:{2, 4, 5, 6},....:{0, 1, 2, 3, 4},....:{0, 1, 2, 5, 7},....:{0, 1, 4, 6, 9},....:{0, 1, 5, 6, 8},....:{0, 8, 3, 4, 5},....:{0, 9, 4, 5, 7},....:{8, 1, 2, 3, 6},....:{1, 2, 9, 6, 7},....:{9, 2, 3, 4, 7},....:{8, 2, 3, 5, 7},....:{8, 9, 3, 4, 6},....:{8, 9, 5, 6, 7}]
sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True>>> from sage.all import *>>> ll = list(graphs.PetersenGraph().minimal_dominating_sets())>>> pp = [{Integer(0), Integer(2), Integer(6)},...
{Integer(0), Integer(9), Integer(3)},...
{Integer(0), Integer(8), Integer(7)},...
{Integer(1), Integer(3), Integer(7)},...
{Integer(1), Integer(4), Integer(5)},...
{Integer(8), Integer(1), Integer(9)},...
{Integer(8), Integer(2), Integer(4)},...
{Integer(9), Integer(2), Integer(5)},...
{Integer(3), Integer(5), Integer(6)},...
{Integer(4), Integer(6), Integer(7)},...
{Integer(0), Integer(8), Integer(2), Integer(9)},...
{Integer(0), Integer(3), Integer(6), Integer(7)},...
{Integer(1), Integer(3), Integer(5), Integer(9)},...
{Integer(8), Integer(1), Integer(4), Integer(7)},...
{Integer(2), Integer(4), Integer(5), Integer(6)},...
{Integer(0), Integer(1), Integer(2), Integer(3), Integer(4)},...
{Integer(0), Integer(1), Integer(2), Integer(5), Integer(7)},...
{Integer(0), Integer(1), Integer(4), Integer(6), Integer(9)},...
{Integer(0), Integer(1), Integer(5), Integer(6), Integer(8)},...
{Integer(0), Integer(8), Integer(3), Integer(4), Integer(5)},...
{Integer(0), Integer(9), Integer(4), Integer(5), Integer(7)},...
{Integer(8), Integer(1), Integer(2), Integer(3), Integer(6)},...
{Integer(1), Integer(2), Integer(9), Integer(6), Integer(7)},...
{Integer(9), Integer(2), Integer(3), Integer(4), Integer(7)},...
{Integer(8), Integer(2), Integer(3), Integer(5), Integer(7)},...
{Integer(8), Integer(9), Integer(3), Integer(4), Integer(6)},...
{Integer(8), Integer(9), Integer(5), Integer(6), Integer(7)}](continues on next page)

1956

Chapter 5. Libraries of algorithms

Graph Theory, Release 10.4

(continued from previous page)>>> len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp)
True

Listing minimal distance-𝑘 dominating sets:
sage: G = graphs.Grid2dGraph(2, 3)
sage: list(G.minimal_dominating_sets(k=0))[{(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)}]sage: list(G.minimal_dominating_sets(k=1))[{(0, 0), (0, 2), (1, 1)},{(0, 1), (1, 1)},{(0, 0), (0, 1), (0, 2)},{(0, 2), (1, 0)},{(0, 0), (1, 2)},{(0, 1), (1, 0), (1, 2)},{(1, 0), (1, 1), (1, 2)}]sage: list(G.minimal_dominating_sets(k=2))[{(0, 0), (1, 2)},{(0, 2), (1, 2)},{(1, 0), (1, 2)},{(0, 1)},{(0, 0), (0, 2)},{(0, 2), (1, 0)},{(0, 0), (1, 0)},{(1, 1)}]
sage: list(G.minimal_dominating_sets(k=3))[{(0, 0)}, {(0, 1)}, {(0, 2)}, {(1, 0)}, {(1, 1)}, {(1, 2)}]>>> from sage.all import *>>> G = graphs.Grid2dGraph(Integer(2), Integer(3))>>> list(G.minimal_dominating_sets(k=Integer(0)))[{(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)}]>>> list(G.minimal_dominating_sets(k=Integer(1)))[{(0, 0), (0, 2), (1, 1)},{(0, 1), (1, 1)},{(0, 0), (0, 1), (0, 2)},{(0, 2), (1, 0)},{(0, 0), (1, 2)},{(0, 1), (1, 0), (1, 2)},{(1, 0), (1, 1), (1, 2)}]>>> list(G.minimal_dominating_sets(k=Integer(2)))[{(0, 0), (1, 2)},{(0, 2), (1, 2)},{(1, 0), (1, 2)},{(0, 1)},{(0, 0), (0, 2)},{(0, 2), (1, 0)},{(0, 0), (1, 0)},{(1, 1)}]>>> list(G.minimal_dominating_sets(k=Integer(3)))[{(0, 0)}, {(0, 1)}, {(0, 2)}, {(1, 0)}, {(1, 1)}, {(1, 2)}]

When parameter work_on_copy is False, the input graph is modified (relabeled):
sage: G = Graph([( A , B )])sage: _ = list(G.minimal_dominating_sets(work_on_copy=True))(continues on next page)

5.43. Domination

1957

Graph Theory, Release 10.4

(continued from previous page)

sage: set(G) == { A , B }True
sage: _ = list(G.minimal_dominating_sets(work_on_copy=False))
sage: set(G) == { A , B }False
sage: set(G) == {0, 1}
True>>> from sage.all import *>>> G = Graph([( A , B )])>>> _ = list(G.minimal_dominating_sets(work_on_copy=True))>>> set(G) == { A , B }True>>> _ = list(G.minimal_dominating_sets(work_on_copy=False))>>> set(G) == { A , B }False>>> set(G) == {Integer(0), Integer(1)}True

sage.graphs.domination.private_neighbors(G, vertex, dom)
Return the private neighbors of a vertex with respect to other vertices.
A private neighbor of a vertex 𝑣 with respect to a vertex subset 𝐷 is a closed neighbor of 𝑣 that is not dominatedby a vertex of 𝐷 ∖ {𝑣}.
INPUT:• vertex – a vertex of G.
• dom – iterable of vertices of G; the vertices possibly stealing private neighbors from vertex.
OUTPUT:
Return the closed neighbors of vertex that are not closed neighbors of any other vertex of dom.
EXAMPLES:
sage: g = graphs.PathGraph(5)sage: list(g.private_neighbors(1, [1, 3, 4]))
[1, 0]
sage: list(g.private_neighbors(1, [3, 4]))
[1, 0]
sage: list(g.private_neighbors(1, [3, 4, 0]))[]>>> from sage.all import *>>> g = graphs.PathGraph(Integer(5))>>> list(g.private_neighbors(Integer(1), [Integer(1), Integer(3), Integer(4)]))[1, 0]>>> list(g.private_neighbors(Integer(1), [Integer(3), Integer(4)]))[1, 0]>>> list(g.private_neighbors(Integer(1), [Integer(3), Integer(4), Integer(0)]))
[]

1958

Chapter 5. Libraries of algorithms

CHAPTERSIX

INDICES AND TABLES• Index• Module Index• Search Page

1959

Graph Theory, Release 10.4

1960

Chapter 6. Indices and Tables

BIBLIOGRAPHY[Lein] Tom Leinster, The magnitude of metric spaces. Doc. Math. 18 (2013), 857-905.

1961

Graph Theory, Release 10.4

1962

Bibliography

PYTHON MODULE INDEX

csage.combinat.designs.incidence_structures, 1509

gsage.graphs.asteroidal_triples, 1565
sage.graphs.base.boost_graph, 1486
sage.graphs.base.c_graph, 1374
sage.graphs.base.dense_graph, 1443
sage.graphs.base.graph_backends, 1479
sage.graphs.base.overview, 1373
sage.graphs.base.sparse_graph, 1431
sage.graphs.base.static_dense_graph,1452
sage.graphs.base.static_sparse_backend, 1470
sage.graphs.base.static_sparse_graph,1462
sage.graphs.bipartite_graph, 732
sage.graphs.centrality, 1561
sage.graphs.cliquer, 1558
sage.graphs.cographs, 1569
sage.graphs.comparability, 1574
sage.graphs.connectivity, 1897
sage.graphs.convexity_properties, 1779
sage.graphs.digraph, 663
sage.graphs.digraph_generators, 1042
sage.graphs.distances_all_pairs, 1788
sage.graphs.domination, 1942
sage.graphs.edge_connectivity, 1940
sage.graphs.generators.basic, 1218
sage.graphs.generators.chessboard, 1242
sage.graphs.generators.classical_geometries, 1146
sage.graphs.generators.distance_regular, 1125
sage.graphs.generators.families, 1162
sage.graphs.generators.intersection,
1249
sage.graphs.generators.platonic_solids, 1258
sage.graphs.generators.random, 1264

sage.graphs.generators.smallgraphs, 1288
sage.graphs.generators.world_map, 1357
sage.graphs.generic_graph, 1
sage.graphs.generic_graph_pyx, 1883
sage.graphs.genus, 1620
sage.graphs.graph, 437
sage.graphs.graph_coloring, 1539
sage.graphs.graph_database, 1065
sage.graphs.graph_decompositions.bandwidth, 1731
sage.graphs.graph_decompositions.clique_separators, 1771
sage.graphs.graph_decompositions.cutwidth, 1734
sage.graphs.graph_decompositions.graph_products, 1740
sage.graphs.graph_decompositions.modular_decomposition, 1747
sage.graphs.graph_decompositions.rankwidth, 1728
sage.graphs.graph_decompositions.tree_decomposition, 1691
sage.graphs.graph_decompositions.vertex_separation, 1709
sage.graphs.graph_editor, 1825
sage.graphs.graph_generators, 773
sage.graphs.graph_generators_pyx, 1064
sage.graphs.graph_input, 1832
sage.graphs.graph_latex, 1804
sage.graphs.graph_list, 1827
sage.graphs.graph_plot, 1649
sage.graphs.graph_plot_js, 1688
sage.graphs.hyperbolicity, 1842
sage.graphs.hypergraph_generators, 1505
sage.graphs.independent_sets, 1567
sage.graphs.isgci, 1360
sage.graphs.line_graph, 1583
sage.graphs.lovasz_theta, 1624
sage.graphs.matchpoly, 1615
sage.graphs.orientations, 1894
sage.graphs.partial_cube, 1857
sage.graphs.path_enumeration, 18601963

Graph Theory, Release 10.4

sage.graphs.planarity, 1630
sage.graphs.pq_trees, 1605
sage.graphs.schnyder, 1625
sage.graphs.spanning_tree, 1588
sage.graphs.strongly_regular_db, 1088
sage.graphs.traversals, 1631
sage.graphs.trees, 1614
sage.graphs.tutte_polynomial, 1849
sage.graphs.views, 762
sage.graphs.weakly_chordal, 1785

1964

Python Module Index

INDEX

Non-alphabetical

add_edges()(sage.graphs.generic_graph.GenericGraphmethod),14__eq__()(sage.graphs.generic_graph.GenericGraph
add_path()(sage.graphs.generic_graph.GenericGraphmethod), 8
method), 15
add_vertex()(sage.graphs.base.c_graph.CGraphA
method), 1376
acyclic_edge_coloring()(inmoduleadd_vertex()(sage.graphs.base.c_graph.CGraphsage.graphs.graph_coloring), 1540
Backend method), 1400
acyclic_orientations()(inmoduleadd_vertex()(sage.graphs.base.graph_backsage.graphs.orientations), 1894
ends.GenericGraphBackend method), 1481
acyclic_orientations()
add_vertex() (sage.graphs.base.static_sparse_back(sage.graphs.graph.Graph method), 467
end.StaticSparseBackend method), 1473
add_arc() (sage.graphs.base.c_graph.CGraph method),
add_vertex() (sage.graphs.base.static_sparse_back1375
end.StaticSparseCGraph method), 1478
add_arc_label() (sage.graphs.base.sparse_graph.Sparseadd_vertex() (sage.graphs.bipartite_graph.BipartiteGraph method), 1436
Graph method), 742
add_child() (sage.graphs.cographs.CoTree method),
add_vertex()(sage.graphs.generic_graph.Generic1570
Graph method), 16
add_clique()(sage.graphs.generic_graph.Genericadd_vertices() (sage.graphs.base.c_graph.CGraph
Graph method), 10
method), 1378
add_cycle()(sage.graphs.generic_graph.Genericadd_vertices() (sage.graphs.base.c_graph.CGraphGraph method), 12
Backend method), 1401
add_edge() (sage.graphs.base.c_graph.CGraphBackadd_vertices()(sage.graphs.base.graph_backend method), 1399
ends.GenericGraphBackend method), 1481
add_edge() (sage.graphs.base.graph_backends.Generadd_vertices() (sage.graphs.base.static_sparse_backicGraphBackend method), 1480
end.StaticSparseBackend method), 1474
add_edge()(sage.graphs.base.static_sparse_backadd_vertices() (sage.graphs.bipartite_graph.Biparend.StaticSparseBackend method), 1473
titeGraph method), 743
add_edge()(sage.graphs.bipartite_graph.Bipartiteadd_vertices() (sage.graphs.generic_graph.GenericGraph method), 740
Graph method), 17
add_edge() (sage.graphs.generic_graph.GenericGraphadjacency_matrix()
method), 12(sage.graphs.generic_graph.GenericGraph
add_edges() (sage.graphs.base.c_graph.CGraphBackmethod), 17
end method), 1400
AffineOrthogonalPolarGraph() (in module
add_edges() (sage.graphs.base.dense_graph.DenseGsage.graphs.generators.classical_geometries),
raphBackend method), 1449
1146
add_edges()(sage.graphs.base.graph_backAffineOrthogonalPolarGraph()ends.GenericGraphBackend method), 1480
(sage.graphs.graph_generators.GraphGeneradd_edges()(sage.graphs.base.static_sparse_backators static method), 783
end.StaticSparseBackend method), 1473
AfricaMap()(inmodulesage.graphs.generaadd_edges() (sage.graphs.bipartite_graph.Bipartitetors.world_map), 1357
Graph method), 740
AfricaMap() (sage.graphs.graph_generators.Graph-

1965

Graph Theory, Release 10.4

Generators static method), 784
AhrensSzekeresGeneralizedQuadrangleGraph() (in module sage.graphs.generators.classical_geometries), 1147
AhrensSzekeresGeneralizedQuadrangleGraph()(sage.graphs.graph_generators.GraphGenerators static method), 785
all_arcs()(sage.graphs.base.c_graph.CGraphmethod), 1380
all_cliques() (in module sage.graphs.cliquer), 1558
all_cliques() (sage.graphs.graph.Graph method),468
all_cycles_iterator() (sage.graphs.digraph.DiGraph method), 673
all_graph_colorings()(inmodulesage.graphs.graph_coloring), 1542
all_max_clique() (in module sage.graphs.cliquer),1559
all_paths() (in module sage.graphs.path_enumeration), 1861
all_paths()(sage.graphs.generic_graph.GenericGraph method), 22
all_paths_iterator()(inmodulesage.graphs.path_enumeration), 1864
all_paths_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 25
all_simple_cycles()(sage.graphs.digraph.DiGraph method), 675
all_simple_paths()(inmodulesage.graphs.path_enumeration), 1869
all_simple_paths()(sage.graphs.generic_graph.GenericGraphmethod), 31
allow_loops() (sage.graphs.bipartite_graph.BipartiteGraph method), 744
allow_loops() (sage.graphs.generic_graph.GenericGraph method), 35
allow_multiple_edges()(sage.graphs.generic_graph.GenericGraphmethod), 37
allows_loops() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1474
allows_loops() (sage.graphs.generic_graph.GenericGraph method), 39
allows_multiple_edges()(sage.graphs.generic_graph.GenericGraphmethod), 40
AlternatingFormsGraph()(inmodulesage.graphs.generators.distance_regular), 1126
AlternatingFormsGraph()(sage.graphs.graph_generators.GraphGenerators static method), 786
am() (sage.graphs.generic_graph.GenericGraph method),
1966

42
antipodal_graph() (in module sage.graphs.distances_all_pairs), 1789
antipodal_graph()(sage.graphs.graph.Graphmethod), 470
antisymmetric() (sage.graphs.generic_graph.GenericGraph method), 46
apex_vertices() (sage.graphs.graph.Graph method),470
apparently_feasible_parameters() (in module sage.graphs.strongly_regular_db), 1098
append_child()(sage.graphs.schnyder.TreeNodemethod), 1626
arboricity() (sage.graphs.graph.Graph method), 472
arc_label()(sage.graphs.base.c_graph.CGraphmethod), 1380
atoms_and_clique_separators() (in module
sage.graphs.graph_decompositions.clique_separators), 1771
atoms_and_clique_separators()(sage.graphs.graph.Graph method), 473
auslander_reiten_quiver()(sage.graphs.digraph.DiGraph method), 680
automorphism_group() (sage.combinat.designs.incidence_structures.IncidenceStructure method),1512
automorphism_group()(sage.graphs.generic_graph.GenericGraphmethod), 48
average_degree() (sage.graphs.generic_graph.GenericGraph method), 53
average_distance()(sage.graphs.generic_graph.GenericGraphmethod), 53
AztecDiamondGraph() (in module sage.graphs.generators.families), 1162
AztecDiamondGraph() (sage.graphs.graph_generators.GraphGenerators static method), 786

Bb_coloring() (in module sage.graphs.graph_coloring),
1544
Balaban10Cage() (in module sage.graphs.generators.smallgraphs), 1288
Balaban10Cage()(sage.graphs.graph_generators.GraphGenerators static method), 787
Balaban11Cage() (in module sage.graphs.generators.smallgraphs), 1289
Balaban11Cage()(sage.graphs.graph_generators.GraphGenerators static method), 788
BalancedTree() (in module sage.graphs.generators.families), 1163
BalancedTree()(sage.graphs.graph_generators.GraphGenerators static method), 789
Index

Graph Theory, Release 10.4

bandwidth() (in module sage.graphs.graph_decompositions.bandwidth), 1732
bandwidth() (sage.graphs.graph.Graph method), 480
bandwidth_heuristics()(inmodulesage.graphs.base.boost_graph), 1487
BarbellGraph() (in module sage.graphs.generators.families), 1164
BarbellGraph()(sage.graphs.graph_generators.GraphGenerators static method), 791
basic (sage.graphs.graph_generators.GraphGenerators
attribute), 1002
BidiakisCube() (in module sage.graphs.generators.smallgraphs), 1291
BidiakisCube()(sage.graphs.graph_generators.GraphGenerators static method), 792
bidirectional_dijkstra()(sage.graphs.base.c_graph.CGraphBackend
method), 1402
bidirectional_dijkstra_special()(sage.graphs.base.c_graph.CGraphBackend
method), 1403
BiggsSmithGraph() (in module sage.graphs.generators.smallgraphs), 1292
BiggsSmithGraph()(sage.graphs.graph_generators.GraphGenerators static method), 794
BilinearFormsGraph() (in module sage.graphs.generators.distance_regular), 1126
BilinearFormsGraph() (sage.graphs.graph_generators.GraphGenerators static method), 795
binary_string_from_dig6()(inmodulesage.graphs.generic_graph_pyx), 1885
binary_string_from_graph6() (in module
sage.graphs.generic_graph_pyx), 1885
binary_string_to_graph6()(inmodulesage.graphs.generic_graph_pyx), 1886
BinomialRandomUniform()(sage.graphs.hypergraph_generators.HypergraphGenerators
method), 1505
bipartite_color()(sage.graphs.graph.Graphmethod), 481
bipartite_double()(sage.graphs.graph.Graphmethod), 482
bipartite_sets()(sage.graphs.graph.Graphmethod), 483
BipartiteGraph(classin
sage.graphs.bipartite_graph), 732
bipartition() (sage.graphs.bipartite_graph.BipartiteGraph method), 744
BishopGraph() (in module sage.graphs.generators.chessboard), 1242
BishopGraph() (sage.graphs.graph_generators.GraphGenerators static method), 795
BlanusaFirstSnarkGraph()(inmodulesage.graphs.generators.smallgraphs), 1293
Index

BlanusaFirstSnarkGraph()(sage.graphs.graph_generators.GraphGenerators static method), 796
BlanusaSecondSnarkGraph()(inmodulesage.graphs.generators.smallgraphs), 1294
BlanusaSecondSnarkGraph()(sage.graphs.graph_generators.GraphGenerators static method), 797
block_sizes()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1513
blocks()(sage.combinat.designs.incidence_structures.IncidenceStructure method), 1514
blocks_and_cut_vertices()(inmodulesage.graphs.base.boost_graph), 1487
blocks_and_cut_vertices()(inmodulesage.graphs.connectivity), 1906
blocks_and_cut_vertices()(sage.graphs.generic_graph.GenericGraphmethod), 54
blocks_and_cuts_tree()(inmodulesage.graphs.connectivity), 1909
blocks_and_cuts_tree()(sage.graphs.generic_graph.GenericGraphmethod), 56
blossoming_contour() (in module sage.graphs.generators.random), 1285
boruvka() (in module sage.graphs.spanning_tree), 1589
BOTH_SPLIT (sage.graphs.graph_decompositions.modular_decomposition.NodeSplit attribute), 1749
bounded_outdegree_orientation()(sage.graphs.graph.Graph method), 483
breadth_first_level_search() (in module
sage.graphs.partial_cube), 1858
breadth_first_search()(sage.graphs.base.c_graph.CGraphBackend
method), 1404
breadth_first_search()(sage.graphs.generic_graph.GenericGraphmethod), 57
bridges() (in module sage.graphs.connectivity), 1910
bridges() (sage.graphs.graph.Graph method), 485
BrinkmannGraph() (in module sage.graphs.generators.smallgraphs), 1294
BrinkmannGraph()(sage.graphs.graph_generators.GraphGenerators static method), 798
BrouwerHaemersGraph()(inmodulesage.graphs.generators.smallgraphs), 1296
BrouwerHaemersGraph() (sage.graphs.graph_generators.GraphGenerators static method), 799
BubbleSortGraph() (in module sage.graphs.generators.families), 1165
BubbleSortGraph()(sage.graphs.graph_generators.GraphGenerators static method), 800
1967

Graph Theory, Release 10.4

BuckyBall() (in module sage.graphs.generators.smallgraphs), 1297
BuckyBall() (sage.graphs.graph_generators.GraphGenerators static method), 801
BullGraph() (in module sage.graphs.generators.basic),
1218
BullGraph() (sage.graphs.graph_generators.GraphGenerators static method), 802
ButterflyGraph() (in module sage.graphs.generators.basic), 1220
ButterflyGraph()(sage.graphs.digraph_generators.DiGraphGenerators method), 1046
ButterflyGraph()(sage.graphs.graph_generators.GraphGenerators static method), 804Cc_graph() (sage.graphs.base.c_graph.CGraphBackend
method), 1406
CaiFurerImmermanGraph()(inmodulesage.graphs.generators.families), 1166
CaiFurerImmermanGraph()(sage.graphs.graph_generators.GraphGenerators static method), 805
CameronGraph() (in module sage.graphs.generators.smallgraphs), 1297
CameronGraph()(sage.graphs.graph_generators.GraphGenerators static method), 807
canaug_traverse_edge()(inmodulesage.graphs.graph_generators), 1039
canaug_traverse_vert()(inmodulesage.graphs.graph_generators), 1040
canonical_label()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1514
canonical_label() (sage.graphs.bipartite_graph.BipartiteGraph method), 744
canonical_label()(sage.graphs.generic_graph.GenericGraphmethod), 61
cardinality() (sage.graphs.generic_graph_pyx.SubgraphSearch method), 1884
cardinality() (sage.graphs.independent_sets.IndependentSets method), 1569
cardinality() (sage.graphs.pq_trees.P method), 1606
cardinality() (sage.graphs.pq_trees.Q method),1611
cartesian_product()(sage.graphs.generic_graph.GenericGraphmethod), 64
categorical_product()(sage.graphs.generic_graph.GenericGraphmethod), 64
Cell120() (in module sage.graphs.generators.smallgraphs), 1298
1968

Cell120() (sage.graphs.graph_generators.GraphGenerators static method), 807
Cell600() (in module sage.graphs.generators.smallgraphs), 1298
Cell600() (sage.graphs.graph_generators.GraphGenerators static method), 808
center() (sage.graphs.digraph.DiGraph method), 680
center() (sage.graphs.graph.Graph method), 486
centrality_betweenness()(inmodulesage.graphs.centrality), 1562
centrality_betweenness()(sage.graphs.generic_graph.GenericGraphmethod), 65
centrality_closeness()(sage.graphs.generic_graph.GenericGraphmethod), 67
centrality_closeness_random_k() (in module
sage.graphs.centrality), 1563
centrality_closeness_top_k() (in module
sage.graphs.centrality), 1563
centrality_degree() (sage.graphs.graph.Graphmethod), 487
CGraph (class in sage.graphs.base.c_graph), 1375
CGraphBackend (class in sage.graphs.base.c_graph),1398
chang_graphs() (in module sage.graphs.generators.families), 1213
chang_graphs()(sage.graphs.graph_generators.GraphGenerators static method), 1002
change_label() (in module sage.graphs.cographs),1571
characteristic_polynomial()(sage.graphs.generic_graph.GenericGraphmethod), 70
charpoly() (sage.graphs.generic_graph.GenericGraphmethod), 70
check_aut() (in module sage.graphs.graph_generators), 1041
check_aut_edge()(inmodulesage.graphs.graph_generators), 1042
check_tkz_graph()(inmodulesage.graphs.graph_latex), 1824
check_vertex() (sage.graphs.base.c_graph.CGraphmethod), 1381
cheeger_constant()(sage.graphs.graph.Graphmethod), 487
chessboard (sage.graphs.graph_generators.GraphGenerators attribute), 1003
ChessboardGraphGenerator()(inmodulesage.graphs.generators.chessboard), 1243
ChessboardGraphGenerator()(sage.graphs.graph_generators.GraphGenerators static method), 808
children_node_type()(inmoduleIndex

Graph Theory, Release 10.4

sage.graphs.graph_decompositions.modular_decomposition), 1750
chromatic_index()(sage.graphs.graph.Graphmethod), 489
chromatic_number()(inmodulesage.graphs.graph_coloring), 1545
chromatic_number()(sage.graphs.graph.Graphmethod), 490
chromatic_polynomial()(sage.graphs.graph.Graph method), 492
chromatic_quasisymmetric_function()(sage.graphs.graph.Graph method), 495
chromatic_symmetric_function()(sage.graphs.graph.Graph method), 497
ChvatalGraph() (in module sage.graphs.generators.smallgraphs), 1299
ChvatalGraph()(sage.graphs.graph_generators.GraphGenerators static method), 809
Circuit() (sage.graphs.digraph_generators.DiGraphGenerators method), 1048
Circulant()(sage.graphs.digraph_generators.DiGraphGenerators method), 1048
CirculantGraph() (in module sage.graphs.generators.families), 1168
CirculantGraph()(sage.graphs.graph_generators.GraphGenerators static method), 810
CircularLadderGraph()(inmodulesage.graphs.generators.basic), 1221
CircularLadderGraph() (sage.graphs.graph_generators.GraphGenerators static method), 813
classes() (sage.graphs.isgci.GraphClasses method),1368
classical_geometries (sage.graphs.graph_generators.GraphGenerators attribute), 1003
ClawGraph() (in module sage.graphs.generators.basic),
1222
ClawGraph() (sage.graphs.graph_generators.GraphGenerators static method), 814
clear()(sage.graphs.generic_graph.GenericGraphmethod), 71
cleave() (in module sage.graphs.connectivity), 1911
cleave() (sage.graphs.graph.Graph method), 498
ClebschGraph() (in module sage.graphs.generators.smallgraphs), 1300
ClebschGraph()(sage.graphs.graph_generators.GraphGenerators static method), 814
clique_complex()(sage.graphs.graph.Graphmethod), 501
clique_maximum()(sage.graphs.graph.Graphmethod), 502
clique_number() (in module sage.graphs.cliquer),1560
clique_number() (sage.graphs.graph.Graph method),
503
Index

clique_polynomial() (sage.graphs.graph.Graphmethod), 505
cliques_containing_vertex()(sage.graphs.graph.Graph method), 505
cliques_get_clique_bipartite()(sage.graphs.graph.Graph method), 507
cliques_get_max_clique_graph()(sage.graphs.graph.Graph method), 508
cliques_maximal()(sage.graphs.graph.Graphmethod), 508
cliques_maximum()(sage.graphs.graph.Graphmethod), 510
cliques_number_of() (sage.graphs.graph.Graphmethod), 511
cliques_vertex_clique_number()(sage.graphs.graph.Graph method), 512
cluster_transitivity()(sage.graphs.generic_graph.GenericGraphmethod), 72
cluster_triangles()(sage.graphs.generic_graph.GenericGraphmethod), 73
clustering_average()(sage.graphs.generic_graph.GenericGraphmethod), 73
clustering_coeff()(inmodulesage.graphs.base.boost_graph), 1488
clustering_coeff()(sage.graphs.generic_graph.GenericGraphmethod), 74
coarsest_equitable_refinement()(sage.graphs.generic_graph.GenericGraphmethod), 75
cocliques_HoffmannSingleton() (in module
sage.graphs.generators.distance_regular), 1136
cocliques_HoffmannSingleton()(sage.graphs.graph_generators.GraphGenerators static method), 1003
cographs() (in module sage.graphs.cographs), 1571
cographs() (sage.graphs.graph_generators.GraphGenerators static method), 1003
cographs_module(sage.graphs.graph_generators.GraphGenerators attribute), 1005
coloring()(sage.combinat.designs.incidence_structures.IncidenceStructure method), 1515
coloring() (sage.graphs.graph.Graph method), 513
common_neighbors_matrix()(sage.graphs.graph.Graph method), 514
complement() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1516
complement() (sage.graphs.base.dense_graph.DenseGraph method), 1446
complement() (sage.graphs.bipartite_graph.BipartiteGraph method), 747
1969

Graph Theory, Release 10.4

complement()(sage.graphs.generic_graph.GenericGraph method), 77
complement_bipartite()(sage.graphs.bipartite_graph.BipartiteGraph method), 747
Complete() (sage.graphs.digraph_generators.DiGraphGenerators method), 1048
complete_poly() (in module sage.graphs.matchpoly),
1615
CompleteBipartiteGraph()(inmodulesage.graphs.generators.basic), 1223
CompleteBipartiteGraph()(sage.graphs.graph_generators.GraphGenerators static method), 815
CompleteGraph() (in module sage.graphs.generators.basic), 1225
CompleteGraph()(sage.graphs.graph_generators.GraphGenerators static method), 818
CompleteMultipartiteGraph() (in module
sage.graphs.generators.basic), 1228
CompleteMultipartiteGraph()(sage.graphs.graph_generators.GraphGenerators static method), 820
CompleteUniform() (sage.graphs.hypergraph_generators.HypergraphGenerators method), 1506
compute_depth_of_self_and_children()(sage.graphs.schnyder.TreeNode method), 1627
compute_number_of_descendants()(sage.graphs.schnyder.TreeNodemethod),1627
connected_component_containing_vertex() (in module sage.graphs.connectivity),1913
connected_component_containing_vertex()(sage.graphs.generic_graph.GenericGraph method), 78
connected_components()(inmodulesage.graphs.connectivity), 1914
connected_components()(sage.graphs.generic_graph.GenericGraphmethod), 79
connected_components_number() (in module
sage.graphs.connectivity), 1915
connected_components_number()(sage.graphs.generic_graph.GenericGraphmethod), 80
connected_components_sizes() (in module
sage.graphs.connectivity), 1916
connected_components_sizes()(sage.graphs.generic_graph.GenericGraphmethod), 80
connected_components_subgraphs() (in module sage.graphs.connectivity), 1916
connected_components_subgraphs()(sage.graphs.generic_graph.GenericGraph1970

method), 81
connected_full_subgraphs()(inmodulesage.graphs.base.static_dense_graph), 1453
connected_subgraph_iterator() (in module
sage.graphs.base.static_dense_graph), 1456
connected_subgraph_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 82
connecting_nodes() (in module sage.graphs.generators.random), 1286
contract_edge() (sage.graphs.generic_graph.GenericGraph method), 84
contract_edges() (sage.graphs.generic_graph.GenericGraph method), 85
contracted_edge()(inmodulesage.graphs.tutte_polynomial), 1853
convexity_properties()(sage.graphs.graph.Graph method), 518
ConvexityProperties (class in sage.graphs.convexity_properties), 1779
ConwaySmith_for_3S7()(inmodulesage.graphs.generators.distance_regular), 1127
ConwaySmith_for_3S7() (sage.graphs.graph_generators.GraphGenerators static method), 821
copy() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1517
copy()(sage.graphs.generic_graph.GenericGraphmethod), 86
copy_tree() (sage.graphs.cographs.CoTree method),
1570
cores() (sage.graphs.graph.Graph method), 519
CorrelationGraph() (in module sage.graphs.generators.basic), 1228
CorrelationGraph() (sage.graphs.graph_generators.GraphGenerators static method), 821
cospectral_graphs() (sage.graphs.graph_generators.GraphGenerators method), 1005
CossidentePenttilaGraph()(inmodulesage.graphs.generators.classical_geometries),
1148
CossidentePenttilaGraph()(sage.graphs.graph_generators.GraphGenerators static method), 822
CoTree (class in sage.graphs.cographs), 1570
CoxeterGraph() (in module sage.graphs.generators.smallgraphs), 1300
CoxeterGraph()(sage.graphs.graph_generators.GraphGenerators static method), 823
create_normal_node()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1751
create_parallel_node()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1751
Index

Graph Theory, Release 10.4

create_prime_node()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1751
create_series_node()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1752
crossing_number()(sage.graphs.generic_graph.GenericGraphmethod), 89
CubeConnectedCycle() (in module sage.graphs.generators.families), 1171
CubeConnectedCycle() (sage.graphs.graph_generators.GraphGenerators static method), 823
CubeGraph() (in module sage.graphs.generators.families), 1172
CubeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 824
current_allocation()(sage.graphs.base.c_graph.CGraphmethod),1383
cutwidth() (in module sage.graphs.graph_decompositions.cutwidth), 1736
cutwidth() (sage.graphs.graph.Graph method), 521
cutwidth_dyn() (in module sage.graphs.graph_decompositions.cutwidth), 1739
cutwidth_MILP() (in module sage.graphs.graph_decompositions.cutwidth), 1737
cycle_basis() (sage.graphs.generic_graph.GenericGraph method), 90
CycleGraph() (in module sage.graphs.generators.basic), 1229
CycleGraph() (sage.graphs.graph_generators.GraphGenerators static method), 826

D
DartGraph() (in module sage.graphs.generators.basic),
1231
DartGraph() (sage.graphs.graph_generators.GraphGenerators static method), 828
data_to_degseq()(inmodulesage.graphs.graph_database), 1085
DeBruijn() (sage.graphs.digraph_generators.DiGraphGenerators method), 1049
degree()(sage.combinat.designs.incidence_structures.IncidenceStructure method), 1517
degree() (sage.graphs.base.c_graph.CGraphBackend
method), 1406
degree() (sage.graphs.base.graph_backends.GenericGraphBackend method), 1481
degree() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1474
degree()(sage.graphs.generic_graph.GenericGraphmethod), 93

Index

degree_constrained_subgraph()(sage.graphs.graph.Graph method), 522
degree_histogram()(sage.graphs.generic_graph.GenericGraphmethod), 95
degree_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 95
degree_polynomial()(sage.graphs.digraph.DiGraph method), 681
degree_sequence(sage.graphs.graph_generators.GraphGenerators attribute), 1007
degree_sequence()(sage.graphs.generic_graph.GenericGraphmethod), 97
degree_to_cell() (sage.graphs.generic_graph.GenericGraph method), 98
degrees()(sage.combinat.designs.incidence_structures.IncidenceStructure method), 1518
DegreeSequence()(sage.graphs.graph_generators.GraphGenerators static method), 828
DegreeSequenceBipartite()(sage.graphs.graph_generators.GraphGenerators static method), 829
DegreeSequenceConfigurationModel()(sage.graphs.graph_generators.GraphGenerators
static method), 830
DegreeSequenceExpected()(sage.graphs.graph_generators.GraphGenerators static method), 831
DegreeSequenceTree() (sage.graphs.graph_generators.GraphGenerators static method), 832
degseq_to_data()(inmodulesage.graphs.graph_database), 1086
DejterGraph() (in module sage.graphs.generators.smallgraphs), 1301
DejterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 833
del_all_arcs() (sage.graphs.base.c_graph.CGraphmethod), 1384
del_arc_label() (sage.graphs.base.c_graph.CGraphmethod), 1386
del_edge() (sage.graphs.base.c_graph.CGraphBackend method), 1407
del_edge() (sage.graphs.base.graph_backends.GenericGraphBackend method), 1481
del_edge()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1475
del_edges() (sage.graphs.base.c_graph.CGraphBackend method), 1408
del_vertex()(sage.graphs.base.c_graph.CGraphmethod), 1386
del_vertex()(sage.graphs.base.c_graph.CGraphBackend method), 1409
1971

Graph Theory, Release 10.4

del_vertex()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1482
del_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1475
del_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 1478
del_vertices() (sage.graphs.base.c_graph.CGraphBackend method), 1409
del_vertices()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1482
delete_edge() (sage.graphs.generic_graph.GenericGraph method), 99
delete_edges() (sage.graphs.generic_graph.GenericGraph method), 101delete_multiedge()(sage.graphs.generic_graph.GenericGraphmethod), 101delete_vertex() (sage.graphs.bipartite_graph.BipartiteGraph method), 747
delete_vertex() (sage.graphs.generic_graph.GenericGraph method), 102delete_vertices() (sage.graphs.bipartite_graph.BipartiteGraph method), 749
delete_vertices()(sage.graphs.generic_graph.GenericGraphmethod), 104DenseGraph (class in sage.graphs.base.dense_graph),
1446
DenseGraphBackend(classin
sage.graphs.base.dense_graph), 1448
density() (sage.graphs.generic_graph.GenericGraphmethod), 104
depth_first_search()(sage.graphs.base.c_graph.CGraphBackend
method), 1410
depth_first_search()(sage.graphs.generic_graph.GenericGraphmethod), 105
depth_first_traversal()(inmodulesage.graphs.partial_cube), 1859
DesarguesGraph() (in module sage.graphs.generators.smallgraphs), 1301
DesarguesGraph()(sage.graphs.graph_generators.GraphGenerators static method), 833
description()(sage.graphs.isgci.GraphClass
method), 1367
diameter() (in module sage.graphs.base.boost_graph),1489
diameter()(inmodulesage.graphs.distances_all_pairs), 1790
diameter() (sage.graphs.digraph.DiGraph method),682
diameter() (sage.graphs.graph.Graph method), 523
diameter_DHV()(inmodule1972

sage.graphs.base.boost_graph), 1490
DiamondGraph() (in module sage.graphs.generators.basic), 1231
DiamondGraph()(sage.graphs.graph_generators.GraphGenerators static method), 833
dig6_string()(sage.graphs.digraph.DiGraphmethod), 683
DiGraph (class in sage.graphs.digraph), 666
DiGraphGenerators (class in sage.graphs.digraph_generators), 1043
DipoleGraph() (in module sage.graphs.generators.families), 1174
DipoleGraph() (sage.graphs.graph_generators.GraphGenerators static method), 834
disjoint_routed_paths()(sage.graphs.generic_graph.GenericGraphmethod), 107disjoint_union() (sage.graphs.generic_graph.GenericGraph method), 108
disjunctive_product()(sage.graphs.generic_graph.GenericGraphmethod), 109
distance() (sage.graphs.generic_graph.GenericGraphmethod), 110
distance_3_doubly_truncated_Golay_code_graph()(inmodulesage.graphs.generators.distance_regular), 1136
distance_3_doubly_truncated_Golay_code_graph()(sage.graphs.graph_generators.GraphGenerators static method), 1007
distance_all_pairs()(sage.graphs.generic_graph.GenericGraphmethod), 111
distance_graph()(sage.graphs.graph.Graphmethod), 525
distance_matrix()(sage.graphs.generic_graph.GenericGraphmethod), 113
distance_regular(sage.graphs.graph_generators.GraphGenerators attribute), 1008
distance_regular_graph()(inmodulesage.graphs.generators.distance_regular), 1136
distance_regular_graph()(sage.graphs.graph_generators.GraphGenerators static method), 1008
distances_all_pairs()(inmodulesage.graphs.distances_all_pairs), 1793
distances_and_predecessors_all_pairs()(in module sage.graphs.distances_all_pairs),
1794
distances_distribution()(inmodulesage.graphs.distances_all_pairs), 1795
distances_distribution()
Index

Graph Theory, Release 10.4

(sage.graphs.generic_graph.GenericGraphmethod), 114
DodecahedralGraph() (in module sage.graphs.generators.platonic_solids), 1258
DodecahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 834
dominating_set() (in module sage.graphs.domination), 1944
dominating_set() (sage.graphs.generic_graph.GenericGraph method), 116
dominating_sets() (in module sage.graphs.domination), 1946
dominating_sets()(sage.graphs.generic_graph.GenericGraphmethod), 119dominator_tree()(inmodulesage.graphs.base.boost_graph), 1490
dominator_tree() (sage.graphs.generic_graph.GenericGraph method), 123
DorogovtsevGoltsevMendesGraph() (in module
sage.graphs.generators.families), 1174
DorogovtsevGoltsevMendesGraph()(sage.graphs.graph_generators.GraphGenerators static method), 835
dot2tex_picture()(sage.graphs.graph_latex.GraphLatex method), 1813
DoubleGeneralizedPetersenGraph() (in module sage.graphs.generators.families), 1174
DoubleGeneralizedPetersenGraph()(sage.graphs.graph_generators.GraphGenerators static method), 836
DoubleGrassmannGraph()(inmodulesage.graphs.generators.distance_regular), 1127
DoubleGrassmannGraph() (sage.graphs.graph_generators.GraphGenerators static method), 836
DoubleOddGraph() (in module sage.graphs.generators.distance_regular), 1128
DoubleOddGraph()(sage.graphs.graph_generators.GraphGenerators static method), 837
DoubleStarSnark() (in module sage.graphs.generators.smallgraphs), 1302
DoubleStarSnark()(sage.graphs.graph_generators.GraphGenerators static method), 837
DoublyTruncatedWittGraph()(inmodulesage.graphs.generators.distance_regular), 1129
DoublyTruncatedWittGraph()(sage.graphs.graph_generators.GraphGenerators static method), 838
dual() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1518
DurerGraph() (in module sage.graphs.generators.smallgraphs), 1302
DurerGraph() (sage.graphs.graph_generators.GraphGenerators static method), 839
Index

DyckGraph() (in module sage.graphs.generators.smallgraphs), 1303
DyckGraph() (sage.graphs.graph_generators.GraphGenerators static method), 840

E
Ear (class in sage.graphs.tutte_polynomial), 1850
ear_decomposition() (sage.graphs.graph.Graphmethod), 528
eccentricity() (in module sage.graphs.distances_all_pairs), 1797
eccentricity()(sage.graphs.digraph.DiGraphmethod), 684
eccentricity() (sage.graphs.graph.Graph method),529
eccentricity_DHV()(inmodulesage.graphs.base.boost_graph), 1492
edge_boundary() (sage.graphs.generic_graph.GenericGraph method), 124
edge_coloring() (in module sage.graphs.graph_coloring), 1546
edge_coloring()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1519
edge_connectivity()(inmodulesage.graphs.base.boost_graph), 1493
edge_connectivity() (in module sage.graphs.connectivity), 1917
edge_connectivity() (sage.graphs.edge_connectivity.GabowEdgeConnectivity method), 1941
edge_connectivity()(sage.graphs.generic_graph.GenericGraphmethod), 126
edge_cut() (sage.graphs.generic_graph.GenericGraphmethod), 130
edge_disjoint_paths()(sage.graphs.generic_graph.GenericGraphmethod), 132
edge_disjoint_spanning_trees() (in module
sage.graphs.spanning_tree), 1590
edge_disjoint_spanning_trees()(sage.graphs.edge_connectivity.GabowEdgeConnectivity method), 1942
edge_disjoint_spanning_trees()(sage.graphs.generic_graph.GenericGraphmethod), 133
edge_isoperimetric_number()(sage.graphs.graph.Graph method), 532
edge_iterator() (sage.graphs.generic_graph.GenericGraph method), 137
edge_label()(sage.graphs.generic_graph.GenericGraph method), 138
edge_labels() (sage.graphs.generic_graph.GenericGraph method), 139
1973Graph Theory, Release 10.4

edge_multiplicities()(inmodulesage.graphs.tutte_polynomial), 1853
edge_polytope() (sage.graphs.generic_graph.GenericGraph method), 139edges()(sage.graphs.generic_graph.GenericGraphmethod), 142edges_incident() (sage.graphs.generic_graph.GenericGraph method), 146
EdgeSelection (class in sage.graphs.tutte_polynomial), 1852
EdgesView (class in sage.graphs.views), 762
effective_resistance()(sage.graphs.graph.Graph method), 533
effective_resistance_matrix()(sage.graphs.graph.Graph method), 535
EgawaGraph() (in module sage.graphs.generators.families), 1175
EgawaGraph() (sage.graphs.graph_generators.GraphGenerators static method), 841
eigenmatrix() (in module sage.graphs.strongly_regular_db), 1100
eigenspaces() (sage.graphs.generic_graph.GenericGraph method), 147
eigenvectors() (sage.graphs.generic_graph.GenericGraph method), 150
either_connected_or_not_connected() (inmodule sage.graphs.graph_decompositions.modular_decomposition), 1752
EllinghamHorton54Graph()(inmodulesage.graphs.generators.smallgraphs), 1305
EllinghamHorton54Graph()(sage.graphs.graph_generators.GraphGenerators static method), 842
EllinghamHorton78Graph()(inmodulesage.graphs.generators.smallgraphs), 1306
EllinghamHorton78Graph()(sage.graphs.graph_generators.GraphGenerators static method), 843
EmptyGraph() (in module sage.graphs.generators.basic), 1232
EmptyGraph() (sage.graphs.graph_generators.GraphGenerators static method), 844
equivalent_trees()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1753
ErreraGraph() (in module sage.graphs.generators.smallgraphs), 1307
ErreraGraph() (sage.graphs.graph_generators.GraphGenerators static method), 845
eulerian_circuit()(sage.graphs.generic_graph.GenericGraphmethod), 153
eulerian_orientation()(sage.graphs.generic_graph.GenericGraph
1974

method), 155
EuropeMap()(inmodulesage.graphs.generators.world_map), 1358
EuropeMap() (sage.graphs.graph_generators.GraphGenerators static method), 846
export_to_file() (sage.graphs.generic_graph.GenericGraph method), 156

F
F26AGraph() (in module sage.graphs.generators.smallgraphs), 1308
F26AGraph() (sage.graphs.graph_generators.GraphGenerators static method), 847
faces()(sage.graphs.generic_graph.GenericGraphmethod), 157
families (sage.graphs.graph_generators.GraphGenerators attribute), 1009
feedback_edge_set()(sage.graphs.digraph.DiGraph method), 686
feedback_vertex_set()(sage.graphs.generic_graph.GenericGraphmethod), 159
feng_k_shortest_simple_paths() (in module
sage.graphs.path_enumeration), 1874
FibonacciTree() (in module sage.graphs.generators.families), 1176
FibonacciTree()(sage.graphs.graph_generators.GraphGenerators static method), 847
filter_kruskal() (in module sage.graphs.spanning_tree), 1592
filter_kruskal_iterator()(inmodulesage.graphs.spanning_tree), 1593
find_ear() (sage.graphs.tutte_polynomial.Ear static
method), 1850
find_hamiltonian()(inmodulesage.graphs.generic_graph_pyx), 1887
find_pivot() (in module sage.graphs.cographs), 1573
first_coloring()(inmodulesage.graphs.graph_coloring), 1548
flatten() (sage.graphs.pq_trees.PQ method), 1608
flow()(sage.graphs.generic_graph.GenericGraphmethod), 161
flow_polytope()(sage.graphs.digraph.DiGraphmethod), 688
FlowerSnark() (in module sage.graphs.generators.smallgraphs), 1309
FlowerSnark() (sage.graphs.graph_generators.GraphGenerators static method), 848
floyd_warshall() (in module sage.graphs.distances_all_pairs), 1797
floyd_warshall_shortest_paths() (in module
sage.graphs.base.boost_graph), 1493
folded_graph() (sage.graphs.graph.Graph method),
537
Index

Graph Theory, Release 10.4

FoldedCubeGraph() (in module sage.graphs.generators.families), 1176
FoldedCubeGraph()(sage.graphs.graph_generators.GraphGenerators static method), 849
FolkmanGraph() (in module sage.graphs.generators.smallgraphs), 1310
FolkmanGraph()(sage.graphs.graph_generators.GraphGenerators static method), 849
forbidden_subgraphs() (sage.graphs.isgci.GraphClass method), 1368
FOREST (sage.graphs.graph_decompositions.modular_decomposition.NodeType attribute), 1749
ForkGraph() (in module sage.graphs.generators.basic),1233
ForkGraph() (sage.graphs.graph_generators.GraphGenerators static method), 850
form_module() (in module sage.graphs.graph_decompositions.modular_decomposition), 1754
format_coloring()(inmodulesage.graphs.graph_coloring), 1548
FosterGraph() (in module sage.graphs.generators.smallgraphs), 1311
FosterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 851
FosterGraph3S6() (in module sage.graphs.generators.distance_regular), 1129
FosterGraph3S6()(sage.graphs.graph_generators.GraphGenerators static method), 851
fractional_chromatic_index() (in module
sage.graphs.graph_coloring), 1549
fractional_chromatic_index()(sage.graphs.graph.Graph method), 538
fractional_chromatic_number() (in module
sage.graphs.graph_coloring), 1550
fractional_chromatic_number()(sage.graphs.graph.Graph method), 539
fractional_clique_number()(sage.graphs.graph.Graph method), 540
FranklinGraph() (in module sage.graphs.generators.smallgraphs), 1311
FranklinGraph()(sage.graphs.graph_generators.GraphGenerators static method), 852
FriendshipGraph() (in module sage.graphs.generators.families), 1177
FriendshipGraph()(sage.graphs.graph_generators.GraphGenerators static method), 853
from_adjacency_matrix()(inmodulesage.graphs.graph_input), 1833
from_dict_of_dicts()(inmodulesage.graphs.graph_input), 1833
from_dict_of_lists()(inmodulesage.graphs.graph_input), 1834
from_dig6() (in module sage.graphs.graph_input),
1835
Index

from_graph6() (in module sage.graphs.graph_input),1835
from_graph6() (in module sage.graphs.graph_list),1827
from_incidence_matrix()(inmodulesage.graphs.graph_input), 1835
from_networkx_graph()(inmodulesage.graphs.graph_input), 1836
from_oriented_incidence_matrix() (in module sage.graphs.graph_input), 1840
from_seidel_adjacency_matrix() (in module
sage.graphs.graph_input), 1841
from_sparse6() (in module sage.graphs.graph_input),1842
from_sparse6() (in module sage.graphs.graph_list),1827
from_whatever() (in module sage.graphs.graph_list),
1827
FruchtGraph() (in module sage.graphs.generators.smallgraphs), 1313
FruchtGraph() (sage.graphs.graph_generators.GraphGenerators static method), 855
fullerenes() (sage.graphs.graph_generators.GraphGenerators method), 1009
FurerGadget() (in module sage.graphs.generators.families), 1179
FurerGadget() (sage.graphs.graph_generators.GraphGenerators static method), 856
fusenes() (sage.graphs.graph_generators.GraphGenerators method), 1011
FuzzyBallGraph() (in module sage.graphs.generators.families), 1181
FuzzyBallGraph()(sage.graphs.graph_generators.GraphGenerators static method), 857

G
G (sage.graphs.edge_connectivity.GabowEdgeConnectivity
attribute), 1941
GabowEdgeConnectivity(classin
sage.graphs.edge_connectivity), 1940
gamma_classes() (in module sage.graphs.graph_decompositions.modular_decomposition), 1754
GemGraph() (in module sage.graphs.generators.basic),1233
GemGraph() (sage.graphs.graph_generators.GraphGenerators static method), 858
gen_html_code()(inmodulesage.graphs.graph_plot_js), 1689
GeneralisedDodecagonGraph() (in module
sage.graphs.generators.distance_regular), 1129
GeneralisedDodecagonGraph()(sage.graphs.graph_generators.GraphGenerators static method), 859

1975

Graph Theory, Release 10.4

GeneralisedHexagonGraph()(inmodulemethod), 1080
sage.graphs.generators.distance_regular), 1130
get_length()(sage.graphs.graph_decomposiGeneralisedHexagonGraph()tions.tree_decomposition.TreelengthConnected(sage.graphs.graph_generators.GraphGenermethod), 1694
ators static method), 859
get_module_type()(inmoduleGeneralisedOctagonGraph()(inmodulesage.graphs.graph_decompositions.modusage.graphs.generators.distance_regular), 1131
lar_decomposition), 1755
GeneralisedOctagonGraph()
get_option() (sage.graphs.graph_latex.GraphLatex(sage.graphs.graph_generators.GraphGenermethod), 1815
ators static method), 860
get_pos() (sage.graphs.generic_graph.GenericGraph
GeneralizedDeBruijn()(sage.graphs.dimethod), 168
graph_generators.DiGraphGenerators method), get_spqr_tree() (sage.graphs.connectivity.Tricon1050
nectivitySPQR method), 1902
GeneralizedPetersenGraph()(inmodule get_tree_decomposition()sage.graphs.generators.families), 1182
(sage.graphs.graph_decompositions.tree_deGeneralizedPetersenGraph()
composition.TreelengthConnected
method),(sage.graphs.graph_generators.GraphGener1695
ators static method), 861
get_triconnected_components()
GeneralizedSierpinskiGraph() (in module(sage.graphs.connectivity.TriconnectivitySPQR
sage.graphs.generators.families), 1183
method), 1905
GeneralizedSierpinskiGraph()
get_vertex()(sage.graphs.generic_graph.Generic(sage.graphs.graph_generators.GraphGenerGraph method), 169
ators static method), 862
get_vertices() (in module sage.graphs.graph_deGenericGraph (class in sage.graphs.generic_graph), 8
compositions.modular_decomposition), 1755
GenericGraph_pyx(classin get_vertices() (sage.graphs.generic_graph.Genericsage.graphs.generic_graph_pyx), 1883
Graph method), 170
GenericGraphBackend(classin girth()(sage.graphs.generic_graph.GenericGraphsage.graphs.base.graph_backends), 1480
method), 170
GenericGraphQuery(classin GoethalsSeidelGraph()(inmodulesage.graphs.graph_database), 1065
sage.graphs.generators.families), 1185
genus()(sage.graphs.generic_graph.GenericGraph GoethalsSeidelGraph() (sage.graphs.graph_genmethod), 163
erators.GraphGenerators static method), 864
genus()(sage.graphs.genus.simple_con- GoldnerHararyGraph() (in module sage.graphs.gennected_genus_backtracker method), 1621
erators.smallgraphs), 1313
geodetic_closure() (in module sage.graphs.convex- GoldnerHararyGraph() (sage.graphs.graph_generaity_properties), 1782
tors.GraphGenerators static method), 866
geodetic_closure()(sage.graphs.graph.Graph GolombGraph() (in module sage.graphs.generamethod), 541
tors.smallgraphs), 1314
get_class() (sage.graphs.isgci.GraphClasses method), GolombGraph() (sage.graphs.graph_generators.Graph1369
Generators static method), 867
get_edge_label() (sage.graphs.base.dense_graph.DenseGgomory_hu_tree()(sage.graphs.graph.Graph
raphBackend method), 1450
method), 542
get_edge_label() (sage.graphs.base.graph_back- GossetGraph() (in module sage.graphs.generaends.GenericGraphBackend method), 1482
tors.smallgraphs), 1315
get_edge_label() (sage.graphs.base.sparse_graph.SparseGGossetGraph() (sage.graphs.graph_generators.GraphraphBackend method), 1441
Generators static method), 868
get_edge_label() (sage.graphs.base.static_sparse_back-Graph (class in sage.graphs.graph), 454
end.StaticSparseBackend method), 1475
graph6_string() (sage.graphs.graph.Graph method),
get_embedding() (sage.graphs.generic_graph.Gener544
icGraph method), 166
graph6_to_plot()(inmoduleget_embedding()(sage.graphs.genus.simple_consage.graphs.graph_database), 1086
nected_genus_backtracker method), 1622
graph_3O73() (in module sage.graphs.generators.disget_graphs_list()tance_regular), 1137
(sage.graphs.graph_database.GraphQuerygraph_3O73() (sage.graphs.graph_generators.Graph1976

Index

Graph Theory, Release 10.4

Generators static method), 1012
graph_db_info()(inmodulesage.graphs.graph_database), 1086
graph_editor() (in module sage.graphs.graph_editor), 1825
graph_from_GQ_spread()(inmodulesage.graphs.generators.distance_regular), 1138
graph_isom_equivalent_non_edge_labeled_graph()(inmodulesage.graphs.generic_graph), 433
graph_with_classical_parameters()(inmodulesage.graphs.generators.distance_regular), 1138
GraphClass (class in sage.graphs.isgci), 1367
GraphClasses (class in sage.graphs.isgci), 1368
GraphDatabase (class in sage.graphs.graph_database),
1066
GraphGenerators (class in sage.graphs.graph_generators), 777
graphics_array_defaults(sage.graphs.generic_graph.GenericGraphattribute), 171
GraphLatex (class in sage.graphs.graph_latex), 1812
GraphPlot (class in sage.graphs.graph_plot), 1653
graphplot()(sage.graphs.generic_graph.GenericGraph method), 171
GraphQuery (class in sage.graphs.graph_database),
1078
graphviz_string()(sage.graphs.generic_graph.GenericGraphmethod), 172
graphviz_to_file_named()(sage.graphs.generic_graph.GenericGraphmethod), 183
GrassmannGraph() (in module sage.graphs.generators.distance_regular), 1131
GrassmannGraph()(sage.graphs.graph_generators.GraphGenerators static method), 868
GrayGraph() (in module sage.graphs.generators.smallgraphs), 1315
GrayGraph() (sage.graphs.graph_generators.GraphGenerators static method), 868
greedy_dominating_set()(inmodulesage.graphs.domination), 1950
greedy_dominating_set()(sage.graphs.generic_graph.GenericGraphmethod), 184
greedy_is_comparability()(inmodulesage.graphs.comparability), 1577
greedy_is_comparability_with_certificate() (in module sage.graphs.comparability),
1578
Grid2dGraph() (in module sage.graphs.generators.basic), 1233
Index

Grid2dGraph() (sage.graphs.graph_generators.GraphGenerators static method), 869
GridGraph() (in module sage.graphs.generators.basic),1234
GridGraph() (sage.graphs.graph_generators.GraphGenerators static method), 870
GritsenkoGraph() (in module sage.graphs.generators.smallgraphs), 1316
GritsenkoGraph()(sage.graphs.graph_generators.GraphGenerators static method), 870
GrotzschGraph() (in module sage.graphs.generators.smallgraphs), 1316
GrotzschGraph()(sage.graphs.graph_generators.GraphGenerators static method), 871
ground_set() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1519
growing_subtrees() (in module sage.graphs.generators.random), 1287
grundy_coloring()(inmodulesage.graphs.graph_coloring), 1552

Hhabib_maurer_algorithm()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1756
HaemersGraph() (in module sage.graphs.generators.classical_geometries), 1149
HaemersGraph()(sage.graphs.graph_generators.GraphGenerators static method), 872
HalfCube() (in module sage.graphs.generators.distance_regular), 1132
HalfCube() (sage.graphs.graph_generators.GraphGenerators static method), 873
HallJankoGraph() (in module sage.graphs.generators.smallgraphs), 1318
HallJankoGraph()(sage.graphs.graph_generators.GraphGenerators static method), 874
hamiltonian_cycle()(sage.graphs.generic_graph.GenericGraphmethod), 187
hamiltonian_path()(sage.graphs.generic_graph.GenericGraphmethod), 189
HammingGraph() (in module sage.graphs.generators.families), 1187
HammingGraph()(sage.graphs.graph_generators.GraphGenerators static method), 875
HanoiTowerGraph() (in module sage.graphs.generators.families), 1188
HanoiTowerGraph()(sage.graphs.graph_generators.GraphGenerators static method), 876
HararyGraph() (in module sage.graphs.generators.families), 1190

1977

Graph Theory, Release 10.4

HararyGraph() (sage.graphs.graph_generators.GraphGenerators static method), 879
HarborthGraph() (in module sage.graphs.generators.smallgraphs), 1319
HarborthGraph()(sage.graphs.graph_generators.GraphGenerators static method), 879
HarriesGraph() (in module sage.graphs.generators.smallgraphs), 1319
HarriesGraph()(sage.graphs.graph_generators.GraphGenerators static method), 879
HarriesWongGraph() (in module sage.graphs.generators.smallgraphs), 1320
HarriesWongGraph() (sage.graphs.graph_generators.GraphGenerators static method), 880
has_arc() (sage.graphs.base.c_graph.CGraph method),1389
has_arc()(sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 1478
has_arc_label() (sage.graphs.base.c_graph.CGraphmethod), 1390
has_edge() (sage.graphs.base.dense_graph.DenseGraphBackend method), 1451
has_edge() (sage.graphs.base.graph_backends.GenericGraphBackend method), 1482
has_edge() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 1441
has_edge()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1475
has_edge() (sage.graphs.generic_graph.GenericGraphmethod), 190
has_homomorphism_to() (sage.graphs.graph.Graphmethod), 544
has_left_split()(sage.graphs.graph_decompositions.modular_decomposition.Node method),1747
has_loops()(sage.graphs.generic_graph.GenericGraph method), 191
has_multiple_edges()(sage.graphs.generic_graph.GenericGraphmethod), 192
has_perfect_matching()(sage.graphs.graph.Graph method), 546
has_right_split() (sage.graphs.graph_decompositions.modular_decomposition.Node method),1747
has_vertex()(sage.graphs.base.c_graph.CGraphmethod), 1391
has_vertex()(sage.graphs.base.c_graph.CGraphBackend method), 1412
has_vertex()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1482
has_vertex() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1475
has_vertex() (sage.graphs.base.static_sparse_back1978

end.StaticSparseCGraph method), 1478
has_vertex()(sage.graphs.generic_graph.GenericGraph method), 194
have_tkz_graph() (in module sage.graphs.graph_latex), 1825
HeawoodGraph() (in module sage.graphs.generators.smallgraphs), 1321
HeawoodGraph()(sage.graphs.graph_generators.GraphGenerators static method), 882
HermitianFormsGraph()(inmodulesage.graphs.generators.distance_regular), 1133
HermitianFormsGraph() (sage.graphs.graph_generators.GraphGenerators static method), 882
HerschelGraph() (in module sage.graphs.generators.smallgraphs), 1322
HerschelGraph()(sage.graphs.graph_generators.GraphGenerators static method), 883
HexahedralGraph() (in module sage.graphs.generators.platonic_solids), 1259
HexahedralGraph()(sage.graphs.graph_generators.GraphGenerators static method), 884
HigmanSimsGraph() (in module sage.graphs.generators.smallgraphs), 1323
HigmanSimsGraph()(sage.graphs.graph_generators.GraphGenerators static method), 885
HoffmanGraph() (in module sage.graphs.generators.smallgraphs), 1325
HoffmanGraph()(sage.graphs.graph_generators.GraphGenerators static method), 887
HoffmanSingletonGraph()(inmodulesage.graphs.generators.smallgraphs), 1325
HoffmanSingletonGraph()(sage.graphs.graph_generators.GraphGenerators static method), 887
HoltGraph() (in module sage.graphs.generators.smallgraphs), 1326
HoltGraph() (sage.graphs.graph_generators.GraphGenerators static method), 888
HortonGraph() (in module sage.graphs.generators.smallgraphs), 1327
HortonGraph() (sage.graphs.graph_generators.GraphGenerators static method), 889
HouseGraph() (in module sage.graphs.generators.basic), 1234
HouseGraph() (sage.graphs.graph_generators.GraphGenerators static method), 890
HouseXGraph() (in module sage.graphs.generators.basic), 1235
HouseXGraph() (sage.graphs.graph_generators.GraphGenerators static method), 890
hull() (sage.graphs.convexity_properties.ConvexityProperties method), 1780
hull_number()(sage.graphs.convexity_properties.ConvexityProperties method), 1780
Index

Graph Theory, Release 10.4

hyperbolicity() (in module sage.graphs.hyperbolicity), 1844
hyperbolicity() (sage.graphs.graph.Graph method),547
hyperbolicity_distribution() (in module
sage.graphs.hyperbolicity), 1848
HypergraphGenerators (class in sage.graphs.hypergraph_generators), 1505
HyperStarGraph() (in module sage.graphs.generators.families), 1191
HyperStarGraph()(sage.graphs.graph_generators.GraphGenerators static method), 891

I
IcosahedralGraph() (in module sage.graphs.generators.platonic_solids), 1260
IcosahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 892
IGraph() (in module sage.graphs.generators.families),
1191
IGraph() (sage.graphs.graph_generators.GraphGenerators static method), 891
igraph_graph() (sage.graphs.generic_graph.GenericGraph method), 195
ihara_zeta_function_inverse()(sage.graphs.graph.Graph method), 552
ImaseItoh()(sage.graphs.digraph_generators.DiGraphGenerators method), 1051
in_branchings()(sage.graphs.digraph.DiGraphmethod), 692
in_degree() (sage.graphs.base.c_graph.CGraphBackend method), 1412
in_degree()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1482
in_degree() (sage.graphs.base.sparse_graph.SparseGraph method), 1437
in_degree()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1476
in_degree()(sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 1479
in_degree() (sage.graphs.digraph.DiGraph method),695
in_degree_iterator() (sage.graphs.digraph.DiGraph method), 695
in_degree_sequence() (sage.graphs.digraph.DiGraph method), 696
in_neighbors() (sage.graphs.base.c_graph.CGraphmethod), 1392
in_neighbors() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 1479
incidence_graph()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),
1520

Index

incidence_matrix() (sage.combinat.designs.incidence_structures.IncidenceStructure
method),1521
incidence_matrix()(sage.graphs.generic_graph.GenericGraphmethod), 198
IncidenceStructure (class in sage.combinat.designs.incidence_structures), 1510
inclusion_digraph()(sage.graphs.isgci.GraphClasses method), 1370
inclusions()(sage.graphs.isgci.GraphClasses
method), 1370
incoming_edge_iterator()(sage.graphs.digraph.DiGraph method), 696
incoming_edges()(sage.graphs.digraph.DiGraphmethod), 697
independent_set()(sage.graphs.graph.Graphmethod), 553
independent_set_of_representatives()(sage.graphs.graph.Graph method), 554
IndependentSets (class in sage.graphs.independent_sets), 1567
induced_substructure()(sage.combinat.designs.incidence_structures.IncidenceStructure
method), 1521
int_to_binary_string()(inmodulesage.graphs.generic_graph_pyx), 1890
interactive_query()(sage.graphs.graph_database.GraphDatabasemethod), 1073
intersection (sage.graphs.graph_generators.GraphGenerators attribute), 1012
intersection_graph() (sage.combinat.designs.incidence_structures.IncidenceStructure method),
1522
IntersectionGraph() (in module sage.graphs.generators.intersection), 1249
IntersectionGraph() (sage.graphs.graph_generators.GraphGenerators static method), 893
IntervalGraph() (in module sage.graphs.generators.intersection), 1249
IntervalGraph()(sage.graphs.graph_generators.GraphGenerators static method), 894
IoninKharaghani765Graph()(inmodulesage.graphs.generators.smallgraphs), 1328
IoninKharaghani765Graph()(sage.graphs.graph_generators.GraphGenerators static method), 895
is_affine_polar()(inmodulesage.graphs.strongly_regular_db), 1107
is_antipodal() (sage.graphs.graph.Graph method),556
is_aperiodic()(sage.graphs.digraph.DiGraphmethod), 697
1979Graph Theory, Release 10.4

is_apex() (sage.graphs.graph.Graph method), 556
is_arc_transitive() (sage.graphs.graph.Graphmethod), 557
is_asteroidal_triple_free() (in module
sage.graphs.asteroidal_triples), 1565
is_asteroidal_triple_free()(sage.graphs.graph.Graph method), 558
is_berge_cyclic()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1522
is_biconnected()(sage.graphs.graph.Graphmethod), 559
is_bipartite() (sage.graphs.bipartite_graph.BipartiteGraph method), 750
is_bipartite() (sage.graphs.generic_graph.GenericGraph method), 204
is_block_graph()(sage.graphs.graph.Graphmethod), 560
is_cactus() (sage.graphs.graph.Graph method), 561
is_cartesian_product()(inmodulesage.graphs.graph_decompositions.graph_products), 1743
is_cartesian_product()(sage.graphs.graph.Graph method), 561
is_cayley()(sage.graphs.generic_graph.GenericGraph method), 205
is_chordal()(sage.graphs.generic_graph.GenericGraph method), 207
is_circulant() (sage.graphs.generic_graph.GenericGraph method), 210
is_circular_planar()(sage.graphs.generic_graph.GenericGraphmethod), 211
is_circumscribable() (sage.graphs.graph.Graphmethod), 563
is_classical_parameters_graph() (in module
sage.graphs.generators.distance_regular), 1140
is_clique()(sage.graphs.generic_graph.GenericGraph method), 213
is_cograph() (sage.graphs.graph.Graph method), 564
is_comparability() (in module sage.graphs.comparability), 1579
is_comparability()(sage.graphs.graph.Graphmethod), 565
is_comparability_MILP()(inmodulesage.graphs.comparability), 1579
is_complete_multipartite()(inmodulesage.graphs.strongly_regular_db), 1107
is_connected() (in module sage.graphs.connectivity),1921
is_connected()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1523
is_connected() (sage.graphs.base.c_graph.CGraph1980

Backend method), 1412
is_connected() (sage.graphs.generic_graph.GenericGraph method), 214
is_cossidente_penttila()(inmodulesage.graphs.strongly_regular_db), 1108
is_cut_edge() (in module sage.graphs.connectivity),1922
is_cut_edge() (sage.graphs.generic_graph.GenericGraph method), 215
is_cut_vertex() (in module sage.graphs.connectivity), 1923
is_cut_vertex() (sage.graphs.generic_graph.GenericGraph method), 217
is_cycle() (sage.graphs.generic_graph.GenericGraphmethod), 218
is_directed() (sage.graphs.base.sparse_graph.SparseGraph method), 1438
is_directed()(sage.graphs.digraph.DiGraphmethod), 698
is_directed() (sage.graphs.graph.Graph method),566
is_directed_acyclic()(sage.graphs.base.c_graph.CGraphBackend
method), 1413
is_directed_acyclic() (sage.graphs.digraph.DiGraph method), 698
is_distance_regular()(inmodulesage.graphs.distances_all_pairs), 1799
is_distance_regular() (sage.graphs.graph.Graphmethod), 566
is_dominating() (in module sage.graphs.domination), 1953
is_dominating() (sage.graphs.graph.Graph method),567
is_drawn_free_of_edge_crossings()(sage.graphs.generic_graph.GenericGraphmethod), 220
is_edge_transitive() (sage.graphs.graph.Graphmethod), 567
is_equitable() (sage.graphs.generic_graph.GenericGraph method), 220
is_eulerian() (sage.graphs.generic_graph.GenericGraph method), 221
is_even_hole_free() (sage.graphs.graph.Graphmethod), 568
is_factor_critical() (sage.graphs.graph.Graphmethod), 570
is_forest() (sage.graphs.graph.Graph method), 572
is_from_GQ_spread() (in module sage.graphs.generators.distance_regular), 1140
is_gallai_tree() (sage.graphs.generic_graph.GenericGraph method), 223
is_generalized_quadrangle()(sage.combinat.designs.incidence_structures.IncidenceStrucIndex

Graph Theory, Release 10.4

ture method), 1523
is_geodetic() (in module sage.graphs.convexity_properties), 1783
is_geodetic() (sage.graphs.generic_graph.GenericGraph method), 224
is_goethals_seidel()(inmodulesage.graphs.strongly_regular_db), 1109
is_GQqmqp() (in module sage.graphs.strongly_regular_db), 1102
is_haemers() (in module sage.graphs.strongly_regular_db), 1110
is_half_transitive() (sage.graphs.graph.Graphmethod), 573
is_hamiltonian() (sage.graphs.generic_graph.GenericGraph method), 225
is_immutable() (sage.graphs.generic_graph.GenericGraph method), 226
is_independent_set()(sage.graphs.generic_graph.GenericGraphmethod), 227
is_inscribable()(sage.graphs.graph.Graphmethod), 574
is_interval() (sage.graphs.generic_graph.GenericGraph method), 227
is_isomorphic()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1524
is_isomorphic() (sage.graphs.generic_graph.GenericGraph method), 228
is_johnson() (in module sage.graphs.strongly_regular_db), 1110
is_less_than_k() (sage.graphs.graph_decompositions.tree_decomposition.TreelengthConnected
method), 1695
is_line_graph() (in module sage.graphs.line_graph),1584
is_line_graph() (sage.graphs.graph.Graph method),575
is_long_antihole_free()(inmodulesage.graphs.weakly_chordal), 1785
is_long_antihole_free()(sage.graphs.graph.Graph method), 577
is_long_hole_free()(inmodulesage.graphs.weakly_chordal), 1786
is_long_hole_free() (sage.graphs.graph.Graphmethod), 578
is_mathon_PC_srg()(inmodulesage.graphs.strongly_regular_db), 1111
is_muzychuk_S6()(inmodulesage.graphs.strongly_regular_db), 1112
is_near_polygon() (in module sage.graphs.generators.distance_regular), 1141
is_NO_F2() (in module sage.graphs.strongly_regular_db), 1103
Index

is_NO_F3() (in module sage.graphs.strongly_regular_db), 1103
is_NOodd() (in module sage.graphs.strongly_regular_db), 1104
is_NOperp_F5() (in module sage.graphs.strongly_regular_db), 1105
is_nowhere0_twoweight()(inmodulesage.graphs.strongly_regular_db), 1112
is_NU() (in module sage.graphs.strongly_regular_db),1105
is_odd_hole_free()(sage.graphs.graph.Graphmethod), 579
is_orthogonal_array_block_graph()(inmodule sage.graphs.strongly_regular_db), 1113
is_orthogonal_polar()(inmodulesage.graphs.strongly_regular_db), 1114
is_overfull() (sage.graphs.graph.Graph method),580
is_paley() (in module sage.graphs.strongly_regular_db), 1115
is_partial_cube() (in module sage.graphs.partial_cube), 1859
is_partial_cube()(sage.graphs.graph.Graphmethod), 583
is_path() (sage.graphs.graph.Graph method), 583
is_perfect() (sage.graphs.graph.Graph method), 584
is_permutation() (in module sage.graphs.comparability), 1580
is_permutation()(sage.graphs.graph.Graphmethod), 586
is_planar() (in module sage.graphs.planarity), 1630
is_planar()(sage.graphs.generic_graph.GenericGraph method), 231
is_polhill() (in module sage.graphs.strongly_regular_db), 1115
is_polyhedral() (sage.graphs.graph.Graph method),587
is_prime() (sage.graphs.graph.Graph method), 587
is_pseudo_partition_graph() (in module
sage.graphs.generators.distance_regular), 1142
is_redundant() (in module sage.graphs.domination),1953
is_redundant() (sage.graphs.graph.Graph method),588
is_regular() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1525
is_regular()(sage.graphs.generic_graph.GenericGraph method), 236
is_resolvable()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1525
is_RSHCD() (in module sage.graphs.strongly_regular_db), 1106
is_self_complementary()
1981

Graph Theory, Release 10.4

(sage.graphs.generic_graph.GenericGraphmethod), 237
is_semi_symmetric() (sage.graphs.graph.Graphmethod), 589
is_simple() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1527
is_split() (sage.graphs.graph.Graph method), 590
is_spread() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1528
is_steiner() (in module sage.graphs.strongly_regular_db), 1116
is_strongly_connected()(inmodulesage.graphs.connectivity), 1924
is_strongly_connected()(sage.graphs.base.c_graph.CGraphBackend
method), 1415
is_strongly_connected()(sage.graphs.digraph.DiGraph method), 700
is_strongly_regular()(inmodulesage.graphs.base.static_dense_graph), 1458
is_strongly_regular() (sage.graphs.graph.Graphmethod), 591
is_subgraph() (sage.graphs.base.c_graph.CGraphBackend method), 1416
is_subgraph() (sage.graphs.generic_graph.GenericGraph method), 238
is_switch_OA_srg()(inmodulesage.graphs.strongly_regular_db), 1117
is_switch_skewhad()(inmodulesage.graphs.strongly_regular_db), 1117
is_t_design()(sage.combinat.designs.incidence_structures.IncidenceStructure
method),1529
is_taylor_twograph_srg()(inmodulesage.graphs.strongly_regular_db), 1118
is_tournament()(sage.graphs.digraph.DiGraphmethod), 700
is_transitive() (in module sage.graphs.comparability), 1582
is_transitive()(sage.graphs.digraph.DiGraphmethod), 701
is_transitively_reduced()(sage.graphs.generic_graph.GenericGraphmethod), 240
is_tree() (sage.graphs.graph.Graph method), 593
is_triangle_free()(inmodulesage.graphs.base.static_dense_graph), 1461
is_triangle_free()(sage.graphs.graph.Graphmethod), 594
is_triconnected() (in module sage.graphs.connectivity), 1925
is_triconnected()(sage.graphs.graph.Graphmethod), 596
is_twograph_descendant_of_srg() (in module
1982

sage.graphs.strongly_regular_db), 1118
is_uniform() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1532
is_unitary_dual_polar()(inmodulesage.graphs.strongly_regular_db), 1119
is_unitary_polar()(inmodulesage.graphs.strongly_regular_db), 1120
is_valid_lex_M_order()(inmodulesage.graphs.traversals), 1631
is_valid_ordering()(inmodulesage.graphs.graph_decompositions.vertex_separation), 1713
is_valid_tree_decomposition() (in module
sage.graphs.graph_decompositions.tree_decomposition), 1696
is_vertex_transitive()(sage.graphs.generic_graph.GenericGraphmethod), 240
is_weakly_chordal()(inmodulesage.graphs.weakly_chordal), 1787
is_weakly_chordal() (sage.graphs.graph.Graphmethod), 597
isomorphic_substructures_iterator()(sage.combinat.designs.incidence_structures.IncidenceStructure method), 1533
iterator_edges() (sage.graphs.base.c_graph.CGraphBackend method), 1417
iterator_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 1482
iterator_edges() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1476
iterator_in_edges()(sage.graphs.base.c_graph.CGraphBackend
method), 1418
iterator_in_edges()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1483
iterator_in_edges()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1476
iterator_in_nbrs()(sage.graphs.base.c_graph.CGraphBackend
method), 1418
iterator_in_nbrs() (sage.graphs.base.graph_backends.GenericGraphBackend method), 1483
iterator_in_nbrs()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1476
iterator_nbrs() (sage.graphs.base.c_graph.CGraphBackend method), 1419
iterator_nbrs()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1483
iterator_nbrs() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1476
Index

Graph Theory, Release 10.4

iterator_out_edges()
JohnsonGraph() (in module sage.graphs.genera(sage.graphs.base.c_graph.CGraphBackend
tors.families), 1192
method), 1419
JohnsonGraph()(sage.graphs.graph_generaiterator_out_edges()
tors.GraphGenerators static method), 898(sage.graphs.base.graph_backends.Genericjoin() (sage.graphs.graph.Graph method), 598
GraphBackend method), 1483
K
iterator_out_edges()(sage.graphs.base.static_sparse_backend.Statickatz_centrality()
SparseBackend method), 1477
(sage.graphs.generic_graph.GenericGraph
iterator_out_nbrs()
method), 241(sage.graphs.base.c_graph.CGraphBackend
katz_matrix() (sage.graphs.generic_graph.Genericmethod), 1420
Graph method), 243
iterator_out_nbrs()
Kautz() (sage.graphs.digraph_generators.DiGraphGen(sage.graphs.base.graph_backends.Genericerators method), 1052
GraphBackend method), 1484
KingGraph() (in module sage.graphs.generators.chessiterator_out_nbrs()board), 1244
(sage.graphs.base.static_sparse_backend.StaticKingGraph() (sage.graphs.graph_generators.GraphSparseBackend method), 1477
Generators static method), 899
iterator_unsorted_edges()
kirchhoff_matrix()(sage.graphs.base.c_graph.CGraphBackend(sage.graphs.generic_graph.GenericGraphmethod), 1420
method), 244
iterator_unsorted_edges()
kirchhoff_symanzik_polynomial()(sage.graphs.base.static_sparse_backend.Static(sage.graphs.graph.Graph method), 599
SparseBackend method), 1477
KittellGraph() (in module sage.graphs.generaiterator_verts() (sage.graphs.base.c_graph.CGraphtors.smallgraphs), 1330
Backend method), 1421
KittellGraph()(sage.graphs.graph_generaiterator_verts() (sage.graphs.base.graph_backtors.GraphGenerators static method), 900
ends.GenericGraphBackend method), 1484
Klein3RegularGraph() (in module sage.graphs.geniterator_verts() (sage.graphs.base.static_sparse_backerators.smallgraphs), 1331
end.StaticSparseBackend method), 1477
Klein3RegularGraph() (sage.graphs.graph_generaIvanovIvanovFaradjevGraph() (in module
tors.GraphGenerators static method), 901
sage.graphs.generators.distance_regular), 1133
Klein7RegularGraph() (in module sage.graphs.genIvanovIvanovFaradjevGraph()erators.smallgraphs), 1331
(sage.graphs.graph_generators.GraphGenerKlein7RegularGraph() (sage.graphs.graph_generaators static method), 896
tors.GraphGenerators static method), 901
KneserGraph() (in module sage.graphs.generaJ
tors.families), 1193
J2Graph() (in module sage.graphs.generators.dis- KneserGraph() (sage.graphs.graph_generators.Graphtance_regular), 1134
Generators static method), 902
J2Graph() (sage.graphs.graph_generators.GraphGener- KnightGraph() (in module sage.graphs.generaators static method), 897
tors.chessboard), 1245
JankoKharaghaniGraph()(inmodule KnightGraph() (sage.graphs.graph_generators.Graphsage.graphs.generators.smallgraphs), 1329
Generators static method), 902
JankoKharaghaniGraph() (sage.graphs.graph_gen- KrackhardtKiteGraph()(inmoduleerators.GraphGenerators static method), 897
sage.graphs.generators.smallgraphs), 1332
JankoKharaghaniTonchevGraph() (in module KrackhardtKiteGraph() (sage.graphs.graph_gensage.graphs.generators.smallgraphs), 1330
erators.GraphGenerators static method), 903
JankoKharaghaniTonchevGraph()kronecker_product()(sage.graphs.graph_generators.GraphGener(sage.graphs.generic_graph.GenericGraphators static method), 898
method), 249
johnson_closeness_centrality() (in module kruskal() (in module sage.graphs.spanning_tree), 1595
sage.graphs.base.boost_graph), 1495
kruskal_iterator() (in module sage.graphs.spanjohnson_shortest_paths()(inmodulening_tree), 1599
sage.graphs.base.boost_graph), 1496
Index

1983

Graph Theory, Release 10.4

kruskal_iterator_from_edges() (in module
sage.graphs.spanning_tree), 1600

Llabel_nice_tree_decomposition() (in module
sage.graphs.graph_decompositions.tree_decomposition), 1697
LadderGraph() (in module sage.graphs.generators.basic), 1235
LadderGraph() (sage.graphs.graph_generators.GraphGenerators static method), 905
laplacian_matrix()(sage.graphs.generic_graph.GenericGraphmethod), 250
LargeWittGraph() (in module sage.graphs.generators.distance_regular), 1134
LargeWittGraph()(sage.graphs.graph_generators.GraphGenerators static method), 906
latex() (sage.graphs.graph_latex.GraphLatex method),1815
latex_options() (sage.graphs.generic_graph.GenericGraph method), 255
latin_squares_graph_parameters() (in module sage.graphs.strongly_regular_db), 1120
layout()(sage.graphs.generic_graph.GenericGraphmethod), 255
layout_acyclic()(sage.graphs.digraph.DiGraphmethod), 702
layout_acyclic_dummy()(sage.graphs.digraph.DiGraph method), 703
layout_circular()(sage.graphs.generic_graph.GenericGraphmethod), 258
layout_default() (sage.graphs.generic_graph.GenericGraph method), 259
layout_extend_randomly()(sage.graphs.generic_graph.GenericGraphmethod), 260
layout_forest() (sage.graphs.generic_graph.GenericGraph method), 261
layout_graphviz()(sage.graphs.generic_graph.GenericGraphmethod), 261
layout_planar() (sage.graphs.generic_graph.GenericGraph method), 263
layout_ranked() (sage.graphs.generic_graph.GenericGraph method), 266
layout_split()(inmodulesage.graphs.generic_graph_pyx), 1890
layout_spring() (sage.graphs.generic_graph.GenericGraph method), 266
layout_tree() (sage.graphs.generic_graph.GenericGraph method), 267

1984layout_tree()(sage.graphs.graph_plot.GraphPlot
method), 1654
LCFGraph() (in module sage.graphs.generators.families), 1193
LCFGraph() (sage.graphs.graph_generators.GraphGenerators static method), 904
least_effective_resistance()(sage.graphs.graph.Graph method), 601
LEFT_OF_SOURCE(sage.graphs.graph_decompositions.modular_decomposition.VertexPosition
attribute), 1750
LEFT_SPLIT (sage.graphs.graph_decompositions.modular_decomposition.NodeSplit attribute), 1749
length_and_string_from_graph6() (in module
sage.graphs.generic_graph_pyx), 1891
length_of_tree_decomposition() (in module
sage.graphs.graph_decompositions.tree_decomposition), 1698
LeonardGraph() (in module sage.graphs.generators.distance_regular), 1134
LeonardGraph()(sage.graphs.graph_generators.GraphGenerators static method), 907
level_sets() (sage.graphs.digraph.DiGraph method),704
lex_BFS() (in module sage.graphs.traversals), 1631
lex_BFS() (sage.graphs.generic_graph.GenericGraphmethod), 269
lex_DFS() (in module sage.graphs.traversals), 1634
lex_DFS() (sage.graphs.generic_graph.GenericGraphmethod), 272
lex_DOWN() (in module sage.graphs.traversals), 1636
lex_DOWN() (sage.graphs.generic_graph.GenericGraphmethod), 274
lex_M() (in module sage.graphs.traversals), 1638
lex_M() (sage.graphs.graph.Graph method), 602
lex_M_fast() (in module sage.graphs.traversals), 1640
lex_M_slow() (in module sage.graphs.traversals), 1641
lex_UP() (in module sage.graphs.traversals), 1642
lex_UP()(sage.graphs.generic_graph.GenericGraphmethod), 276
lexicographic_product()(sage.graphs.generic_graph.GenericGraphmethod), 277
line_graph() (in module sage.graphs.line_graph),1586
line_graph()(sage.graphs.generic_graph.GenericGraph method), 278
line_graph_forbidden_subgraphs() (in module sage.graphs.generators.families), 1214
line_graph_forbidden_subgraphs()(sage.graphs.graph_generators.GraphGenerators static method), 1012
linear_arboricity()(inmodulesage.graphs.graph_coloring), 1553
Index

Graph Theory, Release 10.4

magnitude_function() (sage.graphs.graph.Graphmethod), 605
make_labelled_rooted_tree() (in module
sage.graphs.graph_decompositions.clique_separators), 1777
make_nice_tree_decomposition() (in module
sage.graphs.graph_decompositions.tree_decomposition), 1700
make_tree() (in module sage.graphs.graph_decompositions.clique_separators), 1778
MarkstroemGraph() (in module sage.graphs.generators.smallgraphs), 1335
MarkstroemGraph()(sage.graphs.graph_generators.GraphGenerators static method), 910
matching()(sage.graphs.bipartite_graph.BipartiteGraph method), 752
matching() (sage.graphs.graph.Graph method), 606
matching_polynomial()(inmodulesage.graphs.matchpoly), 1616
matching_polynomial()(sage.graphs.bipartite_graph.BipartiteGraph method), 753
matching_polynomial() (sage.graphs.graph.Graphmethod), 608
MathonPseudocyclicMergingGraph() (in module sage.graphs.generators.families), 1195
MathonPseudocyclicMergingGraph()(sage.graphs.graph_generators.GraphGenerators static method), 911
MathonPseudocyclicStronglyRegularGraph() (in module sage.graphs.generators.families), 1196
MathonPseudocyclicStronglyRegularGraph()(sage.graphs.graph_generators.GraphGenerators static method), 911
MathonStronglyRegularGraph() (in module
sage.graphs.generators.smallgraphs), 1336
MathonStronglyRegularGraph()(sage.graphs.graph_generators.GraphGenerators static method), 913
max_clique() (in module sage.graphs.cliquer), 1561
max_cut() (sage.graphs.generic_graph.GenericGraphmethod), 290
MaximizeDegree (class in sage.graphs.tutte_polynomial), 1852
maximum_average_degree()(sage.graphs.graph.Graph method), 613
maximum_cardinality_search() (in module
sage.graphs.traversals), 1644
M
maximum_cardinality_search()(sage.graphs.graph.Graph method), 614
M22Graph() (in module sage.graphs.generators.smallmaximum_cardinality_search_M()(in module
graphs), 1334
sage.graphs.traversals),1646
M22Graph() (sage.graphs.graph_generators.GraphGenmaximum_cardinality_search_M()
erators static method), 909(sage.graphs.graph.Graph method), 616
linear_ordering_to_path_decomposition() (in module sage.graphs.graph_decompositions.vertex_separation), 1713
LivingstoneGraph() (in module sage.graphs.generators.smallgraphs), 1333
LivingstoneGraph() (sage.graphs.graph_generators.GraphGenerators static method), 907
LjubljanaGraph() (in module sage.graphs.generators.smallgraphs), 1333
LjubljanaGraph()(sage.graphs.graph_generators.GraphGenerators static method), 908
load_afile() (sage.graphs.bipartite_graph.BipartiteGraph method), 750
locally_GQ42_distance_transitive_graph() (in module sage.graphs.generators.distance_regular), 1142
locally_GQ42_distance_transitive_graph()(sage.graphs.graph_generators.GraphGenerators static method), 1013
LocalMcLaughlinGraph()(inmodulesage.graphs.generators.smallgraphs), 1334
LocalMcLaughlinGraph() (sage.graphs.graph_generators.GraphGenerators static method), 909
LollipopGraph() (in module sage.graphs.generators.families), 1195
LollipopGraph()(sage.graphs.graph_generators.GraphGenerators static method), 909
longest_cycle() (sage.graphs.generic_graph.GenericGraph method), 280
longest_path() (sage.graphs.generic_graph.GenericGraph method), 282
loop_edges()(sage.graphs.generic_graph.GenericGraph method), 285
loop_vertices() (sage.graphs.generic_graph.GenericGraph method), 287
loops()(sage.graphs.base.c_graph.CGraphBackend
method), 1421
loops()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1484
loops()(sage.graphs.generic_graph.GenericGraphmethod), 287
lovasz_theta() (in module sage.graphs.lovasz_theta),
1625
lovasz_theta() (sage.graphs.graph.Graph method),604
lower_bound() (in module sage.graphs.graph_decompositions.vertex_separation), 1715

Index

1985

Graph Theory, Release 10.4

maximum_leaf_number()(inmodulesage.graphs.domination), 1954
maximum_leaf_number()(sage.graphs.generic_graph.GenericGraphmethod), 291
McGeeGraph() (in module sage.graphs.generators.smallgraphs), 1336
McGeeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 913
McLaughlinGraph() (in module sage.graphs.generators.smallgraphs), 1337
McLaughlinGraph()(sage.graphs.graph_generators.GraphGenerators static method), 914
md_tree_to_graph()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1760
MeredithGraph() (in module sage.graphs.generators.smallgraphs), 1337
MeredithGraph()(sage.graphs.graph_generators.GraphGenerators static method), 914
merge_vertices() (sage.graphs.generic_graph.GenericGraph method), 291
min_cycle_basis()(inmodulesage.graphs.base.boost_graph), 1498
min_spanning_tree()(inmodulesage.graphs.base.boost_graph), 1499
min_spanning_tree()(sage.graphs.generic_graph.GenericGraphmethod), 293
minimal_dominating_sets()(inmodulesage.graphs.domination), 1954
minimal_dominating_sets()(sage.graphs.graph.Graph method), 618
minimal_schnyder_wood()(inmodulesage.graphs.schnyder), 1628
MinimizeDegree (class in sage.graphs.tutte_polynomial), 1852
MinimizeSingleDegree(classin
sage.graphs.tutte_polynomial), 1852
minimum_cycle_basis()(sage.graphs.generic_graph.GenericGraphmethod), 297
minimum_outdegree_orientation()(sage.graphs.graph.Graph method), 622
minor() (sage.graphs.graph.Graph method), 623
mkgraph() (in module sage.graphs.graph_decompositions.rankwidth), 1730
modular_decomposition()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1761
modular_decomposition()(sage.graphs.graph.Graph method), 625
modulesage.combinat.designs.inci1986

dence_structures, 1509
sage.graphs.asteroidal_triples, 1565
sage.graphs.base.boost_graph, 1486
sage.graphs.base.c_graph, 1374
sage.graphs.base.dense_graph, 1443
sage.graphs.base.graph_backends,
1479
sage.graphs.base.overview, 1373
sage.graphs.base.sparse_graph, 1431
sage.graphs.base.static_dense_graph,1452
sage.graphs.base.static_sparse_backend, 1470
sage.graphs.base.static_sparse_graph,1462
sage.graphs.bipartite_graph, 732
sage.graphs.centrality, 1561
sage.graphs.cliquer, 1558
sage.graphs.cographs, 1569
sage.graphs.comparability, 1574
sage.graphs.connectivity, 1897
sage.graphs.convexity_properties,
1779
sage.graphs.digraph, 663
sage.graphs.digraph_generators, 1042
sage.graphs.distances_all_pairs,
1788
sage.graphs.domination, 1942
sage.graphs.edge_connectivity, 1940
sage.graphs.generators.basic, 1218
sage.graphs.generators.chessboard,1242
sage.graphs.generators.classical_geometries, 1146
sage.graphs.generators.distance_regular, 1125
sage.graphs.generators.families,1162
sage.graphs.generators.intersection, 1249
sage.graphs.generators.platonic_solids, 1258
sage.graphs.generators.random, 1264
sage.graphs.generators.smallgraphs,
1288
sage.graphs.generators.world_map,
1357
sage.graphs.generic_graph, 1
sage.graphs.generic_graph_pyx, 1883
sage.graphs.genus, 1620
sage.graphs.graph, 437
sage.graphs.graph_coloring, 1539
sage.graphs.graph_database, 1065

Index

Graph Theory, Release 10.4

sage.graphs.graph_decompositions.bandwidth, 1731
sage.graphs.graph_decompositions.clique_separators, 1771
sage.graphs.graph_decompositions.cutwidth, 1734
sage.graphs.graph_decompositions.graph_products, 1740
sage.graphs.graph_decompositions.modular_decomposition,
1747
sage.graphs.graph_decompositions.rankwidth, 1728
sage.graphs.graph_decompositions.tree_decomposition, 1691
sage.graphs.graph_decompositions.vertex_separation, 1709
sage.graphs.graph_editor, 1825
sage.graphs.graph_generators, 773
sage.graphs.graph_generators_pyx,1064
sage.graphs.graph_input, 1832
sage.graphs.graph_latex, 1804
sage.graphs.graph_list, 1827
sage.graphs.graph_plot, 1649
sage.graphs.graph_plot_js, 1688
sage.graphs.hyperbolicity, 1842
sage.graphs.hypergraph_generators,
1505
sage.graphs.independent_sets, 1567
sage.graphs.isgci, 1360
sage.graphs.line_graph, 1583
sage.graphs.lovasz_theta, 1624
sage.graphs.matchpoly, 1615
sage.graphs.orientations, 1894
sage.graphs.partial_cube, 1857
sage.graphs.path_enumeration, 1860
sage.graphs.planarity, 1630
sage.graphs.pq_trees, 1605
sage.graphs.schnyder, 1625
sage.graphs.spanning_tree, 1588
sage.graphs.strongly_regular_db,
1088
sage.graphs.traversals, 1631
sage.graphs.trees, 1614
sage.graphs.tutte_polynomial, 1849
sage.graphs.views, 762
sage.graphs.weakly_chordal, 1785
MoebiusKantorGraph() (in module sage.graphs.generators.smallgraphs), 1338
MoebiusKantorGraph() (sage.graphs.graph_generators.GraphGenerators static method), 915
MoebiusLadderGraph() (in module sage.graphs.generators.basic), 1236
Index

MoebiusLadderGraph() (sage.graphs.graph_generators.GraphGenerators static method), 916
MoserSpindle() (in module sage.graphs.generators.smallgraphs), 1339
MoserSpindle()(sage.graphs.graph_generators.GraphGenerators static method), 917
most_common_neighbors()(sage.graphs.graph.Graph method), 627
multicommodity_flow()(sage.graphs.generic_graph.GenericGraphmethod), 298
multiple_edges() (sage.graphs.base.dense_graph.DenseGraphBackend method), 1451
multiple_edges() (sage.graphs.base.graph_backends.GenericGraphBackend method), 1484
multiple_edges() (sage.graphs.base.sparse_graph.SparseGraphBackend method), 1442
multiple_edges() (sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1477
multiple_edges() (sage.graphs.generic_graph.GenericGraph method), 300
multiway_cut() (sage.graphs.generic_graph.GenericGraph method), 302
MuzychukS6Graph() (in module sage.graphs.generators.families), 1198
MuzychukS6Graph()(sage.graphs.graph_generators.GraphGenerators static method), 919
MycielskiGraph() (in module sage.graphs.generators.families), 1199
MycielskiGraph()(sage.graphs.graph_generators.GraphGenerators static method), 920
MycielskiStep() (in module sage.graphs.generators.families), 1200
MycielskiStep()(sage.graphs.graph_generators.GraphGenerators static method), 921

N(sage.graphs.base.graph_backends.GenericGraphBackend method), 1484
name()(sage.graphs.generic_graph.GenericGraphmethod), 304
NauruGraph() (in module sage.graphs.generators.smallgraphs), 1340
NauruGraph() (sage.graphs.graph_generators.GraphGenerators static method), 922
nauty()(sage.graphs.hypergraph_generators.HypergraphGenerators method), 1507
nauty_directg()(sage.graphs.digraph_generators.DiGraphGenerators method), 1062
nauty_genbg() (sage.graphs.graph_generators.GraphGenerators method), 1013
nauty_geng() (sage.graphs.graph_generators.GraphGenerators method), 1016
name()

1987

Graph Theory, Release 10.4

nauty_genktreeg()(sage.graphs.graph_generators.GraphGenerators method), 1018
nauty_gentreeg() (in module sage.graphs.generators.families), 1214
nauty_gentreeg()(sage.graphs.graph_generators.GraphGenerators static method), 1020
near_polygon_graph() (in module sage.graphs.generators.distance_regular), 1143
neighbor_in_iterator()(sage.graphs.digraph.DiGraph method), 706
neighbor_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 305
neighbor_out_iterator()(sage.graphs.digraph.DiGraph method), 706
neighbors()(sage.graphs.generic_graph.GenericGraph method), 306
neighbors_in()(sage.graphs.digraph.DiGraphmethod), 706
neighbors_out()(sage.graphs.digraph.DiGraphmethod), 707
nested_tuple_to_tree()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1765
networkx_graph() (sage.graphs.generic_graph.GenericGraph method), 307
next_tree() (in module sage.graphs.cographs), 1573
NKStarGraph() (in module sage.graphs.generators.families), 1200
NKStarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 921
NO_SPLIT(sage.graphs.graph_decompositions.modular_decomposition.NodeSplit attribute), 1749
Node (class in sage.graphs.graph_decompositions.modular_decomposition), 1747
NodeSplit (class in sage.graphs.graph_decompositions.modular_decomposition), 1749
NodeType (class in sage.graphs.graph_decompositions.modular_decomposition), 1749
NonisotropicOrthogonalPolarGraph()(inmodule sage.graphs.generators.classical_geometries), 1150
NonisotropicOrthogonalPolarGraph()(sage.graphs.graph_generators.GraphGenerators
static method), 923
NonisotropicUnitaryPolarGraph() (in module sage.graphs.generators.classical_geometries),
1152
NonisotropicUnitaryPolarGraph()(sage.graphs.graph_generators.GraphGenerators static method), 925
NORMAL (sage.graphs.graph_decompositions.modular_decomposition.NodeType attribute), 1749
Nowhere0WordsTwoWeightCodeGraph()
(in
1988

module sage.graphs.generators.classical_geometries), 1153
Nowhere0WordsTwoWeightCodeGraph()(sage.graphs.graph_generators.GraphGenerators static method), 925
nowhere_zero_flow()(sage.graphs.generic_graph.GenericGraphmethod), 308
NStarGraph() (in module sage.graphs.generators.families), 1200
NStarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 922
num_blocks() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1534
num_edges() (sage.graphs.base.c_graph.CGraphBackend method), 1422
num_edges()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1484
num_edges()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1478
num_edges()(sage.graphs.generic_graph.GenericGraph method), 310
num_faces()(sage.graphs.generic_graph.GenericGraph method), 310
num_points() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1535
num_verts() (sage.graphs.base.c_graph.CGraphBackend method), 1422
num_verts()(sage.graphs.base.graph_backends.GenericGraphBackend method), 1485
num_verts()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1478
num_verts()(sage.graphs.generic_graph.GenericGraph method), 311
number_of()(sage.graphs.graph_database.GraphQuery method), 1081
number_of_children() (sage.graphs.pq_trees.PQ
method), 1609
number_of_loops()(sage.graphs.generic_graph.GenericGraphmethod), 311
number_of_n_colorings()(inmodulesage.graphs.graph_coloring), 1555
numbers_of_colorings()(inmodulesage.graphs.graph_coloring), 1555

O
OctahedralGraph() (in module sage.graphs.generators.platonic_solids), 1261
OctahedralGraph()(sage.graphs.graph_generators.GraphGenerators static method), 927
odd_girth()(sage.graphs.generic_graph.GenericGraph method), 312

IndexGraph Theory, Release 10.4
OddGraph() (in module sage.graphs.generators.fami- Plies), 1201
P (class in sage.graphs.pq_trees), 1606
OddGraph() (sage.graphs.graph_generators.GraphGen- packing()(sage.combinat.designs.incidence_strucerators static method), 928
tures.IncidenceStructure method), 1535
order()(sage.graphs.generic_graph.GenericGraph pagerank() (sage.graphs.generic_graph.GenericGraphmethod), 314
method), 315
ordering() (sage.graphs.pq_trees.PQ method), 1609
Paley() (sage.graphs.digraph_generators.DiGraphGenorderings() (sage.graphs.pq_trees.P method), 1607
erators method), 1054
orderings() (sage.graphs.pq_trees.Q method), 1611
PaleyGraph() (in module sage.graphs.generators.famiorientations() (sage.graphs.graph.Graph method),lies), 1201
628
PaleyGraph() (sage.graphs.graph_generators.GraphOrthogonalArrayBlockGraph() (in module
Generators static method), 933
sage.graphs.generators.intersection), 1251
PappusGraph() (in module sage.graphs.generaOrthogonalArrayBlockGraph()tors.smallgraphs), 1341
(sage.graphs.graph_generators.GraphGenerPappusGraph() (sage.graphs.graph_generators.Graphators static method), 928
Generators static method), 934
OrthogonalDualPolarGraph()(inmodule PARALLEL(sage.graphs.graph_decompositions.modusage.graphs.generators.classical_geometries),
lar_decomposition.NodeType attribute), 1749
1154
PasechnikGraph() (in module sage.graphs.generaOrthogonalDualPolarGraph()tors.families), 1202
(sage.graphs.graph_generators.GraphGenerPasechnikGraph()(sage.graphs.graph_generaators static method), 931
tors.GraphGenerators static method), 934
OrthogonalPolarGraph()(inmodule Path() (sage.graphs.digraph_generators.DiGraphGenersage.graphs.generators.classical_geometries),
ators method), 1054
1155
path_decomposition()(inmoduleOrthogonalPolarGraph() (sage.graphs.graph_gensage.graphs.graph_decompositions.vertex_sepaerators.GraphGenerators static method), 932
ration), 1715
out_branchings()(sage.graphs.digraph.DiGraph path_semigroup()(sage.graphs.digraph.DiGraphmethod), 707
method), 712
out_degree()(sage.graphs.base.c_graph.CGraph- PathGraph() (in module sage.graphs.generators.basic),
Backend method), 1423
1238
out_degree()(sage.graphs.base.graph_back- PathGraph() (sage.graphs.graph_generators.Graphends.GenericGraphBackend method), 1485
Generators static method), 935
out_degree() (sage.graphs.base.sparse_graph.Sparse- pathwidth() (in module sage.graphs.graph_decomposiGraph method), 1438
tions.vertex_separation), 1717
out_degree() (sage.graphs.base.static_sparse_back- pathwidth() (sage.graphs.graph.Graph method), 629
end.StaticSparseBackend method), 1478
perfect_matchings()(sage.graphs.biparout_degree() (sage.graphs.base.static_sparse_backtite_graph.BipartiteGraph method), 754
end.StaticSparseCGraph method), 1479
perfect_matchings() (sage.graphs.graph.Graph
out_degree() (sage.graphs.digraph.DiGraph method),
method), 631
709
period() (sage.graphs.digraph.DiGraph method), 712
out_degree_iterator() (sage.graphs.digraph.Di- periphery() (sage.graphs.digraph.DiGraph method),
Graph method), 710
713
out_degree_sequence() (sage.graphs.digraph.Di- periphery() (sage.graphs.graph.Graph method), 633
Graph method), 710
PerkelGraph() (in module sage.graphs.generaout_neighbors() (sage.graphs.base.c_graph.CGraph
tors.smallgraphs), 1341
method), 1393
PerkelGraph() (sage.graphs.graph_generators.Graphout_neighbors() (sage.graphs.base.static_sparse_backGenerators static method), 936
end.StaticSparseCGraph method), 1479
PermutationGraph() (in module sage.graphs.generaoutgoing_edge_iterator()(sage.graphs.ditors.intersection), 1254
graph.DiGraph method), 711
PermutationGraph() (sage.graphs.graph_generaoutgoing_edges()(sage.graphs.digraph.DiGraph
tors.GraphGenerators static method), 936
method), 711
permute_decomposition()(inmodulesage.graphs.graph_decompositions.moduIndex

1989

Graph Theory, Release 10.4

lar_decomposition), 1766
petersen_family() (in module sage.graphs.generators.families), 1216
petersen_family()(sage.graphs.graph_generators.GraphGenerators static method), 1021
PetersenGraph() (in module sage.graphs.generators.smallgraphs), 1342
PetersenGraph()(sage.graphs.graph_generators.GraphGenerators static method), 939
planar_dual() (sage.graphs.generic_graph.GenericGraph method), 318
planar_graphs()(sage.graphs.graph_generators.GraphGenerators method), 1022
plantri_gen() (sage.graphs.graph_generators.GraphGenerators method), 1025
platonic_solids(sage.graphs.graph_generators.GraphGenerators attribute), 1028
plot()(sage.graphs.bipartite_graph.BipartiteGraphmethod), 756
plot()(sage.graphs.generic_graph.GenericGraphmethod), 319
plot() (sage.graphs.graph_plot.GraphPlot method),1655
plot3d()(sage.graphs.generic_graph.GenericGraphmethod), 328
PoussinGraph() (in module sage.graphs.generators.smallgraphs), 1342
PoussinGraph()(sage.graphs.graph_generators.GraphGenerators static method), 940
power()(sage.graphs.generic_graph.GenericGraphmethod), 332
PQ (class in sage.graphs.pq_trees), 1608
PRIME (sage.graphs.graph_decompositions.modular_decomposition.NodeType attribute), 1749
print_md_tree() (in module sage.graphs.graph_decompositions.modular_decomposition), 1766
print_triconnected_components()(sage.graphs.connectivity.TriconnectivitySPQR
method), 1905
private_neighbors() (in module sage.graphs.domination), 1958
private_neighbors() (sage.graphs.graph.Graphmethod), 634
project_left() (sage.graphs.bipartite_graph.BipartiteGraph method), 757
project_right() (sage.graphs.bipartite_graph.BipartiteGraph method), 757
pruned_tree() (in module sage.graphs.generators.random), 1287
pseudo_partition_graph()(inmodulesage.graphs.generators.distance_regular), 1144

Q
Q (class in sage.graphs.pq_trees), 1611
1990

quadrangulations() (sage.graphs.graph_generators.GraphGenerators method), 1029
QueenGraph() (in module sage.graphs.generators.chessboard), 1246
QueenGraph() (sage.graphs.graph_generators.GraphGenerators static method), 940
query() (sage.graphs.graph_database.GraphDatabasemethod), 1074
query_iterator() (sage.graphs.graph_database.GraphQuery method), 1081

R
radius() (sage.graphs.digraph.DiGraph method), 714
radius() (sage.graphs.graph.Graph method), 634
radius_DHV()(inmodulesage.graphs.base.boost_graph), 1499
radius_DHV()(inmodulesage.graphs.distances_all_pairs), 1800
random (sage.graphs.graph_generators.GraphGenerators
attribute), 1030
random() (sage.graphs.graph_coloring.Test method),1540
random_all_graph_colorings()(sage.graphs.graph_coloring.Test
method),1540
random_edge() (sage.graphs.generic_graph.GenericGraph method), 333
random_edge_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 333
random_md_tree() (in module sage.graphs.graph_decompositions.modular_decomposition), 1767
random_orientation() (in module sage.graphs.orientations), 1895
random_orientation() (sage.graphs.graph.Graphmethod), 635
random_spanning_tree()(inmodulesage.graphs.spanning_tree), 1601
random_spanning_tree()(sage.graphs.graph.Graph method), 636
random_subgraph()(sage.graphs.generic_graph.GenericGraphmethod), 334
random_vertex() (sage.graphs.generic_graph.GenericGraph method), 334
random_vertex_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 335
RandomBarabasiAlbert()(inmodulesage.graphs.generators.random), 1264
RandomBarabasiAlbert() (sage.graphs.graph_generators.GraphGenerators static method), 942
RandomBicubicPlanar()(inmodulesage.graphs.generators.random), 1265
Index

Graph Theory, Release 10.4

RandomBicubicPlanar() (sage.graphs.graph_generators.GraphGenerators static method), 943
RandomBipartite() (in module sage.graphs.generators.random), 1266
RandomBipartite()(sage.graphs.graph_generators.GraphGenerators static method), 944
RandomBlockGraph() (in module sage.graphs.generators.random), 1267
RandomBlockGraph() (sage.graphs.graph_generators.GraphGenerators static method), 945
RandomBoundedToleranceGraph() (in module
sage.graphs.generators.random), 1269
RandomBoundedToleranceGraph()(sage.graphs.graph_generators.GraphGenerators static method), 947
RandomChordalGraph() (in module sage.graphs.generators.random), 1269
RandomChordalGraph() (sage.graphs.graph_generators.GraphGenerators static method), 948
RandomDirectedAcyclicGraph()(sage.graphs.digraph_generators.DiGraphGenerators method), 1055
RandomDirectedGN() (sage.graphs.digraph_generators.DiGraphGenerators method), 1055
RandomDirectedGNC() (sage.graphs.digraph_generators.DiGraphGenerators method), 1056
RandomDirectedGNM() (sage.graphs.digraph_generators.DiGraphGenerators method), 1057
RandomDirectedGNP() (sage.graphs.digraph_generators.DiGraphGenerators method), 1057
RandomDirectedGNR() (sage.graphs.digraph_generators.DiGraphGenerators method), 1058
RandomGNM() (in module sage.graphs.generators.random), 1271
RandomGNM() (sage.graphs.graph_generators.GraphGenerators static method), 949
RandomGNP() (in module sage.graphs.generators.random), 1272
RandomGNP() (in module sage.graphs.graph_generators_pyx), 1064
RandomGNP() (sage.graphs.graph_generators.GraphGenerators static method), 950
RandomHolmeKim() (in module sage.graphs.generators.random), 1274
RandomHolmeKim()(sage.graphs.graph_generators.GraphGenerators static method), 952
RandomIntervalGraph()(inmodulesage.graphs.generators.random), 1275
RandomIntervalGraph() (sage.graphs.graph_generators.GraphGenerators static method), 953
RandomKTree() (in module sage.graphs.generators.random), 1275
RandomKTree() (sage.graphs.graph_generators.GraphGenerators static method), 953
Index

RandomLobster() (in module sage.graphs.generators.random), 1276
RandomLobster()(sage.graphs.graph_generators.GraphGenerators static method), 954
RandomNewmanWattsStrogatz() (in module
sage.graphs.generators.random), 1277
RandomNewmanWattsStrogatz()(sage.graphs.graph_generators.GraphGenerators static method), 955
RandomPartialKTree() (in module sage.graphs.generators.random), 1278
RandomPartialKTree() (sage.graphs.graph_generators.GraphGenerators static method), 956
RandomRegular() (in module sage.graphs.generators.random), 1278
RandomRegular()(sage.graphs.graph_generators.GraphGenerators static method), 956
RandomRegularBipartite()(inmodulesage.graphs.generators.random), 1279
RandomRegularBipartite()(sage.graphs.graph_generators.GraphGenerators static method), 957
RandomSemiComplete() (sage.graphs.digraph_generators.DiGraphGenerators method), 1059
RandomShell() (in module sage.graphs.generators.random), 1280
RandomShell() (sage.graphs.graph_generators.GraphGenerators static method), 958
RandomToleranceGraph()(inmodulesage.graphs.generators.random), 1281
RandomToleranceGraph() (sage.graphs.graph_generators.GraphGenerators static method), 959
RandomTournament() (sage.graphs.digraph_generators.DiGraphGenerators method), 1059
RandomTree() (in module sage.graphs.generators.random), 1281
RandomTree() (sage.graphs.graph_generators.GraphGenerators static method), 959
RandomTreePowerlaw() (in module sage.graphs.generators.random), 1282
RandomTreePowerlaw() (sage.graphs.graph_generators.GraphGenerators static method), 960
RandomTriangulation()(inmodulesage.graphs.generators.random), 1283
RandomTriangulation() (sage.graphs.graph_generators.GraphGenerators static method), 961
RandomUnitDiskGraph()(inmodulesage.graphs.generators.random), 1284
RandomUnitDiskGraph() (sage.graphs.graph_generators.GraphGenerators static method), 962
rank() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1536
rank_decomposition()(inmodulesage.graphs.graph_decompositions.rankwidth),
1991

Graph Theory, Release 10.4

1730
rank_decomposition() (sage.graphs.graph.Graphmethod), 638
realloc() (sage.graphs.base.c_graph.CGraph method),1394
realloc() (sage.graphs.base.dense_graph.DenseGraphmethod), 1447
realloc()(sage.graphs.base.sparse_graph.SparseGraph method), 1439
rebuild_node() (in module sage.graphs.cographs),1573
recreate_decomposition()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1767
reduced_adjacency_matrix() (sage.graphs.bipartite_graph.BipartiteGraph method), 757
reduced_tree_decomposition() (in module
sage.graphs.graph_decompositions.tree_decomposition), 1703
relabel()(sage.combinat.designs.incidence_structures.IncidenceStructure method), 1536
relabel() (sage.graphs.base.c_graph.CGraphBackend
method), 1423
relabel() (sage.graphs.base.graph_backends.GenericGraphBackend method), 1485
relabel()(sage.graphs.base.static_sparse_backend.StaticSparseBackend method), 1478
relabel() (sage.graphs.generic_graph.GenericGraphmethod), 335
relabel_tree() (in module sage.graphs.graph_decompositions.modular_decomposition), 1768
remove_loops() (sage.graphs.generic_graph.GenericGraph method), 340
remove_multiple_edges()(sage.graphs.generic_graph.GenericGraphmethod), 342
removed_edge() (in module sage.graphs.tutte_polynomial), 1853
removed_from() (sage.graphs.tutte_polynomial.Ear
method), 1850
removed_loops() (in module sage.graphs.tutte_polynomial), 1854
removed_multiedge()(inmodulesage.graphs.tutte_polynomial), 1855
reorder_sets() (in module sage.graphs.pq_trees),1613
reset_info() (sage.graphs.cographs.CoTree method),1571
reverse() (sage.graphs.digraph.DiGraph method), 715
reverse() (sage.graphs.pq_trees.PQ method), 1609
reverse_edge()(sage.graphs.digraph.DiGraphmethod), 715
reverse_edges()(sage.graphs.digraph.DiGraphmethod), 720
1992

RIGHT_OF_SOURCE(sage.graphs.graph_decompositions.modular_decomposition.VertexPosition
attribute), 1750
RIGHT_SPLIT (sage.graphs.graph_decompositions.modular_decomposition.NodeSplit attribute), 1749
RingedTree() (in module sage.graphs.generators.families), 1203
RingedTree() (sage.graphs.graph_generators.GraphGenerators static method), 963
RobertsonGraph() (in module sage.graphs.generators.smallgraphs), 1343
RobertsonGraph()(sage.graphs.graph_generators.GraphGenerators static method), 964
RookGraph() (in module sage.graphs.generators.chessboard), 1248
RookGraph() (sage.graphs.graph_generators.GraphGenerators static method), 965
root_graph() (in module sage.graphs.line_graph),1588
rooted_product() (in module sage.graphs.graph_decompositions.graph_products), 1744
rooted_product() (sage.graphs.generic_graph.GenericGraph method), 342
RoseWindowGraph() (in module sage.graphs.generators.families), 1203
RoseWindowGraph()(sage.graphs.graph_generators.GraphGenerators static method), 966
round_robin() (in module sage.graphs.graph_coloring), 1555Ss (sage.graphs.tutte_polynomial.Ear property), 1851
sage.combinat.designs.incidence_structuresmodule, 1509
sage.graphs.asteroidal_triples
module, 1565
sage.graphs.base.boost_graphmodule, 1486
sage.graphs.base.c_graphmodule, 1374
sage.graphs.base.dense_graphmodule, 1443
sage.graphs.base.graph_backends
module, 1479
sage.graphs.base.overview
module, 1373
sage.graphs.base.sparse_graphmodule, 1431
sage.graphs.base.static_dense_graphmodule, 1452
sage.graphs.base.static_sparse_backend
module, 1470
sage.graphs.base.static_sparse_graphIndex

Graph Theory, Release 10.4

module, 1462
sage.graphs.bipartite_graphmodule, 732
sage.graphs.centrality
module, 1561
sage.graphs.cliquer
module, 1558
sage.graphs.cographs
module, 1569
sage.graphs.comparability
module, 1574
sage.graphs.connectivity
module, 1897
sage.graphs.convexity_properties
module, 1779
sage.graphs.digraphmodule, 663
sage.graphs.digraph_generators
module, 1042
sage.graphs.distances_all_pairs
module, 1788
sage.graphs.domination
module, 1942
sage.graphs.edge_connectivity
module, 1940
sage.graphs.generators.basic
module, 1218
sage.graphs.generators.chessboard
module, 1242
sage.graphs.generators.classical_geometries
module, 1146
sage.graphs.generators.distance_regularmodule, 1125
sage.graphs.generators.families
module, 1162
sage.graphs.generators.intersection
module, 1249
sage.graphs.generators.platonic_solids
module, 1258
sage.graphs.generators.random
module, 1264
sage.graphs.generators.smallgraphs
module, 1288
sage.graphs.generators.world_map
module, 1357
sage.graphs.generic_graphmodule, 1
sage.graphs.generic_graph_pyx
module, 1883
sage.graphs.genus
module, 1620
sage.graphs.graphIndex

module, 437
sage.graphs.graph_coloring
module, 1539
sage.graphs.graph_database
module, 1065
sage.graphs.graph_decompositions.bandwidthmodule, 1731
sage.graphs.graph_decompositions.clique_separators
module, 1771
sage.graphs.graph_decompositions.cutwidthmodule, 1734
sage.graphs.graph_decompositions.graph_products
module, 1740
sage.graphs.graph_decompositions.modular_decomposition
module, 1747
sage.graphs.graph_decompositions.rankwidthmodule, 1728
sage.graphs.graph_decompositions.tree_decomposition
module, 1691
sage.graphs.graph_decompositions.vertex_separation
module, 1709
sage.graphs.graph_editor
module, 1825
sage.graphs.graph_generators
module, 773
sage.graphs.graph_generators_pyx
module, 1064
sage.graphs.graph_input
module, 1832
sage.graphs.graph_latex
module, 1804
sage.graphs.graph_list
module, 1827
sage.graphs.graph_plot
module, 1649
sage.graphs.graph_plot_js
module, 1688
sage.graphs.hyperbolicity
module, 1842
sage.graphs.hypergraph_generators
module, 1505
sage.graphs.independent_sets
module, 1567
sage.graphs.isgci
module, 1360
sage.graphs.line_graph
1993

Graph Theory, Release 10.4

module, 1583
set_edge_label() (sage.graphs.base.sparse_graph.SparseGsage.graphs.lovasz_theta
raphBackend method), 1442
module, 1624
set_edge_label() (sage.graphs.base.static_sparse_backsage.graphs.matchpoly
end.StaticSparseBackend method), 1478
module, 1615
set_edge_label() (sage.graphs.generic_graph.Genersage.graphs.orientations
icGraph method), 345
module, 1894
set_edges()(sage.graphs.graph_plot.GraphPlot
sage.graphs.partial_cube
method), 1675
module, 1857
set_embedding() (sage.graphs.generic_graph.Genersage.graphs.path_enumeration
icGraph method), 348
module, 1860
set_latex_options()
sage.graphs.planarity(sage.graphs.generic_graph.GenericGraph
module, 1630
method), 349
sage.graphs.pq_trees
set_node_split()(sage.graphs.graph_decompomodule, 1605
sitions.modular_decomposition.Node method),
sage.graphs.schnyder
1748
module, 1625
set_option() (sage.graphs.graph_latex.GraphLatex
sage.graphs.spanning_tree
method), 1818
module, 1588
set_options() (sage.graphs.graph_latex.GraphLatex
sage.graphs.strongly_regular_db
method), 1822
module, 1088
set_pos() (sage.graphs.generic_graph.GenericGraphsage.graphs.traversals
method), 349
module, 1631
set_pos() (sage.graphs.graph_plot.GraphPlot method),
sage.graphs.trees
1679
module, 1614
set_vertex()(sage.graphs.generic_graph.Genericsage.graphs.tutte_polynomial
Graph method), 350
module, 1849
set_vertices() (sage.graphs.generic_graph.Genericsage.graphs.views
Graph method), 351
module, 762
set_vertices() (sage.graphs.graph_plot.GraphPlot
sage.graphs.weakly_chordal
method), 1680
module, 1785
setup_latex_preamble()(inmodulesave_afile() (sage.graphs.bipartite_graph.Bipartitesage.graphs.graph_latex), 1825
Graph method), 759
shortened_00_11_binary_GoSchlaefliGraph() (in module sage.graphs.generalay_code_graph()(inmoduletors.smallgraphs), 1344
sage.graphs.generators.distance_regular), 1145
SchlaefliGraph()(sage.graphs.graph_genera- shortened_00_11_binary_Gotors.GraphGenerators static method), 966
lay_code_graph()
Search_iterator (class in sage.graphs.base.c_graph),(sage.graphs.graph_generators.GraphGener1431
ators static method), 1031
seidel_adjacency_matrix()
shortened_000_111_extended_binary_Go(sage.graphs.graph.Graph method), 639
lay_code_graph()(inmoduleseidel_switching()(sage.graphs.graph.Graphsage.graphs.generators.distance_regular), 1144
method), 640
shortened_000_111_extended_biSERIES (sage.graphs.graph_decompositions.modular_denary_Golay_code_graph()
composition.NodeType attribute), 1749
(sage.graphs.graph_generators.GraphGenerset_contiguous() (sage.graphs.pq_trees.P method),ators static method), 1031
1607
shortest_path() (sage.graphs.base.c_graph.CGraphset_contiguous() (sage.graphs.pq_trees.Q method),
Backend method), 1424
1612
shortest_path() (sage.graphs.generic_graph.Generset_edge_label() (sage.graphs.base.dense_graph.DenseGicGraph method), 351
raphBackend method), 1452
shortest_path_all_pairs()(inmoduleset_edge_label() (sage.graphs.base.graph_backsage.graphs.distances_all_pairs), 1801
ends.GenericGraphBackend method), 1485
shortest_path_all_pairs()(sage.graphs.generic_graph.GenericGraph
1994

Index

Graph Theory, Release 10.4

method), 353
shortest_path_all_vertices()(sage.graphs.base.c_graph.CGraphBackend
method), 1424
shortest_path_length()(sage.graphs.generic_graph.GenericGraphmethod), 361
shortest_path_lengths()(sage.graphs.generic_graph.GenericGraphmethod), 364
shortest_path_special()(sage.graphs.base.c_graph.CGraphBackend
method), 1425
shortest_paths()(inmodulesage.graphs.base.boost_graph), 1500
shortest_paths() (sage.graphs.generic_graph.GenericGraph method), 366
shortest_paths_from_vertices() (in module
sage.graphs.base.boost_graph), 1501
shortest_simple_paths()(inmodulesage.graphs.path_enumeration), 1877
shortest_simple_paths()(sage.graphs.generic_graph.GenericGraphmethod), 370
show()(sage.graphs.generic_graph.GenericGraphmethod), 373
show()(sage.graphs.graph_database.GraphQuery
method), 1082
show() (sage.graphs.graph_plot.GraphPlot method),1687
show3d()(sage.graphs.generic_graph.GenericGraphmethod), 373
show_all() (sage.graphs.isgci.GraphClasses method),1370
show_graphs() (in module sage.graphs.graph_list),
1828
ShrikhandeGraph() (in module sage.graphs.generators.smallgraphs), 1344
ShrikhandeGraph()(sage.graphs.graph_generators.GraphGenerators static method), 967
SierpinskiGasketGraph()(inmodulesage.graphs.generators.families), 1204
SierpinskiGasketGraph()(sage.graphs.graph_generators.GraphGenerators static method), 969
simple_connected_genus_backtracker (classin sage.graphs.genus), 1620
simple_connected_graph_genus() (in module
sage.graphs.genus), 1623
simplify() (sage.graphs.pq_trees.PQ method), 1610
SimsGewirtzGraph() (in module sage.graphs.generators.smallgraphs), 1346
SimsGewirtzGraph() (sage.graphs.graph_generators.GraphGenerators static method), 971
Index

sinks() (sage.graphs.digraph.DiGraph method), 722
size()(sage.graphs.generic_graph.GenericGraphmethod), 376
small_integer_to_graph6()(inmodulesage.graphs.generic_graph_pyx), 1892
smallgraphs (sage.graphs.graph_generators.GraphGenerators attribute), 1031
smallgraphs()(sage.graphs.isgci.GraphClasses
method), 1371
SOURCE (sage.graphs.graph_decompositions.modular_decomposition.VertexPosition attribute), 1750
sources() (sage.graphs.digraph.DiGraph method), 723
SousselierGraph() (in module sage.graphs.generators.smallgraphs), 1347
SousselierGraph()(sage.graphs.graph_generators.GraphGenerators static method), 972
spanning_trees() (in module sage.graphs.spanning_tree), 1604
spanning_trees()(sage.graphs.graph.Graphmethod), 641
spanning_trees_count()(sage.graphs.generic_graph.GenericGraphmethod), 376
sparse6_string()(sage.graphs.graph.Graphmethod), 642
SparseGraph (class in sage.graphs.base.sparse_graph),1436
SparseGraphBackend(classin
sage.graphs.base.sparse_graph), 1440
spectral_radius()(inmodulesage.graphs.base.static_sparse_graph), 1465
spectral_radius()(sage.graphs.generic_graph.GenericGraphmethod), 377
spectrum() (sage.graphs.generic_graph.GenericGraphmethod), 381
spqr_tree() (in module sage.graphs.connectivity),1926
spqr_tree() (sage.graphs.graph.Graph method), 642
spqr_tree_to_graph() (in module sage.graphs.connectivity), 1931
spring_layout_fast()(inmodulesage.graphs.generic_graph_pyx), 1892
SquaredSkewHadamardMatrixGraph() (in module sage.graphs.generators.families), 1206
SquaredSkewHadamardMatrixGraph()(sage.graphs.graph_generators.GraphGenerators static method), 972
SRG_100_44_18_20()(inmodulesage.graphs.strongly_regular_db), 1088
SRG_100_45_20_20()(inmodulesage.graphs.strongly_regular_db), 1089
SRG_105_32_4_12()(inmodulesage.graphs.strongly_regular_db), 1089
1995

Graph Theory, Release 10.4

SRG_120_63_30_36()(inmodulesage.graphs.strongly_regular_db), 1089
SRG_120_77_52_44()(inmodulesage.graphs.strongly_regular_db), 1090
SRG_126_25_8_4()(inmodulesage.graphs.strongly_regular_db), 1090
SRG_126_50_13_24()(inmodulesage.graphs.strongly_regular_db), 1090
SRG_144_39_6_12()(inmodulesage.graphs.strongly_regular_db), 1091
SRG_175_72_20_36()(inmodulesage.graphs.strongly_regular_db), 1092
SRG_176_49_12_14()(inmodulesage.graphs.strongly_regular_db), 1092
SRG_176_90_38_54()(inmodulesage.graphs.strongly_regular_db), 1093
SRG_176_105_68_54()(inmodulesage.graphs.strongly_regular_db), 1092
SRG_196_91_42_42()(inmodulesage.graphs.strongly_regular_db), 1093
SRG_210_99_48_45()(inmodulesage.graphs.strongly_regular_db), 1093
SRG_220_84_38_28()(inmodulesage.graphs.strongly_regular_db), 1094
SRG_243_110_37_60()(inmodulesage.graphs.strongly_regular_db), 1094
SRG_253_140_87_65()(inmodulesage.graphs.strongly_regular_db), 1095
SRG_276_140_58_84()(inmodulesage.graphs.strongly_regular_db), 1095
SRG_280_117_44_52()(inmodulesage.graphs.strongly_regular_db), 1095
SRG_280_135_70_60()(inmodulesage.graphs.strongly_regular_db), 1096
SRG_416_100_36_20()(inmodulesage.graphs.strongly_regular_db), 1096
SRG_560_208_72_80()(inmodulesage.graphs.strongly_regular_db), 1097
SRG_630_85_20_10()(inmodulesage.graphs.strongly_regular_db), 1097
SRG_1288_792_476_504()(inmodulesage.graphs.strongly_regular_db), 1091
SRG_from_RSHCD()(inmodulesage.graphs.strongly_regular_db), 1097
StarGraph() (in module sage.graphs.generators.basic),
1239
StarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 973
StaticSparseBackend(classin
sage.graphs.base.static_sparse_backend), 1470
StaticSparseCGraph(classin
sage.graphs.base.static_sparse_backend), 1478
steiner_tree() (sage.graphs.generic_graph.GenericGraph method), 382
1996

strong_articulation_points() (in module
sage.graphs.connectivity), 1932
strong_articulation_points()(sage.graphs.digraph.DiGraph method), 723
strong_orientation() (sage.graphs.graph.Graphmethod), 647
strong_orientations_iterator() (in module
sage.graphs.orientations), 1895
strong_orientations_iterator()(sage.graphs.graph.Graph method), 648
strong_product() (sage.graphs.generic_graph.GenericGraph method), 383
strongly_connected_component_containing_vertex() (in module sage.graphs.connectivity), 1933
strongly_connected_component_containing_vertex()(sage.graphs.base.c_graph.CGraphBackend
method), 1426
strongly_connected_component_containing_vertex()(sage.graphs.digraph.DiGraph method), 724
strongly_connected_components()(sage.graphs.digraph.DiGraph method), 725
strongly_connected_components_digraph()(inmodulesage.graphs.base.static_sparse_graph), 1468
strongly_connected_components_digraph() (in module sage.graphs.connectivity),
1934
strongly_connected_components_digraph()(sage.graphs.digraph.DiGraphmethod), 726
strongly_connected_components_subgraphs() (in module sage.graphs.connectivity), 1936
strongly_connected_components_subgraphs()(sage.graphs.digraph.DiGraphmethod), 728
strongly_regular_db (sage.graphs.graph_generators.GraphGenerators attribute), 1031
strongly_regular_from_two_intersection_set()(inmodulesage.graphs.strongly_regular_db), 1121
strongly_regular_from_two_weight_code()(in module sage.graphs.strongly_regular_db),1121
strongly_regular_graph()(inmodulesage.graphs.strongly_regular_db), 1122
strongly_regular_graph()(sage.graphs.graph_generators.GraphGenerators static method), 1031
strongly_regular_graph_lazy() (in module
sage.graphs.strongly_regular_db), 1125
Index

Graph Theory, Release 10.4

StronglyRegular() (sage.graphs.digraph_generators.DiGraphGenerators method), 1060
subdivide_edge() (sage.graphs.generic_graph.GenericGraph method), 384
subdivide_edges()(sage.graphs.generic_graph.GenericGraphmethod), 386
subgraph() (sage.graphs.generic_graph.GenericGraphmethod), 387
subgraph_given_vertices()(sage.graphs.base.c_graph.CGraphBackend
method), 1427
subgraph_search()(sage.graphs.generic_graph.GenericGraphmethod), 391
subgraph_search_count()(sage.graphs.generic_graph.GenericGraphmethod), 395
subgraph_search_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 397
subgraphs_to_query()(inmodulesage.graphs.graph_database), 1087
SubgraphSearch(classin
sage.graphs.generic_graph_pyx), 1883
SuzukiGraph() (in module sage.graphs.generators.smallgraphs), 1348
SuzukiGraph() (sage.graphs.graph_generators.GraphGenerators static method), 975
SwitchedSquaredSkewHadamardMatrixGraph() (in module sage.graphs.generators.families), 1207
SwitchedSquaredSkewHadamardMatrixGraph()(sage.graphs.graph_generators.GraphGenerators static method), 975
SylvesterGraph() (in module sage.graphs.generators.smallgraphs), 1348
SylvesterGraph()(sage.graphs.graph_generators.GraphGenerators static method), 976
symmetric_edge_polytope()(sage.graphs.generic_graph.GenericGraphmethod), 400
SymplecticDualPolarGraph()(inmodulesage.graphs.generators.classical_geometries),
1156
SymplecticDualPolarGraph()(sage.graphs.graph_generators.GraphGenerators static method), 977
SymplecticPolarGraph()(inmodulesage.graphs.generators.classical_geometries),
1156
SymplecticPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 977
szeged_index() (in module sage.graphs.disIndex

tances_all_pairs), 1801
szeged_index() (sage.graphs.generic_graph.GenericGraph method), 404
SzekeresSnarkGraph() (in module sage.graphs.generators.smallgraphs), 1349
SzekeresSnarkGraph() (sage.graphs.graph_generators.GraphGenerators static method), 978TT2starGeneralizedQuadrangleGraph()(inmodule sage.graphs.generators.classical_geometries), 1157
T2starGeneralizedQuadrangleGraph()(sage.graphs.graph_generators.GraphGenerators
static method), 979
TabacjnGraph() (in module sage.graphs.generators.families), 1207
TabacjnGraph()(sage.graphs.graph_generators.GraphGenerators static method), 980
tachyon_vertex_plot()(inmodulesage.graphs.generic_graph), 437
TadpoleGraph() (in module sage.graphs.generators.families), 1208
TadpoleGraph()(sage.graphs.graph_generators.GraphGenerators static method), 981
tarjan_strongly_connected_components()(inmodulesage.graphs.base.static_sparse_graph), 1468
TaylorTwographDescendantSRG() (in module
sage.graphs.generators.classical_geometries),1159
TaylorTwographDescendantSRG()(sage.graphs.graph_generators.GraphGenerators static method), 981
TaylorTwographSRG() (in module sage.graphs.generators.classical_geometries), 1160
TaylorTwographSRG() (sage.graphs.graph_generators.GraphGenerators static method), 982
tensor_product() (sage.graphs.generic_graph.GenericGraph method), 406
Test (class in sage.graphs.graph_coloring), 1540
test_gamma_modules()(in
modulesage.graphs.graph_decompositions.modular_decomposition), 1768
test_maximal_modules()(in
modulesage.graphs.graph_decompositions.modular_decomposition), 1769
test_modular_decomposition() (in module
sage.graphs.graph_decompositions.modular_decomposition), 1769
test_module() (in module sage.graphs.graph_decompositions.modular_decomposition), 1770
TetrahedralGraph() (in module sage.graphs.generators.platonic_solids), 1262
1997

Graph Theory, Release 10.4

TetrahedralGraph() (sage.graphs.graph_generators.GraphGenerators static method), 983
ThomsenGraph() (in module sage.graphs.generators.smallgraphs), 1349
ThomsenGraph()(sage.graphs.graph_generators.GraphGenerators static method), 984
TietzeGraph() (in module sage.graphs.generators.smallgraphs), 1350
TietzeGraph() (sage.graphs.graph_generators.GraphGenerators static method), 984
tkz_picture() (sage.graphs.graph_latex.GraphLatex
method), 1822
to_dictionary() (sage.graphs.generic_graph.GenericGraph method), 407
to_directed()(sage.graphs.digraph.DiGraphmethod), 729
to_directed() (sage.graphs.graph.Graph method),650
to_graph6() (in module sage.graphs.graph_list), 1830
to_graphics_array()(inmodulesage.graphs.graph_list), 1831
to_simple()(sage.graphs.generic_graph.GenericGraph method), 409
to_sparse6() (in module sage.graphs.graph_list),1831
to_undirected() (sage.graphs.bipartite_graph.BipartiteGraph method), 760
to_undirected()(sage.graphs.digraph.DiGraphmethod), 729
to_undirected() (sage.graphs.graph.Graph method),650
ToleranceGraph() (in module sage.graphs.generators.intersection), 1257
ToleranceGraph()(sage.graphs.graph_generators.GraphGenerators static method), 985
topological_minor() (sage.graphs.graph.Graphmethod), 650
topological_sort() (sage.graphs.digraph.DiGraphmethod), 729
topological_sort_generator()(sage.graphs.digraph.DiGraph method), 731
Toroidal6RegularGrid2dGraph() (in module
sage.graphs.generators.basic), 1241
Toroidal6RegularGrid2dGraph()(sage.graphs.graph_generators.GraphGenerators static method), 986
ToroidalGrid2dGraph()(inmodulesage.graphs.generators.basic), 1241
ToroidalGrid2dGraph() (sage.graphs.graph_generators.GraphGenerators static method), 987
tournaments_nauty() (sage.graphs.digraph_generators.DiGraphGenerators method), 1063
trace() (sage.combinat.designs.incidence_structures.IncidenceStructure method), 1537
1998

transitive_closure()(sage.graphs.generic_graph.GenericGraphmethod), 410
transitive_reduction()(sage.graphs.generic_graph.GenericGraphmethod), 411
transitive_reduction_acyclic() (in module
sage.graphs.generic_graph_pyx), 1893
TransitiveTournament()(sage.graphs.digraph_generators.DiGraphGenerators method),1061
traveling_salesman_problem()(sage.graphs.generic_graph.GenericGraphmethod), 412
tree_to_graph() (in module sage.graphs.cographs),1574
tree_to_nested_tuple()(inmodulesage.graphs.graph_decompositions.modular_decomposition), 1770
TreeIterator (class in sage.graphs.trees), 1614
treelength() (in module sage.graphs.graph_decompositions.tree_decomposition), 1704
treelength() (sage.graphs.graph.Graph method), 652
treelength_lowerbound()(inmodulesage.graphs.graph_decompositions.tree_decomposition), 1706
TreelengthConnected(classin
sage.graphs.graph_decompositions.tree_decomposition), 1693
TreeNode (class in sage.graphs.schnyder), 1625
trees() (in module sage.graphs.generators.families),
1217
trees() (sage.graphs.graph_generators.GraphGenerators static method), 1034
treewidth() (in module sage.graphs.graph_decompositions.tree_decomposition), 1706
treewidth() (sage.graphs.graph.Graph method), 654
triangles_count()(in
modulesage.graphs.base.static_dense_graph), 1461
triangles_count()(in
modulesage.graphs.base.static_sparse_graph), 1469
triangles_count()(sage.graphs.generic_graph.GenericGraphmethod), 415
triangulations()(sage.graphs.graph_generators.GraphGenerators method), 1035
TriconnectivitySPQR (class in sage.graphs.connectivity), 1898
TruncatedIcosidodecahedralGraph()(inmodulesage.graphs.generators.smallgraphs),
1350
TruncatedIcosidodecahedralGraph()(sage.graphs.graph_generators.GraphGenerators static method), 988
IndexGraph Theory, Release 10.4

TruncatedTetrahedralGraph() (in module
sage.graphs.generators.smallgraphs), 1351
TruncatedTetrahedralGraph()(sage.graphs.graph_generators.GraphGenerators static method), 988
TruncatedWittGraph() (in module sage.graphs.generators.distance_regular), 1135
TruncatedWittGraph() (sage.graphs.graph_generators.GraphGenerators static method), 989
TuranGraph() (in module sage.graphs.generators.families), 1209
TuranGraph() (sage.graphs.graph_generators.GraphGenerators static method), 989
Tutte12Cage() (in module sage.graphs.generators.smallgraphs), 1351
Tutte12Cage() (sage.graphs.graph_generators.GraphGenerators static method), 990
tutte_polynomial()(inmodulesage.graphs.tutte_polynomial), 1855
tutte_polynomial()(sage.graphs.graph.Graphmethod), 656
TutteCoxeterGraph() (in module sage.graphs.generators.smallgraphs), 1352
TutteCoxeterGraph() (sage.graphs.graph_generators.GraphGenerators static method), 991
TutteGraph() (in module sage.graphs.generators.smallgraphs), 1353
TutteGraph() (sage.graphs.graph_generators.GraphGenerators static method), 992
two_factor_petersen() (sage.graphs.graph.Graphmethod), 657
twograph() (sage.graphs.graph.Graph method), 659

U
U42Graph216() (in module sage.graphs.generators.smallgraphs), 1354
U42Graph216() (sage.graphs.graph_generators.GraphGenerators static method), 992
U42Graph540() (in module sage.graphs.generators.smallgraphs), 1354
U42Graph540() (sage.graphs.graph_generators.GraphGenerators static method), 993
underlying_graph()(inmodulesage.graphs.tutte_polynomial), 1856
UniformRandomUniform()(sage.graphs.hypergraph_generators.HypergraphGenerators
method), 1506
union()(sage.graphs.generic_graph.GenericGraphmethod), 417
UnitaryDualPolarGraph()(inmodulesage.graphs.generators.classical_geometries),
1160
UnitaryDualPolarGraph()(sage.graphs.graph_generators.GraphGenerIndex

ators static method), 994
UnitaryPolarGraph() (in module sage.graphs.generators.classical_geometries), 1161
UnitaryPolarGraph() (sage.graphs.graph_generators.GraphGenerators static method), 995
unlabeled_edges()(sage.graphs.tutte_polynomial.Ear method), 1851
unpickle_graph_backend()(inmodulesage.graphs.base.graph_backends), 1485
update_db() (sage.graphs.isgci.GraphClasses method),1371
USAMap()(inmodulesage.graphs.generators.world_map), 1358
USAMap() (sage.graphs.graph_generators.GraphGenerators static method), 993
UstimenkoGraph() (in module sage.graphs.generators.distance_regular), 1135
UstimenkoGraph()(sage.graphs.graph_generators.GraphGenerators static method), 995

VvanLintSchrijverGraph()(inmodulesage.graphs.generators.distance_regular), 1145
vanLintSchrijverGraph()(sage.graphs.graph_generators.GraphGenerators static method), 1038
vertex_boundary()(sage.graphs.generic_graph.GenericGraphmethod), 417
vertex_coloring()(inmodulesage.graphs.graph_coloring), 1557
vertex_connectivity()(inmodulesage.graphs.connectivity), 1936
vertex_connectivity()(sage.graphs.generic_graph.GenericGraphmethod), 418
vertex_cover() (sage.graphs.bipartite_graph.BipartiteGraph method), 760
vertex_cover() (sage.graphs.graph.Graph method),659
vertex_cut()(sage.graphs.generic_graph.GenericGraph method), 421
vertex_disjoint_paths()(sage.graphs.generic_graph.GenericGraphmethod), 423
vertex_isoperimetric_number()(sage.graphs.graph.Graph method), 660
vertex_iterator()(sage.graphs.generic_graph.GenericGraphmethod), 423
vertex_separation()(inmodulesage.graphs.graph_decompositions.vertex_separation), 1718
vertex_separation_BAB()(in
module1999

Graph Theory, Release 10.4

sage.graphs.graph_decompositions.vertex_separation), 1721
vertex_separation_exp()(inmodulesage.graphs.graph_decompositions.vertex_separation), 1726
vertex_separation_MILP()(inmodulesage.graphs.graph_decompositions.vertex_separation), 1725
VertexOrder (class in sage.graphs.tutte_polynomial),
1852
VertexPosition (class in sage.graphs.graph_decompositions.modular_decomposition), 1749
vertices (sage.graphs.tutte_polynomial.Ear property),1852
vertices() (sage.graphs.generic_graph.GenericGraphmethod), 425
verts() (sage.graphs.base.c_graph.CGraph method),1397
verts() (sage.graphs.base.static_sparse_backend.StaticSparseCGraph method), 1479

wiener_index() (in module sage.graphs.distances_all_pairs), 1803
wiener_index() (sage.graphs.generic_graph.GenericGraph method), 431
WienerArayaGraph() (in module sage.graphs.generators.smallgraphs), 1356
WienerArayaGraph() (sage.graphs.graph_generators.GraphGenerators static method), 999
WindmillGraph() (in module sage.graphs.generators.families), 1212
WindmillGraph()(sage.graphs.graph_generators.GraphGenerators static method), 1000
world_map (sage.graphs.graph_generators.GraphGenerators attribute), 1039
WorldMap()(inmodulesage.graphs.generators.world_map), 1359
WorldMap() (sage.graphs.graph_generators.GraphGenerators static method), 1001
write_to_eps() (sage.graphs.graph.Graph method),
662

W

Y

WagnerGraph() (in module sage.graphs.genera- yen_k_shortest_simple_paths() (in module
sage.graphs.path_enumeration), 1880
tors.smallgraphs), 1354
WagnerGraph() (sage.graphs.graph_generators.GraphGenerators static method), 996
WatkinsSnarkGraph() (in module sage.graphs.generators.smallgraphs), 1355
WatkinsSnarkGraph() (sage.graphs.graph_generators.GraphGenerators static method), 996
weighted() (sage.graphs.generic_graph.GenericGraphmethod), 427
weighted_adjacency_matrix()(sage.graphs.generic_graph.GenericGraphmethod), 428
WellsGraph() (in module sage.graphs.generators.smallgraphs), 1355
WellsGraph() (sage.graphs.graph_generators.GraphGenerators static method), 997
WheelGraph() (in module sage.graphs.generators.families), 1210
WheelGraph() (sage.graphs.graph_generators.GraphGenerators static method), 998
width_of_cut_decomposition() (in module
sage.graphs.graph_decompositions.cutwidth),1739
width_of_path_decomposition() (in module
sage.graphs.graph_decompositions.vertex_separation), 1727
width_of_tree_decomposition() (in module
sage.graphs.graph_decompositions.tree_decomposition), 1709
wiener_index()(inmodulesage.graphs.base.boost_graph), 1503
2000

Index