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:
| Return a new  | |
| Return an  | |
| 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  | |
| 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. | |
| 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  | |
| Return a random vertex of  | |
| Return an iterator over random vertices of  | |
| Return a random edge of  | |
| Return an iterator over random edges of  | |
| Return a list of all vertices in the external boundary of  | |
| 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  | |
| Return a list of the vertices. | |
| Return a list of neighbors (in and out if directed) of  | |
| Merge vertices. | |
| Add an edge from  | |
| Add edges from an iterable container. | |
| Subdivide an edge \(k\) times. | |
| Subdivide \(k\) times edges from an iterable container. | |
| Delete the edge from  | |
| Delete edges from an iterable container. | |
| Contract an edge from  | |
| Contract edges from an iterable container. | |
| Delete all edges from  | |
| Set the edge label of a given edge. | |
| Check whether  | |
| Return a  | |
| Return a list of edges  | |
| 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  | |
| Remove all multiple edges, retaining one edge for each. | |
| Empty the graph of vertices and edges and removes name, associated objects, and position 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 \(i\)-th 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  | |
| 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. | |
| 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  | |
| Return the union of  | |
| Relabel the vertices of  | |
| Return the number of edges from vertex to an edge in cell. | |
| Return the subgraph containing the given vertices and edges. | |
| Check whether  | 
Graph products:
| Return the Cartesian product of  | |
| Return the tensor product, also called the categorical product, of  | |
| Return the lexicographic product of  | |
| Return the strong product of  | |
| Return the disjunctive product of  | 
Paths and cycles:
| 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  | |
| Return a list of all paths (also lists) between a pair of vertices in the (di)graph. | |
| Return an iterator over the paths of  | |
| Return a list of all the simple paths of  | |
| Return the number of triangles in the (di)graph. | |
| Return an iterator over the simple paths between a pair of vertices. | 
Linear algebra:
| 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:
| Return the number of triangles for the set nbunch of vertices as a dictionary keyed by 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  | 
Automorphism group:
| Return the coarsest partition which is finer than the input partition, and equitable with respect to  | |
| 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  | |
| Test for isomorphism between  | |
| Return the canonical graph. | |
| Check whether the graph is a Cayley graph. | 
Graph properties:
| Return  | |
| Check whether the graph is planar. | |
| Check whether the graph is circular planar (outerplanar) | |
| Return  | |
| 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  | |
| Check whether the input (di)graph is geodetic. | |
| Check whether  | |
| Test whether the digraph is transitively reduced. | |
| Check whether the given partition is equitable with respect to  | |
| Check whether the graph is self-complementary. | 
Traversals:
| 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:
| Return the betweenness centrality | |
| Return 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 \(u\) to \(v\) | |
| 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 it exists. | |
| Return a dictionary of shortest path lengths keyed by targets that are connected by a path from u. | |
| Compute a shortest path between each pair of vertices. | |
| Return the Wiener index of the graph. | |
| Return the average distance between vertices of the graph. | 
Flows, connectivity, trees:
| 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. | |
| Check whether the input edge is a cut-edge or a bridge. | |
| 
 | Check whether the input edges form an edge cut. | 
| Check whether the input vertex is a cut-vertex. | |
| Check whether the input vertices form a vertex cut. | |
| Return a minimum edge cut between vertices \(s\) and \(t\) | |
| Return a minimum vertex cut between non-adjacent vertices \(s\) and \(t\) | |
| Return a maximum flow in the graph from  | |
| Return a \(k\)-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. | |
| Return a dominator tree of the graph. | |
| Iterator over the induced connected subgraphs of order at most \(k\) | 
Plot/embedding-related methods:
| Set a combinatorial embedding dictionary to  | |
| Return the attribute _embedding if it exists. | |
| Return the faces of an embedded graph. | |
| Return the number of faces of an embedded graph. | |
| Return the planar dual of an embedded graph. | |
| Return the position dictionary | |
| Set the position dictionary. | |
| Compute a planar layout of the graph using Schnyder’s algorithm. | |
| Check whether the position dictionary gives a planar embedding. | |
| Return an instance of  | |
| Set multiple options for rendering a graph with LaTeX. | |
| Return a layout for the vertices of this graph. | |
| Return a spring layout for this graph | |
| Return a ranked layout for this graph | |
| Extend randomly a partial layout | |
| Return a circular layout for this graph | |
| Return an ordered tree layout for this graph | |
| Return an ordered forest layout for this graph | |
| Call  | |
| 
 | Set some vertices on a circle in the embedding of this graph. | 
| 
 | Set some vertices on a line in the embedding of this graph. | 
| Return a  | |
| Return a  | |
| Show the (di)graph. | |
| Plot the graph in three dimensions. | |
| Plot the graph using  | |
| Return a representation in the  | |
| Write a representation in the  | |
| Return a  | 
Algorithmically hard stuff:
| 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  | |
| Return a longest path of  | |
| 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-\(k\) dominating set of the graph. | |
| Return the maximum leaf number of the graph. | |
| Return a copy of  | |
| Return the number of labelled occurrences of  | |
| Return an iterator over the labelled copies of  | |
| 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. | 
Miscellaneous
| Return the edge polytope of  | |
| Return the symmetric edge polytope of  | 
Methods¶
- class sage.graphs.generic_graph.GenericGraph[source]¶
- Bases: - GenericGraph_pyx- Base class for graphs and digraphs. - __eq__(other)[source]¶
- Compare - selfand- otherfor equality.- Do not call this method directly. That is, for - G.__eq__(H)write- G == H.- Two graphs are considered equal if the following hold: - they are either both directed, or both undirected 
- they have the same settings for loops, multiedges, and weightedness 
- they have the same set of vertices 
- they have the same (multi)set of arrows/edges, where labels of arrows/edges are taken into account if and only if the graphs are considered weighted. See - weighted().
 - Note that this is not an isomorphism test. - EXAMPLES: - sage: G = graphs.EmptyGraph() sage: H = Graph() sage: G == H True sage: G.to_directed() == H.to_directed() True sage: G = graphs.RandomGNP(8, .9999) sage: H = graphs.CompleteGraph(8) sage: G == H # random - most often true True sage: G = Graph({0: [1, 2, 3, 4, 5, 6, 7]} ) sage: H = Graph({1: [0], 2: [0], 3: [0], 4: [0], 5: [0], 6: [0], 7: [0]} ) sage: G == H True sage: G.allow_loops(True) sage: G == H False sage: G = graphs.RandomGNP(9, .3).to_directed() sage: H = graphs.RandomGNP(9, .3).to_directed() sage: G == H # most often false False sage: G = Graph(multiedges=True, sparse=True) sage: G.add_edge(0, 1) sage: H = copy(G) sage: H.add_edge(0, 1) 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() >>> 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)[source]¶
- Add a clique to the graph with the given vertices. - If the vertices are already present, only the edges are added. - INPUT: - vertices– an iterable container of vertices for the clique to be added, e.g. a list, set, graph, etc.
- loops– boolean (default:- False); whether to add edges from every given vertex to itself. This is allowed only if the (di)graph allows loops.
 - EXAMPLES: - sage: G = Graph() sage: G.add_clique(range(4)) sage: G.is_isomorphic(graphs.CompleteGraph(4)) True sage: D = DiGraph() sage: D.add_clique(range(4)) sage: D.is_isomorphic(digraphs.Complete(4)) True sage: D = DiGraph(loops=True) sage: D.add_clique(range(4), loops=True) sage: D.is_isomorphic(digraphs.Complete(4, loops=True)) True sage: D = DiGraph(loops=False) sage: D.add_clique(range(4), loops=True) Traceback (most recent call last): ... ValueError: cannot add edge from 0 to 0 in graph without loops - >>> 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)] - >>> 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)[source]¶
- Add a cycle to the graph with the given vertices. - If the vertices are already present, only the edges are added. - For digraphs, adds the directed cycle, whose orientation is determined by the list. Adds edges - (vertices[u], vertices[u+1])and- (vertices[-1], vertices[0]).- INPUT: - vertices– an ordered list of the vertices of the cycle to be added
 - EXAMPLES: - sage: G = Graph() sage: G.add_vertices(range(10)); G Graph on 10 vertices sage: show(G) # 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)[source]¶
- Add an edge from - uto- v.- INPUT: The following forms are all accepted: - G.add_edge( 1, 2 ) 
- G.add_edge( (1, 2) ) 
- G.add_edges( [ (1, 2) ]) 
- G.add_edge( 1, 2, ‘label’ ) 
- G.add_edge( (1, 2, ‘label’) ) 
- G.add_edges( [ (1, 2, ‘label’) ] ) 
 - WARNING: The following intuitive input results in nonintuitive output: - sage: G = Graph() sage: G.add_edge((1, 2), 'label') sage: G.edges(sort=False) [('label', (1, 2), None)] - >>> from sage.all import * >>> G = Graph() >>> G.add_edge((Integer(1), Integer(2)), 'label') >>> G.edges(sort=False) [('label', (1, 2), None)] - You must either use the - labelkeyword:- 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')] - 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)[source]¶
- 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 - loopsargument:- 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)[source]¶
- 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 - >>> 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)[source]¶
- 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.- namemust be an immutable object (e.g., an integer, a tuple, etc.).
 - As it is implemented now, if a graph \(G\) 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.- Noneotherwise- EXAMPLES: - sage: G = Graph(); G.add_vertex(); G 0 Graph on 1 vertex - >>> from sage.all import * >>> G = Graph(); G.add_vertex(); G 0 Graph on 1 vertex - sage: D = DiGraph(); D.add_vertex(); D 0 Digraph on 1 vertex - >>> from sage.all import * >>> D = DiGraph(); D.add_vertex(); D 0 Digraph on 1 vertex 
 - add_vertices(vertices)[source]¶
- 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- Nonevalues in- vertices.
 - OUTPUT: - Generated names of new vertices if there is at least one - Nonevalue present in- vertices.- Noneotherwise.- 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] 
 - adjacency_matrix(sparse, vertices=None, base_ring=None, **kwds)[source]¶
- 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 \(i\)-th row and column of the matrix correspond to the \(i\)-th vertex in the ordering of - vertices,
- when - None, the \(i\)-th row and column of the matrix correspond to the \(i\)-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’s basis is indexed by the vertices.
 - If the vertices are not comparable, the keyword - verticesmust be used to specify an ordering, or a- TypeErrorexception 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] [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 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] [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] [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 of Free module generated by {1, 2, 3, 4, 6, 12} over Integer Ring sage: print(phi._unicode_art_matrix()) 1 2 3 4 6 12 1⎛ 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 of Free module generated by {1, 2, 3, 4, 6, 12} over Integer Ring >>> print(phi._unicode_art_matrix()) 1 2 3 4 6 12 1⎛ 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)[source]¶
- Return the list of all paths between a pair of vertices. - If - startis the same vertex as- end, then- [[start]]is returned – a list containing the 1-vertex, 0-edge path “- start”.- If - Ghas 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 each edge as in- sage.graphs.generic_graph.GenericGraph.to_simple()if- report_edgesis- True
- If - True, a path will be reported as many times as the edges multiplicities along that path (when- report_edges = Falseor- labels = False), or with all possible combinations of edge labels (when- report_edges = Trueand- labels = True)
 
- report_edges– boolean (default:- False); whether to report paths as list of vertices (default) or list of edges, if- Falsethen- labelsparameter 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) 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], [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)[source]¶
- 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 all 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 entered at most once and exited at most once.
- max_length– nonnegative 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_edgesis- True
- If - True, a path will be reported as many times as the edges multiplicities along that path (when- report_edges = Falseor- labels = False), or with all possible combinations of edge labels (when- report_edges = Trueand- labels = True)
 
- report_edges– boolean (default:- False); whether to report paths as list of vertices (default) or list of edges, if- Falsethen- labelsparameter 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')] [(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'], 'c': ['d'], 'd': ['c']}, loops=True) sage: pi = g.all_paths_iterator() sage: [len(next(pi)) - 1 for _ in range(7)] [1, 1, 1, 1, 1, 2, 2] - >>> 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] [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'] ['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', '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', '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] - 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)) [['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', 'd'], ['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', '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] 
 - all_simple_paths(starting_vertices=None, ending_vertices=None, max_length=None, trivial=False, use_multiedges=False, report_edges=False, labels=False)[source]¶
- Return a list of all the simple paths of - selfstarting with one of the given vertices.- Simple paths are paths in which no two arcs share a head or share a tail, i.e. every vertex in the path is entered at most once and exited at most once. - INPUT: - starting_vertices– list (default:- None); 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 all vertices are allowed.
- max_length– nonnegative 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_edgesis- True
- If - True, a path will be reported as many times as the edges multiplicities along that path (when- report_edges = Falseor- labels = False), or with all possible combinations of edge labels (when- report_edges = Trueand- labels = True)
 
- report_edges– boolean (default:- False); whether to report paths as list of vertices (default) or list of edges, if- Falsethen- labelsparameter 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: - 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')]] 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'), (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) [[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)[source]¶
- Change whether loops are permitted in the (di)graph. - INPUT: - new– boolean
- check– boolean (default:- True); whether to remove existing loops from the (di)graph when the new status is- False
 - EXAMPLES: - sage: G = Graph(loops=True); G Looped graph on 0 vertices sage: G.has_loops() False sage: G.allows_loops() True sage: G.add_edge((0, 0)) sage: G.has_loops() True 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 >>> 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')[source]¶
- 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- Trueand- newis- False, we remove all multiple edges from the graph
- keep_label– string (default:- 'any'); used only if- newis- Falseand- checkis- 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- TypeErrormight be raised 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 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: - 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()[source]¶
- Return whether loops are permitted in the (di)graph. - EXAMPLES: - sage: G = Graph(loops=True); G Looped graph on 0 vertices sage: G.has_loops() False sage: G.allows_loops() True sage: G.add_edge((0, 0)) sage: G.has_loops() True sage: G.loops() [(0, 0, None)] sage: G.allow_loops(False); G Graph on 1 vertex sage: G.has_loops() False sage: G.edges(sort=True) [] sage: D = DiGraph(loops=True); D Looped digraph on 0 vertices sage: D.has_loops() False sage: D.allows_loops() True sage: D.add_edge((0, 0)) sage: D.has_loops() True sage: D.loops() [(0, 0, None)] sage: D.allow_loops(False); D Digraph on 1 vertex sage: D.has_loops() False sage: D.edges(sort=True) [] - >>> 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) [] 
 - allows_multiple_edges()[source]¶
- 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) [(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)[source]¶
- 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 \(i\)-th row and column of the matrix correspond to the \(i\)-th vertex in the ordering of - vertices,
- when - None, the \(i\)-th row and column of the matrix correspond to the \(i\)-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’s basis is indexed by the vertices.
 - If the vertices are not comparable, the keyword - verticesmust be used to specify an ordering, or a- TypeErrorexception 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] [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 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] [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] [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 of Free module generated by {1, 2, 3, 4, 6, 12} over Integer Ring sage: print(phi._unicode_art_matrix()) 1 2 3 4 6 12 1⎛ 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 of Free module generated by {1, 2, 3, 4, 6, 12} over Integer Ring >>> print(phi._unicode_art_matrix()) 1 2 3 4 6 12 1⎛ 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⎠ 
 - antisymmetric()[source]¶
- Check whether the graph is antisymmetric. - A graph represents an antisymmetric relation if the existence of a path from a vertex \(x\) to a vertex \(y\) implies that there is not a path from \(y\) to \(x\) unless \(x = y\). - 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 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() True 
 - automorphism_group(partition=None, verbosity=0, edge_labels=False, order=False, return_group=True, orbits=False, algorithm=None)[source]¶
- Return the automorphism group of the graph. - With - partitionthis can also return the largest subgroup of the automorphism group of the (di)graph whose orbit partition is finer than the partition given.- INPUT: - partition– default is the unit partition, otherwise computes the subgroup of the full automorphism group respecting the partition.
- edge_labels– (default:- False) whether to allow 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 these on 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() 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: - 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') # optional - bliss Permutation Group with generators [(1,4)(2,3)] 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)] >>> G.automorphism_group(edge_labels=True, algorithm='bliss') # optional - bliss Permutation Group with generators [(1,4)(2,3)] >>> 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.groups 120 - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> G.automorphism_group(return_group=False, order=True) # needs sage.groups 120 - 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 True 
 - average_degree()[source]¶
- Return the average degree of the graph. - The average degree of a graph \(G=(V,E)\) is equal to \(\frac{2|E|}{|V|}\). - EXAMPLES: - The average degree of a regular graph is equal to the degree of any vertex: - sage: g = graphs.CompleteGraph(5) sage: g.average_degree() == 4 True - >>> 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 \(\frac{2|E|}{|V|}\): - 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() True 
 - average_distance(by_weight=False, algorithm=None, weight_function=None, check_weight=True)[source]¶
- Return the average distance between vertices of the graph. - Formally, for a graph \(G\) this value is equal to \(\frac 1 {n(n-1)} \sum_{u,v\in G} d(u,v)\) where \(d(u,v)\) denotes the distance between vertices \(u\) and \(v\) and \(n\) is the number of vertices in \(G\). - For more information on the input variables and more examples, we refer to - wiener_index()and- shortest_path_all_pairs(), which have very similar input variables.- INPUT: - by_weight– boolean (default:- False); if- True, the edges in the graph are weighted, otherwise all edges have weight 1
- algorithm– string (default:- None); one of the algorithms available for method- wiener_index()
- weight_function– function (default:- None); a function that takes as input an edge- (u, v, l)and outputs its weight. If not- None,- by_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the weight_function outputs a number 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)[source]¶
- 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 that can be used for comparisons in the sorting algorithm (we must have- sort=True)
 - OUTPUT: - (B, C), where- Bis a list of blocks - each is a list of vertices and the blocks are the corresponding induced subgraphs - and- Cis 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 - 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: - 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)[source]¶
- 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 \(u\) of type B and a vertex \(v\) of type C if the cut-vertex corresponding to \(v\) is in the block corresponding to \(u\). - The resulting graph is a tree, with the additional characteristic property that the distance between two leaves is even. When - selfis not connected, the resulting graph is a forest.- When - selfis biconnected, the tree is reduced to a single node of type \(B\).- We referred to [HarPri] and [Gallai] for blocks and cuts tree. - EXAMPLES: - sage: from sage.graphs.connectivity import blocks_and_cuts_tree sage: T = blocks_and_cuts_tree(graphs.KrackhardtKiteGraph()); T Graph on 5 vertices sage: T.is_isomorphic(graphs.PathGraph(5)) True sage: from sage.graphs.connectivity import blocks_and_cuts_tree sage: T = graphs.KrackhardtKiteGraph().blocks_and_cuts_tree(); T Graph on 5 vertices - >>> 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 \(B\): - 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, forbidden_vertices=None)[source]¶
- Return an iterator over the vertices in a breadth-first ordering. - INPUT: - start– vertex or list of vertices from which to start the traversal
- ignore_direction– 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- startnodes to traverse. The- startnodes 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,- neighborsis by default the- neighbors()function. For a digraph, the- neighborsfunction defaults to the- neighbor_out_iterator()function of the graph.
- report_distance– boolean (default:- False); if- True, reports pairs- (vertex, distance)where- distanceis the distance from the- startnodes. If- Falseonly 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 - edgesand- report_distancecannot be- Truesimultaneously.
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search. The start vertex- vcannot be in this set.
 - 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_directionparameter:- 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] - You can specify a maximum distance in which to search. A distance of zero returns the - startvertices:- 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 - neighborsfunction. For example, you can traverse the graph backwards by setting- neighborsto be the- neighbors_in()function of the graph:- sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) sage: list(D.breadth_first_search(5, neighbors=D.neighbors_in, distance=2)) [5, 1, 2, 0] sage: list(D.breadth_first_search(5, neighbors=D.neighbors_out, distance=2)) [5, 7, 0] sage: list(D.breadth_first_search(5 ,neighbors=D.neighbors, distance=2)) [5, 1, 2, 7, 0, 4, 6] - >>> 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_distanceto 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() # 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 - edgesparameter:- 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)] - BFS in a graph with forbidden vertices: - sage: G = graphs.PetersenGraph() sage: list(G.breadth_first_search(0, forbidden_vertices=[1, 2])) [0, 4, 5, 3, 9, 7, 8, 6] - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> list(G.breadth_first_search(Integer(0), forbidden_vertices=[Integer(1), Integer(2)])) [0, 4, 5, 3, 9, 7, 8, 6] 
 - canonical_label(partition=None, certificate=False, edge_labels=False, algorithm=None, return_graph=True, immutable=None)[source]¶
- Return the canonical graph. - A canonical graph is the representative graph of an isomorphism class by some canonization function \(c\). If \(G\) and \(H\) are graphs, then \(G \cong c(G)\), and \(c(G) == c(H)\) if and only if \(G \cong H\). - See the Wikipedia article Graph_canonization for more information. - INPUT: - partition– if given, the canonical label with respect to this set partition will be computed. The default is the unit set partition.
- certificate– boolean (default:- False); when set to- True, a dictionary mapping from the vertices of the (di)graph to its canonical label will also be returned.
- edge_labels– boolean (default:- False); when set to- True, allows only permutations respecting edge labels
- algorithm– string (default:- None); the algorithm to use. Currently available:- 'bliss': use the optional package bliss (http://www.tcs.tkk.fi/Software/bliss/index.html);
- 'sage': always use Sage’s implementation.
- None(default): use bliss when available and possible- Note - Make sure you always compare canonical forms obtained by the same algorithm. 
 
- return_graph– boolean (default:- True); when set to- False, returns the list of edges of the canonical graph instead of the canonical graph; only available when- 'bliss'is explicitly set as algorithm.
- immutable– boolean (default:- None); whether to create a mutable/immutable (di)graph.- immutable=None(default) means that the (di)graph and its canonical (di)graph will behave the same way.
 - EXAMPLES: - Canonization changes isomorphism to equality: - sage: g1 = graphs.GridGraph([2,3]) sage: g2 = Graph({1: [2, 4], 3: [2, 6], 5: [4, 2, 6]}) sage: g1 == g2 False sage: g1.is_isomorphic(g2) True sage: g1.canonical_label() == g2.canonical_label() True - >>> 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: g Grid Graph for [2, 3]: Graph on 6 vertices sage: c {(0, 0): 3, (0, 1): 4, (0, 2): 2, (1, 0): 0, (1, 1): 5, (1, 2): 1} - >>> 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] [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) (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') # optional - bliss >>> g_sage.edges(sort=True, labels=False) [(0, 3), (1, 2)] >>> g_bliss.edges(sort=True, labels=False) # optional - bliss [(0, 1), (2, 3)] 
 - cartesian_product(other, immutable=None)[source]¶
- Return the Cartesian product of - selfand- other.- The Cartesian product of \(G\) and \(H\) is the graph \(L\) with vertex set \(V(L)\) equal to the Cartesian product of the vertices \(V(G)\) and \(V(H)\), and \(((u,v), (w,x))\) is an edge iff either - \((u, w)\) is an edge of self and \(v = x\), or - \((v, x)\) is an edge of other and \(u = w\). - INPUT: - other– a graph or a digraph
- immutable– boolean (default:- None); whether to create a mutable/immutable product.- immutable=None(default) means that the graphs and their product will behave the same way. If only one of them is immutable, the product will be mutable.
 - See also - is_cartesian_product()– factorization of graphs according to the Cartesian product
- graph_products– a module on graph products
 
 - categorical_product(other, immutable=None)[source]¶
- Return the tensor product of - selfand- other.- The tensor product of \(G\) and \(H\) is the graph \(L\) with vertex set \(V(L)\) equal to the Cartesian product of the vertices \(V(G)\) and \(V(H)\), and \(((u,v), (w,x))\) is an edge iff - \((u, w)\) is an edge of self, and - \((v, x)\) is an edge of other. - The tensor product is also known as the categorical product and the Kronecker product (referring to the Kronecker matrix product). See the Wikipedia article Kronecker_product. - INPUT: - other– a graph or a digraph
- immutable– boolean (default:- None); whether to create a mutable/immutable product.- immutable=None(default) means that the graphs and their product will behave the same way. If only one of them is immutable, the product will be mutable.
 - 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 - >>> 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)[source]¶
- 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 to its graph. Vertices that occur on more shortest paths between other vertices have higher betweenness than vertices that occur on less. - INPUT: - normalized– boolean (default:- True); if set to- False, result is not normalized
- k– integer (default:- None); if set to an integer, use- knode samples to estimate betweenness. Higher values give better approximations. Not available when- algorithm="Sage".
- weight– string (default:- None); if set to a string, use that attribute of the nodes as weight.- weight = Trueis equivalent to- weight = "weight". Not available when- algorithm="Sage".
- endpoints– boolean (default:- False); if set to- Trueit includes the endpoints in the shortest paths count. Not available when- algorithm="Sage".
- exact– boolean (default:- False); whether to compute over rationals or on- doubleC 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.
 - 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)], 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)[source]¶
- Return the closeness centrality of all vertices in - vert.- In a (strongly) connected graph, the closeness centrality of a vertex \(v\) is equal to the inverse of the average distance between \(v\) and other vertices. If the graph is disconnected, the closeness centrality of \(v\) is multiplied by the fraction of reachable vertices in the graph: this way, central vertices should also reach several other vertices in the graph [OLJ2014]. In formulas, \[c(v)=\frac{r(v)-1}{\sum_{w \in R(v)} d(v,w)}\frac{r(v)-1}{n-1}\]- where \(R(v)\) is the set of vertices reachable from \(v\), and \(r(v)\) is the cardinality of \(R(v)\). - ‘Closeness centrality may be defined as the total graph-theoretic distance of a given vertex from all other vertices… Closeness is an inverse measure of centrality in that a larger value indicates a less central actor while a smaller value indicates a more central actor,’ [Bor1995]. - For more information, see the Wikipedia article Centrality. - INPUT: - vert– the vertex or the list of vertices we want to analyze. If- None(default), all vertices are considered
- by_weight– boolean (default:- False); if- True, the edges in the graph are weighted, and otherwise all edges have weight 1
- algorithm– string (default:- None); one of the following algorithms:- 'BFS': performs a BFS from each vertex that has to be analyzed. Does not work with edge weights.
- 'NetworkX': the NetworkX algorithm (works only with positive weights).
- 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost (works only with positive weights).
- 'Floyd-Warshall-Cython': the Cython implementation of the Floyd-Warshall algorithm. Works only if- by_weight==Falseand 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_weightis- 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- las a weight, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the- weight_functionoutputs a number for each edge
 - OUTPUT: - If - vertis a vertex, the closeness centrality of that vertex. Otherwise, a dictionary associating to each vertex in- vertits closeness centrality. If a vertex has (out)degree 0, its closeness centrality is not defined, and the vertex is not included in the output.- 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} - In a (strongly) connected (di)graph, the closeness centrality of \(v\) is inverse of the average distance between \(v\) 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))) None - Weighted graphs: - sage: D = graphs.GridGraph([2,2]) sage: weight_function = lambda e:10 sage: D.centrality_closeness([(0,0),(0,1)]) # tol abs 1e-12 {(0, 0): 0.75, (0, 1): 0.75} sage: D.centrality_closeness((0,0), weight_function=weight_function) # tol abs 1e-12 0.075 - >>> 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)[source]¶
- Return the characteristic polynomial of the adjacency matrix of the (di)graph. - Let \(G\) be a (simple) graph with adjacency matrix \(A\). Let \(I\) be the identity matrix of dimensions the same as \(A\). The characteristic polynomial of \(G\) is defined as the determinant \(\det(xI - A)\). - Note - characteristic_polynomialand- charpolyare 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 - EXAMPLES: - sage: P = graphs.PetersenGraph() sage: P.characteristic_polynomial() # needs sage.modules x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48 sage: P.charpoly() # needs sage.modules x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48 sage: P.characteristic_polynomial(laplacian=True) # needs sage.modules x^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 - 39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x - >>> from sage.all import * >>> P = graphs.PetersenGraph() >>> P.characteristic_polynomial() # needs sage.modules x^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.modules x^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.modules x^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 - 39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x 
 - charpoly(var='x', laplacian=False)[source]¶
- Return the characteristic polynomial of the adjacency matrix of the (di)graph. - Let \(G\) be a (simple) graph with adjacency matrix \(A\). Let \(I\) be the identity matrix of dimensions the same as \(A\). The characteristic polynomial of \(G\) is defined as the determinant \(\det(xI - A)\). - Note - characteristic_polynomialand- charpolyare 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 - EXAMPLES: - sage: P = graphs.PetersenGraph() sage: P.characteristic_polynomial() # needs sage.modules x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48 sage: P.charpoly() # needs sage.modules x^10 - 15*x^8 + 75*x^6 - 24*x^5 - 165*x^4 + 120*x^3 + 120*x^2 - 160*x + 48 sage: P.characteristic_polynomial(laplacian=True) # needs sage.modules x^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 - 39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x - >>> from sage.all import * >>> P = graphs.PetersenGraph() >>> P.characteristic_polynomial() # needs sage.modules x^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.modules x^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.modules x^10 - 30*x^9 + 390*x^8 - 2880*x^7 + 13305*x^6 - 39882*x^5 + 77640*x^4 - 94800*x^3 + 66000*x^2 - 20000*x 
 - clear()[source]¶
- Empties the graph of vertices and edges and removes name, associated objects, and position information. - EXAMPLES: - sage: G = graphs.CycleGraph(4) sage: G.set_vertices({0:'vertex0'}) sage: print(G.order(), G.size()) 4 4 sage: G.name() 'Cycle graph' sage: G.get_vertex(0) 'vertex0' sage: H = G.copy(sparse=True) sage: H.clear() sage: print(H.order(), H.size()) 0 0 sage: H.name() '' sage: H.get_vertex(0) sage: H = G.copy(sparse=False) sage: H.clear() sage: print(H.order(), H.size()) 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()[source]¶
- Return the transitivity (fraction of transitive triangles) of the graph. - Transitivity is the fraction of all existing triangles over all connected triples (triads), \(T = 3\times\frac{\text{triangles}}{\text{triads}}\). - See also section “Clustering” in chapter “Algorithms” of [HSS]. - EXAMPLES: - sage: graphs.FruchtGraph().cluster_transitivity() # needs networkx 0.25 - >>> from sage.all import * >>> graphs.FruchtGraph().cluster_transitivity() # needs networkx 0.25 
 - cluster_triangles(nbunch=None, implementation=None)[source]¶
- Return the number of triangles for the set \(nbunch\) of vertices as a dictionary keyed by vertex. - See also section “Clustering” in chapter “Algorithms” of [HSS]. - INPUT: - nbunch– list of vertices (default:- None); the vertices to inspect. If- nbunch=None, returns data for all vertices in the graph.
- implementation– string (default:- None); one of- 'sparse_copy',- 'dense_copy',- 'networkx'or- None(default). In the latter case, the best algorithm available is used. Note that- 'networkx'does not support directed graphs.
 - EXAMPLES: - sage: F = graphs.FruchtGraph() sage: list(F.cluster_triangles().values()) [1, 1, 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 
 - clustering_average(implementation=None)[source]¶
- Return the average clustering coefficient. - The clustering coefficient of a node \(i\) is the fraction of existing triangles containing node \(i\) over all possible triangles containing \(i\): \(c_i = T(i) / \binom {k_i} 2\) where \(T(i)\) is the number of existing triangles through \(i\), and \(k_i\) is the degree of vertex \(i\). - A coefficient for the whole graph is the average of the \(c_i\). - See also section “Clustering” in chapter “Algorithms” of [HSS]. - INPUT: - implementation– string (default:- None); one of- 'boost',- 'sparse_copy',- 'dense_copy',- 'networkx'or- None(default). In the latter case, the best algorithm available is used. Note that only- 'networkx'supports directed graphs.
 - EXAMPLES: - sage: (graphs.FruchtGraph()).clustering_average() 1/4 sage: (graphs.FruchtGraph()).clustering_average(implementation='networkx') # 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)[source]¶
- Return the clustering coefficient for each vertex in - nodesas a dictionary keyed by vertex.- For an unweighted graph, the clustering coefficient of a node \(i\) is the fraction of existing triangles containing node \(i\) over all possible triangles containing \(i\): \(c_i = T(i) / \binom {k_i} 2\) where \(T(i)\) is the number of existing triangles through \(i\), and \(k_i\) is the degree of vertex \(i\). - 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 \(c_i\) is assigned \(0\) if \(k_i < 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 = Trueis 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 is used. Note that only- 'networkx'supports directed or weighted graphs, and that- 'sparse_copy'and- 'dense_copy'do not support- nodedifferent from- None
 - EXAMPLES: - sage: graphs.FruchtGraph().clustering_coeff() {0: 1/3, 1: 1/3, 2: 0, 3: 1/3, 4: 1/3, 5: 1/3, 6: 1/3, 7: 1/3, 8: 0, 9: 1/3, 10: 1/3, 11: 0} sage: # needs networkx sage: import numpy sage: if int(numpy.version.short_version[0]) > 1: ....: numpy.set_printoptions(legacy="1.25") sage: graphs.FruchtGraph().clustering_coeff(weight=True) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0, 3: 0.3333333333333333, 4: 0.3333333333333333, 5: 0.3333333333333333, 6: 0.3333333333333333, 7: 0.3333333333333333, 8: 0, 9: 0.3333333333333333, 10: 0.3333333333333333, 11: 0} sage: graphs.FruchtGraph().clustering_coeff(nodes=[0,1,2]) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0.0} sage: graphs.FruchtGraph().clustering_coeff(nodes=[0,1,2], # 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} >>> # needs networkx >>> import numpy >>> if int(numpy.version.short_version[Integer(0)]) > Integer(1): ... numpy.set_printoptions(legacy="1.25") >>> graphs.FruchtGraph().clustering_coeff(weight=True) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0, 3: 0.3333333333333333, 4: 0.3333333333333333, 5: 0.3333333333333333, 6: 0.3333333333333333, 7: 0.3333333333333333, 8: 0, 9: 0.3333333333333333, 10: 0.3333333333333333, 11: 0} >>> 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)[source]¶
- 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 \(C_1\), \(C_2\) of the partition, the number of edges from a vertex of \(C_1\) to \(C_2\) is the same, over all vertices in \(C_1\). - A partition \(P_1\) is finer than \(P_2\) (\(P_2\) is coarser than \(P_1\)) if every cell of \(P_1\) is a subset of a cell of \(P_2\). - INPUT: - partition– list of lists
- sparse– boolean (default:- False); whether to use sparse or dense representation - for small graphs, use dense for speed
 - EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.coarsest_equitable_refinement([[0],list(range(1,10))]) [[0], [2, 3, 6, 7, 8, 9], [1, 4, 5]] sage: G = graphs.CubeGraph(3) sage: verts = G.vertices(sort=True) sage: Pi = [verts[:1], verts[1:]] sage: Pi [['000'], ['001', '010', '011', '100', '101', '110', '111']] sage: [sorted(cell) for cell in G.coarsest_equitable_refinement(Pi)] [['000'], ['011', '101', '110'], ['111'], ['001', '010', '100']] - >>> 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) >>> 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(immutable=None)[source]¶
- 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. - INPUT: - immutable– boolean (default:- None); whether to return a mutable or an immutable version of- self. By default (- None), the graph and its complement behave the same.
 - 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() 0 sage: graphs.CycleGraph(4).complement().edges(sort=True) [(0, 2, None), (1, 3, None)] sage: graphs.CycleGraph(4).complement() complement(Cycle graph): Graph on 4 vertices sage: G = Graph(multiedges=True, sparse=True) sage: G.add_edges([(0, 1)] * 3) sage: G.complement() Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with multiedges. Perhaps this method can be updated to handle them, but in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). - >>> 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 with multiedges. Perhaps this method can be updated to handle them, but in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). 
 - connected_component_containing_vertex(G, vertex, sort=None, key=None, forbidden_vertices=None)[source]¶
- Return a list of the vertices connected to vertex. - INPUT: - G– the input graph
- vertex– 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 - keyis given); otherwise a warning is printed and- sort=Trueis 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 that can be used for comparisons in the sorting algorithm (we must have- sort=True)
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search. The start- vertexcannot be in this set.
 - 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: G.connected_component_containing_vertex(0, sort=True, forbidden_vertices=[1, 3]) [0] 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] >>> G.connected_component_containing_vertex(Integer(0), sort=True, forbidden_vertices=[Integer(1), Integer(3)]) [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)]}) >>> 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, forbidden_vertices=None)[source]¶
- 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- As of Issue #35889, this argument must be explicitly specified (unless a - keyis given); otherwise a warning is printed and- sort=Trueis 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 that can be used for comparisons in the sorting algorithm (we must have- sort=True)
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search
 - 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]] - Connected components in a graph with forbidden vertices: - sage: G = graphs.PathGraph(5) sage: connected_components(G, sort=True, forbidden_vertices=[2]) [[0, 1], [3, 4]] sage: connected_components(G, sort=True, ....: forbidden_vertices=G.neighbor_iterator(2, closed=True)) [[0], [4]] - >>> from sage.all import * >>> G = graphs.PathGraph(Integer(5)) >>> connected_components(G, sort=True, forbidden_vertices=[Integer(2)]) [[0, 1], [3, 4]] >>> connected_components(G, sort=True, ... forbidden_vertices=G.neighbor_iterator(Integer(2), closed=True)) [[0], [4]] 
 - connected_components_number(G, forbidden_vertices=None)[source]¶
- Return the number of connected components. - INPUT: - G– the input graph
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search
 - EXAMPLES: - sage: from sage.graphs.connectivity import connected_components_number sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: connected_components_number(G) 2 sage: G.connected_components_number() 2 sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: connected_components_number(D) 2 sage: connected_components_number(D, forbidden_vertices=[1, 3]) 3 - >>> 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) 2 >>> connected_components_number(D, forbidden_vertices=[Integer(1), Integer(3)]) 3 
 - connected_components_sizes(G, forbidden_vertices=None)[source]¶
- Return the sizes of the connected components as a list. - The list is sorted from largest to lower values. - INPUT: - G– the input graph
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search
 - EXAMPLES: - sage: from sage.graphs.connectivity import connected_components_sizes sage: for x in graphs(3): ....: print(connected_components_sizes(x)) [1, 1, 1] [2, 1] [3] [3] sage: for x in graphs(3): ....: print(x.connected_components_sizes()) [1, 1, 1] [2, 1] [3] [3] sage: G = graphs.PathGraph(5) sage: G.connected_components_sizes() [5] sage: G.connected_components_sizes(forbidden_vertices=[1]) [3, 1] sage: G.connected_components_sizes(forbidden_vertices=[1, 3]) [1, 1, 1] - >>> 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] >>> G = graphs.PathGraph(Integer(5)) >>> G.connected_components_sizes() [5] >>> G.connected_components_sizes(forbidden_vertices=[Integer(1)]) [3, 1] >>> G.connected_components_sizes(forbidden_vertices=[Integer(1), Integer(3)]) [1, 1, 1] 
 - connected_components_subgraphs(G, forbidden_vertices=None)[source]¶
- Return a list of connected components as graph objects. - INPUT: - G– the input graph
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search
 - 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: L = connected_components_subgraphs(G, forbidden_vertices=[1, 3]) 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 >>> L = connected_components_subgraphs(G, forbidden_vertices=[Integer(1), Integer(3)]) >>> 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 
 - connected_subgraph_iterator(G, k=None, vertices_only=False, edges_only=False, labels=False, induced=True, exactly_k=False)[source]¶
- Return an terator over the induced connected subgraphs of order at most \(k\). - 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 \to 1\) is considered connected.- INPUT: - G– a- Graphor 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- inducedis- True.
- edges_only– boolean (default:- False); whether to return (Di)Graph or list of edges. When- vertices_onlyis- True, this parameter is ignored.
- labels– boolean (default:- False); whether to return labeled edges or not. This parameter is used only when- vertices_onlyis- Falseand- edges_onlyis- 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- Falsefor simple (di)graphs only.
- exactly_k– boolean (default:- False);- Trueif we only return graphs of order \(k\),- Falseif we return graphs of order at most \(k\).
 - EXAMPLES: - sage: G = DiGraph([(1, 2), (2, 3), (3, 4), (4, 2)]) sage: list(G.connected_subgraph_iterator()) [Subgraph of (): Digraph on 1 vertex, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 3 vertices, Subgraph of (): Digraph on 4 vertices, Subgraph of (): Digraph on 3 vertices, Subgraph of (): Digraph on 1 vertex, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 3 vertices, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 1 vertex, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 1 vertex] sage: list(G.connected_subgraph_iterator(vertices_only=True)) [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]] sage: list(G.connected_subgraph_iterator(k=2)) [Subgraph of (): Digraph on 1 vertex, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 1 vertex, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 1 vertex, Subgraph of (): Digraph on 2 vertices, Subgraph of (): Digraph on 1 vertex] sage: list(G.connected_subgraph_iterator(k=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))) 6 sage: len(list(G.connected_subgraph_iterator(edges_only=True))) 6 sage: 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], [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)[source]¶
- Contract an edge from - uto- 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’ ) 
- 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)[source]¶
- Contract edges from an iterable container. - If \(e\) is an edge that is not contracted but the vertices of \(e\) are merged by contraction of other edges, then \(e\) will become a loop. - INPUT: - edges– list containing 2-tuples or 3-tuples that represent edges
 - EXAMPLES: - sage: G = graphs.CompleteGraph(4) sage: G.allow_loops(True); G.allow_multiple_edges(True) sage: G.contract_edges([(0, 1), (1, 2), (0, 2)]); G.edges(sort=True) [(0, 3, None), (0, 3, None), (0, 3, None)] sage: G.contract_edges([(1, 3), (2, 3)]); G.edges(sort=True) [(0, 3, None), (0, 3, None), (0, 3, None)] sage: G = graphs.CompleteGraph(4) sage: G.allow_loops(True); G.allow_multiple_edges(True) sage: G.contract_edges([(0, 1), (1, 2), (0, 2), (1, 3), (2, 3)]); G.edges(sort=True) [(0, 0, None)] - >>> 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)] 
 - copy(weighted=None, data_structure=None, sparse=None, immutable=None, hash_labels=None)[source]¶
- 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=Trueis an alias for- data_structure="sparse", and- sparse=Falseis 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- Graphor- 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=Trueis a shortcut for- data_structure='static_sparse'
- immutable=Falsemeans that the created graph is mutable. When used to copy an immutable graph, 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- Trueif the graph is weighted. This parameter is ignored when parameter- immutableis not- True. Beware that trying to hash unhashable labels will raise an error.
 - Note - If the graph uses - StaticSparseBackendand the- _immutableflag, then- selfis 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 - weightedis passed and is not the weightedness of the original, then the copy will not equal the original.- EXAMPLES: - sage: g = Graph({0: [0, 1, 1, 2]}, loops=True, multiedges=True, sparse=True) sage: g == copy(g) True sage: g = DiGraph({0: [0, 1, 1, 2], 1: [0, 1]}, loops=True, multiedges=True, sparse=True) sage: g == copy(g) True - >>> from sage.all import * >>> g = Graph({Integer(0): [Integer(0), Integer(1), Integer(1), Integer(2)]}, 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)) >>> 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 - weightedaffects 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()[source]¶
- Return the crossing number of the graph. - The crossing number of a graph is the minimum number of edge crossings needed to draw the graph on a plane. It can be seen as a measure of non-planarity; a planar graph has crossing number zero. - See the Wikipedia article Crossing_number for more information. - EXAMPLES: - sage: P = graphs.PetersenGraph() sage: P.crossing_number() 2 - >>> from sage.all import * >>> P = graphs.PetersenGraph() >>> P.crossing_number() 2 - ALGORITHM: - This is slow brute force implementation: for every \(k\) 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 \(k+1\) pairs. - Computing the crossing number is NP-hard problem. 
 - cycle_basis(output='vertex')[source]¶
- 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 \(Z/2Z\) sum of the cycles in the basis. - See the Wikipedia article Cycle_basis for more information. - INPUT: - output– string (default:- 'vertex'); whether every cycle is given as a list of vertices (- output == 'vertex') or a list of edges (- output == 'edge')
 - OUTPUT: - A list of lists, each of them representing the vertices (or the edges) of a cycle in a basis. - ALGORITHM: - Uses the NetworkX library for graphs without multiple edges. - Otherwise, by the standard algorithm using a spanning tree. - EXAMPLES: - A cycle basis in Petersen’s Graph - sage: g = graphs.PetersenGraph() sage: g.cycle_basis() # needs networkx, random (changes in networkx 3.2) [[6, 8, 5, 7, 9], [2, 3, 8, 5, 7], [4, 3, 8, 5, 7, 9], [4, 0, 5, 7, 9], [2, 1, 0, 5, 7], [6, 1, 0, 5, 7, 9]] - >>> from sage.all import * >>> g = graphs.PetersenGraph() >>> g.cycle_basis() # needs networkx, random (changes in networkx 3.2) [[6, 8, 5, 7, 9], [2, 3, 8, 5, 7], [4, 3, 8, 5, 7, 9], [4, 0, 5, 7, 9], [2, 1, 0, 5, 7], [6, 1, 0, 5, 7, 9]] - 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) [[(6, 8, None), (8, 5, None), (5, 7, None), (7, 9, None), (9, 6, None)], [(2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None), (7, 2, None)], [(4, 3, None), (3, 8, None), (8, 5, None), (5, 7, None), (7, 9, None), (9, 4, None)], [(4, 0, None), (0, 5, None), (5, 7, None), (7, 9, None), (9, 4, None)], [(2, 1, None), (1, 0, None), (0, 5, None), (5, 7, None), (7, 2, None)], [(6, 1, None), (1, 0, None), (0, 5, None), (5, 7, None), (7, 9, None), (9, 6, None)]] - >>> from sage.all import * >>> g.cycle_basis(output='edge') # needs networkx, random (changes in networkx 3.2) [[(6, 8, None), (8, 5, None), (5, 7, None), (7, 9, None), (9, 6, None)], [(2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None), (7, 2, None)], [(4, 3, None), (3, 8, None), (8, 5, None), (5, 7, None), (7, 9, None), (9, 4, None)], [(4, 0, None), (0, 5, None), (5, 7, None), (7, 9, None), (9, 4, None)], [(2, 1, None), (1, 0, None), (0, 5, None), (5, 7, None), (7, 2, None)], [(6, 1, None), (1, 0, None), (0, 5, None), (5, 7, None), (7, 9, None), (9, 6, 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 \(Z/2Z\). On the way, building a dictionary associating a unique vector to each undirected edge: - sage: m = g.size() sage: edge_space = VectorSpace(FiniteField(2), m) # 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)) - >>> 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), 'b'), (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]] - 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')] # 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), 'c'), (Integer(1), Integer(2), 'd')]) >>> G.cycle_basis() Traceback (most recent call last): ... NotImplementedError: not implemented for directed graphs 
 - degree(vertices=None, labels=False)[source]¶
- 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- verticesis a single vertex, returns the number of neighbors of that vertex. If- verticesis an iterable container of vertices, returns a list of degrees. If- verticesis- None, same as listing all vertices.
- labels– boolean (default:- False); when- True, return a dictionary mapping each vertex in- verticesto its degree. Otherwise, return the degree of a single vertex or a list of the degrees of each vertex in- vertices
 - OUTPUT: - When - verticesis a single vertex and- labelsis- False, returns the degree of that vertex as an integer
- When - verticesis an iterable container of vertices (or- None) and- labelsis- False, returns a list of integers. The \(i\)-th value is the degree of the \(i\)-th vertex in the list- vertices. When- verticesis- None, the \(i\)-th value is the degree of \(i\)-th vertex in the ordering- list(self), which might be different from the ordering of the vertices given by- g.vertices(sort=True).
- When - labelsis- True, returns a dictionary mapping each vertex in- verticesto its degree
 - EXAMPLES: - sage: P = graphs.PetersenGraph() sage: P.degree(5) 3 - >>> from sage.all import * >>> P = graphs.PetersenGraph() >>> P.degree(Integer(5)) 3 - sage: 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=Noneand- labels=False, the \(i\)-th value of the returned list is the degree of the \(i\)-th vertex in the list- list(self):- sage: # needs sage.combinat sage: D = digraphs.DeBruijn(4, 2) sage: D.delete_vertex('20') sage: print(D.degree()) [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] sage: print(D.degree(vertices=list(D))) [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] sage: print(D.degree(vertices=D.vertices(sort=False))) [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] - >>> 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()[source]¶
- Return a list, whose \(i\)-th entry is the frequency of degree \(i\). - 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)[source]¶
- 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- verticesis a single vertex, the iterator will yield the number of neighbors of that vertex. If- verticesis an iterable container of vertices, return an iterator over the degrees of these vertices. If- verticesis- None, same as listing all vertices.
- labels– boolean (default:- False); whether to return an iterator over degrees (- labels=False), or over tuples- (vertex, degree)
 - Note - The returned iterator yields values in order specified by - list(vertices). When- verticesis- None, it yields values in the same order as- list(self), which might be different from the ordering of the vertices given by- g.vertices(sort=True).- EXAMPLES: - sage: G = graphs.Grid2dGraph(3, 4) sage: for i in G.degree_iterator(): ....: print(i) 2 3 3 ... 3 2 sage: for i in G.degree_iterator(labels=True): ....: print(i) ((0, 0), 2) ((0, 1), 3) ((0, 2), 3) ... ((2, 2), 3) ((2, 3), 2) - >>> 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) ... ((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=Noneyields 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()[source]¶
- Return the degree sequence of this (di)graph. - EXAMPLES: - The degree sequence of an undirected graph: - sage: g = Graph({1: [2, 5], 2: [1, 5, 3, 4], 3: [2, 5], 4: [3], 5: [2, 3]}) sage: g.degree_sequence() [4, 3, 3, 2, 2] - >>> 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)[source]¶
- Return 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)) >>> 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)[source]¶
- Delete the edge from - uto- 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)) >>> 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 sage: C.has_edge( (4, 5, 'label') ) # correct! False - >>> 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)[source]¶
- 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)[source]¶
- Delete all edges from - uto- v.- EXAMPLES: - sage: G = Graph(multiedges=True, sparse=True) sage: G.add_edges([(0, 1), (0, 1), (0, 1), (1, 2), (2, 3)]) sage: G.edges(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)[source]¶
- 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 \(i\)-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 - >>> 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 graph - sage: G = graphs.CompleteGraph(4).line_graph(labels=False) sage: G.vertices(sort=True) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] sage: G.delete_vertex(0, in_order=True) sage: G.vertices(sort=True) [(0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] sage: G = graphs.PathGraph(5) sage: G.set_vertices({0: 'no delete', 1: 'delete'}) sage: G.delete_vertex(1) sage: G.get_vertices() {0: 'no delete', 2: None, 3: None, 4: None} sage: G.get_pos() {0: (0, 0), 2: (2, 0), 3: (3, 0), 4: (4, 0)} - >>> 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() {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)[source]¶
- 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 - verticesis deleted.- 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 graph 
 - density()[source]¶
- 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 - >>> 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, forbidden_vertices=None)[source]¶
- 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,- neighborsis by default the- neighbors()function. For a digraph, the- neighborsfunction 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.
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search. The start vertex- vcannot be in this set.
 - See also 
- 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)], 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_directionparameter:- 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 - neighborsfunction. For example, you can traverse the graph backwards by setting- neighborsto 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] 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 - edgesparameter:- 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)] - DFS in a graph with forbidden vertices: - sage: G = graphs.PetersenGraph() sage: list(G.depth_first_search(0, forbidden_vertices=[1, 2])) [0, 5, 8, 6, 9, 7, 4, 3] - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> list(G.depth_first_search(Integer(0), forbidden_vertices=[Integer(1), Integer(2)])) [0, 5, 8, 6, 9, 7, 4, 3] 
 - disjoint_routed_paths(pairs, solver, verbose=None, integrality_tolerance=0)[source]¶
- Return a set of disjoint routed paths. - Given a set of pairs \((s_i,t_i)\), a set of disjoint routed paths is a set of \(s_i-t_i\) paths which can intersect at their endpoints and are vertex-disjoint otherwise. - INPUT: - pairs– list of pairs of vertices
- solver– string (default:- None); specifies 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- solveof 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 - >>> 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)[source]¶
- Return the disjoint union of - selfand- other.- INPUT: - labels– string (default:- 'pairs'); if set to- 'pairs', each element- vin the first graph will be named- (0, v)and each element- uin- otherwill be named- (1, u)in the result. If set to- 'integers', the elements of the result will be relabeled with consecutive integers.
- immutable– boolean (default:- None); whether to create a mutable/immutable disjoint union.- immutable=None(default) means that the graphs and their disjoint union will behave the same way.
 - 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] - >>> 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 path' sage: H = graphs.CycleGraph(3) sage: J = G.disjoint_union(H); J Custom path disjoint_union Cycle graph: Graph on 5 vertices sage: J.vertices(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, immutable=None)[source]¶
- Return the disjunctive product of - selfand- other.- The disjunctive product of \(G\) and \(H\) is the graph \(L\) with vertex set \(V(L)=V(G)\times V(H)\), and \(((u,v), (w,x))\) is an edge iff either : - \((u, w)\) is an edge of \(G\), or 
- \((v, x)\) is an edge of \(H\). 
 - INPUT: - other– a graph or a digraph
- immutable– boolean (default:- None); whether to create a mutable/immutable product.- immutable=None(default) means that the graphs and their product will behave the same way. If only one of them is immutable, the product will be mutable.
 - 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 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)[source]¶
- Return the (directed) distance from - uto- vin the (di)graph.- The distance is the length of the shortest path from - uto- 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); whether to check that the- weight_functionoutputs a number for each edge
 - EXAMPLES: - sage: G = graphs.CycleGraph(9) sage: G.distance(0,1) 1 sage: G.distance(0,4) 4 sage: G.distance(0,5) 4 sage: G = Graph({0:[], 1:[]}) sage: G.distance(0,1) +Infinity sage: G = Graph({ 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, sparse = True) sage: G.plot(edge_labels=True).show() # long time # needs sage.plot 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)[source]¶
- Return the distances between all pairs of vertices. - INPUT: - by_weight– boolean (default:- False); if- True, the edges in the graph are weighted. If- False, all edges have weight 1.
- algorithm– string (default:- None); one of the following algorithms:- 'BFS': the computation is done through a BFS centered on each vertex successively. Works only if- by_weight==False.
- 'Floyd-Warshall-Cython': the Cython implementation of the Floyd-Warshall algorithm. Works only if- by_weight==False.
- 'Floyd-Warshall-Python': the Python implementation of the Floyd-Warshall algorithm. Works also with weighted graphs, even with negative weights (but no negative cycle is allowed).
- 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX. It works with weighted graphs, but no negative weight is allowed.
- 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost (works only with positive weights).
- 'Johnson_Boost': the Johnson algorithm, implemented in Boost (works also with negative weights, if there is no negative cycle).
- None(default): Sage chooses the best algorithm:- 'BFS'if- by_weightis- False,- 'Dijkstra_Boost'if all weights are positive,- 'Floyd-Warshall-Cython'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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); whether to check that the- weight_functionoutputs a number for each edge
 - OUTPUT: a doubly indexed dictionary - Note - There is a Cython version of this method that is usually much faster for large graphs, as most of the time is actually spent building the final double dictionary. Everything on the subject is to be found in the - distances_all_pairsmodule.- 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 - >>> 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 
 - distance_matrix(vertices, base_ring=None, **kwds)[source]¶
- 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- verticesis set, the position of the vertices in this ordering is used. The intersection of row \(i\) and column \(j\) contains the shortest path distance from the vertex at the \(i\)-th position to the vertex at the \(j\)-th position.- Note that even when the vertices are consecutive integers starting from one, usually the vertex is not equal to its index. - INPUT: - vertices– list (default:- None); the ordering of the vertices defining how they should appear in the matrix. By default, the ordering given by- vertices()is used. Because- vertices()only works if the vertices can be sorted, using- verticesis 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] [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 of order \(n\) is \((-1)^{n-1}(n-1)2^{n-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.
 
 - distances_distribution(G)[source]¶
- 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 - dsuch that the number of pairs of vertices at distance- k(if any) is equal to \(d[k] \cdot |V(G)| \cdot (|V(G)|-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 \((v, v)\) at distance \(0\) into account. Empty (di)graphs and (di)graphs of order 1 have no paths and so we return the empty dictionary - {}.- EXAMPLES: - An empty Graph: - sage: g = Graph() sage: g.distances_distribution() {} - >>> 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: - 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)[source]¶
- Return a minimum distance-\(k\) dominating set of the graph. - A minimum dominating set \(S\) of a graph \(G\) is a set of its vertices of minimal cardinality such that any vertex of \(G\) is in \(S\) or has one of its neighbors in \(S\). See the Wikipedia article Dominating_set. - A minimum distance-\(k\) dominating set is a set \(S\) of vertices of \(G\) of minimal cardinality such that any vertex of \(G\) is in \(S\) or at distance at most \(k\) from a vertex in \(S\). A distance-\(0\) dominating set is the set of vertices itself, and when \(k\) is the radius of the graph, any vertex dominates all the other vertices. - As an optimization problem, it can be expressed as follows, where \(N^k(u)\) denotes the set of vertices at distance at most \(k\) from \(u\) (the set of neighbors when \(k=1\)): \[\begin{split}\mbox{Minimize : }&\sum_{v\in G} b_v\\ \mbox{Such that : }&\forall v \in G, b_v+\sum_{u \in N^k(v)} b_u\geq 1\\ &\forall x\in G, b_x\mbox{ is a binary variable}\end{split}\]- INPUT: - k– nonnegative 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); specifies 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- solveof 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)) # 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 2 >>> g = graphs.PathGraph(Integer(3)) >>> g.dominating_set(value_only=True) # needs sage.numerical.mip 1 - Cardinality of distance-\(k\) 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] 
 - dominating_sets(g, k, independent=1, total=False, connected=False, solver=False, verbose=None, integrality_tolerance=0)[source]¶
- Return an iterator over the minimum distance-\(k\) dominating sets of the graph. - A minimum dominating set \(S\) of a graph \(G\) is a set of its vertices of minimal cardinality such that any vertex of \(G\) is in \(S\) or has one of its neighbors in \(S\). See the Wikipedia article Dominating_set. - A minimum distance-\(k\) dominating set is a set \(S\) of vertices of \(G\) of minimal cardinality such that any vertex of \(G\) is in \(S\) or at distance at most \(k\) from a vertex in \(S\). A distance-\(0\) dominating set is the set of vertices itself, and when \(k\) is the radius of the graph, any vertex dominates all the other vertices. - As an optimization problem, it can be expressed as follows, where \(N^k(u)\) denotes the set of vertices at distance at most \(k\) from \(u\) (the set of neighbors when \(k=1\)): \[\begin{split}\mbox{Minimize : }&\sum_{v\in G} b_v\\ \mbox{Such that : }&\forall v \in G, b_v+\sum_{u \in N^k(v)} b_u\geq 1\\ &\forall x\in G, b_x\mbox{ is a binary variable}\end{split}\]- We use constraints generation to iterate over the minimum distance-\(k\) dominating sets. That is, after reporting a solution, we add a constraint to discard it and solve the problem again until no more solution can be found. - INPUT: - k– nonnegative 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 (see Wikipedia article Connected_dominating_set)
- solver– string (default:- None); specifies 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- solveof 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-\(k\) 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 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], [3, 5, 6], [4, 6, 7]] - Independent distance-\(k\) 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: - 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]] - >>> 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)[source]¶
- Use Boost to compute the dominator tree of - g, rooted at- root.- A node \(d\) dominates a node \(n\) if every path from the entry node - rootto \(n\) must go through \(d\). The immediate dominator of a node \(n\) is the unique node that strictly dominates \(n\) but does not dominate any other node that dominates \(n\). 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 \(v\) is: - the root if \(v\) is in the same biconnected component as the root; 
- the first cut vertex in a path from \(v\) to the root, otherwise. 
 - If the graph is not connected, the dominator tree of the whole graph is equal to the dominator tree of the connected component of the root. - If the graph is directed, computing a dominator tree is more complicated, and it needs time \(O(m\log m)\), where \(m\) is the number of edges. The implementation provided by Boost is the most general one, so it needs time \(O(m\log m)\) even for undirected graphs. - INPUT: - g– the input Sage (Di)Graph
- root– the root of the dominator tree
- return_dict– boolean (default:- False); if- True, the function returns a dictionary associating to each vertex its parent in the dominator tree. If- False(default), it returns the whole tree, as a- 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- Nonein correspondence of- rootand 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 \(C_1,C_2\) connected by an edge \((v,w)\), with \(v \in C_1\), \(w \in C_2\), the cut vertices are \(v\) and \(w\), the biconnected components are \(C_1\), \(C_2\), and the edge \((v,w)\). If the root is in \(C_1\), the parent of each vertex in \(C_1\) is the root, the parent of \(w\) is \(v\), and the parent of each vertex in \(C_2\) is \(w\): - 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)[source]¶
- Return a list of edges - (u,v,l)with- uin- vertices1and- vin- vertices2.- If - vertices2is- None, then it is set to the complement of- vertices1.- In a digraph, the external boundary of a vertex \(v\) are those vertices \(u\) with an arc \((v, u)\). - INPUT: - labels– boolean (default:- True); if- False, each edge is a tuple \((u,v)\) 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 value that 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)] >>> D.edge_boundary([Integer(0)], labels=False, sort=True) [(0, 1), (0, 2)] - Using the - keyargument 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)[source]¶
- 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 \(k\)-connected if there are \(k\) disjoint paths between any two vertices \(u, v\)). If you do not want to consider strong connectivity, the best is probably to convert your - DiGraphobject 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.
- 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); specifies 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- solveof 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) 3 sage: 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) >>> 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=Trueand- 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() >>> 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.0 sage: edge_connectivity(g, implementation='boost') 1 sage: g.add_edge(1, 0) sage: edge_connectivity(g) 0.0 sage: edge_connectivity(g, implementation='boost') 0 - >>> 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') 0 
 - edge_cut(s, t, value_only, use_edge_labels=True, vertices=False, algorithm=False, solver='FF', verbose=None, integrality_tolerance=0)[source]¶
- Return a minimum edge cut between vertices \(s\) and \(t\). - A minimum edge cut between two vertices \(s\) and \(t\) of - selfis a set \(A\) of edges of minimum weight such that the graph obtained by removing \(A\) from the graph is disconnected. For more information, see the Wikipedia article Cut_(graph_theory).- INPUT: - s– source vertex
- t– sink vertex
- value_only– boolean (default:- True); whether to return only the weight of a minimum cut (- True) or a list of edges of a minimum cut (- False)
- use_edge_labels– boolean (default:- False); whether to compute a weighted minimum edge cut where the weight of an edge is defined by its label (if an edge has no label, \(1\) is assumed), or to compute a cut of minimum cardinality (i.e., edge weights are set to 1)
- vertices– boolean (default:- False); whether set to- True, return a list of edges in the edge cut and the two sets of vertices that are disconnected by the cut- Note: - vertices=Trueimplies- value_only=False.
- algorithm– string (default:- 'FF'); algorithm to use:- If - algorithm = "FF", a Python implementation of the Ford-Fulkerson algorithm is used
- If - algorithm = "LP", the problem is solved using Linear Programming.
- If - algorithm = "igraph", the igraph implementation of the Goldberg-Tarjan algorithm is used (only available when- igraphis installed)
- If - algorithm = None, the problem is solved using the default maximum flow algorithm (see- flow())
 
- solver– string (default:- None); specifies 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- solveof the class- MixedIntegerLinearProgram.
- verbose– integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
- integrality_tolerance– float; parameter for use with MILP solvers over an inexact base ring; see- MixedIntegerLinearProgram.get_values().
 - Note - The use of Linear Programming for non-integer problems may possibly mean the presence of a (slight) numerical noise. - OUTPUT: - Real number or tuple, depending on the given arguments (examples are given below). - EXAMPLES: - A basic application in the Pappus graph: - sage: g = graphs.PappusGraph() sage: g.edge_cut(1, 2, value_only=True) 3 - >>> 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]) == minimum True - >>> 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() True 
 - edge_disjoint_paths(s, t, algorithm, solver='FF', verbose=None, integrality_tolerance=False)[source]¶
- 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 \(s\) and`t` (the minimum number of edges whose removal disconnects \(s\) and \(t\)) is equal to the maximum number of pairwise edge-independent paths from \(s\) to \(t\). - 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); specifies 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- solveof the class- MixedIntegerLinearProgram.- Only used when - algorithmis- 'LP'.
- verbose– integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.- Only used when - algorithmis- 'LP'.
- integrality_tolerance– float; parameter for use with MILP solvers over an inexact base ring; see- MixedIntegerLinearProgram.get_values().- Only used when - algorithmis- 'LP'.
 - Note - This function is topological: it does not take the eventual weights of the edges into account. - EXAMPLES: - In a complete bipartite graph - sage: g = graphs.CompleteBipartiteGraph(2, 3) sage: g.edge_disjoint_paths(0, 1) [[0, 2, 1], [0, 3, 1], [0, 4, 1]] - >>> 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)[source]¶
- 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 finding edge-disjoint spanning-trees in undirected simple graphs in time \(O(m\log{m} + k^2n^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 to- None, the first vertex in the graph is picked.
- solver– string (default:- None); specifies 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- solveof 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: - EXAMPLES: - The Petersen Graph does have a spanning tree (it is connected): - 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(|V|-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 \(k\)-connected always has \(k\) 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 time True sage: all(a.is_connected() for a in arborescences) # long time True - >>> 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')) ... 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 time True >>> all(a.is_connected() for a in arborescences) # long time True - 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') >>> 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 - >>> 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)[source]¶
- Return an iterator over edges. - The iterator returned is over the edges incident with any vertex given in the parameter - vertices. If the graph is directed, iterates over edges going out only. If- verticesis- None, then returns an iterator over all edges. If- selfis 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 is a tuple \((u,v)\) of vertices
- ignore_direction– boolean (default:- False); only applies to directed graphs. If- True, searches across edges in either direction.
- sort_vertices– boolean (default:- True); only applies to undirected graphs. If- True, sort the ends of the edges. Not sorting the ends is faster.
 - Note - It is somewhat safe to modify the graph during iterating. - verticesmust 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) (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)[source]¶
- Return the label of an edge. - If the graph allows multiple edges, then the list of labels on the edges is returned. - See also - EXAMPLES: - sage: G = Graph({0: {1: 'edgelabel'}}) sage: G.edge_label(0, 1) 'edgelabel' sage: D = DiGraph({1: {2: 'up'}, 2: {1: 'down'}}) sage: D.edge_label(2, 1) '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)) 'down' - sage: G = Graph(multiedges=True) sage: [G.add_edge(0, 1, i) for i in range(1, 6)] [None, None, None, None, None] sage: sorted(G.edge_label(0, 1)) [1, 2, 3, 4, 5] - >>> 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()[source]¶
- 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)[source]¶
- Return the edge polytope of - self.- The edge polytope (EP) of a Graph on \(n\) vertices is the polytope in \(\ZZ^{n}\) defined as the convex hull of \(e_i + e_j\) for each edge \((i, j)\). Here \(e_1, \dots, e_n\) denotes the standard basis. - INPUT: - backend– string or- None(default); the backend to use; see- sage.geometry.polyhedron.constructor.Polyhedron()
 - EXAMPLES: - The EP of a \(4\)-cycle is a square: - sage: G = graphs.CycleGraph(4) sage: P = G.edge_polytope(); P # 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.polyhedron sage: P1 = G1.edge_polytope() # needs networkx sage.geometry.polyhedron sage: P2 = G2.edge_polytope() # needs networkx sage.geometry.polyhedron sage: 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 \(n\) 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.polyhedron sage: P2 = G2.edge_polytope() # needs sage.geometry.polyhedron sage: 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): # 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.polyhedron 19 - >>> 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)[source]¶
- Return a - EdgesViewof edges.- Each edge is a triple - (u, v, l)where- uand- vare vertices and- lis a label. If the parameter- labelsis- Falsethen a list of couple- (u, v)is returned where- uand- vare vertices.- The returned - EdgesViewis over the edges incident with any vertex given in the parameter- vertices(all edges if- None). If- selfis directed, iterates over outgoing edges only, unless parameter- ignore_directionis- Truein 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 the- labelskeyword) as its one argument and returns a value that can be used for comparisons in the sorting algorithm
- ignore_direction– boolean (default:- False); only applies to directed graphs. If- True, searches across edges in either direction.
- sort_vertices– boolean (default:- True); only applies to undirected graphs. If- True, sort the ends of the edges. Not sorting the ends is faster.
 - OUTPUT: a - EdgesView- Warning - Since any object may be a vertex, there is no guarantee that any two vertices will be comparable, and thus no guarantee how two edges may compare. With default objects for vertices (all integers), or when all the vertices are of the same simple type, then there should not be a problem with how the vertices will be sorted. However, if you need to guarantee a total order for the sorting of the edges, use the - keyargument, 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), (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 overridden by specifying a key function. This first example just ignores the labels in the third component of the triple: - sage: G = graphs.CycleGraph(5) sage: G.edges(sort=True, key=lambda x: (x[1], -x[0])) [(0, 1, None), (1, 2, None), (2, 3, None), (3, 4, None), (0, 4, None)] - >>> from sage.all import * >>> G = graphs.CycleGraph(Integer(5)) >>> G.edges(sort=True, key=lambda x: (x[Integer(1)], -x[Integer(0)])) [(0, 1, None), (1, 2, None), (2, 3, None), (3, 4, None), (0, 4, None)] - We set the labels to characters and then perform a default sort followed by a sort according to the labels: - sage: G = graphs.CycleGraph(5) sage: for e in G.edges(sort=False): ....: G.set_edge_label(e[0], e[1], chr(ord('A') + e[0] + 5 * e[1])) sage: G.edges(sort=True) [(0, 1, 'F'), (0, 4, 'U'), (1, 2, 'L'), (2, 3, 'R'), (3, 4, 'X')] 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)] 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)[source]¶
- Return incident edges to some vertices. - If - verticesis a vertex, then it returns the list of edges incident to that vertex. If- verticesis a list of vertices then it returns the list of all edges adjacent to those vertices. If- verticesis- None, it returns a list of 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 is a tuple \((u,v)\) of vertices
- sort– boolean (default:- False); if- Truethe 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) [(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)[source]¶
- Return the right eigenspaces of the adjacency matrix of the graph. - INPUT: - laplacian– boolean (default:- False); if- True, use the Laplacian matrix (see- kirchhoff_matrix())
 - OUTPUT: - A list of pairs. Each pair is an eigenvalue of the adjacency matrix of the graph, followed by the vector space that is the eigenspace for that eigenvalue, when the eigenvectors are placed on the right of the matrix. - For some graphs, some of the eigenspaces are described exactly by vector spaces over a - NumberField(). For numerical eigenvectors use- eigenvectors().- EXAMPLES: - sage: P = graphs.PetersenGraph() sage: P.eigenspaces() # 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] [ 0 1 0 0 -1 0 -2 -1 1 2] [ 0 0 1 0 -1 1 -1 -2 0 2] [ 0 0 0 1 -1 1 0 -1 -1 1]), (1, Vector space of degree 10 and dimension 5 over Rational Field User basis matrix: [ 1 0 0 0 0 1 -1 0 0 -1] [ 0 1 0 0 0 -1 1 -1 0 0] [ 0 0 1 0 0 0 -1 1 -1 0] [ 0 0 0 1 0 0 0 -1 1 -1] [ 0 0 0 0 1 -1 0 0 -1 1])] - Eigenspaces for the Laplacian should be identical since the Petersen graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different: - sage: P.eigenspaces(laplacian=True) # 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])] - 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 over Number Field in a3 with defining polynomial x^2 - 2 User basis matrix: [ 1 0 -1 -a3 -1 0 1 a3] [ 0 1 a3 1 0 -1 -a3 -1])] - >>> 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 over Number Field in a3 with defining polynomial x^2 - 2 User basis matrix: [ 1 0 -1 -a3 -1 0 1 a3] [ 0 1 a3 1 0 -1 -a3 -1])] - A digraph may have complex eigenvalues and eigenvectors. For a 3-cycle, we have: - sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) sage: T.eigenspaces() # 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])] - >>> 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)[source]¶
- Return the right eigenvectors of the adjacency matrix of the graph. - INPUT: - laplacian– boolean (default:- False); if- True, use the Laplacian matrix (see- kirchhoff_matrix())
 - OUTPUT: - A list of triples. Each triple begins with an eigenvalue of the adjacency matrix of the graph. This is followed by a list of eigenvectors for the eigenvalue, when the eigenvectors are placed on the right side of the matrix. Together, the eigenvectors form a basis for the eigenspace. The triple concludes with the algebraic multiplicity of the eigenvalue. - For some graphs, the exact eigenspaces provided by - eigenspaces()provide additional insight into the structure of the eigenspaces.- EXAMPLES: - sage: P = graphs.PetersenGraph() sage: P.eigenvectors() # 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)] - >>> 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 the output 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), (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.414213562373095?, [(1, 0, -1, 1.414213562373095?, -1, 0, 1, -1.414213562373095?), (0, 1, -1.414213562373095?, 1, 0, -1, 1.414213562373095?, -1)], 2), (1.414213562373095?, [(1, 0, -1, -1.414213562373095?, -1, 0, 1, 1.414213562373095?), (0, 1, 1.414213562373095?, 1, 0, -1, -1.414213562373095?, -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.414213562373095?, [(1, 0, -1, 1.414213562373095?, -1, 0, 1, -1.414213562373095?), (0, 1, -1.414213562373095?, 1, 0, -1, 1.414213562373095?, -1)], 2), (1.414213562373095?, [(1, 0, -1, -1.414213562373095?, -1, 0, 1, 1.414213562373095?), (0, 1, 1.414213562373095?, 1, 0, -1, -1.414213562373095?, -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.50000000000000000? - 0.866025403784439?*I, [(1, -0.50000000000000000? - 0.866025403784439?*I, -0.50000000000000000? + 0.866025403784439?*I)], 1), (-0.50000000000000000? + 0.866025403784439?*I, [(1, -0.50000000000000000? + 0.866025403784439?*I, -0.50000000000000000? - 0.866025403784439?*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.50000000000000000? - 0.866025403784439?*I, [(1, -0.50000000000000000? - 0.866025403784439?*I, -0.50000000000000000? + 0.866025403784439?*I)], 1), (-0.50000000000000000? + 0.866025403784439?*I, [(1, -0.50000000000000000? + 0.866025403784439?*I, -0.50000000000000000? - 0.866025403784439?*I)], 1)] 
 - eulerian_circuit(return_vertices=False, labels=True, path=False)[source]¶
- 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); optionally provide a list of vertices for the path
- labels– boolean (default:- True); whether to return edges with labels (3-tuples)
- path– boolean (default:- False); find an Eulerian path instead
 - OUTPUT: - either ([edges], [vertices]) or [edges] of an Eulerian circuit (or path) - EXAMPLES: - sage: g = graphs.CycleGraph(5) sage: g.eulerian_circuit() [(0, 4, None), (4, 3, None), (3, 2, None), (2, 1, None), (1, 0, None)] sage: g.eulerian_circuit(labels=False) [(0, 4), (4, 3), (3, 2), (2, 1), (1, 0)] - >>> 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)] - >>> 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)] 
 - export_to_file(filename, format=None, **kwds)[source]¶
- 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), the format 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: - 'adjlist'- 'dot'- 'edgelist'- 'gexf'- 'gml'- 'graphml'- 'multiline_adjlist'- networkx.readwrite.multiline_adjlist.write_multiline_adjlist()- '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: - 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)[source]¶
- Return the faces of an embedded graph. - A combinatorial embedding of a graph is a clockwise ordering of the neighbors of each vertex. From this information one can define the faces of the embedding, which is what this method returns. - If no embedding is provided or stored as - self._embedding, this method will compute the set of faces from the embedding returned by- is_planar()(if the graph is, of course, planar).- Warning - This method is not well defined when the graph is not connected. Indeed, the result may contain several faces corresponding to the external face. - INPUT: - embedding– dictionary (default:- None); a combinatorial embedding dictionary. Format:- {v1: [v2,v3], v2: [v1], v3: [v1]}(clockwise ordering of neighbors at each vertex). If set to- None(default) the method will use the embedding stored as- self._embedding. If none is stored, the method will compute the set of faces from the embedding returned by- is_planar()(if the graph is, of course, planar).
 - Note - embeddingis 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.- 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): - 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)[source]¶
- 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 \(S\) of vertices such that the digraph \(G-S\) 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- Setof vertices of a minimal feedback vertex set
- solver– string (default:- None); specifies 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- solveof 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 when solving 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_generationis enabled (default) the following MILP formulation is used to solve the problem:\[\begin{split}\mbox{Minimize : }&\sum_{v\in G} b_{v}\\ \mbox{Such that : }&\\ &\forall C\text{ circuits }\subseteq G, \sum_{v\in C}b_{v}\geq 1\\\end{split}\]- 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 \(G\), each time adding to the list of its constraints the circuit which its last answer had left intact. - (Another formulation based on an ordering of the vertices) - When the graph is directed, a second (and very slow) formulation is available, which should only be used to check the result of the first implementation in case of doubt. \[\begin{split}\mbox{Minimize : }&\sum_{v\in G} b_v\\ \mbox{Such that : }&\\ &\forall (u,v)\in G, d_u-d_v+nb_u+nb_v\geq 0\\ &\forall u\in G, 0\leq d_u\leq |G|\\\end{split}\]- 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 \((u,v)\in G\), then \(u<v\). Thus, this linear program is built in order to assign to each vertex \(v\) a number \(d_v\in [0,\dots,n-1]\) such that if there exists an edge \((u,v)\in G\) then either \(d_v<d_u\) or one of \(u\) or \(v\) 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) 3 sage: 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 creating a cycle of length two. Hence, to remove all the cycles from the graph, each edge must see one of its neighbors removed: a feedback vertex set is in this situation a vertex cover: - sage: # 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 >>> 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)[source]¶
- Return a maximum flow in the graph from - xto- 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 : \[\begin{split}\mbox{Maximize : }&\sum_{e\in G.edges()} w_e b_e\\ \mbox{Such that : }&\forall v \in G, \sum_{(u,v)\in G.edges()} b_{(u,v)}\leq 1\\ &\forall x\in G, b_x\mbox{ is a binary variable}\end{split}\]- Observe that the integrality of the flow variables is automatic for all available solvers when all capacities are integers. - INPUT: - x– source vertex
- y– sink vertex
- value_only– boolean (default:- True); whether to return only the value of a maximal flow, or to also return a flow graph (a copy of the current graph, such that each edge has the flow using it as a label, the edges without flow being omitted)
- integer– boolean (default:- True); whether to compute an optimal solution under the constraint that the flow going through an edge has to be an integer, or without this constraint
- use_edge_labels– boolean (default:- False); whether to compute a maximum flow where each edge has a capacity defined by its label (if an edge has no label, capacity \(1\) is assumed), or to use default edge capacity of \(1\)
- vertex_bound– boolean (default:- False); when set to- True, sets the maximum flow leaving a vertex different from \(x\) 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- igraphimplementation of the Goldberg-Tarjan algorithm is used (only available when- igraphis installed and- vertex_bound = False)
 - When - algorithm = None(default), we use- LPif- vertex_bound = True, otherwise, we use- igraphif it is available,- FFif it is not available.
- solver– string (default:- None); specifies 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- solveof 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 - PappusGraphand the- ButterflyGraphwith 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))) 3 - sage: 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 - The flow method can be used to compute a matching in a bipartite graph by linking a source \(s\) to all the vertices of the first set and linking a sink \(t\) to all the vertices of the second set, then computing a maximum \(s-t\) 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)[source]¶
- 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. - Note - This function uses Euler’s formula and thus it is necessary to consider only connected graphs. - INPUT: - set_embedding– boolean (default:- True); whether or not to store an embedding attribute of the computed (minimal) genus of the graph
- on_embedding– two kinds of input are allowed (default:
- None):
 - a dictionary representing a combinatorial embedding on which the genus should be computed. Note that 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 as values. The value of- on_embeddingtakes precedence over a stored- _embeddingattribute if- minimalis set to- False.
- The value - True, in order to indicate that the embedding stored as- _embeddingshould 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- maximalmust be- Trueor- on_embeddingmust not be- None. If- on_embeddingis not- None, it will take priority over- minimal. Similarly, if- maximalis- 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- maximalis- False, then either- minimalmust be- Trueor- on_embeddingmust not be- None. If- on_embeddingis not- None, it will take priority over- maximal. However,- maximaltakes priority over the default- minimal.
- circular– list (default:- None); if- circularis a list of vertices, the method computes the genus preserving a planar embedding of the this list. If- circularis defined,- on_embeddingis not a valid option.
- ordered– boolean (default:- True); if- circularis- True, then whether or not the boundary order may be permuted (default:- True, which means the boundary order is preserved)
 - EXAMPLES: - sage: g = graphs.PetersenGraph() sage: g.genus() # tests for minimal genus by default 1 sage: g.genus(on_embedding=True, maximal=True) # on_embedding overrides minimal and maximal arguments 1 sage: g.genus(maximal=True) # setting maximal to True overrides default minimal=True 3 sage: g.genus(on_embedding=g.get_embedding()) # can also send a valid combinatorial embedding dict 3 sage: (graphs.CubeGraph(3)).genus() 0 sage: K23 = graphs.CompleteBipartiteGraph(2,3) sage: K23.genus() 0 sage: K33 = graphs.CompleteBipartiteGraph(3,3) sage: K33.genus() 1 - >>> 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=True 3 >>> g.genus(on_embedding=g.get_embedding()) # can also send a valid combinatorial embedding dict 3 >>> (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']) 0 sage: cube.is_circular_planar() True sage: cube.genus(circular=['01','10']) 0 sage: 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 >>> 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 trivially correspond to that of its simple graph: - sage: G = DiGraph({0: [0, 1, 1, 1], 1: [2, 2, 3, 3], 2: [1, 3, 3], 3: [0, 3]}) sage: G.genus() Traceback (most recent call last): ... NotImplementedError: cannot work with embeddings of non-simple graphs sage: G.to_simple().genus() 0 sage: G.genus(set_embedding=False) 0 sage: G.genus(maximal=True, set_embedding=False) Traceback (most recent call last): ... NotImplementedError: cannot compute the maximal genus of a graph with loops or multiple edges - >>> 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 
 - get_embedding()[source]¶
- 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 - Noneis returned. In case some vertex/edge has been deleted, the stored embedding is updated accordingly.- EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.genus() 1 sage: G.get_embedding() {0: [1, 4, 5], 1: [0, 2, 6], 2: [1, 3, 7], 3: [2, 4, 8], 4: [0, 3, 9], 5: [0, 7, 8], 6: [1, 9, 8], 7: [2, 5, 9], 8: [3, 6, 5], 9: [4, 6, 7]} - >>> 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: - 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)[source]¶
- 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...)} - 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)[source]¶
- Retrieve the object associated with a given vertex. - If no associated object is found, - Noneis 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) >>> T.get_vertex(Integer(1)) Flower Snark: Graph on 20 vertices 
 - get_vertices(verts=None)[source]¶
- 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)[source]¶
- 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- gis the girth and- cis a list of vertices of a (directed) cycle of length- gin the graph, thus providing a certificate that the girth is at most- g, or- Noneif- ginfinite
 - EXAMPLES: - sage: graphs.TetrahedralGraph().girth() 3 sage: graphs.CubeGraph(3).girth() 4 sage: graphs.PetersenGraph().girth(certificate=True) # random (5, [4, 3, 2, 1, 0]) sage: graphs.HeawoodGraph().girth() 6 sage: next(graphs.trees(9)).girth() +Infinity - >>> from sage.all import * >>> graphs.TetrahedralGraph().girth() 3 >>> graphs.CubeGraph(Integer(3)).girth() 4 >>> graphs.PetersenGraph().girth(certificate=True) # random (5, [4, 3, 2, 1, 0]) >>> graphs.HeawoodGraph().girth() 6 >>> next(graphs.trees(Integer(9))).girth() +Infinity - See also - odd_girth()– return the odd girth of the graph.
 
 - graphics_array_defaults = {'graph_border': True, 'layout': 'circular', 'vertex_labels': False, 'vertex_size': 50}¶
 - graphplot(**options)[source]¶
- Return a - GraphPlotobject.- See - GraphPlotfor more details.- INPUT: - **options– parameters for the- GraphPlotconstructor
 - EXAMPLES: - Creating a - GraphPlotobject 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 - GraphPlotobject. Notice that the changes are cumulative:- sage: # needs sage.plot sage: GP.set_edges(edge_style='solid') sage: GP.plot() Graphics object consisting of 22 graphics primitives sage: GP.set_vertices(talk=True) sage: GP.plot() Graphics object consisting of 22 graphics primitives - >>> 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)[source]¶
- Return a representation in the - dotlanguage.- The - dotlanguage 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 in hexadecimal code. 
 
- edge_colors– dictionary (default:- None); a dictionary whose keys are colors and values are list of edges. The list of edges need not to be complete in which case the default color is used. See the option- edge_colorfor a description of valid color formats.
- color_by_label– 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_colorand- edge_colors. See the option- edge_colorfor a description of valid color formats.
- edge_options– a function (or tuple thereof) mapping edges to a dictionary of options for this edge
- rankdir–- 'left',- 'right',- 'up', or- 'down'(default:- 'down', for consistency with- graphviz); the preferred ranking direction for acyclic layouts; see the- rankdiroption of- graphviz.
- subgraph_clusters– list of lists of vertices (default:- []); From [dotspec]: “If supported, the layout engine will do the layout so that the nodes belonging to the cluster are drawn together, with the entire drawing of the cluster contained within a bounding rectangle. Note that, for good and bad, cluster subgraphs are not part of the- dotlanguage, 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')) 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: 'foo'}, 3: {}}, ....: sparse=True) sage: print(G.graphviz_string(edge_color='red')) digraph { node_0 [label="0"]; node_1 [label="1"]; node_2 [label="2"]; node_3 [label="3"]; edge [color="red"]; node_0 -> node_1; node_0 -> node_2; node_1 -> node_2; node_2 -> node_3; } - >>> 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() 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', # 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$"]; 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', # random # 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$"]; 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"]; } 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}$"]; 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', # random # 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"]; } >>> 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"]; 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 - graphvizrenders digraphs using a hierarchical layout, ranking the vertices down from top to bottom. Here we specify alternative ranking directions for this layout:- sage: D = DiGraph([(1, 2)]) sage: print(D.graphviz_string(rankdir='up')) digraph { rankdir=BT node_0 [label="1"]; node_1 [label="2"]; node_0 -> node_1; } sage: print(D.graphviz_string(rankdir='down')) digraph { node_0 [label="1"]; node_1 [label="2"]; node_0 -> node_1; } sage: print(D.graphviz_string(rankdir='left')) digraph { rankdir=RL node_0 [label="1"]; node_1 [label="2"]; node_0 -> node_1; } sage: print(D.graphviz_string(rankdir='right')) digraph { 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 { 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- dotformat)
- '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 -> vit draws it as- v -> u [dir=back]and instead of- u -> v [dir=back]it draws it as- v -> u, this changes the way it is drawn by Graphviz’s dot program: vertex- vwill be above vertex- uinstead of below.
 - Here we state that the graph should be laid out so that edges starting from - 1are going backward (e.g. going up 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)) # 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"]; 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)) # 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; 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; } - 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 { 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 = "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:- 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)[source]¶
- Write a representation in the - dotlanguage in a file.- The - dotlanguage is a plaintext format for graph structures. See the documentation of- graphviz_string()for available options.- INPUT: - filename– the name of the file to write in
- **options– options for the graphviz string
 - EXAMPLES: - sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, ....: 2: {0: None, 1: None, 3: 'foo'}, 3: {2: 'foo'}}, ....: sparse=True) sage: 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)[source]¶
- Return a greedy distance-\(k\) dominating set of the graph. - A distance-\(k\) dominating set \(S\) of a graph \(G\) is a set of its vertices of minimal cardinality such that any vertex of \(G\) is in \(S\) or is at distance at most \(k\) from a vertex in \(S\). See the Wikipedia article Dominating_set. - When \(G\) is directed, vertex \(u\) can be a dominator of vertex \(v\) if there is a directed path of length at most \(k\) from \(u\) to \(v\). - 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 the specified vertices only
- ordering– string (default:- None); specify the order in which to consider the vertices- None– if- verticesis- 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. This parameter is use only when- return_setsis- 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} 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 >>> 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)[source]¶
- 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 depending on the instance. - ALGORITHM: - See - traveling_salesman_problem()for ‘tsp’ algorithm and- find_hamiltonian()from- sage.graphs.generic_graph_pyxfor ‘backtrack’ algorithm.- INPUT: - algorithm– string (default:- 'tsp'); one of ‘tsp’ or ‘backtrack’
- solver– string (default:- None); specifies 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- solveof the class- MixedIntegerLinearProgram.
- constraint_generation– boolean (default:- None); whether to use constraint generation when solving the Mixed Integer Linear Program.- When - constraint_generation = None, constraint generation is used whenever the graph has a density larger than 70%.
- verbose– integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
- verbose_constraints– boolean (default:- False); whether to display which constraints are being generated
- integrality_tolerance– float; parameter for use with MILP solvers over an inexact base ring; see- MixedIntegerLinearProgram.get_values().
 - OUTPUT: - If using the - 'tsp'algorithm, returns a Hamiltonian cycle/circuit if it exists; otherwise, raises a- EmptySetErrorexception. If using the- 'backtrack'algorithm, returns a pair- (B, P). If- Bis- Truethen- Pis a Hamiltonian cycle and if- Bis- False,- Pis a longest path found by the algorithm. Observe that if- Bis- False, the graph may still be Hamiltonian. The- 'backtrack'algorithm is only implemented for undirected graphs.- Warning - The - 'backtrack'algorithm may loop endlessly on graphs with vertices of degree 1.- NOTE: - This function, as - is_hamiltonian(), computes a Hamiltonian cycle if it exists: the user should NOT test for Hamiltonicity using- is_hamiltonian()before calling this function, as it would result in computing it twice.- The backtrack algorithm is only implemented for undirected graphs. - EXAMPLES: - The Heawood Graph is known to be Hamiltonian - sage: g = graphs.HeawoodGraph() sage: g.hamiltonian_cycle() # 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 graph - sage: 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 graph - sage: G = graphs.PetersenGraph() sage: B, P = G.hamiltonian_cycle(algorithm='backtrack') sage: B False sage: len(P) 10 sage: G.has_edge(P[0], P[-1]) False - >>> 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, immutable='MILP', solver=None, verbose=None, integrality_tolerance=0)[source]¶
- Return a Hamiltonian path of the current graph/digraph. - A path is Hamiltonian if it goes through all the vertices exactly once. Computing a Hamiltonian path being NP-Complete, this algorithm could run for some time depending on the instance. - When - use_edge_labels == True, this method returns either a minimum weight hamiltonian path or a maximum weight Hamiltonian path (if- maximize == True).- See also - INPUT: - s– vertex (default:- None); if specified, then forces the source of the path (the method then returns a Hamiltonian path starting at- s)
- t– vertex (default:- None); if specified, then forces the destination of the path (the method then returns a Hamiltonian path ending at- t)
- use_edge_labels– boolean (default:- False); whether to compute a weighted hamiltonian path where the weight of an edge is defined by its label (a label set to- Noneor- {}being considered as a weight of \(1\)), or a non-weighted hamiltonian path
- maximize– boolean (default:- False); whether to compute a minimum (default) or a 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:- 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=Truewill force the use of the MILP algorithm.
 
- immutable– boolean (default:- None); whether to create a mutable/immutable (di)graph.- immutable=None(default) means that the (di)graph and its hamiltonian path will behave the same way.
- solver– string (default:- None); specifies 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- solveof 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 - selfcorresponding to a (directed if- selfis directed) hamiltonian path. If no hamiltonian path is found, return- None. If- use_edge_labels == True, a pair- weight, pathis returned.- EXAMPLES: - The \(3 \times 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)[source]¶
- Check whether - (u, v)is an edge of the (di)graph.- INPUT: The following forms are accepted: - G.has_edge( 1, 2 ) 
- G.has_edge( (1, 2) ) 
- G.has_edge( 1, 2, ‘label’ ) 
- G.has_edge( (1, 2, ‘label’) ) 
 - EXAMPLES: - sage: graphs.EmptyGraph().has_edge(9, 2) False sage: DiGraph().has_edge(9, 2) False sage: G = Graph(sparse=True) sage: G.add_edge(0, 1, "label") sage: G.has_edge(0, 1, "different label") False sage: G.has_edge(0, 1, "label") True - >>> 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()[source]¶
- Return whether there are loops in the (di)graph. - EXAMPLES: - sage: G = Graph(loops=True); G Looped graph on 0 vertices sage: G.has_loops() False sage: G.allows_loops() True sage: G.add_edge((0, 0)) sage: G.has_loops() True sage: G.loops() [(0, 0, None)] sage: G.allow_loops(False); G Graph on 1 vertex sage: G.has_loops() False sage: G.edges(sort=True) [] sage: D = DiGraph(loops=True); D Looped digraph on 0 vertices sage: D.has_loops() False sage: D.allows_loops() True sage: D.add_edge((0, 0)) sage: D.has_loops() True sage: D.loops() [(0, 0, None)] sage: D.allow_loops(False); D Digraph on 1 vertex sage: D.has_loops() False sage: D.edges(sort=True) [] - >>> 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)[source]¶
- Return whether there are multiple edges in the (di)graph. - INPUT: - to_undirected– (default:- False); if- True, runs the test on the undirected version of a DiGraph. Otherwise, treats DiGraph edges- (u, v)and- (v, u)as unique individual edges.
 - EXAMPLES: - sage: G = Graph(multiedges=True, sparse=True); G Multi-graph on 0 vertices sage: G.has_multiple_edges() False sage: G.allows_multiple_edges() 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 >>> 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): 'g'}}, 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')] - 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)[source]¶
- Check if - vertexis one of the vertices of this graph.- INPUT: - vertex– the name of a vertex (see- add_vertex())
 - EXAMPLES: - sage: g = Graph({0: [1, 2, 3], 2: [4]}); g Graph on 5 vertices sage: 2 in g True sage: 10 in g False sage: graphs.PetersenGraph().has_vertex(99) False - >>> 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={})[source]¶
- Return an - igraphgraph 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 -i python_igraph. For more information on the Python version of igraph, see https://python.igraph.org/.- 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- vertices()will be used instead. Because- vertices()only works if the vertices can be sorted, using- vertex_listis 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 \(i\) the label of the \(i\)-th vertex in the list- vertex_listif it is given or in- vertices()when- vertex_list == None(see https://python.igraph.org/en/stable/api/igraph.Graph.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 \(i\) the label of the \(i\)-th edge in the list outputted by- edge_iterator()(see https://python.igraph.org/en/stable/api/igraph.Graph.html#__init__ for more information)
 - Note - In - igraph, a graph is weighted if the edge attribute- weightis present. Hence, to create a weighted graph, it is enough to add this attribute.- Note - Often, Sage uses its own defined types for integers/floats. These types may not be igraph-compatible (see example below). - EXAMPLES: - Standard conversion: - sage: G = graphs.TetrahedralGraph() sage: H = G.igraph_graph() # optional - python_igraph sage: H.summary() # optional - python_igraph 'IGRAPH U--- 4 6 -- ' sage: G = digraphs.Path(3) sage: H = G.igraph_graph() # optional - python_igraph sage: 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]}) # optional - python_igraph sage: H.es['label'] # optional - python_igraph ['a', 'b'] - >>> 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_igraph sage: H.is_weighted() # optional - python_igraph True sage: H.es['weight'] # optional - python_igraph [1, 2] - >>> from sage.all import * >>> G = Graph([(Integer(1), Integer(2), {'weight': Integer(1)}), (Integer(2), 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_igraph True >>> 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_igraph sage: 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}) # optional - python_igraph sage: H.vs()['name'] == V # optional - python_igraph True - >>> 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}) # optional - python_igraph >>> H.vs()['name'] == V # optional - python_igraph True - Sometimes, Sage integers/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_igraph sage: H.maxflow_value(0, 1, 'capacity') # optional - python_igraph 1.0 sage: H = G.igraph_graph(edge_attrs={'capacity': [float(e[2]) for e in E]}) # optional - python_igraph sage: 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_igraph 2.0 
 - incidence_matrix(oriented, sparse=None, vertices=True, edges=None, base_ring=None, **kwds)[source]¶
- 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- verticesis given (see below), and the edges as obtained by the method- edge_iterator().- If the graph is not directed, then return a matrix with entries in \(\{0,1,2\}\). Each column will either contain two \(1\) (at the position of the endpoint of the edge), or one \(2\) (if the corresponding edge is a loop). - If the graph is directed return a matrix in \(\{-1,0,1\}\) where \(-1\) and \(+1\) correspond respectively to the source and the target of the edge. A loop will correspond to a zero column. In particular, it is not possible to recover the loops of an oriented graph from its incidence matrix. - See the Wikipedia article Incidence_matrix for more information. - INPUT: - oriented– boolean (default:- None); when set to- True, the matrix will be oriented (i.e. with entries in \(-1\), \(0\), \(1\)) and if set to- Falsethe matrix will be not oriented (i.e. with entries in \(0\), \(1\), \(2\)). By default, this argument is inferred from the graph type. Note that in the case the graph is not directed and with the option- directed=True, a somewhat random direction is chosen for each edge.
- sparse– boolean (default:- True); whether to use a sparse or a dense matrix
- vertices– list;- None, or- True(default:- None)- when a list, the \(i\)-th row of the matrix corresponds to the \(i\)-th vertex in the ordering of - vertices,
- when - None, the \(i\)-th row of the matrix corresponds to the \(i\)-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 \(i\)-th column of the matrix corresponds to the \(i\)-th edge in the ordering of - edges,
- when - None, the \(i\)-th column of the matrix corresponds to the \(i\)-th edge in the ordering given by method- edge_iterator(),
- when - True, construct a morphism of free modules instead of a matrix, where the domain’s basis is indexed 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] [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 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] [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] - >>> 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 Ring sage: 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⎠ 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 - >>> 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)[source]¶
- Check whether the graph is bipartite. - Traverse the graph \(G\) 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 \(G\) 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 - >>> 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)[source]¶
- Check whether the graph is a Cayley graph. - If none of the parameters are - True, return a boolean indicating whether the graph is a Cayley graph. Otherwise, return a tuple containing said boolean and the requested data. If the graph is not a Cayley graph, each of the data will be- None.- The empty graph is defined to be not a Cayley graph. - Note - For this routine to work on all graphs, the optional package - gap_packagesneeds to be installed: to do so, it is enough to run- sage -i gap_packages.- INPUT: - return_group– boolean (default:- False); if- True, return a group for which the graph is a Cayley graph
- mapping– boolean (default:- False); if- True, return a mapping from vertices to group elements
- generators– boolean (default:- False); if- True, return the generating set of the Cayley graph
- allow_disconnected– boolean (default:- False); if- True, disconnected graphs are considered Cayley if they can be obtained from the Cayley construction with a generating set that does not generate the group.
 - ALGORITHM: - For connected graphs, find a regular subgroup of the automorphism group. For disconnected graphs, check that the graph is vertex-transitive and perform the check on one of its connected components. If a simple graph has density over 1/2, perform the check on its complement as its disconnectedness may increase performance. - EXAMPLES: - A Petersen Graph is not a Cayley graph: - sage: g = graphs.PetersenGraph() sage: g.is_cayley() # 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),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')[source]¶
- Check whether the given graph is chordal. - A Graph \(G\) 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 \(G\) is an ordering \(v_1,...,v_n\) of its vertex set such that for all \(i\), the neighbors of \(v_i\) whose index is greater that \(i\) induce a complete subgraph in \(G\). Hence, the graph \(G\) can be totally erased by successively removing vertices whose neighborhood is a clique (also called simplicial vertices) [FG1965]. - (It can be seen that if \(G\) contains an induced hole, then it cannot have a perfect elimination order. Indeed, if we write \(h_1,...,h_k\) the \(k\) vertices of such a hole, then the first of those vertices to be removed would have two non-adjacent neighbors in the graph.) - A Graph is then chordal if and only if it has a Perfect Elimination Order. - INPUT: - certificate– boolean (default:- False); whether to return a certificate- If - certificate = False(default), returns- Trueor- Falseaccordingly.
- If - certificate = True, returns :- (True, peo)when the graph is chordal, where- peois a perfect elimination order of its vertices.
- (False, Hole)when the graph is not chordal, where- Hole(a- Graphobject) is an induced subgraph of- selfisomorphic to a hole.
 
 
- algorithm– string (default:- 'B'); the algorithm to choose among- 'A'or- 'B'. While they will agree 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 \(O(n+m)\) for - SparseGraphand \(O(n^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 \(v\) the subgraph induced by its non-deleted neighbors, then testing 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 Graph - sage: 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: - 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 >>> hole.is_isomorphic(graphs.CycleGraph(Integer(5))) True 
 - is_circulant(certificate=False)[source]¶
- 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 - certificateis set to- False(default) this method only returns- Trueor- Falseanswers. When- certificateis set to- True, the method either returns- (False, None)or- (True, lists_of_parameters)each element of- lists_of_parameterscan be used to define the graph as a circulant graph.- See the documentation of - CirculantGraph()and- Circulant()for more information, and the examples below.- See also - CirculantGraph()– a constructor for circulant graphs.- EXAMPLES: - The Petersen graph is not a circulant graph: - sage: g = graphs.PetersenGraph() sage: g.is_circulant() # 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: - 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)[source]¶
- 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 specific set (the boundary) can be drawn on a circle, all other vertices being drawn inside of the circle. An order can be defined on the vertices of the boundary in order to define how they are to appear on the circle. - INPUT: - on_embedding– dictionary (default:- None); the embedding dictionary to test planarity on (i.e.: will return- Trueor- Falseonly for the given embedding)
- kuratowski– boolean (default:- False); whether to return a tuple with boolean first entry and the Kuratowski subgraph (i.e. an edge subdivision of \(K_5\) or \(K_{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- v1is a vertex and- n1,n2,n3are 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- Noneby default, meaning that all vertices should be drawn on the boundary.
- ordered– boolean (default:- False); whether or not to consider the order of the boundary. It required- boundaryto be defined.
- set_pos– boolean (default:- False); whether or not to set the position dictionary (for plotting) to reflect the combinatorial embedding. Note that this value will default to- Falseif- set_embeddingis set to- False. Also, the position dictionary will only be updated if a circular planar embedding is found.
 - OUTPUT: - The method returns - Trueif the graph is circular planar, and- Falseif it is not.- If - kuratowskiis set to- True, then this function will return a tuple, whose first entry is a boolean and whose second entry is the Kuratowski subgraph (i.e. an edge subdivision of \(K_5\) or \(K_{3,3}\)) isolated by the Boyer-Myrvold algorithm. Note that this graph might contain a vertex or edges that were not in the initial graph. These would be elements referred to below as parts of the wheel and the star, which were added to the graph to require that the boundary can be drawn on the boundary of a disc, with all other vertices drawn inside (and no edge crossings).- ALGORITHM: - This is a linear time algorithm to test for circular planarity. It relies on the edge-addition planarity algorithm due to Boyer-Myrvold. We accomplish linear time for circular planarity by modifying the graph before running the general planarity algorithm. - REFERENCE: - EXAMPLES: - sage: g439 = Graph({1: [5, 7], 2: [5, 6], 3: [6, 7], 4: [5, 6, 7]}) sage: g439.show() # 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)]) (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)[source]¶
- 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- selfis a clique
- directed_clique– boolean (default:- False); if set to- False, only consider the underlying undirected graph. If set to- Trueand the graph is directed, only return- Trueif 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.
- loops– boolean (default:- False); if set to- True, check that each vertex of the graph has a loop, and exactly one if furthermore- induced == True. If set to- False, check that the graph has no loop when- induced == True, and ignore loops otherwise.
 - EXAMPLES: - sage: g = graphs.CompleteGraph(4) sage: g.is_clique([1, 2, 3]) True sage: g.is_clique() True sage: h = graphs.CycleGraph(4) sage: h.is_clique([1, 2]) True sage: h.is_clique([1, 2, 3]) False sage: h.is_clique() False 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, forbidden_vertices=None)[source]¶
- Check whether the (di)graph is connected. - Note that in a graph, path connected is equivalent to connected. - INPUT: - G– the input graph
- forbidden_vertices– list (default:- None); set of vertices to avoid during the search
 - See also - EXAMPLES: - sage: from sage.graphs.connectivity import is_connected sage: G = Graph({0: [1, 2], 1: [2], 3: [4, 5], 4: [5]}) sage: is_connected(G) False sage: G.is_connected() False sage: G.add_edge(0,3) sage: is_connected(G) True sage: is_connected(G, forbidden_vertices=[3]) False sage: is_connected(G, forbidden_vertices=[1]) True sage: D = DiGraph({0: [1, 2], 1: [2], 3: [4, 5], 4: [5]}) sage: is_connected(D) False sage: D.add_edge(0, 3) sage: is_connected(D) True sage: D = DiGraph({1: [0], 2: [0]}) sage: is_connected(D) True - >>> 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 >>> is_connected(G, forbidden_vertices=[Integer(3)]) False >>> is_connected(G, forbidden_vertices=[Integer(1)]) 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)[source]¶
- Check whether the edge - (u, v)is a cut-edge or a bridge of graph- G.- A cut edge (or bridge) is an edge that when removed increases the number of connected components. This function works with simple graphs as well as graphs with loops and multiedges. In a digraph, a cut edge is an edge that when removed increases the number of (weakly) connected components. - INPUT: The following forms are accepted - is_cut_edge(G, 1, 2 ) 
- is_cut_edge(G, (1, 2) ) 
- is_cut_edge(G, 1, 2, ‘label’ ) 
- is_cut_edge(G, (1, 2, ‘label’) ) 
 - OUTPUT: - Returns - Trueif (u,v) is a cut edge, False otherwise
 - EXAMPLES: - sage: from sage.graphs.connectivity import is_cut_edge sage: G = graphs.CompleteGraph(4) sage: is_cut_edge(G,0,2) False sage: G.is_cut_edge(0,2) False sage: G = graphs.CompleteGraph(4) sage: G.add_edge((0,5,'silly')) sage: is_cut_edge(G,(0,5,'silly')) True sage: G = Graph([[0,1],[0,2],[3,4],[4,5],[3,5]]) sage: is_cut_edge(G,(0,1)) True sage: G = Graph([[0,1],[0,2],[1,1]], loops = True) sage: is_cut_edge(G,(1,1)) False sage: G = digraphs.Circuit(5) sage: is_cut_edge(G,(0,1)) False sage: G = graphs.CompleteGraph(6) sage: is_cut_edge(G,(0,7)) Traceback (most recent call last): ... ValueError: edge not in graph - >>> 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 graph 
 - is_cut_vertex(G, u, weak=False)[source]¶
- 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 leaves 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 - Trueif- uis a cut-vertex, and- Falseotherwise.- 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: D = digraphs.Circuit(6) sage: D.is_strongly_connected() True sage: is_cut_vertex(D, 2) True sage: is_cut_vertex(D, 2, weak=True) False - >>> from sage.all import * >>> D = digraphs.Circuit(Integer(6)) >>> D.is_strongly_connected() 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 graph 
 - is_cycle(directed_cycle=True)[source]¶
- Check whether - selfis a (directed) cycle graph.- We follow the definition provided in [BM2008] for undirected graphs. A cycle on three or more vertices is a simple graph whose vertices can be arranged in a cyclic order so that two vertices are adjacent if they are consecutive in the order, and not adjacent otherwise. A cycle on a vertex consists of a single vertex provided with a loop and a cycle with two vertices consists of two vertices connected by a pair of parallel edges. In other words, an undirected graph is a cycle if it is 2-regular and connected. The empty graph is not a cycle. - For directed graphs, a directed cycle, or circuit, on two or more vertices is a strongly connected directed graph without loops nor multiple edges with has many arcs as vertices. A circuit on a vertex consists of a single vertex provided with a loop. - INPUT: - directed_cycle– boolean (default:- True); if set to- Trueand the graph is directed, only return- Trueif- selfis a directed cycle graph (i.e., a circuit). If set to- False, we ignore the direction of edges and so opposite arcs become multiple (parallel) edges. This parameter is ignored for undirected graphs.
 - EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.is_cycle() False sage: graphs.CycleGraph(5).is_cycle() True sage: Graph([(0,1 )]).is_cycle() False sage: Graph([(0, 1), (0, 1)], multiedges=True).is_cycle() True sage: Graph([(0, 1), (0, 1), (0, 1)], multiedges=True).is_cycle() False sage: Graph().is_cycle() False sage: G = Graph([(0, 0)], loops=True) sage: G.is_cycle() True sage: digraphs.Circuit(3).is_cycle() True sage: digraphs.Circuit(2).is_cycle() True sage: digraphs.Circuit(2).is_cycle(directed_cycle=False) True sage: D = DiGraph(graphs.CycleGraph(3)) sage: D.is_cycle() False sage: D.is_cycle(directed_cycle=False) False sage: D.edges(sort=True, labels=False) [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - >>> 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 >>> 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()[source]¶
- 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 - _posattribute 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() True 
 - is_edge_cut(G, edges)[source]¶
- Check whether - edgesform an edge cut.- A set of edges is an edge cut of a graph if its removal increases the number of connected components. In a digraph, we consider the number of (weakly) connected components. - This method is not working for (di)graphs with multiple edges. Furthermore, edge labels are ignored. - INPUT: - G– a (di)graph
- edges– a set of edges
 - EXAMPLES: - A cycle graph of order 4: - sage: from sage.graphs.connectivity import is_edge_cut sage: G = graphs.CycleGraph(4) sage: is_edge_cut(G, [(1, 2)]) False sage: is_edge_cut(G, [(1, 2), (2, 3)]) True sage: is_edge_cut(G, [(1, 2), (3, 0)]) True - >>> from sage.all import * >>> from sage.graphs.connectivity import is_edge_cut >>> G = graphs.CycleGraph(Integer(4)) >>> is_edge_cut(G, [(Integer(1), Integer(2))]) False >>> is_edge_cut(G, [(Integer(1), Integer(2)), (Integer(2), Integer(3))]) True >>> is_edge_cut(G, [(Integer(1), Integer(2)), (Integer(3), Integer(0))]) True - A pending edge is a cut-edge: - sage: G.add_edge((0, 5, 'silly')) sage: is_edge_cut(G, [(0, 5, 'silly')]) True - >>> from sage.all import * >>> G.add_edge((Integer(0), Integer(5), 'silly')) >>> is_edge_cut(G, [(Integer(0), Integer(5), 'silly')]) True - Edge labels are ignored, even if specified: - sage: G.add_edge((2, 5, 'xyz')) sage: is_edge_cut(G, [(0, 5), (2, 5)]) True sage: is_edge_cut(G, [(0, 5), (2, 5, 'xyz')]) True sage: is_edge_cut(G, [(0, 5, 'silly'), (2, 5)]) True sage: is_edge_cut(G, [(0, 5, 'aa'), (2, 5, 'bb')]) True - >>> from sage.all import * >>> G.add_edge((Integer(2), Integer(5), 'xyz')) >>> is_edge_cut(G, [(Integer(0), Integer(5)), (Integer(2), Integer(5))]) True >>> is_edge_cut(G, [(Integer(0), Integer(5)), (Integer(2), Integer(5), 'xyz')]) True >>> is_edge_cut(G, [(Integer(0), Integer(5), 'silly'), (Integer(2), Integer(5))]) True >>> is_edge_cut(G, [(Integer(0), Integer(5), 'aa'), (Integer(2), Integer(5), 'bb')]) True - The graph can have loops: - sage: G.allow_loops(True) sage: G.add_edge(0, 0) sage: is_edge_cut(G, [(0, 5), (2, 5)]) True sage: is_edge_cut(G, [(0, 0), (0, 5), (2, 5)]) True - >>> from sage.all import * >>> G.allow_loops(True) >>> G.add_edge(Integer(0), Integer(0)) >>> is_edge_cut(G, [(Integer(0), Integer(5)), (Integer(2), Integer(5))]) True >>> is_edge_cut(G, [(Integer(0), Integer(0)), (Integer(0), Integer(5)), (Integer(2), Integer(5))]) True - Multiple edges are not allowed: - sage: G.allow_multiple_edges(True) sage: is_edge_cut(G, [(0, 5), (2, 5)]) Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with multiedges. Perhaps this method can be updated to handle them, but in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). - >>> from sage.all import * >>> G.allow_multiple_edges(True) >>> is_edge_cut(G, [(Integer(0), Integer(5)), (Integer(2), Integer(5))]) Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with multiedges. Perhaps this method can be updated to handle them, but in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). - An error is raised if an element of - edgesis not an edge of \(G\):- sage: G = graphs.CycleGraph(4) sage: is_edge_cut(G, [(0, 2)]) Traceback (most recent call last): ... ValueError: edge (0, 2) is not an edge of the graph - >>> from sage.all import * >>> G = graphs.CycleGraph(Integer(4)) >>> is_edge_cut(G, [(Integer(0), Integer(2))]) Traceback (most recent call last): ... ValueError: edge (0, 2) is not an edge of the graph - For digraphs, this method considers the number of (weakly) connected components: - sage: G = digraphs.Circuit(4) sage: is_edge_cut(G, [(0, 1)]) False sage: G = digraphs.Circuit(4) sage: is_edge_cut(G, [(0, 1), (1, 2)]) True - >>> from sage.all import * >>> G = digraphs.Circuit(Integer(4)) >>> is_edge_cut(G, [(Integer(0), Integer(1))]) False >>> G = digraphs.Circuit(Integer(4)) >>> is_edge_cut(G, [(Integer(0), Integer(1)), (Integer(1), Integer(2))]) True - For disconnected (di)graphs, the method checks if the number of (weakly) connected components increases: - sage: G = graphs.CycleGraph(4) * 2 sage: is_edge_cut(G, [(1, 2), (2, 3)]) True sage: G = digraphs.Circuit(4) * 2 sage: is_edge_cut(G, [(0, 1), (1, 2)]) True - >>> from sage.all import * >>> G = graphs.CycleGraph(Integer(4)) * Integer(2) >>> is_edge_cut(G, [(Integer(1), Integer(2)), (Integer(2), Integer(3))]) True >>> G = digraphs.Circuit(Integer(4)) * Integer(2) >>> is_edge_cut(G, [(Integer(0), Integer(1)), (Integer(1), Integer(2))]) True 
 - is_equitable(partition, quotient_matrix=False)[source]¶
- Check whether the given partition is equitable with respect to - self.- A partition is equitable with respect to a graph if for every pair of cells C1, C2 of the partition, the number of edges from a vertex of C1 to C2 is the same, over all vertices in C1. - INPUT: - partition– list of lists
- quotient_matrix– boolean (default:- False); if- True, and the partition is equitable, returns a matrix over the integers whose rows and columns represent cells of the partition, and whose i,j entry is the number of vertices in cell j adjacent to each vertex in cell i (since the partition is equitable, this is well defined)
 - EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8],[7]]) False sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8,7]]) True sage: G.is_equitable([[0,4],[1,3,5,9],[2,6,8,7]], quotient_matrix=True) # needs sage.modules [1 2 0] [1 0 2] [0 2 1] - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> 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)[source]¶
- Check whether the graph is Eulerian. - A graph is Eulerian if it has a (closed) tour that visits each edge exactly once. - INPUT: - path– boolean (default:- False); by default this function finds if the graph contains a closed tour visiting each edge once, i.e. an Eulerian cycle. If you want to test the existence of an Eulerian path, set this argument to- True. Graphs with this property are sometimes called semi-Eulerian.
 - OUTPUT: - Trueor- Falsefor the closed tour case. For an open tour search (- path``=``True) the function returns- Falseif the graph is not semi-Eulerian, or a tuple (u, v) in the other case. This tuple defines the edge that would make the graph Eulerian, i.e. close an existing open tour. This edge may or may not be already present in the graph.- EXAMPLES: - sage: graphs.CompleteGraph(4).is_eulerian() False sage: graphs.CycleGraph(4).is_eulerian() True sage: g = DiGraph({0:[1,2], 1:[2]}); g.is_eulerian() False sage: g = DiGraph({0:[2], 1:[3], 2:[0,1], 3:[2]}); g.is_eulerian() True sage: g = DiGraph({0:[1], 1:[2], 2:[0], 3:[]}); g.is_eulerian() True sage: g = Graph([(1,2), (2,3), (3,1), (4,5), (5,6), (6,4)]); g.is_eulerian() False - >>> 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 - 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()[source]¶
- Return whether the current graph is a Gallai tree. - A graph is a Gallai tree if and only if it is connected and its \(2\)-connected components are all isomorphic to complete graphs or odd cycles. - A connected graph is not degree-choosable if and only if it is a Gallai tree [ERT1979]. - EXAMPLES: - A complete graph is, or course, a Gallai Tree: - sage: g = graphs.CompleteGraph(15) sage: g.is_gallai_tree() True - >>> 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 - 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)[source]¶
- Check whether the input (di)graph is geodetic. - A graph \(G\) is geodetic if there exists only one shortest path between every pair of its vertices. This can be checked in time \(O(nm)\) for - SparseGraphand \(O(nm+n^2)\) for- DenseGraphin unweighted (di)graphs with \(n\) nodes and \(m\) 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() True sage: all(graphs.CompleteGraph(n).is_geodetic() for n in range(8)) True sage: 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() True sage: 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)[source]¶
- Test whether the current graph is Hamiltonian. - A graph (resp. digraph) is said to be Hamiltonian if it contains as a subgraph a cycle (resp. a circuit) going through all the vertices. - Testing for Hamiltonicity being NP-Complete, this algorithm could run for some time depending on the instance. - ALGORITHM: - See - traveling_salesman_problem().- INPUT: - solver– string (default:- None); specifies 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- solveof the class- MixedIntegerLinearProgram.
- constraint_generation– boolean; whether to use constraint generation when solving the Mixed Integer Linear Program. When- constraint_generation = None, constraint generation is used whenever the graph has a density larger than 70%.
- verbose– integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
- verbose_constraints– 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 - Trueif a Hamiltonian cycle/circuit exists, and- Falseotherwise.- NOTE: - This function, as - hamiltonian_cycleand- traveling_salesman_problem, computes a Hamiltonian cycle if it exists: the user should NOT test for Hamiltonicity using- is_hamiltonianbefore calling- hamiltonian_cycleor- traveling_salesman_problemas 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()[source]¶
- Check whether the graph is immutable. - EXAMPLES: - 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)[source]¶
- Check whether - verticesis an independent set of- self.- An independent set is a set of vertices such that there is no edge between any two vertices. - INPUT: - vertices– a single vertex or an iterable container of vertices (default:- None); when set, check whether the given set of vertices is an independent set, otherwise, check whether the set of vertices of- selfis 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)[source]¶
- Check whether the graph is an interval graph. - An interval graph is one where every vertex can be seen as an interval on the real line so that there is an edge in the graph iff the corresponding intervals intersects. - See the Wikipedia article Interval_graph for more information. - INPUT: - certificate– boolean (default:- False)- When - certificate=False, returns- Trueif the graph is an interval graph and- Falseotherwise
- When - certificate=True, returns either- (False, None)or- (True, d)where- dis a dictionary whose keys are the vertices and values are pairs of integers. They correspond to an embedding of the interval graph, each vertex being represented by an interval going from the first of the two values to the second.
 
 - ALGORITHM: - Through the use of PQ-Trees. - AUTHOR: - Nathann Cohen (implementation) - EXAMPLES: - sage: g = Graph({1: [2, 3, 4], 4: [2, 3]}) sage: g.is_interval() True sage: g.is_interval(certificate=True) (True, {1: (0, 5), 2: (4, 6), 3: (1, 3), 4: (2, 7)}) - >>> 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 
- PQ– implementation of PQ-Trees
 
 - is_isomorphic(other, certificate=False, verbosity=0, edge_labels=False)[source]¶
- Test for isomorphism between - selfand- other.- INPUT: - certificate– if- True, then output is \((a, b)\), where \(a\) is a boolean and \(b\) is either a map or- None
- edge_labels– boolean (default:- False); if- Trueallows only permutations respecting edge labels
 - OUTPUT: - either a boolean or, if - certificateis- 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 - >>> 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) True - Multigraphs: - sage: G = Graph(multiedges=True,sparse=True) sage: G.add_edge((0,1,1)) sage: G.add_edge((0,1,2)) sage: G.add_edge((0,1,3)) sage: G.add_edge((0,1,4)) sage: H = Graph(multiedges=True,sparse=True) sage: H.add_edge((3,4)) sage: H.add_edge((3,4)) sage: H.add_edge((3,4)) sage: H.add_edge((3,4)) sage: G.is_isomorphic(H) True - >>> 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 - 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)[source]¶
- Check whether the graph is planar. - This wraps the reference implementation provided by John Boyer of the linear time planarity algorithm by edge addition due to Boyer Myrvold. (See reference code in - planarity).- Note - The argument on_embedding takes precedence over - set_embedding. This means that only the- on_embeddingcombinatorial embedding will be tested for planarity and no- _embeddingattribute will be set as a result of this function call, unless- on_embeddingis None.- REFERENCE: - See also - “Almost planar graph”: - is_apex()
- “Measuring non-planarity”: - genus(),- crossing_number()
 - INPUT: - on_embedding– dictionary (default:- None); the embedding dictionary to test planarity on (i.e.: will return- Trueor- Falseonly for the given embedding)
- kuratowski– boolean (default:- False); whether to return a tuple with boolean as first entry. If the graph is nonplanar, will return the Kuratowski subgraph (i.e. an edge subdivision of \(K_5\) or \(K_{3,3}\)) as the second tuple entry. If the graph is planar, returns- Noneas 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- v1is a vertex and- n1,n2,n3are its neighbors.
- set_pos– boolean (default:- False); whether to set the position dictionary (for plotting) to reflect the combinatorial embedding. Note that this value will default to False if set_emb is set to False. Also, the position dictionary will only be updated if a planar embedding is found.
 - EXAMPLES: - sage: g = graphs.CubeGraph(4) sage: g.is_planar() False - >>> 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], 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 - >>> 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 of multiple-edged or looped graphs sage: G.is_planar(set_embedding=True) Traceback (most recent call last): ... NotImplementedError: cannot compute with embeddings of multiple-edged or looped graphs sage: G.is_planar(kuratowski=True) (True, None) sage: G.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 of multiple-edged or looped graphs >>> G.is_planar(set_embedding=True) Traceback (most recent call last): ... NotImplementedError: cannot compute with embeddings of multiple-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() 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 of digraphs with pairs of opposite arcs sage: D.is_planar(set_embedding=True) Traceback (most recent call last): ... NotImplementedError: cannot compute with embeddings of digraphs 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 of multiple-edged or looped graphs sage: D.is_planar(on_embedding={}) Traceback (most recent call last): ... NotImplementedError: cannot compute with embeddings of multiple-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 of digraphs with pairs of opposite arcs >>> D.is_planar(set_embedding=True) Traceback (most recent call last): ... NotImplementedError: cannot compute with embeddings of digraphs with pairs of opposite arcs >>> 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 of multiple-edged or looped graphs >>> D.is_planar(on_embedding={}) Traceback (most recent call last): ... NotImplementedError: cannot compute with embeddings of multiple-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: b False 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)[source]¶
- Check whether this graph is (\(k\)-)regular. - INPUT: - k– integer (default:- None); the degree of regularity to check for
 - EXAMPLES: - sage: G = graphs.HoffmanSingletonGraph() sage: G.is_regular() True sage: G.is_regular(9) False - >>> 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 \(k\)-regular for every \(k\): - sage: Graph().is_regular() True - >>> from sage.all import * >>> Graph().is_regular() True 
 - is_self_complementary()[source]¶
- Check whether the graph is self-complementary. - A (di)graph is self-complementary if it is isomorphic to its (di)graph complement. For instance, the path graph \(P_4\) and the cycle graph \(C_5\) are self-complementary. - See also 
- OEIS sequence A000171 for the numbers of self-complementary graphs of order \(n\) 
- OEIS sequence A003086 for the numbers of self-complementary digraphs of order \(n\). 
 - EXAMPLES: - The only self-complementary path graph is \(P_4\): - sage: graphs.PathGraph(4).is_self_complementary() True sage: 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 \(P_2\): - sage: digraphs.Path(2).is_self_complementary() True sage: 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)[source]¶
- Check whether - selfis a subgraph of- other.- Warning - The arguments - inducedand- up_to_isomorphismare set respectively to- Trueand- Falseby default.- INPUT: - other– a Sage (Di)Graph
- induced– boolean (default:- True); if set to- Truecheck whether the graph is an induced subgraph of- otherthat is if the vertices of the graph are also vertices of- other, and the edges of the graph are equal to the edges of- otherbetween the vertices contained in the graph.- If set to - Falsetests whether the graph is a subgraph of- otherthat is if all vertices of the graph are also in- otherand all edges of the graph are also in- other.
- up_to_isomorphism– boolean (default:- False); if set to- Truecheck whether- otheris a subgraph ignoring the labeling of vertices and edges. Otherwise, vertex and edge labellings must coincide in the copy or induced copy.
 - OUTPUT: - boolean – - Trueiff 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- otherinside of the graph
- subgraph_search_count()– count the number of such copies
- subgraph_search_iterator()– iterator over all the copies of- othercontained 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 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()[source]¶
- 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_cut(G, cut, weak=False)[source]¶
- Check whether the input vertices form a vertex cut. - A set of vertices is a vertex cut if its removal from the (di)graph increases the number of (strongly) connected components. This function works with simple graphs as well as graphs with loops and multiple edges. - INPUT: - G– a Sage (Di)Graph
- cut– a set of vertices
- weak– boolean (default:- False); whether the connectivity of directed graphs is to be taken in the weak sense, that is ignoring edges orientations
 - EXAMPLES: - Giving a cycle graph of order 4: - sage: from sage.graphs.connectivity import is_vertex_cut sage: G = graphs.CycleGraph(4) sage: is_vertex_cut(G, [0, 1]) False sage: is_vertex_cut(G, [0, 2]) True - >>> from sage.all import * >>> from sage.graphs.connectivity import is_vertex_cut >>> G = graphs.CycleGraph(Integer(4)) >>> is_vertex_cut(G, [Integer(0), Integer(1)]) False >>> is_vertex_cut(G, [Integer(0), Integer(2)]) True - Giving a disconnected graph: - sage: from sage.graphs.connectivity import is_vertex_cut sage: G = graphs.CycleGraph(4) * 2 sage: G.connected_components() [[0, 1, 2, 3], [4, 5, 6, 7]] sage: is_vertex_cut(G, [0, 2]) True sage: is_vertex_cut(G, [4, 6]) True sage: is_vertex_cut(G, [0, 6]) False sage: is_vertex_cut(G, [0, 4, 6]) True - >>> from sage.all import * >>> from sage.graphs.connectivity import is_vertex_cut >>> G = graphs.CycleGraph(Integer(4)) * Integer(2) >>> G.connected_components() [[0, 1, 2, 3], [4, 5, 6, 7]] >>> is_vertex_cut(G, [Integer(0), Integer(2)]) True >>> is_vertex_cut(G, [Integer(4), Integer(6)]) True >>> is_vertex_cut(G, [Integer(0), Integer(6)]) False >>> is_vertex_cut(G, [Integer(0), Integer(4), Integer(6)]) True - Comparing the weak and strong connectivity of a digraph: - sage: D = digraphs.Circuit(6) sage: D.is_strongly_connected() True sage: is_vertex_cut(D, [2]) True sage: is_vertex_cut(D, [2], weak=True) False - >>> from sage.all import * >>> D = digraphs.Circuit(Integer(6)) >>> D.is_strongly_connected() True >>> is_vertex_cut(D, [Integer(2)]) True >>> is_vertex_cut(D, [Integer(2)], weak=True) False - Giving a vertex that is not in the graph: - sage: G = graphs.CompleteGraph(4) sage: is_vertex_cut(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_vertex_cut(G, [Integer(7)]) Traceback (most recent call last): ... ValueError: vertex (7) is not a vertex of the graph 
 - is_vertex_transitive(partition=None, verbosity=0, edge_labels=False, order=False, return_group=True, orbits=False)[source]¶
- Return whether the automorphism group of - selfis 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.groups True sage: D = graphs.DodecahedralGraph() sage: D.is_vertex_transitive() # needs sage.groups True 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)[source]¶
- Return the Katz centrality of vertex \(u\). - Katz centrality of a node is a measure of centrality in a graph network. Katz centrality computes the relative influence of a node within a network. Connections made with distant neighbors are, however penalized by an attenuation factor \(\alpha\). - 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: list containing the Katz centrality of each vertex if u=None otherwise Katz centrality of the vertex u. - EXAMPLES: - We compute the Katz centrality of a 4-cycle (note that by symmetry, all 4 vertices have the same centrality) - sage: G = graphs.CycleGraph(4) sage: G.katz_centrality(1/20) # 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 these nodes 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} 
 - katz_matrix(alpha, nonedgesonly=False, vertices=None)[source]¶
- 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 an attenuation factor \(\alpha\). - 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 the matrix. 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/198 0] [ 0 0 0 1/198] [1/198 0 0 0] [ 0 1/198 0 0] - >>> from sage.all import * >>> G.katz_matrix(Integer(1)/Integer(20), True) # needs sage.modules sage.rings.number_field [ 0 0 1/198 0] [ 0 0 0 1/198] [1/198 0 0 0] [ 0 1/198 0 0] - 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/2256 545/4512 25/188 605/4512 25/188 545/4512 485/4512] [ 545/4512 7081/297792 4355/37224 229/9024 595/37224 4073/297792 109/9024] [ 25/188 4355/37224 172/4653 45/376 125/4653 595/37224 5/376] [ 605/4512 229/9024 45/376 337/9024 45/376 229/9024 121/9024] [ 25/188 595/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/2256 545/4512 25/188 605/4512 25/188 545/4512 485/4512] [ 545/4512 7081/297792 4355/37224 229/9024 595/37224 4073/297792 109/9024] [ 25/188 4355/37224 172/4653 45/376 125/4653 595/37224 5/376] [ 605/4512 229/9024 45/376 337/9024 45/376 229/9024 121/9024] [ 25/188 595/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] 
 - kirchhoff_matrix(weighted=None, indegree=True, normalized=False, signless=False, **kwds)[source]¶
- Return the Kirchhoff matrix (a.k.a. the Laplacian) of the graph. - The Kirchhoff matrix is defined to be \(D + M\) if signless and \(D - M\) otherwise, where \(D\) is the diagonal degree matrix (each diagonal entry is the degree of the corresponding vertex), and \(M\) is the adjacency matrix. If - normalizedis- True, then the returned matrix is \(D^{-1/2}(D+M)D^{-1/2}\) if signless and \(D^{-1/2}(D-M)D^{-1/2}\) otherwise.- (In the special case of DiGraphs, \(D\) 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 \(M\), and the diagonal matrix \(D\) takes into account the weight of edges (replace in the definition “degree” by “sum of the incident edges”)
- Else, each edge is assumed to have weight 1 
 - Default is to take weights into consideration if and only if the graph is weighted. 
- indegree– boolean (default:- True); this parameter is considered only for digraphs- If - True, each diagonal entry of \(D\) is equal to the in-degree of the corresponding vertex
- Else, each diagonal entry of \(D\) is equal to the out-degree of the corresponding vertex 
 - By default, - indegreeis set to- True
- normalized– boolean (default:- False)- If - True, the returned matrix is \(D^{-1/2}(D+M)D^{-1/2}\) for signless and \(D^{-1/2}(D-M)D^{-1/2}\) otherwise, a normalized version of the Laplacian matrix. More accurately, the normalizing matrix used is equal to \(D^{-1/2}\) only for non-isolated vertices. If vertex \(i\) is isolated, then diagonal entry \(i\) in the matrix is 1, rather than a division by zero
- Else, the matrix \(D+M\) for signless and \(D-M\) otherwise is returned 
 
- signless– boolean (default:- False)- If - True, \(D+M\) is used in calculation of Kirchhoff matrix
- Else, \(D-M\) is used in calculation of Kirchhoff matrix 
 
- vertices– list;- None, or- True(default:- None)- when a list, the \(i\)-th row and column of the matrix correspond to the \(i\)-th vertex in the ordering of - vertices,
- when - None, the \(i\)-th row and column of the matrix correspond to the \(i\)-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’s basis is indexed by the vertices.
 - If the vertices are not comparable, the keyword - verticesmust be used to specify an ordering, or a- TypeErrorexception will be raised.
 - Note that any additional keywords will be passed on to either the - adjacency_matrix()or- weighted_adjacency_matrix()method.- AUTHORS: - Tom Boothby 
- Jason Grout 
 - EXAMPLES: - sage: G = Graph(sparse=True) sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)]) sage: M = G.kirchhoff_matrix(weighted=True); M # 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) -1/3*sqrt(3)] [-1/6*sqrt(3)*sqrt(2) 1 -1/2 0] [-1/6*sqrt(3)*sqrt(2) -1/2 1 0] [ -1/3*sqrt(3) 0 0 1] sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M # 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] >>> 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 [ 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=Trueis 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', 'D', 4)]) sage: phi = G.laplacian_matrix(weighted=True, vertices=True); phi Generic endomorphism of Free module generated by {'A', 'B', 'C', 'D'} over Integer Ring sage: print(phi._unicode_art_matrix()) A B C D A⎛ 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', 'C', Integer(3)), ('A', 'D', Integer(4))]) >>> phi = G.laplacian_matrix(weighted=True, vertices=True); phi Generic endomorphism of Free module generated by {'A', 'B', 'C', 'D'} over Integer Ring >>> print(phi._unicode_art_matrix()) A B C D A⎛ 8 -1 -3 -4⎞ B⎜-1 3 -2 0⎟ C⎜-3 -2 5 0⎟ D⎝-4 0 0 4⎠ 
 - kronecker_product(other, immutable=None)[source]¶
- Return the tensor product of - selfand- other.- The tensor product of \(G\) and \(H\) is the graph \(L\) with vertex set \(V(L)\) equal to the Cartesian product of the vertices \(V(G)\) and \(V(H)\), and \(((u,v), (w,x))\) is an edge iff - \((u, w)\) is an edge of self, and - \((v, x)\) is an edge of other. - The tensor product is also known as the categorical product and the Kronecker product (referring to the Kronecker matrix product). See the Wikipedia article Kronecker_product. - INPUT: - other– a graph or a digraph
- immutable– boolean (default:- None); whether to create a mutable/immutable product.- immutable=None(default) means that the graphs and their product will behave the same way. If only one of them is immutable, the product will be mutable.
 - 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 - >>> 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)[source]¶
- Return the Kirchhoff matrix (a.k.a. the Laplacian) of the graph. - The Kirchhoff matrix is defined to be \(D + M\) if signless and \(D - M\) otherwise, where \(D\) is the diagonal degree matrix (each diagonal entry is the degree of the corresponding vertex), and \(M\) is the adjacency matrix. If - normalizedis- True, then the returned matrix is \(D^{-1/2}(D+M)D^{-1/2}\) if signless and \(D^{-1/2}(D-M)D^{-1/2}\) otherwise.- (In the special case of DiGraphs, \(D\) 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 \(M\), and the diagonal matrix \(D\) takes into account the weight of edges (replace in the definition “degree” by “sum of the incident edges”)
- Else, each edge is assumed to have weight 1 
 - Default is to take weights into consideration if and only if the graph is weighted. 
- indegree– boolean (default:- True); this parameter is considered only for digraphs- If - True, each diagonal entry of \(D\) is equal to the in-degree of the corresponding vertex
- Else, each diagonal entry of \(D\) is equal to the out-degree of the corresponding vertex 
 - By default, - indegreeis set to- True
- normalized– boolean (default:- False)- If - True, the returned matrix is \(D^{-1/2}(D+M)D^{-1/2}\) for signless and \(D^{-1/2}(D-M)D^{-1/2}\) otherwise, a normalized version of the Laplacian matrix. More accurately, the normalizing matrix used is equal to \(D^{-1/2}\) only for non-isolated vertices. If vertex \(i\) is isolated, then diagonal entry \(i\) in the matrix is 1, rather than a division by zero
- Else, the matrix \(D+M\) for signless and \(D-M\) otherwise is returned 
 
- signless– boolean (default:- False)- If - True, \(D+M\) is used in calculation of Kirchhoff matrix
- Else, \(D-M\) is used in calculation of Kirchhoff matrix 
 
- vertices– list;- None, or- True(default:- None)- when a list, the \(i\)-th row and column of the matrix correspond to the \(i\)-th vertex in the ordering of - vertices,
- when - None, the \(i\)-th row and column of the matrix correspond to the \(i\)-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’s basis is indexed by the vertices.
 - If the vertices are not comparable, the keyword - verticesmust be used to specify an ordering, or a- TypeErrorexception will be raised.
 - Note that any additional keywords will be passed on to either the - adjacency_matrix()or- weighted_adjacency_matrix()method.- AUTHORS: - Tom Boothby 
- Jason Grout 
 - EXAMPLES: - sage: G = Graph(sparse=True) sage: G.add_edges([(0, 1, 1), (1, 2, 2), (0, 2, 3), (0, 3, 4)]) sage: M = G.kirchhoff_matrix(weighted=True); M # 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) -1/3*sqrt(3)] [-1/6*sqrt(3)*sqrt(2) 1 -1/2 0] [-1/6*sqrt(3)*sqrt(2) -1/2 1 0] [ -1/3*sqrt(3) 0 0 1] sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M # 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] >>> 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 [ 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=Trueis 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', 'D', 4)]) sage: phi = G.laplacian_matrix(weighted=True, vertices=True); phi Generic endomorphism of Free module generated by {'A', 'B', 'C', 'D'} over Integer Ring sage: print(phi._unicode_art_matrix()) A B C D A⎛ 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', 'C', Integer(3)), ('A', 'D', Integer(4))]) >>> phi = G.laplacian_matrix(weighted=True, vertices=True); phi Generic endomorphism of Free module generated by {'A', 'B', 'C', 'D'} over Integer Ring >>> print(phi._unicode_art_matrix()) A B C D A⎛ 8 -1 -3 -4⎞ B⎜-1 3 -2 0⎟ C⎜-3 -2 5 0⎟ D⎝-4 0 0 4⎠ 
 - latex_options()[source]¶
- Return an instance of - GraphLatexfor 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_latexmodule.- 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': 'Classic'} - >>> 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'} 
 - layout(layout=None, pos=None, dim=2, save_pos=False, **options)[source]¶
- 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)
 - If - layoutis set, the specified algorithm is used to compute the positions.- Otherwise, if - posis 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...]} - Some safety tests: - sage: sorted(D2.keys()) == sorted(D3.keys()) == sorted(g) True sage: 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 -- boolean. option dim : The dimension of the layout -- 2 or 3. option forest_roots : An iterable specifying which vertices to use as roots for the ``layout='forest'`` option. If no root is specified for a tree, then one is chosen close to the center of the tree. Ignored unless ``layout='forest'``. option heights : A dictionary mapping heights to the list of vertices at this height. option iterations : The number of times to execute the spring layout algorithm. option layout : A layout algorithm -- one of : "acyclic", "circular" (plots the graph with vertices evenly distributed on a circle), "ranked", "graphviz", "planar", "spring" (traditional spring layout, using the graph's current positions as initial positions), or "tree" (the tree will be plotted in levels, depending on minimum distance for the root). option prog : Which graphviz layout program to use -- one of "circo", "dot", "fdp", "neato", or "twopi". option save_pos : Whether or not to save the computed position for the graph. option spring : Use spring layout to finalize the current layout. option tree_orientation : The direction of tree branches -- 'up', 'down', 'left' or 'right'. option tree_root : A vertex designation for drawing trees. A vertex of the tree to be used as the root for the ``layout='tree'`` option. If no root is specified, then one is chosen close to the center of the tree. Ignored unless ``layout='tree'``. - >>> 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)) option by_component : Whether to do the spring layout by connected component -- boolean. option dim : The dimension of the layout -- 2 or 3. option forest_roots : An iterable specifying which vertices to use as roots for the ``layout='forest'`` option. If no root is specified for a tree, then one is chosen close to the center of the tree. Ignored unless ``layout='forest'``. option heights : A dictionary mapping heights to the list of vertices at this height. option iterations : The number of times to execute the spring layout algorithm. option layout : A layout algorithm -- one of : "acyclic", "circular" (plots the graph with vertices evenly distributed on a circle), "ranked", "graphviz", "planar", "spring" (traditional spring layout, using the graph's current positions as initial positions), or "tree" (the tree will be plotted in levels, depending on minimum distance for the root). option prog : Which graphviz layout program to use -- one of "circo", "dot", "fdp", "neato", or "twopi". option save_pos : Whether or not to save the computed position for the graph. option spring : Use spring layout to finalize the current layout. option tree_orientation : The direction of tree branches -- 'up', 'down', 'left' or 'right'. option tree_root : A vertex designation for drawing trees. A vertex of the tree to be used as the root for the ``layout='tree'`` option. If no root is specified, then one is chosen close to the center of the tree. Ignored unless ``layout='tree'``. - Some of them only apply to certain layout algorithms. For details, see - layout_acyclic(),- layout_planar(),- layout_circular(),- layout_spring(), …- Warning - unknown optional arguments are silently ignored - Warning - graphvizand- dot2texare currently required to obtain a nice- 'acyclic'layout. See- layout_graphviz()for installation instructions.- A subclass may implement another layout algorithm - 'blah', by implementing a method- .layout_blah. It may override the default layout by overriding- layout_default(), and similarly override the predefined layouts.- Todo - use this feature for all the predefined graphs classes (like for the Petersen graph, …), rather than systematically building the layout at construction time. 
 - layout_circular(dim=2, center=(0, 0), radius=1, shift=0, angle=0, **options)[source]¶
- 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
- shift– (default: 0) rotation of the circle. A value of- shift=1will replace in the drawing the \(i\)-th element of the list by the \((i-1)\)-th. Non-integer values are admissible, and a value of \(\alpha\) corresponds to a rotation of the circle by an angle of \(\alpha 2\pi/n\) (where \(n\) is the number of vertices set on the circle).
- angle– (default: 0) rotate the embedding of all vertices. For instance, when- angle == 0, the first vertex get position- (center[0] + radius, center[1]). With a value of \(\pi/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)[source]¶
- Return a spring layout for this graph. - INPUT: - by_components– boolean (default:- True)
- **options– options for method
 
 - 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_extend_randomly(pos, dim=2)[source]¶
- Extend randomly a partial layout. - INPUT: - pos– 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 - posare assigned random positions within the box delimited by the other vertices.- EXAMPLES: - sage: H = digraphs.ButterflyGraph(1) sage: pos = {('0', 0): (0, 0), ('1', 1): (1, 1)} sage: H.layout_extend_randomly(pos) # random {('0', 0): (0, 0), ('0', 1): [0.0446..., 0.332...], ('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) >>> (xmin, ymin) == (Integer(0), Integer(0)) and (xmax, ymax) == (Integer(1), Integer(1)) True 
 - layout_forest(tree_orientation='down', forest_roots=None, **options)[source]¶
- 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; a vertex is chosen close to the center of each component for which no root is specified in- forest_rootsor if- forest_rootsis- 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)[source]¶
- Call - graphvizto compute a layout of the vertices of this graph.- INPUT: - 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- dotlayout program. One may specify an alternative 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 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 - graphvizand the- dot2texspkg. Here are some installation tips:- Install - graphviz>= 2.14 so that the programs- dot,- neato, etc. are in your path. The graphviz suite can be download from http://graphviz.org.
- Install - dot2texwith- 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)[source]¶
- Compute a planar layout of the graph using Schnyder’s algorithm. - If - set_embeddingis set, a new combinatorial embedding is computed for the layout. Otherwise: if- on_embeddingis 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 \((u,v)\) of vertices (default:- None); the external face of the drawing is chosen in such a way that \(u\) and \(v\) are consecutive vertices in the clockwise traversal of the external face, in particular \(uv\) has to be an edge of the graph. If- external_face == None, an arbitrary external face is chosen.
- test– boolean (default:- False); whether to perform sanity tests along the way
- circular– ignored
 - EXAMPLES: - sage: g = graphs.PathGraph(10) sage: g.layout(layout='planar', save_pos=True, test=True) {0: [0, 8], 1: [8, 1], 2: [1, 0], 3: [7, 1], 4: [1, 1], 5: [5, 3], 6: [2, 3], 7: [2, 4], 8: [1, 6], 9: [2, 5]} sage: g = graphs.BalancedTree(3, 4) # 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] >>> 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], 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)[source]¶
- 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)[source]¶
- Return a spring layout for this graph. - INPUT: - by_components– boolean (default:- True)
- **options– options for method
 
 - 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)[source]¶
- 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 is chosen 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: - 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], 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')[source]¶
- 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 last)
- initial_vertex– (default:- None) the first vertex to consider
- algorithm– string (default:- 'fast'); algorithm to use among:- 'slow'– it use the generic algorithm for all the lexicographic searchs. See the documentation of the- traversalsmodule for more details.
- 'fast'– this algorithm uses the notion of partition refinement to determine the position of the vertices in the ordering. The time complexity of this algorithm is in \(O(n + m)\), and our implementation follows that complexity for- SparseGraph. For- DenseGraph, the complexity is \(O(n^2)\). See [HMPV2000] and [TCHP2008] for more details. This algorithm is also used to compute slice decompositions of undirected graphs, a more thorough description can be found in the documentation of the- slice_decompositionmodule.
 
 - Note - Loops and multiple edges are ignored during the computation of - lex_BFSand directed graphs are converted to undirected graphs.- See also 
- slice_decompositionmodule and- slice_decomposition()– compute a slice decomposition of the graph using an extended lex BFS algorithm
- 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: - sage: g = graphs.CompleteGraph(6) sage: set(g.lex_BFS()) == set(g) True - >>> from sage.all import * >>> g = graphs.CompleteGraph(Integer(6)) >>> set(g.lex_BFS()) == set(g) 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: correct_anwsers = [[2, 1, 3], [2, 3, 1]] sage: G.lex_BFS(initial_vertex=2, algorithm='slow') in correct_anwsers True sage: G.lex_BFS(initial_vertex=2, algorithm='fast') in correct_anwsers True - >>> from sage.all import * >>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1), Integer(3))]) >>> correct_anwsers = [[Integer(2), Integer(1), Integer(3)], [Integer(2), Integer(3), Integer(1)]] >>> G.lex_BFS(initial_vertex=Integer(2), algorithm='slow') in correct_anwsers True >>> G.lex_BFS(initial_vertex=Integer(2), algorithm='fast') in correct_anwsers True - For a Chordal Graph, a reversed Lex BFS is a Perfect Elimination Order: - sage: g = graphs.PathGraph(3).lexicographic_product(graphs.CompleteGraph(2)) sage: g.lex_BFS(reverse=True) [(2, 1), (2, 0), (1, 1), (1, 0), (0, 1), (0, 0)] - >>> 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): - 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)[source]¶
- 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 last)
- initial_vertex– (default:- None) the first vertex to consider
 - Note - Loops and multiple edges are ignored during the computation of - lex_DFSand directed graphs are converted to undirected graphs.- 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
 - ALGORITHM: - See the documentation of the - traversalsmodule.- EXAMPLES: - A Lex DFS is obviously an ordering of the vertices: - sage: g = graphs.CompleteGraph(6) sage: set(g.lex_DFS()) == set(g) True - >>> from sage.all import * >>> g = graphs.CompleteGraph(Integer(6)) >>> set(g.lex_DFS()) == set(g) 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: correct_anwsers = [[2, 1, 3], [2, 3, 1]] sage: G.lex_DFS(initial_vertex=2) in correct_anwsers True - >>> from sage.all import * >>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1), Integer(3))]) >>> correct_anwsers = [[Integer(2), Integer(1), Integer(3)], [Integer(2), Integer(3), Integer(1)]] >>> G.lex_DFS(initial_vertex=Integer(2)) in correct_anwsers True - 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', '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') ['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_DOWN(G, reverse=False, tree=False, initial_vertex=None)[source]¶
- 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)
- initial_vertex– (default:- None) the first vertex to consider
 - Note - Loops and multiple edges are ignored during the computation of - lex_DOWNand directed graphs are converted to undirected graphs.- See also - ALGORITHM: - See the documentation of the - traversalsmodule.- EXAMPLES: - A Lex DOWN is obviously an ordering of the vertices: - sage: g = graphs.CompleteGraph(6) sage: set(g.lex_DOWN()) == set(g) True - >>> from sage.all import * >>> g = graphs.CompleteGraph(Integer(6)) >>> set(g.lex_DOWN()) == set(g) 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: correct_anwsers = [[2, 1, 3], [2, 3, 1]] sage: G.lex_DOWN(initial_vertex=2) in correct_anwsers True - >>> from sage.all import * >>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1), Integer(3))]) >>> correct_anwsers = [[Integer(2), Integer(1), Integer(3)], [Integer(2), Integer(3), Integer(1)]] >>> G.lex_DOWN(initial_vertex=Integer(2)) in correct_anwsers True - 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', '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') ['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_UP(G, reverse=False, tree=False, initial_vertex=None)[source]¶
- 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 last)
- initial_vertex– (default:- None) the first vertex to consider
 - Note - Loops and multiple edges are ignored during the computation of - lex_UPand directed graphs are converted to undirected graphs.- 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
 - ALGORITHM: - See the documentation of the - traversalsmodule.- EXAMPLES: - A Lex UP is obviously an ordering of the vertices: - sage: g = graphs.CompleteGraph(6) sage: set(g.lex_UP()) == set(g) True - >>> from sage.all import * >>> g = graphs.CompleteGraph(Integer(6)) >>> set(g.lex_UP()) == set(g) 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] - The method also works for directed graphs: - sage: G = DiGraph([(1, 2), (2, 3), (1, 3)]) sage: correct_anwsers = [[2, 1, 3], [2, 3, 1]] sage: G.lex_UP(initial_vertex=2) in correct_anwsers True - >>> from sage.all import * >>> G = DiGraph([(Integer(1), Integer(2)), (Integer(2), Integer(3)), (Integer(1), Integer(3))]) >>> correct_anwsers = [[Integer(2), Integer(1), Integer(3)], [Integer(2), Integer(3), Integer(1)]] >>> G.lex_UP(initial_vertex=Integer(2)) in correct_anwsers True - 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', '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') ['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'] 
 - lexicographic_product(other, immutable=None)[source]¶
- Return the lexicographic product of - selfand- other.- The lexicographic product of \(G\) and \(H\) is the graph \(L\) with vertex set \(V(L)=V(G)\times V(H)\), and \(((u,v), (w,x))\) is an edge iff : - \((u, w)\) is an edge of \(G\), or 
- \(u = w\) and \((v, x)\) is an edge of \(H\). 
 - INPUT: - other– a graph or a digraph
- immutable– boolean (default:- None); whether to create a mutable/immutable product.- immutable=None(default) means that the graphs and their product will behave the same way. If only one of them is immutable, the product will be mutable.
 - EXAMPLES: - sage: Z = graphs.CompleteGraph(2) sage: C = graphs.CycleGraph(5) sage: L = C.lexicographic_product(Z); L Graph on 10 vertices sage: L.plot() # long time # 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_labels=False)[source]¶
- Return the line graph of the (di)graph - g(multiedges and loops allowed).- 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. In case of multiple edges, the vertices of the line graph will be triples- (u,v,an integer).
- return_labels– boolean (default:- False); whether edge labels should be stored or not. If g has multiple edges and if- return_labels=True, the method returns a list the first element of which is the line-graph of g and the second element is a dictionary {vertex of the line-graph: former corresponding edge with its original label}. If- return_labels=False, the method returns only the line-graph.
 - The line graph of an undirected graph G is an undirected simple 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. - Loops are not adjacent to themselves. - The line graph of a directed graph G is a directed graph H such that the vertices of H are the edges of G and two vertices e and f of H are adjacent if e and f share a common vertex in G and the terminal vertex of e is the initial vertex of f. In other words, an edge in H represents a (directed) path of length 2 in G. - Note - As a - Graphobject 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=Falseto ignore labels.- See also - The - line_graphmodule
- 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 [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)] - Examples with multiple edges: - sage: L = Graph([(0,1),(0,1),(1,2)],multiedges=True).line_graph() sage: L.edges() [((0, 1, 0), (0, 1, 1), None), ((0, 1, 1), (1, 2, 2), None), ((0, 1, 0), (1, 2, 2), None)] sage: G = Graph([(0,1),(0,1,'a'),(0,1,'b'),(0,2),(1,2,'c')], ....: multiedges=True) sage: L = G.line_graph(False,True) sage: L[0].edges() [((0, 1, 1), (0, 1, 2), None), ((0, 1, 0), (0, 1, 2), None), ((0, 1, 2), (0, 2, 3), None), ((0, 1, 2), (1, 2, 4), None), ((0, 1, 0), (0, 1, 1), None), ((0, 1, 1), (0, 2, 3), None), ((0, 1, 1), (1, 2, 4), None), ((0, 1, 0), (0, 2, 3), None), ((0, 1, 0), (1, 2, 4), None), ((0, 2, 3), (1, 2, 4), None)] sage: L[1] {(0, 1, 0): (0, 1, None), (0, 1, 1): (0, 1, 'b'), (0, 1, 2): (0, 1, 'a'), (0, 2, 3): (0, 2, None), (1, 2, 4): (1, 2, 'c')} sage: g = DiGraph([(0,1),(0,1),(1,2)],multiedges=True) sage: g.line_graph().edges() [((0, 1, 1), (1, 2, 2), None), ((0, 1, 0), (1, 2, 2), None)] - >>> from sage.all import * >>> L = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(1)),(Integer(1),Integer(2))],multiedges=True).line_graph() >>> L.edges() [((0, 1, 0), (0, 1, 1), None), ((0, 1, 1), (1, 2, 2), None), ((0, 1, 0), (1, 2, 2), None)] >>> G = Graph([(Integer(0),Integer(1)),(Integer(0),Integer(1),'a'),(Integer(0),Integer(1),'b'),(Integer(0),Integer(2)),(Integer(1),Integer(2),'c')], ... multiedges=True) >>> L = G.line_graph(False,True) >>> L[Integer(0)].edges() [((0, 1, 1), (0, 1, 2), None), ((0, 1, 0), (0, 1, 2), None), ((0, 1, 2), (0, 2, 3), None), ((0, 1, 2), (1, 2, 4), None), ((0, 1, 0), (0, 1, 1), None), ((0, 1, 1), (0, 2, 3), None), ((0, 1, 1), (1, 2, 4), None), ((0, 1, 0), (0, 2, 3), None), ((0, 1, 0), (1, 2, 4), None), ((0, 2, 3), (1, 2, 4), None)] >>> L[Integer(1)] {(0, 1, 0): (0, 1, None), (0, 1, 1): (0, 1, 'b'), (0, 1, 2): (0, 1, 'a'), (0, 2, 3): (0, 2, None), (1, 2, 4): (1, 2, 'c')} >>> g = DiGraph([(Integer(0),Integer(1)),(Integer(0),Integer(1)),(Integer(1),Integer(2))],multiedges=True) >>> g.line_graph().edges() [((0, 1, 1), (1, 2, 2), None), ((0, 1, 0), (1, 2, 2), None)] - An example with a loop: - sage: g = Graph([(0,0),(0,1),(0,2),(1,2)],multiedges=True,loops=True) sage: L = g.line_graph() sage: L.edges() [((0, 0, None), (0, 1, None), None), ((0, 0, None), (0, 2, None), None), ((0, 1, None), (0, 2, None), None), ((0, 1, None), (1, 2, None), None), ((0, 2, None), (1, 2, None), None)] - >>> from sage.all import * >>> g = Graph([(Integer(0),Integer(0)),(Integer(0),Integer(1)),(Integer(0),Integer(2)),(Integer(1),Integer(2))],multiedges=True,loops=True) >>> L = g.line_graph() >>> L.edges() [((0, 0, None), (0, 1, None), None), ((0, 0, None), (0, 2, None), None), ((0, 1, None), (0, 2, None), None), ((0, 1, None), (1, 2, None), None), ((0, 2, None), (1, 2, None), None)] 
 - longest_cycle(induced, use_edge_labels=False, immutable=False, solver=None, verbose=None, integrality_tolerance=0)[source]¶
- Return the longest (induced) cycle of - self.- This method uses an integer linear programming formulation based on subtour elimination constraints to find the 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- Noneor- {}being considered as a weight of \(1\)), or to compute a cycle with the largest possible number of edges (i.e., edge weights are set to 1)
- immutable– boolean (default:- None); whether to create a mutable/immutable (di)graph.- immutable=None(default) means that the (di)graph and its longest cycle will behave the same way.
- solver– string (default:- None); specifies 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- solveof 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 - selfcorresponding to a (directed if- selfis directed) longest (induced) cycle. If- use_edge_labels == True, a pair- weight, cycleis returned.- 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) 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, immutable='MILP', solver=None, verbose=None, integrality_tolerance=0)[source]¶
- Return a longest path of - self.- INPUT: - s– a vertex (default:- None); forces the source of the path (the method then returns the longest path starting at- s). The argument is set to- Noneby default, which means that no constraint is set upon the first vertex in the path.- This parameter can only be used when - algorithmis- 'MILP'.
- t– a vertex (default:- None); forces the destination of the path (the method then returns the longest path ending at- t). The argument is set to- Noneby default, which means that no constraint is set upon the last vertex in the path.- This parameter can only be used when - algorithmis- '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- Noneor- {}being considered as a weight of \(1\)), or to compute a path with the longest possible number of edges (i.e., edge weights are set to 1)- This parameter can only be used when - algorithmis- '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,- tand- use_edge_labels. An error is raised if these parameters are set.
 
- immutable– boolean (default:- None); whether to create a mutable/immutable (di)graph.- immutable=None(default) means that the (di)graph and its longest path will behave the same way.
- solver– string (default:- None); specifies 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- solveof the class- MixedIntegerLinearProgram.
- verbose– integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
- integrality_tolerance– float; parameter for use with MILP solvers over an inexact base ring; see- MixedIntegerLinearProgram.get_values().
 - Note - The length of a path is assumed to be the number of its edges, or the sum of their labels (when - use_edge_labels == True).- OUTPUT: - A subgraph of - selfcorresponding to a (directed if- selfis directed) longest path. If- use_edge_labels == True, a pair- weight, pathis 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 \(n - 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) 9 - >>> from sage.all import * >>> g = graphs.PetersenGraph() >>> p = g.longest_path(algorithm='heuristic').edges(sort=True, labels=False) >>> len(p) 9 - Let us compute the longest path on a random graph with random weights, and ensure the resulting graph is indeed 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() # 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)[source]¶
- 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() 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)] - >>> 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()[source]¶
- 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)[source]¶
- 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() 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)] - >>> 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)] 
 - max_cut(value_only, use_edge_labels=True, vertices=False, solver=False, verbose=None, integrality_tolerance=0)[source]¶
- 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 cut of maximum cardinality (i.e., edge weights are set to 1)
- vertices– boolean (default:- False); whether to return the two sets of vertices that are disconnected by the cut. This implies- value_only=False.
- solver– string (default:- None); specifies 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- solveof 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 the two 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: - 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)[source]¶
- Return the maximum leaf number of the graph. - The maximum leaf number is the maximum possible number of leaves of a spanning tree of \(G\). This is also 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); specifies 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- solveof 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() 0 - Petersen graph: - sage: G = graphs.PetersenGraph() sage: G.maximum_leaf_number() 6 - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> G.maximum_leaf_number() 6 
 - merge_vertices(vertices)[source]¶
- Merge vertices. - This function replaces a set \(S\) of vertices by a single vertex \(v_{new}\), such that the edge \(uv_{new}\) exists if and only if \(\exists v'\in S: (u,v')\in G\). - The new vertex is named after the first vertex in the list given in argument. If this first name is - None, a new vertex is created.- In the case of multigraphs, the multiplicity is preserved. - INPUT: - vertices– the list of vertices to be merged
 - Note - If - uand- vare distinct vertices in- vertices, any edges between- uand- vwill 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 - verticesis- 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 - 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)[source]¶
- 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 a minimum spanning tree (available only for- Prim_fringeand- Prim_edge).
- check– boolean (default:- False); whether to first perform sanity checks on the input graph- G. If appropriate,- checkis passed on to any minimum spanning tree functions that are invoked from the current method. See the documentation of the corresponding functions for details on what sort of sanity checks will be performed.
- weight_function– function (default:- None); a function that takes as input an edge- (u, v, l)and outputs its weight. If not- None,- by_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight. The- weight_functioncan be used to transform the label into a weight (note that, if the weight returned is not convertible to a float, an error is raised)
- by_weight– boolean (default:- False); if- True, the edges in the graph are weighted, otherwise all edges have weight 1
- check_weight– boolean (default:- True); whether to check that the- weight_functionoutputs a number for each edge
 - OUTPUT: - The edges of a minimum spanning tree of - G, if one exists, otherwise returns the empty list.- See also - EXAMPLES: - Kruskal’s algorithm: - sage: g = graphs.CompleteGraph(5) sage: len(g.min_spanning_tree()) 4 sage: weight = lambda e: 1 / ((e[0] + 1) * (e[1] + 1)) sage: 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) >>> 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': 'a', 'weight': 1}), ....: (0, 2, {'name': 'b', 'weight': 3}), ....: (1, 2, {'name': 'b', 'weight': 1})]) 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 - weightedto- 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 the other: - 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)[source]¶
- 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 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: - 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as 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_functionoutputs 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) [[2, 3, 1], [2, 3, 4, 1], [6, 7, 5]] sage: g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX') # needs networkx, random (changes in networkx 3.2) [[3, 4, 1], [2, 3, 1], [6, 7, 5]] - >>> 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) [[2, 3, 1], [2, 3, 4, 1], [6, 7, 5]] >>> g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX') # needs networkx, random (changes in networkx 3.2) [[3, 4, 1], [2, 3, 1], [6, 7, 5]] - 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) [[3, 4, 5], [5, 3, 2, 1]] - >>> 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) [[3, 4, 5], [5, 3, 2, 1]] 
 - multicommodity_flow(terminals, integer, use_edge_labels=True, vertex_bound=False, solver=False, verbose=None, integrality_tolerance=0)[source]¶
- Solve a multicommodity flow problem. - In the multicommodity flow problem, we are given a set of pairs \((s_i, t_i)\), called terminals meaning that \(s_i\) is willing some flow to \(t_i\). - 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– list of pairs \((s_i, t_i)\) or triples \((s_i, t_i, w_i)\) representing a flow from \(s_i\) to \(t_i\) of intensity \(w_i\). When the pairs are of size \(2\), an intensity of \(1\) is assumed.
- integer– boolean (default:- True); whether to require an integer multicommodity flow
- 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 of flow even though- vertex_boundis set to- True, as this parameter is meant to represent topological properties.
- solver– string (default:- None); specifies 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- solveof 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 - integeris- 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 - gas 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 >>> 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)[source]¶
- 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 value that 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() 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() False >>> D.edges(sort=True) [(0, 1, None)] >>> G = DiGraph({Integer(1): {Integer(2): 'h'}, Integer(2): {Integer(1): 'g'}}, 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')] - Using the - keyargument 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)[source]¶
- Return a minimum edge multiway cut. - A multiway cut for a vertex set \(S\) in a graph or a digraph \(G\) is a set \(C\) of edges such that any two vertices \(u,v\) in \(S\) are disconnected when removing the edges of \(C\) from \(G\). ( 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 compute a cut of minimum cardinality (i.e., edge weights are set to 1)
- solver– string (default:- None); specifies 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- solveof 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\times 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 save \(4\) edges in the multiway cut: - sage: g.multiway_cut([0,7,9], value_only=True) == 2*3 - 1 # needs sage.numerical.mip True - >>> 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 to mutualise 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)[source]¶
- 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- nameis set, the string representation of that object becomes the new name of the (di)graph (- new == ''removes any name).
 - EXAMPLES: - sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], 5: [7, 8], 6: [8,9], 7: [9]} sage: G = Graph(d); G Graph on 10 vertices sage: G.name("Petersen Graph"); G Petersen Graph: Graph on 10 vertices sage: G.name(new=""); G Graph on 10 vertices sage: G.name() '' sage: G.name(42); G 42: Graph on 10 vertices sage: G.name() '42' - >>> 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"); G Petersen Graph: Graph on 10 vertices >>> G.name(new=""); G Graph on 10 vertices >>> G.name() '' >>> G.name(Integer(42)); G 42: Graph on 10 vertices >>> G.name() '42' 
 - neighbor_iterator(vertex, closed=False)[source]¶
- Return an iterator over neighbors of - vertex.- When - closedis set to- True, the returned iterator also contains- vertex.- INPUT: - vertex– a vertex of- self
- closed– boolean (default:- False); whether to return the closed neighborhood of- vertex, i.e., including- vertex, or the open neighborhood in which- vertexis included only if there is a loop on that vertex.
 - EXAMPLES: - sage: G = graphs.PetersenGraph() sage: for i in G.neighbor_iterator(0): ....: print(i) 1 4 5 sage: D = G.to_directed() sage: for i in D.neighbor_iterator(0): ....: print(i) 1 4 5 - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> for i in G.neighbor_iterator(Integer(0)): ... print(i) 1 4 5 >>> D = G.to_directed() >>> for i in D.neighbor_iterator(Integer(0)): ... print(i) 1 4 5 - sage: 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)[source]¶
- Return a list of neighbors (in and out if directed) of - vertex.- G[vertex]also works. When- closedis set to- True, the returned iterator also contains- vertex.- INPUT: - vertex– a vertex of- self
- closed– boolean (default:- False); whether to return the closed neighborhood of- vertex, i.e., including- vertex, or the open neighborhood in which- vertexis included only if there is a loop on that vertex.
 - EXAMPLES: - sage: P = graphs.PetersenGraph() sage: sorted(P.neighbors(3)) [2, 4, 8] sage: sorted(P[4]) [0, 3, 9] sage: sorted(P.neighbors(3, closed=True)) [2, 3, 4, 8] - >>> 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)[source]¶
- Return a new - NetworkXgraph 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() # 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)[source]¶
- Return a - k-nowhere zero flow of the (di)graph.- A flow on a graph \(G = (V, E)\) is a pair \((D, f)\) such that \(D\) is an orientation of \(G\) and \(f\) is a function on \(E\) satisfying \[\sum_{u \in N^-_D(v)} f(uv) = \sum_{w \in N^+_D(v)} f(vw), \ \forall v \in V.\]- A - nowhere zero flowon a graph \(G = (V, E)\) is a flow \((D, f)\) such that \(f(e) \neq 0\) for every \(e \in E\). For a positive integer \(k\), a \(k\)-flow on a graph \(G = (V, E)\) is a flow \((D, f)\) such that \(f: E \to Z\) and \(-(k - 1) \leq f(e) \leq k - 1\) for every \(e \in E\). A \(k\)-flow is positive if \(f(e) > 0\) for every \(e \in E\). A \(k\)-flow which is nowhere zero is called a \(k\)-nowhere zero flow (or \(k\)-NZF).- The following are equivalent. - \(G\) admits a positive \(k\)-flow. 
- \(G\) admits a \(k\)-NZF. 
- Every orientation of \(G\) admits a \(k\)-NZF. 
 - Furthermore, a (di)graph admits a \(k\)-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 - selfis not directed, we search for a \(k\)-NZF on any orientation of- selfand then build a positive \(k\)-NZF by reverting edges with negative flow.- INPUT: - k– integer (default: \(6\)); when set to a positive integer \(\geq 2\), search for a \(k\)-nowhere zero flow
- solver– string (default:- None); specifies 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- solveof 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 \(k\)-nowhere zero flow is found. If - selfis 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)) # needs sage.combinat sage.numerical.mip >>> sorted(set(h.edge_labels())) # needs sage.combinat sage.numerical.mip [-1, 1] 
 - num_edges()[source]¶
- Return the number of edges. - Note that - num_edges()also returns the number of edges in \(G\).- EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.size() 15 - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> G.size() 15 
 - num_faces(embedding=None)[source]¶
- Return the number of faces of an embedded graph. - If no embedding is provided or stored as - self._embedding, this method uses Euler’s formula (see the Wikipedia article Euler_characteristic) to determine the number of faces if the graph is planar. If the graph is not planar, an error is raised.- If an embedding is provided or stored as - self._embedding, this method calls method- faces()to get the list of faces induced by the embedding in each connected component of the graph. Then it returns the sum of size of these lists minus the number of connected components plus one to ensure that the external face is counted only once.- INPUT: - embedding– dictionary (default:- None); a combinatorial embedding dictionary. Format:- {v1: [v2,v3], v2: [v1], v3: [v1]}(clockwise ordering of neighbors at each vertex). If set to- None(default) the method will use the embedding stored as- self._embedding. If none is stored, the method will compute the set of faces from the embedding returned by- is_planar()(if the graph is, of course, planar).
 - EXAMPLES: - sage: T = graphs.TetrahedralGraph() sage: T.num_faces() 4 - >>> 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 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()[source]¶
- Return the number of vertices. - Note that - len(G)and- num_verts()also return the number of vertices in \(G\).- EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.order() 10 - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> G.order() 10 - sage: G = graphs.TetrahedralGraph() sage: len(G) 4 - >>> from sage.all import * >>> G = graphs.TetrahedralGraph() >>> len(G) 4 
 - number_of_loops()[source]¶
- Return the number of edges that are loops. - EXAMPLES: - sage: G = Graph(4, loops=True) sage: G.add_edges([(0, 0), (1, 1), (2, 2), (3, 3), (2, 3)]) sage: G.edges(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)[source]¶
- Return the odd girth of the graph. - The odd girth is the length of the shortest cycle of odd length in the graph (directed cycle if the graph is directed). Bipartite graphs have infinite odd girth. - INPUT: - algorithm– string (default:- 'bfs'); the algorithm to use:- 'bfs'– BFS-based algorithm
- any algorithm accepted by - charpoly()for computation from the characteristic polynomial (see [Har1962] and [Big1993], p. 45)
 
- certificate– boolean (default:- False); whether to return- (g, c), where- gis the odd girth and- cis a list of vertices of a (directed) cycle of length- gin the graph, thus providing a certificate that the odd girth is at most- g, or- Noneif- gis infinite. So far, this parameter is accepted only when- algorithm = "bfs".
 - EXAMPLES: - The McGee graph has girth 7 and therefore its odd girth is 7 as well: - sage: G = graphs.McGeeGraph() # 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 girth 3: - sage: G = graphs.CompleteGraph(5) sage: G.odd_girth(certificate=True) # random (3, [2, 1, 0]) sage: G = digraphs.Complete(5) sage: G.odd_girth(certificate=True) # random (3, [1, 2, 0]) - >>> 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() +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()[source]¶
- Return the number of vertices. - Note that - len(G)and- num_verts()also return the number of vertices in \(G\).- EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.order() 10 - >>> from sage.all import * >>> G = graphs.PetersenGraph() >>> G.order() 10 - sage: G = graphs.TetrahedralGraph() sage: len(G) 4 - >>> from sage.all import * >>> G = graphs.TetrahedralGraph() >>> len(G) 4 
 - pagerank(alpha=0.85, personalization=None, by_weight=False, weight_function=None, check_weight=True, dangling=None, algorithm='scipy')[source]¶
- 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.- alphais 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– dictionary (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 all edges have weight 1
- weight_function– function (default:- None); a function that takes as input an edge- (u, v, l)and outputs its weight. If not- None,- by_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); whether to check that the- weight_functionoutputs a number for each edge
- dangling– dictionary (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 in computing 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 node - Note - Parameters - alpha,- by_weightand- weight_functionare common to all algorithms. Parameters- personalizationand- danglingare used only by algorithms- NetworkX,- Numpyand- Scipy.- EXAMPLES: - 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') # abs tol 1e-9, 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") # abs tol 1e-9 # 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) # abs tol 1e-9 # 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') # 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} sage: 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} sage: G.pagerank(algorithm='igraph') # abs tol 1e-9, optional - python_igraph {1: 0.16112198303979128, 2: 0.16195368558382262, 3: 0.16112198303979125, 4: 0.23749999999999993, 5: 0.17775603392041744, 6: 0.10054631441617742} sage: G.pagerank() # abs tol 1e-9 # needs networkx {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} sage: G.pagerank(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} - >>> 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, 2: 0.16195368558382262, 3: 0.16112198303979125, 4: 0.23749999999999993, 5: 0.17775603392041744, 6: 0.10054631441617742} >>> G.pagerank() # 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(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} - See also 
 - planar_dual(embedding=None)[source]¶
- Return the planar dual of an embedded graph. - A combinatorial embedding of a graph is a clockwise ordering of the neighbors of each vertex. From this information one can obtain the dual of a plane graph, which is what the method returns. The vertices of the dual graph correspond to faces of the primal graph. - INPUT: - embedding– dictionary (default:- None); a combinatorial embedding dictionary. Format:- {v1: [v2,v3], v2: [v1], v3: [v1]}(clockwise ordering of neighbors at each vertex). If set to- None(default) the method will use the embedding stored as- self._embedding. If none is stored, the method will compute the set of faces from the embedding returned by- is_planar()(if the graph is, of course, planar).
 - EXAMPLES: - sage: C = graphs.CubeGraph(3) sage: C.planar_dual() Graph on 6 vertices sage: graphs.IcosahedralGraph().planar_dual().is_isomorphic(graphs.DodecahedralGraph()) True - >>> 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 - 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 - Todo - Implement the method for graphs that are not 3-vertex-connected, or at least have a faster 3-vertex-connectivity test (Issue #24635). 
 - plot(**options)[source]¶
- Return a - Graphicsobject 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 of- str(l)is printed on the edge for each label \(l\). Labels equal to- Noneare not printed (to set edge labels, see- set_edge_label()).
- edge_labels_background– the color of the edge labels background. The default is “white”. To achieve a transparent background use “transparent”.
- vertex_size– size of vertices displayed
- vertex_shape– the shape to draw the vertices, for example- 'o'for circle or- 's'for square. Whole list is available at https://matplotlib.org/api/markers_api.html. (Not available for multiedge digraphs.)
- graph_border– boolean (default:- False); whether to include a box around the graph
- vertex_colors– dictionary (default:- None); optional dictionary to specify vertex colors: each key is a color recognizable by matplotlib, and each corresponding entry is a list of vertices. If a vertex is not listed, it looks invisible on the resulting plot (it doesn’t get drawn).
- edge_colors– dictionary (default:- None); a dictionary specifying edge colors: each key is a color recognized by matplotlib, and each entry is a list of edges.
- partition– a partition of the vertex set (default:- None); if specified, plot will show each cell in a different color.- vertex_colorstakes 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– 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_colorand- edge_colors.
- heights– dictionary (default:- None); if specified, this is a dictionary from a set of floating point heights to a set of vertices
- edge_style– keyword arguments passed into the edge-drawing routine. This currently only works for directed graphs, since we pass off the undirected graph to networkx
- tree_root– a vertex (default:- None); if specified, this vertex is used as the root for the- layout="tree"option. Otherwise, then one is chosen at random. Ignored unless- layout='tree'.
- tree_orientation– string (default:- 'down'); one of “up” or “down”. If “up” (resp., “down”), then the root of the tree will appear on the bottom (resp., top) and the tree will grow upwards (resp. downwards). Ignored unless- layout='tree'.
- save_pos– boolean (default:- False); save position computed during plotting
 - Note - This method supports any parameter accepted by - sage.plot.graphics.Graphics.show().
- See the documentation of the - sage.graphs.graph_plotmodule 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 - optionsmechanism. For more information on this different way to set default parameters, see the help of the- options decorator.
- See also the - sage.graphs.graph_latexmodule for ways to use LaTeX to produce an image of a graph.
 - EXAMPLES: - sage: from sage.graphs.graph_plot import graphplot_options sage: sorted(graphplot_options.items()) [...] sage: from math import sin, cos, pi sage: P = graphs.PetersenGraph() sage: d = {'#FF0000': [0, 5], '#FF9900': [1, 6], '#FFFF00': [2, 7], ....: '#00FF00': [3, 8], '#0000FF': [4, 9]} sage: pos_dict = {} sage: for i in range(5): ....: x = float(cos(pi/2 + ((2*pi)/5)*i)) ....: y = float(sin(pi/2 + ((2*pi)/5)*i)) ....: pos_dict[i] = [x,y] sage: for i in range(5, 10): ....: x = float(0.5*cos(pi/2 + ((2*pi)/5)*i)) ....: y = float(0.5*sin(pi/2 + ((2*pi)/5)*i)) ....: pos_dict[i] = [x,y] sage: pl = P.plot(pos=pos_dict, vertex_colors=d) # 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) + ',' + str(v) + ')') sage: G.plot(edge_labels=True).show() # needs sage.plot - >>> from sage.all import * >>> G = graphs.HeawoodGraph() >>> for u, v, l in G.edges(sort=False): ... G.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')') >>> G.plot(edge_labels=True).show() # needs sage.plot - 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)): ... 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) # 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') # 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))) >>> 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 - 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': 'red'}, # needs sage.plot ....: edge_style='dashed') Graphics object consisting of 34 graphics primitives sage: g = Graph({}, loops=True, multiedges=True, sparse=True) sage: g.add_edges([(0, 0, 'a'), (0, 0, 'b'), (0, 1, 'c'), (0, 1, 'd'), ....: (0, 1, 'e'), (0, 1, 'f'), (0, 1, 'f'), (2, 1, 'g'), (2, 2, 'h')]) sage: g.plot(edge_labels=True, color_by_label=True, edge_style='dashed') # 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': 'red'}, # needs sage.plot ... edge_style='dashed') Graphics object consisting of 34 graphics primitives >>> 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')]) >>> 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)[source]¶
- Plot a graph in three dimensions. - See also the - sage.graphs.graph_latexmodule for ways to use LaTeX to produce an image of a graph.- INPUT: - bgcolor– rgb tuple (default:- (1,1,1))
- vertex_size– float (default: \(0.06\))
- vertex_labels– boolean (default:- False); whether to display vertices using text labels instead of 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– 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_colorand- edge_colors.
- edge_size– float (default: \(0.02\))
- edge_size2– float (default: \(0.0325\)); used for- Tachyonsleeves
- 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) # long time, needs sage.plot Graphics3d Object - >>> 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 - Tachyonexamples:- 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)], ... (Integer(0),Integer(0),Integer(1)): [(Integer(1),Integer(2),None)]}).show() - A directed version of the dodecahedron - sage: D = DiGraph({0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], ....: 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], ....: 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], ....: 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], ....: 17: [18], 18: [19], 19: []}) sage: D.plot3d().show() # long time # 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() 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 - partitionkeyword:- 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.plot Graphics3d Object - See also 
 - power(k)[source]¶
- Return the \(k\)-th power graph of - self.- In the \(k\)-th power graph of a graph \(G\), there is an edge between any pair of vertices at distance at most \(k\) in \(G\), where the distance is considered in the unweighted graph. In a directed graph, there is an arc from a vertex \(u\) to a vertex \(v\) if there is a path of length at most \(k\) in \(G\) from \(u\) to \(v\). - INPUT: - k– integer; the maximum path length for considering edges in the power graph
 - OUTPUT: the \(k\)-th 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)] - >>> 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)[source]¶
- 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() # random (3, 4, None) - >>> from sage.all import * >>> g.random_edge() # random (3, 4, None) 
 - random_edge_iterator(*args, **kwds)[source]¶
- 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: - *argsand- **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)[source]¶
- Return a random subgraph containing each vertex with probability - p.- INPUT: - p– the probability of choosing a vertex
- inplace– boolean (default:- False); using- inplace=Truewill 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... 
 - random_vertex(**kwds)[source]¶
- 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 True 
 - random_vertex_iterator(*args, **kwds)[source]¶
- 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: - *argsand- **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)[source]¶
- Relabel the vertices of - self.- INPUT: - perm– a function, dictionary, iterable, permutation, or- None(default:- None)
- inplace– boolean (default:- True)
- return_map– boolean (default:- False)
- check_input– boolean; whether to test input for correctness. This can potentially be very time-consuming !
- complete_partial_function– boolean; whether to automatically complete the permutation if some elements of the graph are not associated with any new name. In this case, those elements are not relabeled This can potentially be very time-consuming !.
- immutable– boolean; with- inplace=False, whether to create a mutable/immutable relabelled copy.- immutable=None(default) means that the graph and its copy will behave the same way.
 - If - permis a function- f, then each vertex- vis relabeled to- f(v).- If - permis a dictionary- d, then each vertex- v(which should be a key of- d) is relabeled to- d[v].- If - permis 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 - permis a permutation, then each vertex- vis relabeled to- perm(v).- If - permis- None, the graph is relabeled to be on the vertices \(\{0,1,...,n-1\}\). This is not any kind of canonical labeling, but it is consistent (relabeling twice will give the same result).- If - inplaceis- True, the graph is modified in place and- Noneis returned. Otherwise a relabeled copy of the graph is returned.- If - return_mapis- Truea 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): - 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 [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) 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, '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', '101', '110', '111'] sage: G.relabel() sage: G.vertices(sort=True) [0, 1, 2, 3, 4, 5, 6, 7] - >>> from sage.all import * >>> G = graphs.CubeGraph(Integer(3)) >>> G.vertices(sort=True) ['000', '001', '010', '011', '100', '101', '110', '111'] >>> G.relabel() >>> G.vertices(sort=True) [0, 1, 2, 3, 4, 5, 6, 7] - 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} 
 - remove_loops(vertices=None)[source]¶
- Remove loops on vertices in - vertices.- If - verticesis- 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() False 
 - remove_multiple_edges()[source]¶
- 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)[source]¶
- Return the rooted product of \(G\) and \(H\). - The rooted product of two graphs \(G\) and \(H\) is the graph \(R\) defined as follows: take a copy of \(G\) and \(|V(G)|\) copies of \(H\), and for every vertex \(g_i\) of \(G\), identify \(g_i\) with the root of the \(i\)-th copy of \(H\). Mode formally, let \(V(G) = \{g_1, g_2, \ldots, g_n\}\), \(V(H) = \{h_1, h_2, \ldots, h_m\}\), and let \(h_1\) be the root vertex of \(H\). The vertex set \(V(R)\) is equal to the cartesian product of the sets of vertices \(V(G)\) and \(V(H)\), that is \(V(R) = \{(g_i, h_j) : g_i \in V(G), h_j \in V(H)\}\). The edge set \(E(R)\) is the union of the edges of a copy of \(G\), that is \(\{((g_i, h_1), (g_j, h_1)) : (g_i, g_j) \in E(G)\}\), and the edges of the copies of \(H\) for every \(g_i \in V(G)\), that is \(\{((g_i, h_j), (g_i, h_k)) : (h_j, h_k) \in V(H)\}\). - 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 \(G\) and \(H\) depends on the selected root in \(H\): - 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 \(G\) and a path of order 2 is the order of \(G\): - 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 - >>> 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)[source]¶
- 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), 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) + ',' + str(v) + ')') sage: G.edges(sort=True) [(0, 1, '(0,1)'), (0, 5, '(0,5)'), (0, 13, '(0,13)'), ... (11, 12, '(11,12)'), (12, 13, '(12,13)')] - >>> from sage.all import * >>> G = graphs.HeawoodGraph() >>> for u,v,l in G.edges(sort=False): ... G.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')') >>> G.edges(sort=True) [(0, 1, '(0,1)'), (0, 5, '(0,5)'), (0, 13, '(0,13)'), ... (11, 12, '(11,12)'), (12, 13, '(12,13)')] - sage: g = Graph({0: [0, 1, 1, 2]}, loops=True, multiedges=True, sparse=True) sage: g.set_edge_label(0, 0, 'test') sage: g.edges(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)] - 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)[source]¶
- Set a combinatorial embedding dictionary to - _embeddingattribute.- The dictionary - embeddingrepresents a combinatorial embedding of- selfand is organized as a mapping from vertex labels to list of vertex neighbors in clockwise order.- Parameter - embeddingis 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), 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)[source]¶
- Set multiple options for rendering a graph with LaTeX. - INPUT: - kwds– any number of option/value pairs to set many graph latex options at once (a variable number, in any order). Existing values are overwritten, new values are added. Existing values can be cleared by setting the value to- None. Possible options are documented at- sage.graphs.graph_latex.GraphLatex.set_option().
 - This method is a convenience for setting the options of a graph directly on an instance of the graph. For a full explanation of how to use LaTeX to render graphs, see the introduction to the - graph_latexmodule.- 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)[source]¶
- Set the position dictionary. - The position dictionary specifies the coordinates of each vertex. - INPUT: - pos– a position dictionary for the vertices of the (di)graph
- dim– integer (default: 2); the number of coordinates per vertex
 - EXAMPLES: - sage: G = graphs.PetersenGraph() sage: G.get_pos() {0: (..., ...), ... 9: (..., ...)} - >>> 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)[source]¶
- 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() >>> 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 graph 
 - set_vertices(vertex_dict)[source]¶
- 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)[source]¶
- Return a list of vertices representing some shortest path from - uto- v.- If there is no path from \(u\) to \(v\), 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 all edges have weight 1
- algorithm– string (default:- None); one of the following algorithms:- 'BFS': performs a BFS from- u. Does not work with edge weights.
- 'BFS_Bid': performs a BFS from- uand from- v. Does not work with edge weights.
- 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX. Works only with positive weights.
- 'Dijkstra_Bid_NetworkX': performs a Dijkstra visit from- uand from- v(NetworkX implementation). Works only with positive weights.
- 'Dijkstra_Bid': a Cython implementation that performs a Dijkstra visit from- uand from- v. Works only with positive weights.
- 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost. Works also with negative weights, if there is no negative cycle.
- None(default): Sage chooses the best algorithm:- 'BFS_Bid'if- by_weightis- False,- 'Dijkstra_Bid'otherwise.
 - Note - If there are negative weights and algorithm is - None, the result is not reliable. This occurs because, for performance reasons, we cannot check whether there are edges with 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the weight_function outputs a number for each edge
 - EXAMPLES: - sage: D = graphs.DodecahedralGraph() sage: D.shortest_path(4, 9) [4, 17, 16, 12, 13, 9] sage: D.shortest_path(4, 9, algorithm='BFS') [4, 3, 2, 1, 8, 9] sage: D.shortest_path(4, 8, algorithm='Dijkstra_NetworkX') # 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, 2, 1, 8, 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, # 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, 2, 1, 8, 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)[source]¶
- Return a shortest path between each pair of vertices. - INPUT: - by_weight– boolean (default:- False); if- True, the edges in the graph are weighted, otherwise all edges have weight 1
- algorithm– string (default:- None); one of the following algorithms:- 'BFS': 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 with weighted graphs, but no negative weight is allowed.
- 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost (works only with positive weights).
- 'Johnson_Boost': the Johnson algorithm, implemented in Boost (works also with negative weights, if there is no negative cycle).
- None(default): Sage chooses the best algorithm:- 'BFS'if- by_weightis- 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the weight_function outputs a number for each edge
 - OUTPUT: - A tuple - (dist, pred). They are both dicts of dicts. The first indicates the length- dist[u][v]of the shortest weighted path from \(u\) to \(v\). The second is a compact representation of all the paths - it indicates the predecessor- pred[u][v]of \(v\) in the shortest path from \(u\) to \(v\).- Note - Only reachable vertices are present in the dictionaries. - Note - There is a Cython version of this method that is usually much faster for large graphs, as most of the time is actually spent building the final double dictionary. Everything on the subject is to be found in the - distances_all_pairsmodule.- 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 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':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\) is - pred[0][3] == 2, the predecessor of \(2\) is- pred[0][2] == 1, and the predecessor of \(1\) is- pred[0][1] == 0.- sage: G = Graph({0: {1:None}, 1: {2:None}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, sparse=True) sage: G.shortest_path_all_pairs() ({0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2}, 3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1}, 4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0}}, {0: {0: None, 1: 0, 2: 1, 3: 4, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 4, 1: 2, 2: 3, 3: None, 4: 3}, 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}}) sage: G.shortest_path_all_pairs(weight_function=lambda e:(e[2] if e[2] is not None else 1)) ({0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}}, {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}}) - >>> 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}, 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) 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 >>> 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}}, {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 >>> 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)[source]¶
- Return the minimal length of a path from - uto- v.- If there is no path from \(u\) to \(v\), returns - Infinity.- For more information and more examples, we refer to - shortest_path()and- shortest_paths(), which have very similar inputs.- INPUT: - u,- v– the start and the end vertices of the paths
- by_weight– boolean (default:- False); if- True, the edges in the graph are weighted, otherwise all edges have weight 1
- algorithm– string (default:- None); one of the following algorithms:- 'BFS': performs a BFS from- u. Does not work with edge weights.
- 'BFS_Bid': performs a BFS from- uand from- v. Does not work with edge weights.
- 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX. Works only with positive weights.
- 'Dijkstra_Bid_NetworkX': performs a Dijkstra visit from- uand from- v(NetworkX implementation). Works only with positive weights.
- 'Dijkstra_Bid': a Cython implementation that performs a Dijkstra visit from- uand from- v. Works only with positive weights.
- 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost. Works also with negative weights, if there is no negative cycle.
- None(default): Sage chooses the best algorithm:- 'BFS_Bid'if- by_weightis- False,- 'Dijkstra_Bid'otherwise.
 - Note - If there are negative weights and algorithm is - None, the result is not reliable. This occurs because, for performance reasons, we cannot check whether there are edges with 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the weight_function outputs a number for each edge
 - EXAMPLES: - Standard examples: - sage: D = graphs.DodecahedralGraph() sage: D.shortest_path_length(4, 9) 5 sage: D.shortest_path_length(4, 9, algorithm='BFS') 5 sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_NetworkX') # 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') 3 sage: 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 >>> 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 - >>> 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)[source]¶
- Return the length of a shortest path from - uto any other vertex.- Returns a dictionary of shortest path lengths keyed by targets, excluding all vertices that are not reachable from \(u\). - For more information on the input variables and more examples, we refer to - shortest_paths()which has the same input variables.- INPUT: - u– the starting vertex
- by_weight– boolean (default:- False); if- True, the edges in the graph are weighted, otherwise all edges have weight 1
- algorithm– string (default:- None); one of the following algorithms:- 'BFS': performs a BFS from- u. Does not work with edge weights.
- 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX (works only with positive weights).
- 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost (works only with positive weights).
- 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost (works also with negative weights, if there is no negative cycle).
- None(default): Sage chooses the best algorithm:- 'BFS'if- by_weightis- 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the weight_function outputs a number for each edge
 - EXAMPLES: - Unweighted case: - sage: D = graphs.DodecahedralGraph() sage: D.shortest_path_lengths(0) {0: 0, 1: 1, 2: 2, 3: 2, 4: 3, 5: 4, 6: 3, 7: 3, 8: 2, 9: 2, 10: 1, 11: 2, 12: 3, 13: 3, 14: 4, 15: 5, 16: 4, 17: 3, 18: 2, 19: 1} - >>> 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})]) 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)[source]¶
- Return a dictionary associating to each vertex - va shortest path from- uto- v, if it exists.- If \(u\) and \(v\) are not connected, vertex \(v\) 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 all edges have weight 1
- algorithm– string (default:- None); one of the following algorithms:- 'BFS': performs a BFS from- u. Does not work with edge weights.
- 'Dijkstra_NetworkX': the Dijkstra algorithm, implemented in NetworkX (works only with positive weights).
- 'Dijkstra_Boost': the Dijkstra algorithm, implemented in Boost (works only with positive weights).
- 'Bellman-Ford_Boost': the Bellman-Ford algorithm, implemented in Boost (works also with negative weights, if there is no negative cycle).
- None(default): Sage chooses the best algorithm:- 'BFS'if- by_weightis- 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- l, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the weight_function outputs a number for each edge
- cutoff– integer (default:- None); 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 - >>> from sage.all import * >>> all(D.subgraph(p).is_isomorphic(graphs.PathGraph(len(p))) for p in D.shortest_paths(Integer(0)).values()) True - sage: D.shortest_paths(0, cutoff=2) {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 18: [0, 19, 18], 19: [0, 19]} sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }, sparse=True) sage: G.plot(edge_labels=True).show() # long time # 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_weightis 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':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_weightis 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): ... 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)[source]¶
- 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 - sourceto- target. By default (- by_weightis- 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 - sourceis the same vertex as- target, then- [[source]]is returned – a list containing the 1-vertex, 0-edge path- source.- By default - Yen'salgorithm [Yen1970] is used for undirected graphs and- Feng'salgorithm 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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- las 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_functionoutputs a number for each edge
- algorithm– string (default:- None); the algorithm to use in computing- kshortest 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 of edges. When set to- False, the- labelsparameter 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- sourceand- targetis returned. 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, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 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)]] - >>> 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, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 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, ... 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)[source]¶
- 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.plotand- 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)[source]¶
- Plot the graph and show the resulting plot. - INPUT: - bgcolor– rgb tuple (default:- (1,1,1))
- vertex_size– float (default: \(0.06\))
- vertex_labels– boolean (default:- False); whether to display vertices using text labels instead of 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).
- 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– 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_colorand- edge_colors.
- edge_size– float (default: \(0.02\))
- edge_size2– float (default: \(0.0325\)); used for- Tachyonsleeves
- 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) # long time, needs sage.plot - >>> 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 # 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 - Tachyonexamples:- 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 ... 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()[source]¶
- Return the number of edges. - Note that - num_edges()also returns the number of edges in \(G\).- 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)[source]¶
- Return the number of spanning trees in a graph. - In the case of a digraph, counts the number of spanning out-trees rooted in - root_vertex. Default is to set first vertex as root.- This computation uses Kirchhoff’s Matrix Tree Theorem [1] to calculate the number of spanning trees. For complete graphs on \(n\) vertices the result can also be reached using Cayley’s formula: the number of spanning trees are \(n^(n-2)\). - For digraphs, the augmented Kirchhoff Matrix as defined in [2] is used for calculations. Here the result is the number of out-trees rooted at a specific vertex. - INPUT: - root_vertex– a vertex (default:- None); the vertex that will be used as root for all spanning out-trees if the graph is a directed graph. Otherwise, the first vertex returned by- vertex_iterator()is used. This argument is ignored if the graph is not a digraph.
 - See also - spanning_trees()– enumerates all spanning trees of a graph- REFERENCES: 
- [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() # 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) 1 sage: 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)) 2 
 - spectral_radius(G, prec=1e-10)[source]¶
- Return an interval of floating point number that encloses the spectral radius of this graph - The input graph - Gmust 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 nonnegative matrices. Namely, if \(A\) is a nonnegative square matrix with Perron-Frobenius eigenvalue \(\lambda\) then the following inequality is valid for any vector \(x\) \[\min_i \frac{(Ax)_i}{x_i} \leq \lambda \leq \max_i \frac{(Ax)_i}{x_i}\]- 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 True - This function also works for graphs: - sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(2,4),(3,4)]) sage: e_min, e_max = spectral_radius(G, 1e-14) sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) # needs sage.modules sage.rings.number_field sage: 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: p x^201 - x^199 - 1 sage: r = p.roots(AA, multiplicities=False)[0] # needs sage.rings.number_field sage: 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() >>> p x^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 # long time (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 # long time (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)) >>> G.spectral_radius() # abs tol 1e-10 (1.7320508075688772, 1.7320508075688774) 
 - spectrum(laplacian=False)[source]¶
- 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() # 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)[source]¶
- 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 \(n \log(n)\) time (and in linear time if all weights are equal) where \(n = V + E\). On the other hand, if one is given a large (possibly weighted) graph and a subset of its vertices, it is NP-Hard to find a tree of minimum weight connecting the given set of vertices, which is then called a Steiner Tree. - See the Wikipedia article Steiner_tree_problem for more information. - INPUT: - vertices– the vertices to be connected by the Steiner Tree
- weighted– boolean (default:- False); whether to consider the graph as weighted, and use each edge’s label as a weight, considering- Noneas a weight of \(1\). If- weighted=False(default) all edges are considered to have a weight of \(1\).
- solver– string (default:- None); specifies 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- solveof 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 graph is actually a digraph. 
- The graph is assumed not to have multiple edges. 
 - ALGORITHM: - Solved through Linear Programming. - COMPLEXITY: - NP-Hard. - Note that this algorithm first checks whether the given set of vertices induces a connected graph, returning one of its spanning trees if - weightedis 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 the same connected component: - sage: g = 2 * graphs.PetersenGraph() sage: st = g.steiner_tree([5, 15]) Traceback (most recent call last): ... EmptySetError: the given vertices do not all belong to the same connected component. This problem has no solution ! - >>> 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 ! 
 - strong_product(other, immutable=None)[source]¶
- Return the strong product of - selfand- other.- The strong product of \(G\) and \(H\) is the graph \(L\) with vertex set \(V(L)=V(G)\times V(H)\), and \(((u,v), (w,x))\) is an edge of \(L\) iff either : - \((u, w)\) is an edge of \(G\) and \(v = x\), or 
- \((v, x)\) is an edge of \(H\) and \(u = w\), or 
- \((u, w)\) is an edge of \(G\) and \((v, x)\) is an edge of \(H\). 
 - In other words, the edges of the strong product is the union of the edges of the tensor and Cartesian products. - INPUT: - other– a graph or a digraph
- immutable– boolean (default:- None); whether to create a mutable/immutable product.- immutable=None(default) means that the graphs and their product will behave the same way. If only one of them is immutable, the product will be mutable.
 - 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)[source]¶
- Subdivide an edge \(k\) times. - INPUT: - The following forms are all accepted to subdivide \(8\) times the edge between vertices \(1\) and \(2\) labeled with - 'my_label'.- G.subdivide_edge( 1, 2, 8 )
- G.subdivide_edge( (1, 2), 8 )
- G.subdivide_edge( (1, 2, "my_label"), 8 )
 - Note - If the given edge is labelled with \(l\), all the edges created by the subdivision will have the same label 
- If no label is given, the label used will be the one returned by the method - edge_label()on the pair- u,v
 - EXAMPLES: - Subdividing \(5\) times an edge in a path of length \(3\) makes it a path of length \(8\): - sage: g = graphs.PathGraph(3) sage: edge = next(g.edge_iterator()) sage: g.subdivide_edge(edge, 5) sage: g.is_isomorphic(graphs.PathGraph(8)) True - >>> 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, 'label1'), (3, 4, 'label1'), (4, 5, 'label1')] - >>> 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: - 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)[source]¶
- Subdivide \(k\) times edges from an iterable container. - For more information on the behaviour of this method, please refer to the documentation of - subdivide_edge().- INPUT: - edges– list of edges
- k– integer; common length of the subdivisions
 - Note - If a given edge is labelled with \(l\), 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
 
 - subgraph(vertices=None, edges=None, inplace=False, vertex_property=None, edge_property=None, algorithm=None, immutable=None)[source]¶
- 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 not specified, returns the subgraph induced by the vertices. - INPUT: - inplace– boolean (default:- False); using- inplace=Truewill 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 graph is an induced subgraph. In the case of multiple edges, specifying an edge as \((u,v)\) means to keep all edges \((u,v)\), regardless of the label.
- vertex_property– function (default:- None); a function that inputs a vertex and outputs a boolean value, i.e., a vertex- vin- verticesis 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- ein- edgesis kept if- edge_property(e) == True
- algorithm– string (default:- None); one of the following:- If - algorithm="delete"or- inplace=True, then the graph is constructed by deleting edges and vertices
- If - algorithm="add", then the graph is constructed by building a new graph from the appropriate vertices and edges. Implies- inplace=False.
- If - algorithm=None, then the algorithm is chosen based on the number of vertices in the subgraph.
 
- immutable– boolean (default:- None); whether to create a mutable/immutable subgraph.- immutable=None(default) means that the graph and its subgraph will behave the same way.
 - EXAMPLES: - sage: G = graphs.CompleteGraph(9) sage: H = G.subgraph([0, 1, 2]); H Subgraph of (Complete graph): Graph on 3 vertices sage: G Complete graph: Graph on 9 vertices sage: J = G.subgraph(edges=[(0, 1)]) sage: J.edges(sort=True, labels=False) [(0, 1)] sage: set(J) == set(G) True sage: G.subgraph([0, 1, 2], inplace=True); G Subgraph of (Complete graph): Graph on 3 vertices sage: G.subgraph() == G True - >>> 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 >>> 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() == D True - A more complicated example involving multiple edges and labels: - sage: G = Graph(multiedges=True, sparse=True) sage: G.add_edges([(0, 1, 'a'), (0, 1, 'b'), (1, 0, 'c'), (0, 2, 'd'), (0, 2, 'e'), (2, 0, 'f'), (1, 2, 'g')]) sage: G.subgraph(edges=[(0, 1), (0, 2,'d'), (0, 2, 'not in graph')]).edges(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] 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, 'c'), (0, 2, 'd'), (0, 2, 'e'), (2, 0, 'f'), (1, 2, 'g')]) sage: D.subgraph(edges=[(0, 1), (0, 2, 'd'), (0, 2, 'not in graph')]).edges(sort=True) [(0, 1, 'a'), (0, 1, 'b'), (0, 2, 'd')] sage: H = D.subgraph(vertices=[0, 1], edges=[(0, 1, 'a'), (0, 2, 'c')]) sage: H.edges(sort=True) [(0, 1, 'a')] sage: H.vertices(sort=True) [0, 1] - >>> 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] - >>> 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', '11', None)] sage: S.edges(sort=True) [('00', '01', None), ('10', '11', None)] - >>> 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' algorithm Subgraph of (Path graph): Graph on 10 vertices - >>> from sage.all import * >>> g = graphs.PathGraph(Integer(1000)) >>> g.subgraph(list(range(Integer(10)))) # uses the 'add' algorithm Subgraph of (Path graph): Graph on 10 vertices 
 - subgraph_search(G, induced=False)[source]¶
- Return a copy of - Gin- 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- Gin- self
 - OUTPUT: - If - induced=False, return a copy of- Gin this graph. Otherwise, return an induced copy of- Gin- self. If- Gis the empty graph, return the empty graph since it is a subgraph of every graph. Now suppose- Gis not the empty graph. If there is no copy (induced or otherwise) of- Gin- 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 \(H\) inside of \(G\)
- subgraph_search_iterator()– iterator over the copies of \(H\) inside of \(G\)
 - ALGORITHM: - See the documentation of - SubgraphSearch.- EXAMPLES: - The Petersen graph contains the path graph \(P_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 \(K_{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 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 \(K_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 \(P_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) # 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, \(P_3\) is not an induced subgraph of \(K_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} - >>> 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)[source]¶
- Return the number of labelled occurrences of - Gin- 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- Gin- 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 \(H\) inside of a graph \(G\)
- subgraph_search_iterator()– iterator over the copies of a graph \(H\) inside of a graph \(G\)
 - EXAMPLES: - Counting the number of paths \(P_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 \(T_k\) (the transitive tournament on \(k\) vertices) as the graph on \(\{0, ..., k-1\}\) such that \(ij \in T_k\) if \(i<j\), how many directed triangles can be found in \(T_5\) ? The answer is of course \(0\): - sage: T5 = digraphs.TransitiveTournament(5) sage: T5.subgraph_search_count(digraphs.Circuit(3)) # needs sage.modules 0 - >>> 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 \(T_3\) in \(T_5\), we expect the answer to be \(\binom{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') >>> g.subgraph_search_count(graphs.PathGraph(Integer(5))) # needs sage.modules 240 
 - subgraph_search_iterator(G, induced=False, return_graphs=True)[source]¶
- Return an iterator over the labelled copies of - Gin- 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- Gin- self
- return_graphs– boolean (default:- True); whether to return (di)graphs or only the list of vertices of 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 - Gin- self, as lists or (di)graphs. For each value \((v_1, v_2, ..., v_k)\) returned, the first vertex of \(G\) is associated with \(v_1\), the second with \(v_2\), etc.- Note - This method works on - Graph,- DiGraphand- BipartiteGraph.- See also - subgraph_search()– finds a subgraph isomorphic to \(H\) inside of \(G\)
- subgraph_search_count()– counts the number of copies of \(H\) inside of \(G\)
 - EXAMPLES: - Iterating through all the labelled \(P_3\) of \(P_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) 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] - 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)) True sage: sum(1 for h in H.subgraph_search_iterator(P4, induced=True)) # needs sage.modules 4 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.modules 0 sage: 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.modules 0 >>> 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 - >>> 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)[source]¶
- Return the symmetric edge polytope of - self.- The symmetric edge polytope (SEP) of a Graph on \(n\) vertices is the polytope in \(\ZZ^{n}\) defined as the convex hull of \(e_i - e_j\) and \(e_j - e_i\) for each edge \((i, j)\). Here \(e_1, \dots, e_n\) 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()) # needs sage.geometry.polyhedron True - The SEP of a graph with edges on \(n\) vertices has dimension \(n\) 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.polyhedron sage: 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.polyhedron sage: P1 = G1.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron sage: P2 = G2.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron sage: 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.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 \(n\) 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.polyhedron sage: P2 = G2.symmetric_edge_polytope() # needs sage.geometry.polyhedron sage: 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) # 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.polyhedron sage: P2 = G2.symmetric_edge_polytope() # needs sage.geometry.polyhedron sage: 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: - 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.polyhedron sage: PH = H.symmetric_edge_polytope() # needs networkx sage.geometry.polyhedron sage: 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)[source]¶
- Return the Szeged index of the graph \(G\). - Let \(G = (V, E)\) be a connected graph, and for any \(uv\in E\), let \(N_u(uv) = \{w\in V:d(u,w)<d(v,w)\}\) and \(n_u(uv)=|N_u(uv)|\). The Szeged index of \(G\) is then defined as [KRG1996] \[`\sum_{uv \in E(G)}n_u(uv)\times n_v(uv)`\]- 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 \(O(nm)\) and space complexity in \(O(m)\). This implementation is currently valid only for simple (without loops or multiple edges) connected graphs.
- 'high'– algorithm with time complexity in \(O(nm)\) and space complexity in \(O(n^2)\). It cannot be used on graphs with more than \(65536 = 2^{16}\) vertices.
 - By default ( - None), the- 'low'algorithm is used for graphs and the- 'high'algorithm for digraphs.
 - 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) True - Check 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') >>> a == b True - The Szeged index of a directed circuit of order \(n\) is \((n-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, immutable=None)[source]¶
- Return the tensor product of - selfand- other.- The tensor product of \(G\) and \(H\) is the graph \(L\) with vertex set \(V(L)\) equal to the Cartesian product of the vertices \(V(G)\) and \(V(H)\), and \(((u,v), (w,x))\) is an edge iff - \((u, w)\) is an edge of self, and - \((v, x)\) is an edge of other. - The tensor product is also known as the categorical product and the Kronecker product (referring to the Kronecker matrix product). See the Wikipedia article Kronecker_product. - INPUT: - other– a graph or a digraph
- immutable– boolean (default:- None); whether to create a mutable/immutable product.- immutable=None(default) means that the graphs and their product will behave the same way. If only one of them is immutable, the product will be mutable.
 - 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 - >>> 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 
 - tikz(format=None, edge_labels=None, color_by_label=False, prog='dot', rankdir='down', standalone_config=None, usepackage=None, usetikzlibrary=None, macros=None, use_sage_preamble=None, **kwds)[source]¶
- Return a TikzPicture of the graph. - If graphviz and dot2tex are available, it uses these packages for placements of vertices and edges. - INPUT: - format– string (default:- None),- 'dot2tex'or- 'tkz_graph'. If- None, it is set to- 'dot2tex'if dot2tex is present, otherwise it is set to- 'tkz_graph'.
- edge_labels– bool (default:- None), if- Noneit is set to- Trueif and only if format is- 'dot2tex'
- color_by_label– 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;
 - When using format - 'dot2tex', the following inputs are considered:- prog– string (default:- 'dot') the program used for the layout corresponding to one of the software of the graphviz suite: ‘dot’, ‘neato’, ‘twopi’, ‘circo’ or ‘fdp’.
- rankdir– string (default:- 'down'), direction of graph layout when prog is- 'dot', possible values are- 'down',- 'up',- 'right'and- 'left'.
- 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.
 - Additionnal keywords arguments are forwarded to - sage.graphs.graph_latex.GraphLatex.set_option().- The following inputs define the preamble of the latex standalone document class file containing the tikzpicture: - standalone_config– list of strings (default:- ["border=4mm"]); latex document class standalone configuration options
- usepackage– list of strings (default:- []); latex packages
- usetikzlibrary– list of strings (default:- []); tikz libraries to use
- macros– list of strings (default:- []); list of newcommands needed for the picture
- use_sage_preamble– bool (default:- None), if- Noneit is set to- Trueif and only if format is- 'tkz_graph'
 - OUTPUT: - An instance of - sage.misc.latex_standalone.TikzPicture.- Note - Prerequisite: dot2tex optional Sage package and graphviz must be installed when using format - 'dot2tex'.- EXAMPLES: - sage: g = graphs.PetersenGraph() sage: tikz = g.tikz() # optional - dot2tex graphviz # long time sage: _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time - >>> from sage.all import * >>> g = graphs.PetersenGraph() >>> tikz = g.tikz() # optional - dot2tex graphviz # long time >>> _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time - sage: tikz = g.tikz(format='tkz_graph') sage: _ = tikz.pdf(view=False) # optional - latex - >>> from sage.all import * >>> tikz = g.tikz(format='tkz_graph') >>> _ = tikz.pdf(view=False) # optional - latex - Using another value for - prog:- sage: tikz = g.tikz(prog='neato') # optional - dot2tex graphviz # long time sage: _ = tikz.pdf() # optional - dot2tex graphviz latex # long time - >>> from sage.all import * >>> tikz = g.tikz(prog='neato') # optional - dot2tex graphviz # long time >>> _ = tikz.pdf() # optional - dot2tex graphviz latex # long time - Using - color_by_labelwith default rainbow colors:- sage: G = DiGraph({0: {1: 333, 2: 444}, 1: {0: 444}, 2: {0: 555}}) sage: t = G.tikz(color_by_label=True) # optional - dot2tex graphviz # long time sage: _ = t.pdf(view=False) # optional - dot2tex graphviz latex # long time - >>> from sage.all import * >>> G = DiGraph({Integer(0): {Integer(1): Integer(333), Integer(2): Integer(444)}, Integer(1): {Integer(0): Integer(444)}, Integer(2): {Integer(0): Integer(555)}}) >>> t = G.tikz(color_by_label=True) # optional - dot2tex graphviz # long time >>> _ = t.pdf(view=False) # optional - dot2tex graphviz latex # long time - Using - color_by_labelwith colors given as a dictionary:- sage: G = DiGraph({0: {1: 333, 2: 444}, 1: {0: 444}, 2: {0: 555}}) sage: cbl = {333:'orange', 444: 'yellow', 555: 'purple'} sage: t = G.tikz(color_by_label=cbl) # optional - dot2tex graphviz # long time sage: _ = t.pdf(view=False) # optional - dot2tex graphviz latex # long time - >>> from sage.all import * >>> G = DiGraph({Integer(0): {Integer(1): Integer(333), Integer(2): Integer(444)}, Integer(1): {Integer(0): Integer(444)}, Integer(2): {Integer(0): Integer(555)}}) >>> cbl = {Integer(333):'orange', Integer(444): 'yellow', Integer(555): 'purple'} >>> t = G.tikz(color_by_label=cbl) # optional - dot2tex graphviz # long time >>> _ = t.pdf(view=False) # optional - dot2tex graphviz latex # long time - Using - color_by_labelwith colors given as a function:- sage: G = DiGraph({0: {1: -333, 2: -444}, 1: {0: 444}, 2: {0: 555}}) sage: cbl = lambda label:'green' if label >= 0 else 'orange' sage: t = G.tikz(color_by_label=cbl) # optional - dot2tex graphviz # long time sage: _ = t.pdf(view=False) # optional - dot2tex graphviz latex # long time - >>> from sage.all import * >>> G = DiGraph({Integer(0): {Integer(1): -Integer(333), Integer(2): -Integer(444)}, Integer(1): {Integer(0): Integer(444)}, Integer(2): {Integer(0): Integer(555)}}) >>> cbl = lambda label:'green' if label >= Integer(0) else 'orange' >>> t = G.tikz(color_by_label=cbl) # optional - dot2tex graphviz # long time >>> _ = t.pdf(view=False) # optional - dot2tex graphviz latex # long time - Using another value for - rankdir:- sage: tikz = g.tikz(rankdir='right') # optional - dot2tex graphviz # long time sage: _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time - >>> from sage.all import * >>> tikz = g.tikz(rankdir='right') # optional - dot2tex graphviz # long time >>> _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time - Using subgraphs clusters (broken when using labels, see Issue #22070): - sage: S = FiniteSetMaps(5) sage: I = S((0,1,2,3,4)) sage: a = S((0,1,3,0,0)) sage: b = S((0,2,4,1,0)) sage: roots = [I] sage: succ = lambda v: [v*a,v*b,a*v,b*v] sage: R = RecursivelyEnumeratedSet(roots, succ) sage: G = R.to_digraph() sage: G Looped multi-digraph on 27 vertices sage: C = G.strongly_connected_components() sage: tikz = G.tikz(subgraph_clusters=C)# optional - dot2tex graphviz # long time sage: tikz.add_usepackage('amstext') # optional - dot2tex graphviz # long time sage: _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time - >>> from sage.all import * >>> S = FiniteSetMaps(Integer(5)) >>> I = S((Integer(0),Integer(1),Integer(2),Integer(3),Integer(4))) >>> a = S((Integer(0),Integer(1),Integer(3),Integer(0),Integer(0))) >>> b = S((Integer(0),Integer(2),Integer(4),Integer(1),Integer(0))) >>> roots = [I] >>> succ = lambda v: [v*a,v*b,a*v,b*v] >>> R = RecursivelyEnumeratedSet(roots, succ) >>> G = R.to_digraph() >>> G Looped multi-digraph on 27 vertices >>> C = G.strongly_connected_components() >>> tikz = G.tikz(subgraph_clusters=C)# optional - dot2tex graphviz # long time >>> tikz.add_usepackage('amstext') # optional - dot2tex graphviz # long time >>> _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time - An example coming from - graphviz_stringdocumentation in SageMath:- sage: # needs sage.symbolic sage: f(x) = -1 / x sage: g(x) = 1 / (x + 1) sage: G = DiGraph() sage: G.add_edges((i, f(i), f) for i in (1, 2, 1/2, 1/4)) sage: G.add_edges((i, g(i), g) for i in (1, 2, 1/2, 1/4)) sage: tikz = G.tikz(format='dot2tex') # optional - dot2tex graphviz # long time sage: _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time 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: tikz = G.tikz(format='dot2tex', # optional - dot2tex graphviz # long time ....: edge_options=edge_options) sage: _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time - >>> 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))) >>> tikz = G.tikz(format='dot2tex') # optional - dot2tex graphviz # long time >>> _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time >>> 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 >>> tikz = G.tikz(format='dot2tex', # optional - dot2tex graphviz # long time ... edge_options=edge_options) >>> _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time 
 - to_dictionary(edge_labels=False, multiple_edges=False)[source]¶
- 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 == Falseand- multiple_edges == False, the output is a dictionary associating to each vertex the list of its neighbors.
- If - edge_labels == Falseand- multiple_edges == True, the output is a dictionary the same as previously with one difference: the neighbors are listed with multiplicity.
- If - edge_labels == Trueand- multiple_edges == False, the output is a dictionary associating to each vertex \(u\) [a dictionary associating to each vertex \(v\) incident to \(u\) the label of edge \((u,v)\)].
- If - edge_labels == Trueand- multiple_edges == True, the output is a dictionary associating to each vertex \(u\) [a dictionary associating to each vertex \(v\) incident to \(u\) [the list of labels of all edges between \(u\) and \(v\)]].
 - Note - When used on directed graphs, the explanations above can be understood by replacing the word “neighbors” by “out-neighbors” - EXAMPLES: - sage: g = graphs.PetersenGraph().to_dictionary() sage: [(key, sorted(g[key])) for key in g] [(0, [1, 4, 5]), (1, [0, 2, 6]), (2, [1, 3, 7]), (3, [2, 4, 8]), (4, [0, 3, 9]), (5, [0, 7, 8]), (6, [1, 8, 9]), (7, [2, 5, 9]), (8, [3, 5, 6]), (9, [4, 6, 7])] sage: graphs.PetersenGraph().to_dictionary(multiple_edges=True) {0: [1, 4, 5], 1: [0, 2, 6], 2: [1, 3, 7], 3: [2, 4, 8], 4: [0, 3, 9], 5: [0, 7, 8], 6: [1, 8, 9], 7: [2, 5, 9], 8: [3, 5, 6], 9: [4, 6, 7]} sage: graphs.PetersenGraph().to_dictionary(edge_labels=True) {0: {1: None, 4: None, 5: None}, 1: {0: None, 2: None, 6: None}, 2: {1: None, 3: None, 7: None}, 3: {2: None, 4: None, 8: None}, 4: {0: None, 3: None, 9: None}, 5: {0: None, 7: None, 8: None}, 6: {1: None, 8: None, 9: None}, 7: {2: None, 5: None, 9: None}, 8: {3: None, 5: None, 6: None}, 9: {4: None, 6: None, 7: None}} sage: graphs.PetersenGraph().to_dictionary(edge_labels=True,multiple_edges=True) {0: {1: [None], 4: [None], 5: [None]}, 1: {0: [None], 2: [None], 6: [None]}, 2: {1: [None], 3: [None], 7: [None]}, 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}, 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)[source]¶
- 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 undirected graph
- 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- TypeErrormight be raised when working with non-comparable objects.- immutable– boolean (default:- Non); whether to create a mutable/immutable copy.- immutable=None(default) means that the graph and its copy will behave the same way.
 - EXAMPLES: - sage: G = DiGraph(loops=True, multiedges=True, sparse=True) sage: G.add_edges([(0, 0, None), (1, 1, None), (2, 2, None), ....: (2, 3, 1), (2, 3, 2), (3, 2, None)]) sage: G.edges(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) [(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=None, immutable=None)[source]¶
- Return the transitive closure of the (di)graph. - The transitive closure of a graph \(G\) has an edge \((x, y)\) if and only if there is a path between \(x\) and \(y\) in \(G\). - The transitive closure of any (strongly) connected component of a (di)graph is a complete graph. The transitive closure of a directed acyclic graph is a directed acyclic graph representing the full partial order. - INPUT: - loops– boolean (default:- None); whether to allow loops in the returned (di)graph. By default (- None), if the (di)graph allows loops, its transitive closure will have one loop edge per vertex. This can be prevented by disallowing loops in the (di)graph (- self.allow_loops(False)).
- immutable– boolean (default:- None); whether to create a mutable/immutable transitive closure.- immutable=None(default) means that the (di)graph and its transitive closure will behave the same way.
 - EXAMPLES: - sage: g = graphs.PathGraph(4) sage: g.transitive_closure() Transitive closure of Path graph: Graph on 4 vertices sage: g.transitive_closure().is_isomorphic(graphs.CompleteGraph(4)) True sage: g = DiGraph({0: [1, 2], 1: [3], 2: [4, 5]}) sage: g.transitive_closure().edges(sort=True, labels=False) [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 3), (2, 4), (2, 5)] - >>> 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): [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 - loopsallows 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)] - Check the behavior of parameter - loops:- sage: G = graphs.CycleGraph(3) sage: G.transitive_closure().loop_edges(labels=False) [] sage: G.transitive_closure(loops=True).loop_edges(labels=False) [(0, 0), (1, 1), (2, 2)] sage: G.allow_loops(True) sage: G.transitive_closure().loop_edges(labels=False) [(0, 0), (1, 1), (2, 2)] sage: G.transitive_closure(loops=False).loop_edges(labels=False) [] - >>> from sage.all import * >>> G = graphs.CycleGraph(Integer(3)) >>> G.transitive_closure().loop_edges(labels=False) [] >>> G.transitive_closure(loops=True).loop_edges(labels=False) [(0, 0), (1, 1), (2, 2)] >>> G.allow_loops(True) >>> G.transitive_closure().loop_edges(labels=False) [(0, 0), (1, 1), (2, 2)] >>> G.transitive_closure(loops=False).loop_edges(labels=False) [] - Check the behavior of parameter - immutable:- sage: G = Graph([(0, 1)]) sage: G.transitive_closure().is_immutable() False sage: G.transitive_closure(immutable=True).is_immutable() True sage: G = Graph([(0, 1)], immutable=True) sage: G.transitive_closure().is_immutable() True sage: G.transitive_closure(immutable=False).is_immutable() False - >>> from sage.all import * >>> G = Graph([(Integer(0), Integer(1))]) >>> G.transitive_closure().is_immutable() False >>> G.transitive_closure(immutable=True).is_immutable() True >>> G = Graph([(Integer(0), Integer(1))], immutable=True) >>> G.transitive_closure().is_immutable() True >>> G.transitive_closure(immutable=False).is_immutable() False 
 - transitive_reduction(immutable=None)[source]¶
- Return a transitive reduction of a graph. - A transitive reduction \(H\) of \(G\) has a path from \(x\) to \(y\) if and only if there was a path from \(x\) to \(y\) in \(G\). Deleting any edge of \(H\) destroys this property. A transitive reduction is not unique in general. A transitive reduction has the same transitive closure as the original graph. - A transitive reduction of a complete graph is a tree. A transitive reduction of a tree is itself. - INPUT: - immutable– boolean (default:- None); whether to create a mutable/immutable transitive closure.- immutable=None(default) means that the (di)graph and its transitive closure will behave the same way.
 - EXAMPLES: - sage: g = graphs.PathGraph(4) sage: g.transitive_reduction() == g True sage: g = graphs.CompleteGraph(5) sage: h = g.transitive_reduction(); h.size() 4 sage: (2*g).transitive_reduction().size() 8 sage: g = DiGraph({0: [1, 2], 1: [2, 3, 4, 5], 2: [4, 5]}) sage: g.transitive_reduction().size() 5 sage: (2*g).transitive_reduction().size() 10 - >>> 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 >>> (Integer(2)*g).transitive_reduction().size() 8 >>> 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 >>> (Integer(2)*g).transitive_reduction().size() 10 
 - traveling_salesman_problem(use_edge_labels, maximize=False, solver=False, constraint_generation=None, verbose=None, verbose_constraints=0, integrality_tolerance=False)[source]¶
- Solve the traveling salesman problem (TSP). - Given a graph (resp. a digraph) \(G\) with weighted edges, the traveling salesman problem consists in finding a Hamiltonian cycle (resp. circuit) of the graph of minimum cost. - This TSP is one of the most famous NP-Complete problems, this function can thus be expected to take some time before returning its result. - INPUT: - use_edge_labels– boolean (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- Noneor- {}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); specifies 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- solveof the class- MixedIntegerLinearProgram.
- constraint_generation– boolean (default:- None); whether to use constraint generation when solving the Mixed Integer Linear Program.- When - constraint_generation = None, constraint generation is used whenever the graph has a density larger than 70%.
- verbose– integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet.
- verbose_constraints– boolean (default:- False); whether to display which constraints are being generated
- integrality_tolerance– float; parameter for use with MILP solvers over an inexact base ring; see- MixedIntegerLinearProgram.get_values().
 - OUTPUT: - A solution to the TSP, as a - Graphobject whose vertex set is \(V(G)\), and whose edges are only those of the solution.- ALGORITHM: - This optimization problem is solved through the use of Linear Programming. - Note - This function is correctly defined for both graph and digraphs. In the second case, the returned cycle is a circuit of optimal cost. - EXAMPLES: - The Heawood graph is known to be Hamiltonian: - sage: g = graphs.HeawoodGraph() sage: tsp = g.traveling_salesman_problem(); 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 - >>> 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 - 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)[source]¶
- Return the number of triangles in the (di)graph. - For digraphs, we count the number of directed circuit of length 3. - INPUT: - algorithm– string (default:- None); specifies the algorithm to use (note that only- 'iter'is available for directed graphs):- 'sparse_copy'– counts the triangles in a sparse copy of the graph (see- sage.graphs.base.static_sparse_graph). Calls- static_sparse_graph.triangles_count
- 'dense_copy'– counts the triangles in a dense copy of the graph (see- sage.graphs.base.static_dense_graph). Calls- static_dense_graph.triangles_count
- 'matrix'uses the trace of the cube of the adjacency matrix
- 'iter'iterates over the pairs of neighbors of each vertex. No copy of the graph is performed
- None– for undirected graphs, uses- 'sparse_copy'or- 'dense_copy'depending on whether the graph is stored as dense or sparse. For directed graphs, uses- 'iter'.
 
 - EXAMPLES: - The Petersen graph is triangle free and thus: - sage: G = graphs.PetersenGraph() sage: G.triangles_count() 0 - >>> 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.symbolic True - The 2-dimensional DeBruijn graph of 2 symbols has 2 directed \(C_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.combinat 2 - The directed \(n\)-cycle is trivially triangle free for \(n > 3\): - sage: G = digraphs.Circuit(10) sage: G.triangles_count() # needs sage.modules 0 - >>> from sage.all import * >>> G = digraphs.Circuit(Integer(10)) >>> G.triangles_count() # needs sage.modules 0 
 - union(other, immutable=None)[source]¶
- Return the union of - selfand- other.- If the graphs have common vertices, the common vertices will be identified. - If one of the two graphs allows loops (or multiple edges), the resulting graph will allow loops (or multiple edges). - If both graphs are weighted the resulting graphs is weighted. - If both graphs are immutable, the resulting graph is immutable, unless requested otherwise. - INPUT: - immutable– boolean (default:- None); whether to create a mutable/immutable union.- immutable=None(default) means that the graphs and their union will behave the same way.
 - See also - 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)[source]¶
- Return a list of all vertices in the external boundary of - vertices1, intersected with- vertices2.- If - vertices2is- None, then- vertices2is the complement of- vertices1. This is much faster if- vertices1is smaller than- vertices2.- The external boundary of a set of vertices is the union of the neighborhoods of each vertex in the set. Note that in this implementation, since - vertices2defaults to the complement of- vertices1, if a vertex \(v\) has a loop, then- vertex_boundary(v)will not contain \(v\).- In a digraph, the external boundary of a vertex \(v\) are those vertices \(u\) with an arc \((v, u)\). - EXAMPLES: - sage: G = graphs.CubeGraph(4) sage: l = ['0111', '0000', '0001', '0011', '0010', '0101', '0100', '1111', '1101', '1011', '1001'] sage: 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', '0100', '1111', '1101', '1011', '1001'] >>> sorted(G.vertex_boundary(['0000', '1111'], l)) ['0001', '0010', '0100', '0111', '1011', '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)[source]¶
- Return the vertex connectivity of the graph. - For more information, see the Wikipedia article Connectivity_(graph_theory) and the Wikipedia article K-vertex-connected_graph. - Note - When the graph is directed, this method actually computes the strong connectivity, (i.e. a directed graph is strongly \(k\)-connected if there are \(k\) vertex disjoint paths between any two vertices \(u, v\)). If you do not want to consider strong connectivity, the best is probably to convert your - DiGraphobject to a- Graphobject, and compute the connectivity of this other graph.
- By convention, a complete graph on \(n\) vertices is \(n-1\) connected. In this case, no certificate can be given as there is no pair of vertices split by a cut of order \(k-1\). For this reason, the certificates returned in this situation are empty. 
 - INPUT: - G– the input Sage (Di)Graph
- value_only– boolean (default:- True)- When set to - True(default), only the value is returned.
- When set to - False, both the value and a minimum vertex cut are returned.
 
- sets– boolean (default:- False); whether to also return the two
- sets of vertices that are disconnected by the cut (implies - value_only=False)
 
- k– integer (default:- None); when specified, check if the vertex connectivity of the (di)graph is larger or equal to \(k\). The method thus outputs a boolean only.
- solver– string (default:- None); specifies 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- solveof 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\): - 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 - >>> 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 - kis 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)[source]¶
- Return a minimum vertex cut between non-adjacent vertices \(s\) and \(t\) represented by a list of vertices. - A vertex cut between two non-adjacent vertices is a set \(U\) of vertices of - selfsuch that the graph obtained by removing \(U\) from- selfis disconnected. For more information, see the Wikipedia article Cut_(graph_theory).- INPUT: - value_only– boolean (default:- True); whether to return only the size of the minimum cut, or to also return the set \(U\) 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_onlyset to- False.
- solver– string (default:- None); specifies 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- solveof 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 \(K_{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 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)[source]¶
- 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 \(s\) and \(t\) (the minimum number of vertices whose removal disconnects \(s\) and \(t\)) is equal to the maximum number of pairwise vertex-independent paths from \(s\) to \(t\). - This function returns a list of such paths. - INPUT: - s,- t– two vertices of the graph
- solver– string (default:- None); specifies 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- solveof 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 graph - sage: 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)[source]¶
- Return an iterator over the given vertices. - Returns - Falseif not given a vertex, sequence, iterator or- None.- Noneis equivalent to a list of every vertex. Note that- for v in Gsyntax is allowed.- INPUT: - vertices– iterated vertices are these intersected with the vertices of the (di)graph
- degree– nonnegative integer (default:- None); a vertex- vis 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- vis 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) 0 1 2 3 - >>> from sage.all import * >>> G = graphs.TetrahedralGraph() >>> for i in G: ... print(i) 0 1 2 3 - sage: H = graphs.PathGraph(5) sage: prop = lambda l: l % 3 == 1 sage: for v in H.vertex_iterator(degree=1, vertex_property=prop): ....: print(v) 4 - >>> 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) 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)[source]¶
- 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 value that can be used for comparisons in the sorting algorithm (we must have- sort=True)
- degree– nonnegative integer (default:- None); a vertex- vis 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- vis kept if- vertex_property(v) == True
 - OUTPUT: - 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 to guarantee a total order for the sorting of the edges, use the - keyargument, 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 the following alternative: - sage: # not tested sage: timeit V = P.vertices(sort=True) 625 loops, best of 3: 3.86 [micro]s per loop 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 - keyto 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 are polynomials, and use the discriminant function to provide an ordering. Note that since functions are first-class objects in Python, we can specify precisely the function from the Sage library that we wish to use as the key: - sage: # 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_rational_flint sage: dsc = Polynomial_rational_flint.discriminant sage: 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)[source]¶
- 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 immutable graphs.- Edge weightings can still exist for (di)graphs - Gwhere- G.weighted()is- False.- EXAMPLES: - Here we have two graphs with different labels, but - weighted()is- Falsefor both, so we just check for the presence of edges:- sage: G = Graph({0: {1: 'a'}}, sparse=True) sage: H = Graph({0: {1: 'b'}}, sparse=True) sage: G == H True - >>> from sage.all import * >>> G = Graph({Integer(0): {Integer(1): 'a'}}, sparse=True) >>> H = Graph({Integer(0): {Integer(1): 'b'}}, sparse=True) >>> G == H True - Now one is weighted and the other is not, and thus the graphs are not equal: - sage: G.weighted(True) sage: H.weighted() False sage: G == H False - >>> 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)[source]¶
- 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 \(i\)-th row and column of the matrix correspond to the \(i\)-th vertex in the ordering of - vertices,
- when - None, the \(i\)-th row and column of the matrix correspond to the \(i\)-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’s basis is indexed by the vertices.
 - If the vertices are not comparable, the keyword - verticesmust be used to specify an ordering, or a- TypeErrorexception will be raised.
- default_weight– (default:- None) specifies the weight to replace any- Noneedge 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] [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] - 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', 'D', 4)]) sage: phi = G.weighted_adjacency_matrix(vertices=True); phi Generic endomorphism of Free module generated by {'A', 'B', 'C', 'D'} over Integer Ring sage: print(phi._unicode_art_matrix()) A B C D A⎛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', 'C', Integer(3)), ('A', 'D', Integer(4))]) >>> phi = G.weighted_adjacency_matrix(vertices=True); phi Generic endomorphism of Free module generated by {'A', 'B', 'C', 'D'} over Integer Ring >>> print(phi._unicode_art_matrix()) A B C D A⎛0 1 3 4⎞ B⎜1 0 2 0⎟ C⎜3 2 0 0⎟ D⎝4 0 0 0⎠ 
 - wiener_index(by_weight=False, algorithm=None, weight_function=None, check_weight=True)[source]¶
- Return the Wiener index of - self.- The graph is expected to have no cycles of negative weight. - The Wiener index of a undirected graph \(G\) is \(W(G) = \frac{1}{2} \sum_{u,v\in G} d(u,v)\) where \(d(u,v)\) denotes the distance between vertices \(u\) and \(v\) (see [KRG1996]). - The Wiener index of a directed graph \(G\) is defined as the sum of the distances between each pairs of vertices, i.e., \(W(G) = \sum_{u,v\in G} d(u,v)\). - For more information on the input variables and more examples, we refer to - shortest_paths()and- shortest_path_all_pairs(), which have very similar input variables.- INPUT: - by_weight– boolean (default:- False); if- True, the edges in the graph are weighted, otherwise all edges have weight 1
- algorithm– string (default:- None); one of the following algorithms:- For - by_weight==Falseonly:- '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_weightis automatically set to- True. If- Noneand- by_weightis- True, we use the edge label- las a weight, if- lis not- None, else- 1as a weight.
- check_weight– boolean (default:- True); if- True, we check that the weight_function outputs a number for each edge
 - Note - Some algorithms (e.g., Boost algorithms) use floating point numbers for internal computations. Whenever the solution is integral, we try to convert the returned value to an integer. - EXAMPLES: - sage: G = Graph( { 0: {1: None}, 1: {2: None}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }, sparse=True) sage: G.wiener_index() 15 sage: G.wiener_index(weight_function=lambda e:(e[2] if e[2] is not None else 1)) 20 sage: G.wiener_index(weight_function=lambda e:(e[2] if e[2] is not None else 200)) 820 sage: G.wiener_index(algorithm='BFS') 15 sage: G.wiener_index(algorithm='Floyd-Warshall-Cython') 15 sage: G.wiener_index(algorithm='Floyd-Warshall-Python') 15 sage: G.wiener_index(algorithm='Dijkstra_Boost') 15 sage: G.wiener_index(algorithm='Bellman-Ford_Boost') 15 sage: G.wiener_index(algorithm='Johnson_Boost') 15 sage: G.wiener_index(algorithm='Dijkstra_NetworkX') # 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: - 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 graph 
 
- 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, immutable=None)[source]¶
- 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 a graph without multiple edges. At this point, we create another (partially bipartite) graph, whose left vertices are the original vertices of the graph, and whose right vertices represent the labeled edges. Any unlabeled edges in the original graph are also present in the new graph, and – this is the bipartite aspect – for every labeled edge \(e\) from \(v\) to \(w\) in the original graph, there is an edge between the right vertex corresponding to \(e\) and each of the left vertices corresponding to \(v\) and \(w\). We partition the left vertices as they were originally, and the right vertices by common labels: only automorphisms taking edges to like-labeled edges are allowed, and this additional partition information enforces this on the new graph.- INPUT: - g– Graph or DiGraph
- partition– list (default:- None); a partition of the vertices as a list of lists of vertices. If given, the partition of the vertices is as well relabeled
- standard_label– (default:- None) edges in- gwith 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_labelsare returned (useful if inplace is- True)
- inplace– boolean (default:- False); whether the input (di)graph- gis modified or the return a new (di)graph. Note that attributes of- gare not copied for speed issues, only edges and vertices.- This parameter cannot be set to - Trueif the input graph- gis immutable.
- ignore_edge_labels– boolean (default:- False); if- True, ignore edge labels, so when constructing the new graph, only multiple edges are replaced with vertices. Labels on multiple edges are ignored – only the multiplicity is relevant, so multiple edges with the same multiplicity in the original graph correspond to right vertices in the same partition in the new graph.
- immutable– boolean (default:- None); whether to create a mutable/immutable (di)graph.- immutable=None(default) means that the (di)graph and the returned (di)graph will behave the same way.- This parameter is ignored when - inplaceis- True.
 - OUTPUT: - if - inplaceis- False: the unlabeled graph without multiple edges
- the partition of the vertices 
- if - return_relabelingis- True: a dictionary containing the relabeling
- if - return_edge_labelsis- True: the list of (former) edge labels is returned
 - EXAMPLES: - sage: from sage.graphs.generic_graph import graph_isom_equivalent_non_edge_labeled_graph sage: G = Graph(multiedges=True,sparse=True) sage: G.add_edges((0, 1, i) for i in range(10)) sage: G.add_edge(1,2,'string') sage: G.add_edge(2,123) sage: 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 [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) >>> 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)[source]¶
- 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'>