### Navigation

- index
- modules |
- next |
- previous |
- Graph Theory »

# Undirected graphs

This module implements functions and operations involving undirected graphs.

Graph basic operations:

`write_to_eps()` | Writes a plot of the graph to `filename` in `eps` format.
`to_undirected()` | Since the graph is already undirected, simply returns a copy of itself.
`to_directed()` | Returns a directed version of the graph.
`sparse6_string()` | Returns the sparse6 representation of the graph as an ASCII string.
`graph6_string()` | Returns the graph6 representation of the graph as an ASCII string.
`bipartite_sets()` | Returns \((X,Y)\) where X and Y are the nodes in each bipartite set of graph.
`bipartite_color()` | Returns a dictionary with vertices as the keys and the color class as the values.
`is_directed()` | Since graph is undirected, returns False.
`join()` | Returns the join of self and other.

Distances:

`centrality_closeness()` | Returns the closeness centrality (1/average distance to all vertices)
`centrality_degree()` | Returns the degree centrality
`centrality_betweenness()` | Returns the betweenness centrality

Graph properties:

`is_prime()` | Tests whether the current graph is prime.
`is_split()` | Returns `True` if the graph is a Split graph, `False` otherwise.
`is_triangle_free()` | Returns whether `self` is triangle-free.
`is_bipartite()` | Returns True if graph G is bipartite, False if not.
`is_line_graph()` | Tests wether the graph is a line graph.
`is_odd_hole_free()` | Tests whether `self` contains an induced odd hole.
`is_even_hole_free()` | Tests whether `self` contains an induced even hole.
`is_cartesian_product()` | Tests whether `self` is a cartesian product of graphs.
`is_long_hole_free()` | Tests whether `self` contains an induced cycle of length at least 5.
`is_long_antihole_free()` | Tests whether `self` contains an induced anticycle of length at least 5.
`is_weakly_chordal()` | Tests whether `self` is weakly chordal.
`is_strongly_regular()` | Tests whether `self` is strongly regular.
`is_distance_regular()` | Tests whether `self` is distance-regular.
`is_tree()` | Return True if the graph is a tree.
`is_forest()` | Return True if the graph is a forest, i.e. a disjoint union of trees.
`is_overfull()` | Tests whether the current graph is overfull.
`odd_girth()` | Returns the odd girth of `self`.
`is_edge_transitive()` | Returns true if self is edge-transitive.
`is_arc_transitive()` | Returns true if self is arc-transitive.
`is_half_transitive()` | Returns true if self is a half-transitive graph.
`is_semi_symmetric()` | Returns true if self is a semi-symmetric graph.

Connectivity, orientations, trees:

`gomory_hu_tree()` | Returns a Gomory-Hu tree of self.
`minimum_outdegree_orientation()` | Returns an orientation of `self` with the smallest possible maximum outdegree
`bounded_outdegree_orientation()` | Computes an orientation of `self` such that every vertex \(v\) has out-degree less than \(b(v)\)
`strong_orientation()` | Returns a strongly connected orientation of the current graph.
`degree_constrained_subgraph()` | Returns a degree-constrained subgraph.
`bridges()` | Returns the list of all bridges.
`spanning_trees()` | Returns the list of all spanning trees.
`random_spanning_tree()` | Returns a random spanning tree.

Clique-related methods:

`clique_complex()` | Returns the clique complex of self
`cliques_containing_vertex()` | Returns the cliques containing each vertex
`cliques_vertex_clique_number()` | Returns a dictionary of sizes of the largest maximal cliques containing each vertex
`cliques_get_clique_bipartite()` | Returns a bipartite graph constructed such that maximal cliques are the right vertices and the left vertices are retained from the given graph
`cliques_get_max_clique_graph()` | Returns a graph constructed with maximal cliques as vertices, and edges between maximal cliques sharing vertices.
`cliques_number_of()` | Returns a dictionary of the number of maximal cliques containing each vertex, keyed by vertex.
`clique_number()` | Returns the order of the largest clique of the graph.
`clique_maximum()` | Returns the vertex set of a maximal order complete subgraph.
`cliques_maximum()` | Returns the list of all maximum cliques
`cliques_maximal()` | Returns the list of all maximal cliques
`clique_polynomial()` | Returns the clique polynomial

Algorithmically hard stuff:

`vertex_cover()` | Returns a minimum vertex cover of self
`independent_set()` | Returns a maximum independent set.
`topological_minor()` | Returns a topological \(H\)-minor from `self` if one exists.
`convexity_properties()` | Returns a `ConvexityProperties` objet corresponding to `self`.
`matching_polynomial()` | Computes the matching polynomial of the graph \(G\).
`rank_decomposition()` | Returns an rank-decomposition of `self` achieving optiml rank-width.
`minor()` | Returns the vertices of a minor isomorphic to \(H\) in the current graph.
`independent_set_of_representatives()` | Returns an independent set of representatives.
`coloring()` | Returns the first (optimal) proper vertex-coloring found.
`has_homomorphism_to()` | Checks whether there is a morphism between two graphs.
`chromatic_number()` | Returns the minimal number of colors needed to color the vertices of the graph.
`chromatic_polynomial()` | Returns the chromatic polynomial of the graph.
`tutte_polynomial()` | Returns the Tutte polynomial of the graph.
`is_perfect()` | Tests whether the graph is perfect.
`treewidth()` | Computes the tree-width and provides a decomposition.

Leftovers:

`cores()` | Returns the core number for each vertex in an ordered list.
`matching()` | Returns a maximum weighted matching of the graph
`fractional_chromatic_index()` | Computes the fractional chromatic index of `self`
`kirchhoff_symanzik_polynomial()` | Returns the Kirchhoff-Symanzik polynomial of the graph.
`modular_decomposition()` | Returns the modular decomposition of the current graph.
`maximum_average_degree()` | Returns the Maximum Average Degree (MAD) of the current graph.
`two_factor_petersen()` | Returns a decomposition of the graph into 2-factors.
`ihara_zeta_function_inverse()` | Returns the inverse of the zeta function of the graph.

AUTHORS:

- Robert L. Miller (2006-10-22): initial version

- William Stein (2006-12-05): Editing

- Robert L. Miller (2007-01-13): refactoring, adjusting for NetworkX-0.33, fixed plotting bugs (2007-01-23): basic tutorial, edge labels, loops, multiple edges and arcs (2007-02-07): graph6 and sparse6 formats, matrix input

- Emily Kirkmann (2007-02-11): added graph_border option to plot and show

- Robert L. Miller (2007-02-12): vertex color-maps, graph boundaries, graph6 helper functions in Cython

- Robert L. Miller Sage Days 3 (2007-02-17-21): 3d plotting in Tachyon

- Robert L. Miller (2007-02-25): display a partition

- Robert L. Miller (2007-02-28): associate arbitrary objects to vertices, edge and arc label display (in 2d), edge coloring

- Robert L. Miller (2007-03-21): Automorphism group, isomorphism check, canonical label

- Robert L. Miller (2007-06-07-09): NetworkX function wrapping

- Michael W. Hansen (2007-06-09): Topological sort generation

- Emily Kirkman, Robert L. Miller Sage Days 4: Finished wrapping NetworkX

- Emily Kirkman (2007-07-21): Genus (including circular planar, all embeddings and all planar embeddings), all paths, interior paths

- Bobby Moretti (2007-08-12): fixed up plotting of graphs with edge colors differentiated by label

- Jason Grout (2007-09-25): Added functions, bug fixes, and general enhancements

- Robert L. Miller (Sage Days 7): Edge labeled graph isomorphism

- Tom Boothby (Sage Days 7): Miscellaneous awesomeness

- Tom Boothby (2008-01-09): Added graphviz output

- David Joyner (2009-2): Fixed docstring bug related to GAP.

- Stephen Hartke (2009-07-26): Fixed bug in blocks_and_cut_vertices() that caused an incorrect result when the vertex 0 was a cut vertex.

- Stephen Hartke (2009-08-22): Fixed bug in blocks_and_cut_vertices() where the list of cut_vertices is not treated as a set.

- Anders Jonsson (2009-10-10): Counting of spanning trees and out-trees added.

- Nathann Cohen (2009-09) : Cliquer, Connectivity, Flows

    and everything that uses Linear Programming and class numerical.MIP

- Nicolas M. Thiery (2010-02): graph layout code refactoring, dot2tex/graphviz interface

- David Coudert (2012-04) : Reduction rules in vertex_cover.

- Birk Eisermann (2012-06): added recognition of weakly chordal graphs and

    long-hole-free / long-antihole-free graphs

- Alexandre P. Zuge (2013-07): added join operation.

- Amritanshu Prasad (2014-08): added clique polynomial

## Graph Format

### Supported formats

Sage Graphs can be created from a wide range of inputs. A few examples are covered here.

- NetworkX dictionary format:

      sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], \
            5: [7, 8], 6: [8,9], 7: [9]}
      sage: G = Graph(d); G
      Graph on 10 vertices
      sage: G.plot().show()    # or G.show()

- A NetworkX graph:

      sage: import networkx
      sage: K = networkx.complete_bipartite_graph(12,7)
      sage: G = Graph(K)
      sage: G.degree()
      [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12]

- graph6 or sparse6 format:

      sage: s = ':I`AKGsaOs`cI]Gb~'
      sage: G = Graph(s, sparse=True); G
      Looped multi-graph on 10 vertices
      sage: G.plot().show()    # or G.show()

  Note that the `\` character is an escape character in Python, and also a character used by graph6 strings:

      sage: G = Graph('Ihe\n@GUA')
      Traceback (most recent call last):
      ...
      RuntimeError: The string (Ihe) seems corrupt: for n = 10, the string is too short.

  In Python, the escaped character `\` is represented by `\\`:

      sage: G = Graph('Ihe\\n@GUA')
      sage: G.plot().show()    # or G.show()

- adjacency matrix: In an adjacency matrix, each column and each row represent a vertex. If a 1 shows up in row \(i\), column \(j\), there is an edge \((i,j)\).

      sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0),(1,0,1,0,0,0,1,0,0,0), \
      (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),(1,0,0,1,0,0,0,0,0,1), \
      (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),(0,0,1,0,0,1,0,0,0,1), \
      (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)])
      sage: M
      [0 1 0 0 1 1 0 0 0 0]
      [1 0 1 0 0 0 1 0 0 0]
      [0 1 0 1 0 0 0 1 0 0]
      [0 0 1 0 1 0 0 0 1 0]
      [1 0 0 1 0 0 0 0 0 1]
      [1 0 0 0 0 0 0 1 1 0]
      [0 1 0 0 0 0 0 0 1 1]
      [0 0 1 0 0 1 0 0 0 1]
      [0 0 0 1 0 1 1 0 0 0]
      [0 0 0 0 1 0 1 1 0 0]
      sage: G = Graph(M); G
      Graph on 10 vertices
      sage: G.plot().show()    # or G.show()

- incidence matrix: In an incidence matrix, each row represents a vertex and each column represents an edge.

      sage: M = Matrix([(-1,0,0,0,1,0,0,0,0,0,-1,0,0,0,0), \
      (1,-1,0,0,0,0,0,0,0,0,0,-1,0,0,0),(0,1,-1,0,0,0,0,0,0,0,0,0,-1,0,0), \
      (0,0,1,-1,0,0,0,0,0,0,0,0,0,-1,0),(0,0,0,1,-1,0,0,0,0,0,0,0,0,0,-1), \
      (0,0,0,0,0,-1,0,0,0,1,1,0,0,0,0),(0,0,0,0,0,0,0,1,-1,0,0,1,0,0,0), \
      (0,0,0,0,0,1,-1,0,0,0,0,0,1,0,0),(0,0,0,0,0,0,0,0,1,-1,0,0,0,1,0), \
      (0,0,0,0,0,0,1,-1,0,0,0,0,0,0,1)])
      sage: M
      [-1  0  0  0  1  0  0  0  0  0 -1  0  0  0  0]
      [ 1 -1  0  0  0  0  0  0  0  0  0 -1  0  0  0]
      [ 0  1 -1  0  0  0  0  0  0  0  0  0 -1  0  0]
      [ 0  0  1 -1  0  0  0  0  0  0  0  0  0 -1  0]
      [ 0  0  0  1 -1  0  0  0  0  0  0  0  0  0 -1]
      [ 0  0  0  0  0 -1  0  0  0  1  1  0  0  0  0]
      [ 0  0  0  0  0  0  0  1 -1  0  0  1  0  0  0]
      [ 0  0  0  0  0  1 -1  0  0  0  0  0  1  0  0]
      [ 0  0  0  0  0  0  0  0  1 -1  0  0  0  1  0]
      [ 0  0  0  0  0  0  1 -1  0  0  0  0  0  0  1]
      sage: G = Graph(M); G
      Graph on 10 vertices
      sage: G.plot().show()    # or G.show()
      sage: DiGraph(matrix(2,[0,0,-1,1]), format="incidence_matrix")
      Traceback (most recent call last):
      ...
      ValueError: There must be two nonzero entries (-1 & 1) per column.

- a list of edges:

      sage: g = Graph([(1,3),(3,8),(5,2)])
      sage: g
      Graph on 5 vertices

## Generators

If you wish to iterate through all the isomorphism types of graphs, type, for example:

    sage: for g in graphs(4):
    ...     print g.spectrum()
    [0, 0, 0, 0]
    [1, 0, 0, -1]
    [1.4142135623..., 0, 0, -1.4142135623...]
    [2, 0, -1, -1]
    [1.7320508075..., 0, 0, -1.7320508075...]
    [1, 1, -1, -1]
    [1.6180339887..., 0.6180339887..., -0.6180339887..., -1.6180339887...]
    [2.1700864866..., 0.3111078174..., -1, -1.4811943040...]
    [2, 0, 0, -2]
    [2.5615528128..., 0, -1, -1.5615528128...]
    [3, -1, -1, -1]

For some commonly used graphs to play with, type

    sage: graphs.[tab]          # not tested

and hit {tab}. Most of these graphs come with their own custom plot, so you can see how people usually visualize these graphs.

    sage: G = graphs.PetersenGraph()
    sage: G.plot().show()    # or G.show()
    sage: G.degree_histogram()
    [0, 0, 0, 10]
    sage: G.adjacency_matrix()
    [0 1 0 0 1 1 0 0 0 0]
    [1 0 1 0 0 0 1 0 0 0]
    [0 1 0 1 0 0 0 1 0 0]
    [0 0 1 0 1 0 0 0 1 0]
    [1 0 0 1 0 0 0 0 0 1]
    [1 0 0 0 0 0 0 1 1 0]
    [0 1 0 0 0 0 0 0 1 1]
    [0 0 1 0 0 1 0 0 0 1]
    [0 0 0 1 0 1 1 0 0 0]
    [0 0 0 0 1 0 1 1 0 0]

    sage: S = G.subgraph([0,1,2,3])
    sage: S.plot().show()    # or S.show()
    sage: S.density()
    1/2

    sage: G = GraphQuery(display_cols=['graph6'], num_vertices=7, diameter=5)
    sage: L = G.get_graphs_list()
    sage: graphs_list.show_graphs(L)

## Labels

Each vertex can have any hashable object as a label. These are things like strings, numbers, and tuples. Each edge is given a default label of `None`, but if specified, edges can have any label at all. Edges between vertices \(u\) and \(v\) are represented typically as `(u, v, l)`, where `l` is the label for the edge.

Note that vertex labels themselves cannot be mutable items:

    sage: M = Matrix( [[0,0],[0,0]] )
    sage: G = Graph({ 0 : { M : None } })
    Traceback (most recent call last):
    ...
    TypeError: mutable matrices are unhashable

However, if one wants to define a dictionary, with the same keys and arbitrary objects for entries, one can make that association:

    sage: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), \
          2 : graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }
    sage: d[2]
    Moebius-Kantor Graph: Graph on 16 vertices
    sage: T = graphs.TetrahedralGraph()
    sage: T.vertices()
    [0, 1, 2, 3]
    sage: T.set_vertices(d)
    sage: T.get_vertex(1)
    Flower Snark: Graph on 20 vertices

## Database

There is a database available for searching for graphs that satisfy a certain set of parameters, including number of vertices and edges, density, maximum and minimum degree, diameter, radius, and connectivity. To see a list of all search parameter keywords broken down by their designated table names, type

    sage: graph_db_info()
    {...}

For more details on data types or keyword input, enter

    sage: GraphQuery?    # not tested

The results of a query can be viewed with the show method, or can be viewed individually by iterating through the results:

    sage: Q = GraphQuery(display_cols=['graph6'],num_vertices=7, diameter=5)
    sage: Q.show()
    Graph6
    --------------------
    F?`po
    F?gqg
    F@?]O
    F@OKg
    F@R@o
    FA_pW
    FEOhW
    FGC{o
    FIAHo

Show each graph as you iterate through the results:

    sage: for g in Q:
    ...     show(g)

## Visualization

To see a graph \(G\) you are working with, there are three main options. You can view the graph in two dimensions via matplotlib with `show()`.

    sage: G = graphs.RandomGNP(15,.3)
    sage: G.show()

And you can view it in three dimensions via jmol with `show3d()`.

    sage: G.show3d()

Or it can be rendered with \(\LaTeX\). This requires the right additions to a standard \(\mbox{\rm\TeX}\) installation. Then standard Sage commands, such as `view(G)` will display the graph, or `latex(G)` will produce a string suitable for inclusion in a \(\LaTeX\) document. More details on this are at the `sage.graphs.graph_latex` module.

    sage: from sage.graphs.graph_latex import check_tkz_graph
    sage: check_tkz_graph()  # random - depends on TeX installation
    sage: latex(G)
    \begin{tikzpicture}
    ...
    \end{tikzpicture}

## Mutability

Graphs are mutable, and thus unusable as dictionary keys, unless `data_structure="static_sparse"` is used:

    sage: G = graphs.PetersenGraph()
    sage: {G:1}[G]
    Traceback (most recent call last):
    ...
    TypeError: This graph is mutable, and thus not hashable. Create an immutable copy by `g.copy(immutable=True)`
    sage: G_immutable = Graph(G, immutable=True)
    sage: G_immutable == G
    True
    sage: {G_immutable:1}[G_immutable]
    1

## Methods

class `sage.graphs.graph.``Graph`(data=None, pos=None, loops=None, format=None, boundary=None, weighted=None, implementation='c_graph', data_structure='sparse', vertex_labels=True, name=None, multiedges=None, convert_empty_dict_labels_to_None=None, sparse=True, immutable=False)

  Bases: `sage.graphs.generic_graph.GenericGraph`

  Undirected graph.

  A graph is a set of vertices connected by edges. See also the Wikipedia article on graphs.

  One can very easily create a graph in Sage by typing:

      sage: g = Graph()

  By typing the name of the graph, one can get some basic information about it:

      sage: g
      Graph on 0 vertices

  This graph is not very interesting as it is by default the empty graph. But Sage contains a large collection of pre-defined graph classes that can be listed this way:

  - Within a Sage session, type `graphs.` (Do not press “Enter”, and do not forget the final period ”.”)
  - Hit “tab”.

  You will see a list of methods which will construct named graphs. For example:

      sage: g = graphs.PetersenGraph()
      sage: g.plot()
      Graphics object consisting of 26 graphics primitives

  or:

      sage: g = graphs.ChvatalGraph()
      sage: g.plot()
      Graphics object consisting of 37 graphics primitives

  In order to obtain more information about these graph constructors, access the documentation using the command `graphs.RandomGNP?`.

  Once you have defined the graph you want, you can begin to work on it by using the almost 200 functions on graphs in the Sage library! If your graph is named `g`, you can list these functions as previously this way

  - Within a Sage session, type `g.` (Do not press “Enter”, and do not forget the final period ”.” )
  - Hit “tab”.

  As usual, you can get some information about what these functions do by typing (e.g. if you want to know about the `diameter()` method) `g.diameter?`.

  If you have defined a graph `g` having several connected components (i.e. `g.is_connected()` returns False), you can print each one of its connected components with only two lines:

      sage: for component in g.connected_components():
      ....:      g.subgraph(component).plot()
      Graphics object consisting of 37 graphics primitives

  INPUT:

  - `data` – can be any of the following (see the `format` argument):

  > 1. An integer specifying the number of vertices
  > 2. A dictionary of dictionaries
  > 3. A dictionary of lists
  > 4. A NumPy matrix or ndarray
  > 5. A Sage adjacency matrix or incidence matrix
  > 6. A pygraphviz graph
  > 7. A SciPy sparse matrix
  > 8. A NetworkX graph

  - `pos` - a positioning dictionary: for example, the spring layout from NetworkX for the 5-cycle is:

        {0: [-0.91679746, 0.88169588],
         1: [ 0.47294849, 1.125     ],
         2: [ 1.125     ,-0.12867615],
         3: [ 0.12743933,-1.125     ],
         4: [-1.125     ,-0.50118505]}

  - `name` - (must be an explicitly named parameter, i.e., `name="complete")` gives the graph a name

  - `loops` - boolean, whether to allow loops (ignored if data is an instance of the `Graph` class)

  - `multiedges` - boolean, whether to allow multiple edges (ignored if data is an instance of the `Graph` class)

  - `weighted` - whether graph thinks of itself as weighted or not. See `self.weighted()`

  - `format` - if None, Graph tries to guess- can be several values, including:

    - `'int'` - an integer specifying the number of vertices in an edge-free graph with vertices labelled from 0 to n-1

    - `'graph6'` - Brendan McKay’s graph6 format, in a string (if the string has multiple graphs, the first graph is taken)

    - `'sparse6'` - Brendan McKay’s sparse6 format, in a string (if the string has multiple graphs, the first graph is taken)

    - `'adjacency_matrix'` - a square Sage matrix M, with M[i,j] equal to the number of edges {i,j}

    - `'weighted_adjacency_matrix'` - a square Sage matrix M, with M[i,j] equal to the weight of the single edge {i,j}. Given this format, weighted is ignored (assumed True).

    - `'incidence_matrix'` - a Sage matrix, with one column C for each edge, where if C represents {i, j}, C[i] is -1 and C[j] is 1

    - `'elliptic_curve_congruence'` - data must be an iterable container of elliptic curves, and the graph produced has each curve as a vertex (it’s Cremona label) and an edge E-F labelled p if and only if E is congruent to F mod p

    - `NX` - data must be a NetworkX Graph.

      > Note

      > As Sage’s default edge labels is `None` while NetworkX uses `{}`, the `{}` labels of a NetworkX graph are automatically set to `None` when it is converted to a Sage graph. This behaviour can be overruled by setting the keyword `convert_empty_dict_labels_to_None` to `False` (it is `True` by default).

  - `boundary` - a list of boundary vertices, if empty, graph is considered as a ‘graph without boundary’

  - `implementation` - what to use as a backend for the graph. Currently, the options are either ‘networkx’ or ‘c_graph’

  - `sparse` (boolean) – `sparse=True` is an alias for `data_structure="sparse"`, and `sparse=False` is an alias for `data_structure="dense"`.

  - `data_structure` – one of the following

    - `"dense"` – selects the `dense_graph` backend.
    - `"sparse"` – selects the `sparse_graph` backend.
    - `"static_sparse"` – selects the `static_sparse_backend` (this backend is faster than the sparse backend and smaller in memory, and it is immutable, so that the resulting graphs can be used as dictionary keys).

    Only available when `implementation == 'c_graph'`

  - `immutable` (boolean) – whether to create a immutable graph. Note that `immutable=True` is actually a shortcut for `data_structure='static_sparse'`. Set to `False` by default, only available when `implementation='c_graph'`

  - `vertex_labels` - only for implementation == ‘c_graph’. Whether to allow any object as a vertex (slower), or only the integers 0, ..., n-1, where n is the number of vertices.

  - `convert_empty_dict_labels_to_None` - this arguments sets the default edge labels used by NetworkX (empty dictionaries) to be replaced by None, the default Sage edge label. It is set to `True` iff a NetworkX graph is on the input.

  EXAMPLES:

  We illustrate the first seven input formats (the other two involve packages that are currently not standard in Sage):

  1. An integer giving the number of vertices:

         sage: g = Graph(5); g
         Graph on 5 vertices
         sage: g.vertices()
         [0, 1, 2, 3, 4]
         sage: g.edges()
         []

  2. A dictionary of dictionaries:

         sage: g = Graph({0:{1:'x',2:'z',3:'a'}, 2:{5:'out'}}); g
         Graph on 5 vertices

     The labels (‘x’, ‘z’, ‘a’, ‘out’) are labels for edges. For example, ‘out’ is the label for the edge on 2 and 5. Labels can be used as weights, if all the labels share some common parent.

         sage: a,b,c,d,e,f = sorted(SymmetricGroup(3))
         sage: Graph({b:{d:'c',e:'p'}, c:{d:'p',e:'c'}})
         Graph on 4 vertices

  3. A dictionary of lists:

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

  4. A list of vertices and a function describing adjacencies. Note that the list of vertices and the function must be enclosed in a list (i.e., [list of vertices, function]).

     Construct the Paley graph over GF(13).

         sage: g=Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()])
         sage: g.vertices()
         [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
         sage: g.adjacency_matrix()
         [0 1 0 1 1 0 0 0 0 1 1 0 1]
         [1 0 1 0 1 1 0 0 0 0 1 1 0]
         [0 1 0 1 0 1 1 0 0 0 0 1 1]
         [1 0 1 0 1 0 1 1 0 0 0 0 1]
         [1 1 0 1 0 1 0 1 1 0 0 0 0]
         [0 1 1 0 1 0 1 0 1 1 0 0 0]
         [0 0 1 1 0 1 0 1 0 1 1 0 0]
         [0 0 0 1 1 0 1 0 1 0 1 1 0]
         [0 0 0 0 1 1 0 1 0 1 0 1 1]
         [1 0 0 0 0 1 1 0 1 0 1 0 1]
         [1 1 0 0 0 0 1 1 0 1 0 1 0]
         [0 1 1 0 0 0 0 1 1 0 1 0 1]
         [1 0 1 1 0 0 0 0 1 1 0 1 0]

     Construct the line graph of a complete graph.

         sage: g=graphs.CompleteGraph(4)
         sage: line_graph=Graph([g.edges(labels=false), \
                lambda i,j: len(set(i).intersection(set(j)))>0], \
                loops=False)
         sage: line_graph.vertices()
         [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
         sage: line_graph.adjacency_matrix()
         [0 1 1 1 1 0]
         [1 0 1 1 0 1]
         [1 1 0 0 1 1]
         [1 1 0 0 1 1]
         [1 0 1 1 0 1]
         [0 1 1 1 1 0]

  5. A NumPy matrix or ndarray:

         sage: import numpy
         sage: A = numpy.array([[0,1,1],[1,0,1],[1,1,0]])
         sage: Graph(A)
         Graph on 3 vertices

  6. A graph6 or sparse6 string: Sage automatically recognizes whether a string is in graph6 or sparse6 format:

         sage: s = ':I`AKGsaOs`cI]Gb~'
         sage: Graph(s,sparse=True)
         Looped multi-graph on 10 vertices

         sage: G = Graph('G?????')
         sage: G = Graph("G'?G?C")
         Traceback (most recent call last):
         ...
         RuntimeError: The string seems corrupt: valid characters are
         ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
         sage: G = Graph('G??????')
         Traceback (most recent call last):
         ...
         RuntimeError: The string (G??????) seems corrupt: for n = 8, the string is too long.

         sage: G = Graph(":I'AKGsaOs`cI]Gb~")
         Traceback (most recent call last):
         ...
         RuntimeError: The string seems corrupt: valid characters are
         ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

     There are also list functions to take care of lists of graphs:

         sage: s = ':IgMoqoCUOqeb\n:I`AKGsaOs`cI]Gb~\n:I`EDOAEQ?PccSsge\N\n'
         sage: graphs_list.from_sparse6(s)
         [Looped multi-graph on 10 vertices, Looped multi-graph on 10 vertices, Looped multi-graph on 10 vertices]

  7. A Sage matrix: Note: If format is not specified, then Sage assumes a symmetric square matrix is an adjacency matrix, otherwise an incidence matrix.

     - an adjacency matrix:

           sage: M = graphs.PetersenGraph().am(); M
           [0 1 0 0 1 1 0 0 0 0]
           [1 0 1 0 0 0 1 0 0 0]
           [0 1 0 1 0 0 0 1 0 0]
           [0 0 1 0 1 0 0 0 1 0]
           [1 0 0 1 0 0 0 0 0 1]
           [1 0 0 0 0 0 0 1 1 0]
           [0 1 0 0 0 0 0 0 1 1]
           [0 0 1 0 0 1 0 0 0 1]
           [0 0 0 1 0 1 1 0 0 0]
           [0 0 0 0 1 0 1 1 0 0]
           sage: Graph(M)
           Graph on 10 vertices

           sage: Graph(matrix([[1,2],[2,4]]),loops=True,sparse=True)
           Looped multi-graph on 2 vertices

           sage: M = Matrix([[0,1,-1],[1,0,-1/2],[-1,-1/2,0]]); M
           [   0    1   -1]
           [   1    0 -1/2]
           [  -1 -1/2    0]
           sage: G = Graph(M,sparse=True); G
           Graph on 3 vertices
           sage: G.weighted()
           True

     - an incidence matrix:

           sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M
           [-1  0  0  0  1]
           [ 1 -1  0  0  0]
           [ 0  1 -1  0  0]
           [ 0  0  1 -1  0]
           [ 0  0  0  1 -1]
           [ 0  0  0  0  0]
           sage: Graph(M)
           Graph on 6 vertices

           sage: Graph(Matrix([[1],[1],[1]]))
           Traceback (most recent call last):
           ...
           ValueError: Non-symmetric or non-square matrix assumed to be an incidence matrix: There must be two nonzero entries (-1 & 1) per column.
           sage: Graph(Matrix([[1],[1],[0]]))
           Traceback (most recent call last):
           ...
           ValueError: Non-symmetric or non-square matrix assumed to be an incidence matrix: Each column represents an edge: -1 goes to 1.

           sage: M = Matrix([[0,1,-1],[1,0,-1],[-1,-1,0]]); M
           [ 0  1 -1]
           [ 1  0 -1]
           [-1 -1  0]
           sage: Graph(M,sparse=True)
           Graph on 3 vertices

           sage: M = Matrix([[0,1,1],[1,0,1],[-1,-1,0]]); M
           [ 0  1  1]
           [ 1  0  1]
           [-1 -1  0]
           sage: Graph(M)
           Traceback (most recent call last):
           ...
           ValueError: Non-symmetric or non-square matrix assumed to be an incidence matrix: Each column represents an edge: -1 goes to 1.

     >     sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]])      # trac 9714
     >     sage: MI = Graph(MA, format='adjacency_matrix').incidence_matrix(); MI
     >     [-1 -1  0  0  0  1]
     >     [ 1  1  0  1  1  0]
     >     [ 0  0  1  0  0  0]
     >     sage: Graph(MI).edges(labels=None)
     >     [(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)]

     >     sage: M = Matrix([[1], [-1]]); M
     >     [ 1]
     >     [-1]
     >     sage: Graph(M).edges()
     >     [(0, 1, None)]

  8. a list of edges, or labelled edges:

         sage: g = Graph([(1,3),(3,8),(5,2)])
         sage: g
         Graph on 5 vertices

         ::

         sage: g = Graph([(1,2,"Peace"),(7,-9,"and"),(77,2, "Love")])
         sage: g
         Graph on 5 vertices
         sage: g = Graph([(0, 2, '0'), (0, 2, '1'), (3, 3, '2')])
         sage: g.loops()
         [(3, 3, '2')]

  9. A NetworkX MultiGraph:

         sage: import networkx
         sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]})
         sage: Graph(g)
         Graph on 5 vertices

  10. A NetworkX graph:

          sage: import networkx
          sage: g = networkx.Graph({0:[1,2,3], 2:[4]})
          sage: DiGraph(g)
          Digraph on 5 vertices

  Note that in all cases, we copy the NetworkX structure.

  >     sage: import networkx
  >     sage: g = networkx.Graph({0:[1,2,3], 2:[4]})
  >     sage: G = Graph(g, implementation='networkx')
  >     sage: H = Graph(g, implementation='networkx')
  >     sage: G._backend._nxg is H._backend._nxg
  >     False

  All these graphs are mutable and can thus not be used as a dictionary key:

      sage: {G:1}[H]
      Traceback (most recent call last):
      ...
      TypeError: This graph is mutable, and thus not hashable. Create an immutable copy by `g.copy(immutable=True)`

  When providing the optional arguments `data_structure="static_sparse"` or `immutable=True` (both mean the same), then an immutable graph results. Note that this does not use the NetworkX data structure:

      sage: G_imm = Graph(g, immutable=True)
      sage: H_imm = Graph(g, data_structure='static_sparse')
      sage: G_imm == H_imm == G == H
      True
      sage: hasattr(G_imm._backend, "_nxg")
      False
      sage: {G_imm:1}[H_imm]
      1

  `bipartite_color`()

    Returns a dictionary with vertices as the keys and the color class as the values. Fails with an error if the graph is not bipartite.

    EXAMPLES:

        sage: graphs.CycleGraph(4).bipartite_color()
        {0: 1, 1: 0, 2: 1, 3: 0}
        sage: graphs.CycleGraph(5).bipartite_color()
        Traceback (most recent call last):
        ...
        RuntimeError: Graph is not bipartite.

  `bipartite_sets`()

    Returns \((X,Y)\) where \(X\) and \(Y\) are the nodes in each bipartite set of graph \(G\). Fails with an error if graph is not bipartite.

    EXAMPLES:

        sage: graphs.CycleGraph(4).bipartite_sets()
        ({0, 2}, {1, 3})
        sage: graphs.CycleGraph(5).bipartite_sets()
        Traceback (most recent call last):
        ...
        RuntimeError: Graph is not bipartite.

  `bounded_outdegree_orientation`(bound)

    Computes an orientation of `self` such that every vertex \(v\) has out-degree less than \(b(v)\)

    INPUT:

    - `bound` – Maximum bound on the out-degree. Can be of three different types :

      > - An integer \(k\). In this case, computes an orientation whose maximum out-degree is less than \(k\).
      > - A dictionary associating to each vertex its associated maximum out-degree.
      > - A function associating to each vertex its associated maximum out-degree.

    OUTPUT:

    A DiGraph representing the orientation if it exists. A `ValueError` exception is raised otherwise.

    ALGORITHM:

    The problem is solved through a maximum flow :

    Given a graph \(G\), we create a `DiGraph` \(D\) defined on \(E(G)\cup V(G)\cup \{s,t\}\). We then link \(s\) to all of \(V(G)\) (these edges having a capacity equal to the bound associated to each element of \(V(G)\)), and all the elements of \(E(G)\) to \(t\) . We then link each \(v \in V(G)\) to each of its incident edges in \(G\). A maximum integer flow of value \(|E(G)|\) corresponds to an admissible orientation of \(G\). Otherwise, none exists.

    EXAMPLES:

    There is always an orientation of a graph \(G\) such that a vertex \(v\) has out-degree at most \(\lceil \frac {d(v)} 2 \rceil\):

        sage: g = graphs.RandomGNP(40, .4)
        sage: b = lambda v : ceil(g.degree(v)/2)
        sage: D = g.bounded_outdegree_orientation(b)
        sage: all( D.out_degree(v) <= b(v) for v in g )
        True

    Chvatal’s graph, being 4-regular, can be oriented in such a way that its maximum out-degree is 2:

        sage: g = graphs.ChvatalGraph()
        sage: D = g.bounded_outdegree_orientation(2)
        sage: max(D.out_degree())
        2

    For any graph \(G\), it is possible to compute an orientation such that the maximum out-degree is at most the maximum average degree of \(G\) divided by 2. Anything less, though, is impossible.

    > sage: g = graphs.RandomGNP(40, .4) sage: mad = g.maximum_average_degree()

    Hence this is possible

        sage: d = g.bounded_outdegree_orientation(ceil(mad/2))

    While this is not:

        sage: try:
        ...      g.bounded_outdegree_orientation(ceil(mad/2-1))
        ...      print "Error"
        ... except ValueError:
        ...       pass

    TESTS:

    As previously for random graphs, but more intensively:

        sage: for i in xrange(30):      # long time (up to 6s on sage.math, 2012)
        ...       g = graphs.RandomGNP(40, .4)
        ...       b = lambda v : ceil(g.degree(v)/2)
        ...       D = g.bounded_outdegree_orientation(b)
        ...       if not (
        ...            all( D.out_degree(v) <= b(v) for v in g ) or
        ...            D.size() != g.size()):
        ...           print "Something wrong happened"

  `bridges`()

    Returns a list of the bridges (or cut edges).

    A bridge is an edge so that deleting it disconnects the graph.

    Note

    This method assumes the graph is connected.

    EXAMPLES:

        sage: g = 2*graphs.PetersenGraph()
        sage: g.add_edge(1,10)
        sage: g.is_connected()
        True
        sage: g.bridges()
        [(1, 10, None)]

  `centrality_betweenness`(k=None, normalized=True, weight=None, endpoints=False, seed=None)

    Returns the betweenness centrality (fraction of number of shortest paths that go through each vertex) as a dictionary keyed by vertices. The betweenness is normalized by default to be in range (0,1). This wraps NetworkX’s implementation of the algorithm described in [Brandes2003].

    Measures of the centrality of a vertex within a graph determine the relative importance of that vertex to its graph. Vertices that occur on more shortest paths between other vertices have higher betweenness than vertices that occur on less.

    INPUT:

    - `normalized` - boolean (default True) - if set to False, result is not normalized.
    - `k` - integer or None (default None) - if set to an integer, use `k` node samples to estimate betweenness. Higher values give better approximations.
    - `weight` - None or string. If set to a string, use that attribute of the nodes as weight. `weight = True` is equivalent to `weight = "weight"`
    - `endpoints` - Boolean. If set to True it includes the endpoints in the shortest paths count

    REFERENCE:

    [Brandes2003] | Ulrik Brandes. (2003). Faster Evaluation of Shortest-Path Based Centrality Indices. [Online] Available: http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.43.1504

    EXAMPLES:

        sage: (graphs.ChvatalGraph()).centrality_betweenness()
        {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: (graphs.ChvatalGraph()).centrality_betweenness(
        ...     normalized=False)
        {0: 3.833333333333333, 1: 3.833333333333333, 2: 3.333333333333333,
         3: 3.333333333333333, 4: 3.833333333333333, 5: 3.833333333333333,
         6: 3.333333333333333, 7: 3.333333333333333, 8: 3.333333333333333,
         9: 3.333333333333333, 10: 3.333333333333333,
         11: 3.333333333333333}
        sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: D.show(figsize=[2,2])
        sage: D = D.to_undirected()
        sage: D.show(figsize=[2,2])
        sage: D.centrality_betweenness()
        {0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0}

  `centrality_closeness`(v=None)

    Returns the closeness centrality (1/average distance to all vertices) as a dictionary of values keyed by vertex. The degree centrality is normalized 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. ‘Closeness centrality may be defined as the total graph-theoretic distance of a given vertex from all other vertices... Closeness is an inverse measure of centrality in that a larger value indicates a less central actor while a smaller value indicates a more central actor,’ [Borgatti95].

    INPUT:

    - `v` - a vertex label (to find degree centrality of only one vertex)

    REFERENCE:

    [Borgatti95] | Stephen P Borgatti. (1995). Centrality and AIDS. [Online] Available: http://www.analytictech.com/networks/centaids.htm

    EXAMPLES:

        sage: (graphs.ChvatalGraph()).centrality_closeness()
        {0: 0.61111111111111..., 1: 0.61111111111111..., 2: 0.61111111111111..., 3: 0.61111111111111..., 4: 0.61111111111111..., 5: 0.61111111111111..., 6: 0.61111111111111..., 7: 0.61111111111111..., 8: 0.61111111111111..., 9: 0.61111111111111..., 10: 0.61111111111111..., 11: 0.61111111111111...}
        sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: D.show(figsize=[2,2])
        sage: D = D.to_undirected()
        sage: D.show(figsize=[2,2])
        sage: D.centrality_closeness()
        {0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75}
        sage: D.centrality_closeness(v=1)
        1.0

  `centrality_degree`(v=None)

    Returns the degree centrality (fraction of vertices connected to) as a dictionary of values keyed by vertex. The degree centrality is normalized 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. Degree centrality measures the number of links incident upon a vertex.

    INPUT:

    - `v` - a vertex label (to find degree centrality of only one vertex)

    EXAMPLES:

        sage: (graphs.ChvatalGraph()).centrality_degree()
        {0: 0.36363636363636365, 1: 0.36363636363636365, 2: 0.36363636363636365, 3: 0.36363636363636365, 4: 0.36363636363636365, 5: 0.36363636363636365, 6: 0.36363636363636365, 7: 0.36363636363636365, 8: 0.36363636363636365, 9: 0.36363636363636365, 10: 0.36363636363636365, 11: 0.36363636363636365}
        sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: D.show(figsize=[2,2])
        sage: D = D.to_undirected()
        sage: D.show(figsize=[2,2])
        sage: D.centrality_degree()
        {0: 1.0, 1: 1.0, 2: 0.6666666666666666, 3: 0.6666666666666666}
        sage: D.centrality_degree(v=1)
        1.0

  `chromatic_number`(algorithm='DLX', verbose=0)

    Returns the minimal number of colors needed to color the vertices of the graph \(G\).

    INPUT:

    - `algorithm` – Select an algorithm from the following supported algorithms:
      - If `algorithm="DLX"` (default), the chromatic number is computed using the dancing link algorithm. It is inefficient speedwise to compute the chromatic number through the dancing link algorithm because this algorithm computes all the possible colorings to check that one exists.
      - If `algorithm="CP"`, the chromatic number is computed using the coefficients of the chromatic polynomial. Again, this method is inefficient in terms of speed and it only useful for small graphs.
      - If `algorithm="MILP"`, the chromatic number is computed using a mixed integer linear program. The performance of this implementation is affected by whether optional MILP solvers have been installed (see the `MILP module`, or Sage’s tutorial on Linear Programming).
    - `verbose` – integer (default: `0`). Sets the level of verbosity for the MILP algorithm. Its default value is 0, which means quiet.

    See also

    For more functions related to graph coloring, see the module `sage.graphs.graph_coloring`.

    EXAMPLES:

        sage: G = Graph({0: [1, 2, 3], 1: [2]})
        sage: G.chromatic_number(algorithm="DLX")
        3
        sage: G.chromatic_number(algorithm="MILP")
        3
        sage: G.chromatic_number(algorithm="CP")
        3

    A bipartite graph has (by definition) chromatic number 2:

        sage: graphs.RandomBipartite(50,50,0.7).chromatic_number()
        2

    A complete multipartite graph with k parts has chromatic number k:

        sage: all(graphs.CompleteMultipartiteGraph([5]*i).chromatic_number() == i for i in xrange(2,5))
        True

    The complete graph has the largest chromatic number from all the graphs of order n. Namely its chromatic number is n:

        sage: all(graphs.CompleteGraph(i).chromatic_number() == i for i in xrange(10))
        True

    The Kneser graph with parameters (n,2) for n > 3 has chromatic number n-2:

        sage: all(graphs.KneserGraph(i,2).chromatic_number() == i-2 for i in xrange(4,6))
        True

    A snark has chromatic index 4 hence its line graph has chromatic number 4:

        sage: graphs.FlowerSnark().line_graph().chromatic_number()
        4

    TESTS:

        sage: G = Graph({0: [1, 2, 3], 1: [2]})
        sage: G.chromatic_number(algorithm="foo")
        Traceback (most recent call last):
        ...
        ValueError: The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'.

  `chromatic_polynomial`(G, return_tree_basis=False)

    Computes the chromatic polynomial of the graph G.

    The algorithm used is a recursive one, based on the following observations of Read:

    > - The chromatic polynomial of a tree on n vertices is x(x-1)^(n-1).
    > - If e is an edge of G, G’ is the result of deleting the edge e, and G’’ is the result of contracting e, then the chromatic polynomial of G is equal to that of G’ minus that of G’‘.

    EXAMPLES:

        sage: graphs.CycleGraph(4).chromatic_polynomial()
        x^4 - 4*x^3 + 6*x^2 - 3*x
        sage: graphs.CycleGraph(3).chromatic_polynomial()
        x^3 - 3*x^2 + 2*x
        sage: graphs.CubeGraph(3).chromatic_polynomial()
        x^8 - 12*x^7 + 66*x^6 - 214*x^5 + 441*x^4 - 572*x^3 + 423*x^2 - 133*x
        sage: graphs.PetersenGraph().chromatic_polynomial()
        x^10 - 15*x^9 + 105*x^8 - 455*x^7 + 1353*x^6 - 2861*x^5 + 4275*x^4 - 4305*x^3 + 2606*x^2 - 704*x
        sage: graphs.CompleteBipartiteGraph(3,3).chromatic_polynomial()
        x^6 - 9*x^5 + 36*x^4 - 75*x^3 + 78*x^2 - 31*x
        sage: for i in range(2,7):
        ...     graphs.CompleteGraph(i).chromatic_polynomial().factor()
        (x - 1) * x
        (x - 2) * (x - 1) * x
        (x - 3) * (x - 2) * (x - 1) * x
        (x - 4) * (x - 3) * (x - 2) * (x - 1) * x
        (x - 5) * (x - 4) * (x - 3) * (x - 2) * (x - 1) * x
        sage: graphs.CycleGraph(5).chromatic_polynomial().factor()
        (x - 2) * (x - 1) * x * (x^2 - 2*x + 2)
        sage: graphs.OctahedralGraph().chromatic_polynomial().factor()
        (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
        sage: graphs.WheelGraph(5).chromatic_polynomial().factor()
        (x - 2) * (x - 1) * x * (x^2 - 5*x + 7)
        sage: graphs.WheelGraph(6).chromatic_polynomial().factor()
        (x - 3) * (x - 2) * (x - 1) * x * (x^2 - 4*x + 5)
        sage: C(x)=graphs.LCFGraph(24, [12,7,-7], 8).chromatic_polynomial()  # long time (6s on sage.math, 2011)
        sage: C(2)  # long time
        0

    By definition, the chromatic number of a graph G is the least integer k such that the chromatic polynomial of G is strictly positive at k:

        sage: G = graphs.PetersenGraph()
        sage: P = G.chromatic_polynomial()
        sage: min((i for i in xrange(11) if P(i) > 0)) == G.chromatic_number()
        True

        sage: G = graphs.RandomGNP(10,0.7)
        sage: P = G.chromatic_polynomial()
        sage: min((i for i in xrange(11) if P(i) > 0)) == G.chromatic_number()
        True

  `clique_complex`()

    Returns the clique complex of self. This is the largest simplicial complex on the vertices of self whose 1-skeleton is self.

    This is only makes sense for undirected simple graphs.

    EXAMPLES:

        sage: g = Graph({0:[1,2],1:[2],4:[]})
        sage: g.clique_complex()
        Simplicial complex with vertex set (0, 1, 2, 4) and facets {(4,), (0, 1, 2)}

        sage: h = Graph({0:[1,2,3,4],1:[2,3,4],2:[3]})
        sage: x = h.clique_complex()
        sage: x
        Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0, 1, 2, 3)}
        sage: i = x.graph()
        sage: i==h
        True
        sage: x==i.clique_complex()
        True

  `clique_maximum`(algorithm='Cliquer')

    Returns the vertex set of a maximal order complete subgraph.

    INPUT:

    - `algorithm` – the algorithm to be used :

      > - If `algorithm = "Cliquer"` (default) - This wraps the C program Cliquer [NisOst2003].

      > - If `algorithm = "MILP"`, the problem is solved through a Mixed Integer Linear Program.

      >   (see `MixedIntegerLinearProgram`)

      > - If `algorithm = "mcqd"` - Uses the MCQD solver (http://www.sicmm.org/~konc/maxclique/). Note that the MCQD package must be installed.

    Note

    Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph.

    ALGORITHM:

    This function is based on Cliquer [NisOst2003].

    EXAMPLES:

    Using Cliquer (default):

        sage: C=graphs.PetersenGraph()
        sage: C.clique_maximum()
        [7, 9]
        sage: C = Graph('DJ{')
        sage: C.clique_maximum()
        [1, 2, 3, 4]

    Through a Linear Program:

        sage: len(C.clique_maximum(algorithm = "MILP"))
        4

    TESTS:

    Wrong algorithm:

        sage: C.clique_maximum(algorithm = "BFS")
        Traceback (most recent call last):
        ...
        NotImplementedError: Only 'MILP', 'Cliquer' and 'mcqd' are supported.

  `clique_number`(algorithm='Cliquer', cliques=None)

    Returns the order of the largest clique of the graph (the clique number).

    Note

    Currently only implemented for undirected graphs. Use `to_undirected` to convert a digraph to an undirected graph.

    INPUT:

    - `algorithm` – the algorithm to be used :

      > - If `algorithm = "Cliquer"` - This wraps the C program Cliquer [NisOst2003].

      > - If `algorithm = "networkx"` - This function is based on NetworkX’s implementation of the Bron and Kerbosch Algorithm [BroKer1973].

      > - If `algorithm = "MILP"`, the problem is solved through a Mixed Integer Linear Program.

      >   (see `MixedIntegerLinearProgram`)

      > - If `algorithm = "mcqd"` - Uses the MCQD solver (http://www.sicmm.org/~konc/maxclique/). Note that the MCQD package must be installed.

    - `cliques` - an optional list of cliques that can be input if already computed. Ignored unless `algorithm=="networkx"`.

    ALGORITHM:

    This function is based on Cliquer [NisOst2003] and [BroKer1973].

    EXAMPLES:

        sage: C = Graph('DJ{')
        sage: C.clique_number()
        4
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.clique_number()
        3

    By definition the clique number of a complete graph is its order:

        sage: all(graphs.CompleteGraph(i).clique_number() == i for i in xrange(1,15))
        True

    A non-empty graph without edges has a clique number of 1:

        sage: all((i*graphs.CompleteGraph(1)).clique_number() == 1 for i in xrange(1,15))
        True

    A complete multipartite graph with k parts has clique number k:

        sage: all((i*graphs.CompleteMultipartiteGraph(i*[5])).clique_number() == i for i in xrange(1,6))
        True

    TESTS:

        sage: g = graphs.PetersenGraph()
        sage: g.clique_number(algorithm="MILP")
        2
        sage: for i in range(10):                                            # optional - mcqd
        ...       g = graphs.RandomGNP(15,.5)                                # optional - mcqd
        ...       if g.clique_number() != g.clique_number(algorithm="mcqd"): # optional - mcqd
        ...           print "This is dead wrong !"                           # optional - mcqd

  `clique_polynomial`(t=None)

    Returns the clique polynomial of self.

    This is the polynomial where the coefficient of \(t^n\) is the number of cliques in the graph with \(n\) vertices. The constant term of the clique polynomial is always taken to be one.

    EXAMPLES:

        sage: g = Graph()
        sage: g.clique_polynomial()
        1
        sage: g = Graph({0:[1]})
        sage: g.clique_polynomial()
        t^2 + 2*t + 1
        sage: g = graphs.CycleGraph(4)
        sage: g.clique_polynomial()
        4*t^2 + 4*t + 1

  `cliques_containing_vertex`(vertices=None, cliques=None)

    Returns the cliques containing each vertex, represented as a dictionary of lists of lists, keyed by vertex. (Returns a single list if only one input vertex).

    Note

    Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph.

    INPUT:

    - `vertices` - the vertices to inspect (default is entire graph)
    - `cliques` - list of cliques (if already computed)

    EXAMPLES:

        sage: C = Graph('DJ{')
        sage: C.cliques_containing_vertex()
        {0: [[4, 0]], 1: [[4, 1, 2, 3]], 2: [[4, 1, 2, 3]], 3: [[4, 1, 2, 3]], 4: [[4, 0], [4, 1, 2, 3]]}
        sage: E = C.cliques_maximal()
        sage: E
        [[0, 4], [1, 2, 3, 4]]
        sage: C.cliques_containing_vertex(cliques=E)
        {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], 3: [[1, 2, 3, 4]], 4: [[0, 4], [1, 2, 3, 4]]}
        sage: F = graphs.Grid2dGraph(2,3)
        sage: X = F.cliques_containing_vertex()
        sage: for v in sorted(X.iterkeys()):
        ...    print v, X[v]
        (0, 0) [[(0, 1), (0, 0)], [(1, 0), (0, 0)]]
        (0, 1) [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]]
        (0, 2) [[(0, 1), (0, 2)], [(1, 2), (0, 2)]]
        (1, 0) [[(1, 0), (0, 0)], [(1, 0), (1, 1)]]
        (1, 1) [[(0, 1), (1, 1)], [(1, 2), (1, 1)], [(1, 0), (1, 1)]]
        (1, 2) [[(1, 2), (0, 2)], [(1, 2), (1, 1)]]
        sage: F.cliques_containing_vertex(vertices=[(0, 1), (1, 2)])
        {(0, 1): [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]], (1, 2): [[(1, 2), (0, 2)], [(1, 2), (1, 1)]]}
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.cliques_containing_vertex()
        {0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], 3: [[0, 1, 3]]}

  `cliques_get_clique_bipartite`(**kwds)

    Returns a bipartite graph constructed such that maximal cliques are the right vertices and the left vertices are retained from the given graph. Right and left vertices are connected if the bottom vertex belongs to the clique represented by a top vertex.

    Note

    Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph.

    EXAMPLES:

        sage: (graphs.ChvatalGraph()).cliques_get_clique_bipartite()
        Bipartite graph on 36 vertices
        sage: ((graphs.ChvatalGraph()).cliques_get_clique_bipartite()).show(figsize=[2,2], vertex_size=20, vertex_labels=False)
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.cliques_get_clique_bipartite()
        Bipartite graph on 6 vertices
        sage: (G.cliques_get_clique_bipartite()).show(figsize=[2,2])

  `cliques_get_max_clique_graph`(name='')

    Returns a graph constructed with maximal cliques as vertices, and edges between maximal cliques with common members in the original graph.

    For more information, see the Wikipedia article Clique_graph.

    Note

    Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph.

    INPUT:

    - `name` - The name of the new graph.

    EXAMPLES:

        sage: (graphs.ChvatalGraph()).cliques_get_max_clique_graph()
        Graph on 24 vertices
        sage: ((graphs.ChvatalGraph()).cliques_get_max_clique_graph()).show(figsize=[2,2], vertex_size=20, vertex_labels=False)
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.cliques_get_max_clique_graph()
        Graph on 2 vertices
        sage: (G.cliques_get_max_clique_graph()).show(figsize=[2,2])

  `cliques_maximal`(algorithm='native')

    Returns the list of all maximal cliques, with each clique represented by a list of vertices. A clique is an induced complete subgraph, and a maximal clique is one not contained in a larger one.

    INPUT:

    - `algorithm` – can be set to `"native"` (default) to use Sage’s own implementation, or to `"NetworkX"` to use NetworkX’ implementation of the Bron and Kerbosch Algorithm [BroKer1973].

    Note

    This method sorts its output before returning it. If you prefer to save the extra time, you can call `sage.graphs.independent_sets.IndependentSets` directly.

    Note

    Sage’s implementation of the enumeration of maximal independent sets is not much faster than NetworkX’ (expect a 2x speedup), which is surprising as it is written in Cython. This being said, the algorithm from NetworkX appears to be sligthly different from this one, and that would be a good thing to explore if one wants to improve the implementation.

    ALGORITHM:

    This function is based on NetworkX’s implementation of the Bron and Kerbosch Algorithm [BroKer1973].

    REFERENCE:

    [BroKer1973] | (1, 2, 3, 4, 5) Coen Bron and Joep Kerbosch. (1973). Algorithm 457: Finding All Cliques of an Undirected Graph. Commun. ACM. v 16. n 9. pages 575-577. ACM Press. [Online] Available: http://www.ram.org/computing/rambin/rambin.html

    EXAMPLES:

        sage: graphs.ChvatalGraph().cliques_maximal()
        [[0, 1], [0, 4], [0, 6], [0, 9], [1, 2], [1, 5], [1, 7], [2, 3],
         [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10],
         [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]]
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.cliques_maximal()
        [[0, 1, 2], [0, 1, 3]]
        sage: C=graphs.PetersenGraph()
        sage: C.cliques_maximal()
        [[0, 1], [0, 4], [0, 5], [1, 2], [1, 6], [2, 3], [2, 7], [3, 4],
         [3, 8], [4, 9], [5, 7], [5, 8], [6, 8], [6, 9], [7, 9]]
        sage: C = Graph('DJ{')
        sage: C.cliques_maximal()
        [[0, 4], [1, 2, 3, 4]]

    Comparing the two implementations:

        sage: g = graphs.RandomGNP(20,.7)
        sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX")))
        sage: s2 = Set(map(Set, g.cliques_maximal(algorithm="native")))
        sage: s1 == s2
        True

  `cliques_maximum`(graph)

    Returns the vertex sets of ALL the maximum complete subgraphs.

    Returns the list of all maximum cliques, with each clique represented by a list of vertices. A clique is an induced complete subgraph, and a maximum clique is one of maximal order.

    Note

    Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph.

    ALGORITHM:

    This function is based on Cliquer [NisOst2003].

    EXAMPLES:

        sage: graphs.ChvatalGraph().cliques_maximum() # indirect doctest
        [[0, 1], [0, 4], [0, 6], [0, 9], [1, 2], [1, 5], [1, 7], [2, 3],
         [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10],
         [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]]
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.cliques_maximum()
        [[0, 1, 2], [0, 1, 3]]
        sage: C=graphs.PetersenGraph()
        sage: C.cliques_maximum()
        [[0, 1], [0, 4], [0, 5], [1, 2], [1, 6], [2, 3], [2, 7], [3, 4],
         [3, 8], [4, 9], [5, 7], [5, 8], [6, 8], [6, 9], [7, 9]]
        sage: C = Graph('DJ{')
        sage: C.cliques_maximum()
        [[1, 2, 3, 4]]

    TEST:

        sage: g = Graph()
        sage: g.cliques_maximum()
        [[]]

  `cliques_number_of`(vertices=None, cliques=None)

    Returns a dictionary of the number of maximal cliques containing each vertex, keyed by vertex. (Returns a single value if only one input vertex).

    Note

    Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph.

    INPUT:

    - `vertices` - the vertices to inspect (default is entire graph)
    - `cliques` - list of cliques (if already computed)

    EXAMPLES:

        sage: C = Graph('DJ{')
        sage: C.cliques_number_of()
        {0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
        sage: E = C.cliques_maximal()
        sage: E
        [[0, 4], [1, 2, 3, 4]]
        sage: C.cliques_number_of(cliques=E)
        {0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
        sage: F = graphs.Grid2dGraph(2,3)
        sage: X = F.cliques_number_of()
        sage: for v in sorted(X.iterkeys()):
        ...    print v, X[v]
        (0, 0) 2
        (0, 1) 3
        (0, 2) 2
        (1, 0) 2
        (1, 1) 3
        (1, 2) 2
        sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)])
        {(0, 1): 3, (1, 2): 2}
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.cliques_number_of()
        {0: 2, 1: 2, 2: 1, 3: 1}

  `cliques_vertex_clique_number`(algorithm='cliquer', vertices=None, cliques=None)

    Returns a dictionary of sizes of the largest maximal cliques containing each vertex, keyed by vertex. (Returns a single value if only one input vertex).

    Note

    Currently only implemented for undirected graphs. Use to_undirected to convert a digraph to an undirected graph.

    INPUT:

    > - `algorithm` - either `cliquer` or `networkx`

    >   - `cliquer` - This wraps the C program Cliquer [NisOst2003].

    >   - `networkx` - This function is based on NetworkX’s implementation

    >       of the Bron and Kerbosch Algorithm [BroKer1973].

    - `vertices` - the vertices to inspect (default is entire graph). Ignored unless `algorithm=='networkx'`.
    - `cliques` - list of cliques (if already computed). Ignored unless `algorithm=='networkx'`.

    EXAMPLES:

        sage: C = Graph('DJ{')
        sage: C.cliques_vertex_clique_number()
        {0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
        sage: E = C.cliques_maximal()
        sage: E
        [[0, 4], [1, 2, 3, 4]]
        sage: C.cliques_vertex_clique_number(cliques=E,algorithm="networkx")
        {0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
        sage: F = graphs.Grid2dGraph(2,3)
        sage: X = F.cliques_vertex_clique_number(algorithm="networkx")
        sage: for v in sorted(X.iterkeys()):
        ...    print v, X[v]
        (0, 0) 2
        (0, 1) 2
        (0, 2) 2
        (1, 0) 2
        (1, 1) 2
        (1, 2) 2
        sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)])
        {(0, 1): 2, (1, 2): 2}
        sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
        sage: G.show(figsize=[2,2])
        sage: G.cliques_vertex_clique_number()
        {0: 3, 1: 3, 2: 3, 3: 3}

  `coloring`(algorithm='DLX', hex_colors=False, verbose=0)

    Returns the first (optimal) proper vertex-coloring found.

    INPUT:

    - `algorithm` – Select an algorithm from the following supported algorithms:
      - If `algorithm="DLX"` (default), the coloring is computed using the dancing link algorithm.
      - If `algorithm="MILP"`, the coloring is computed using a mixed integer linear program. The performance of this implementation is affected by whether optional MILP solvers have been installed (see the `MILP module`).
    - `hex_colors` – (default: `False`) if `True`, return a dictionary which can easily be used for plotting.
    - `verbose` – integer (default: `0`). Sets the level of verbosity for the MILP algorithm. Its default value is 0, which means quiet.

    See also

    For more functions related to graph coloring, see the module `sage.graphs.graph_coloring`.

    EXAMPLES:

        sage: G = Graph("Fooba")
        sage: P = G.coloring(algorithm="MILP"); P
        [[2, 1, 3], [0, 6, 5], [4]]
        sage: P = G.coloring(algorithm="DLX"); P
        [[1, 2, 3], [0, 5, 6], [4]]
        sage: G.plot(partition=P)
        Graphics object consisting of 16 graphics primitives
        sage: H = G.coloring(hex_colors=True, algorithm="MILP")
        sage: for c in sorted(H.keys()):
        ...       print c, H[c]
        #0000ff [4]
        #00ff00 [0, 6, 5]
        #ff0000 [2, 1, 3]
        sage: H = G.coloring(hex_colors=True, algorithm="DLX")
        sage: for c in sorted(H.keys()):
        ...       print c, H[c]
        #0000ff [4]
        #00ff00 [1, 2, 3]
        #ff0000 [0, 5, 6]
        sage: G.plot(vertex_colors=H)
        Graphics object consisting of 16 graphics primitives

    TESTS:

        sage: G.coloring(algorithm="foo")
        Traceback (most recent call last):
        ...
        ValueError: The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.

  `convexity_properties`()

    Returns a `ConvexityProperties` object corresponding to `self`.

    This object contains the methods related to convexity in graphs (convex hull, hull number) and caches useful information so that it becomes comparatively cheaper to compute the convex hull of many different sets of the same graph.

    See also

    In order to know what can be done through this object, please refer to module `sage.graphs.convexity_properties`.

    Note

    If you want to compute many convex hulls, keep this object in memory ! When it is created, it builds a table of useful information to compute convex hulls. As a result

        sage: g = graphs.PetersenGraph()
        sage: g.convexity_properties().hull([1, 3])
        [1, 2, 3]
        sage: g.convexity_properties().hull([3, 7])
        [2, 3, 7]

    Is a terrible waste of computations, while

        sage: g = graphs.PetersenGraph()
        sage: CP = g.convexity_properties()
        sage: CP.hull([1, 3])
        [1, 2, 3]
        sage: CP.hull([3, 7])
        [2, 3, 7]

    Makes perfect sense.

  `cores`(k=None, with_labels=False)

    Returns the core number for each vertex in an ordered list.

    (for homomorphisms cores, see the `Graph.has_homomorphism_to()` method)

    DEFINITIONS

    - K-cores in graph theory were introduced by Seidman in 1983 and by Bollobas in 1984 as a method of (destructively) simplifying graph topology to aid in analysis and visualization. They have been more recently defined as the following by Batagelj et al:

      Given a graph `G` with vertices set `V` and edges set `E`, the `k`-core of `G` is the graph obtained from `G` by recursively removing the vertices with degree less than `k`, for as long as there are any.

      This operation can be useful to filter or to study some properties of the graphs. For instance, when you compute the 2-core of graph G, you are cutting all the vertices which are in a tree part of graph. (A tree is a graph with no loops). [WPkcore]

      [PSW1996] defines a \(k\)-core of \(G\) as the largest subgraph (it is unique) of \(G\) with minimum degree at least \(k\).

    - Core number of a vertex

      The core number of a vertex \(v\) is the largest integer \(k\) such that \(v\) belongs to the \(k\)-core of \(G\).

    - Degeneracy

      The degeneracy of a graph \(G\), usually denoted \(\delta^*(G)\), is the smallest integer \(k\) such that the graph \(G\) can be reduced to the empty graph by iteratively removing vertices of degree \(\leq k\). Equivalently, \(\delta^*(G)=k\) if \(k\) is the smallest integer such that the \(k\)-core of \(G\) is empty.

    IMPLEMENTATION

    This implementation is based on the NetworkX implementation of the algorithm described in [BZ].

    INPUT

    - `k` (integer)

      > - If `k = None` (default), returns the core number for each vertex.
      > - If `k` is an integer, returns a pair `(ordering, core)`, where `core` is the list of vertices in the \(k\)-core of `self`, and `ordering` is an elimination order for the other vertices such that each vertex is of degree strictly less than \(k\) when it is to be eliminated from the graph.

    - `with_labels` (boolean)

      > - When set to `False`, and `k = None`, the method returns a list whose \(i\) th element is the core number of the \(i\) th vertex. When set to `True`, the method returns a dictionary whose keys are vertices, and whose values are the corresponding core numbers.

      >   By default, `with_labels = False`.

    See also

    - Graph cores is also a notion related to graph homomorphisms. For this second meaning, see `Graph.has_homomorphism_to()`.

    REFERENCE:

    [WPkcore] | K-core. Wikipedia. (2007). [Online] Available: Wikipedia article K-core

    [PSW1996] | Boris Pittel, Joel Spencer and Nicholas Wormald. Sudden Emergence of a Giant k-Core in a Random Graph. (1996). J. Combinatorial Theory. Ser B 67. pages 111-151. [Online] Available: http://cs.nyu.edu/cs/faculty/spencer/papers/k-core.pdf

    [BZ] | Vladimir Batagelj and Matjaz Zaversnik. An \(O(m)\) Algorithm for Cores Decomposition of Networks. Arxiv cs/0310049v1.

    EXAMPLES:

        sage: (graphs.FruchtGraph()).cores()
        [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
        sage: (graphs.FruchtGraph()).cores(with_labels=True)
        {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3}
        sage: a=random_matrix(ZZ,20,x=2,sparse=True, density=.1)
        sage: b=Graph(20)
        sage: b.add_edges(a.nonzero_positions())
        sage: cores=b.cores(with_labels=True); cores
        {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
        sage: [v for v,c in cores.items() if c>=2] # the vertices in the 2-core
        [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

    Checking the 2-core of a random lobster is indeed the empty set:

        sage: g = graphs.RandomLobster(20,.5,.5)
        sage: ordering, core = g.cores(2)
        sage: len(core) == 0
        True

  `degree_constrained_subgraph`(bounds=None, solver=None, verbose=0)

    Returns a degree-constrained subgraph.

    Given a graph \(G\) and two functions \(f, g:V(G)\rightarrow \mathbb Z\) such that \(f \leq g\), a degree-constrained subgraph in \(G\) is a subgraph \(G' \subseteq G\) such that for any vertex \(v \in G\), \(f(v) \leq d_{G'}(v) \leq g(v)\).

    INPUT:

    - `bounds` – (default: `None`) Two possibilities:
      - A dictionary whose keys are the vertices, and values a pair of real values `(min,max)` corresponding to the values \((f(v),g(v))\).
      - A function associating to each vertex a pair of real values `(min,max)` corresponding to the values \((f(v),g(v))\).
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet.

    OUTPUT:

    - When a solution exists, this method outputs the degree-constained subgraph as a Graph object.
    - When no solution exists, returns `False`.

    Note

    - This algorithm computes the degree-constrained subgraph of minimum weight.
    - If the graph’s edges are weighted, these are taken into account.
    - This problem can be solved in polynomial time.

    EXAMPLES:

    Is there a perfect matching in an even cycle?

        sage: g = graphs.CycleGraph(6)
        sage: bounds = lambda x: [1,1]
        sage: m = g.degree_constrained_subgraph(bounds=bounds)
        sage: m.size()
        3

  `fractional_chromatic_index`(solver=None, verbose_constraints=0, verbose=0)

    Computes the fractional chromatic index of `self`

    The fractional chromatic index is a relaxed version of edge-coloring. An edge coloring of a graph being actually a covering of its edges into the smallest possible number of matchings, the fractional chromatic index of a graph \(G\) is the smallest real value \(\chi_f(G)\) such that there exists a list of matchings \(M_1, ..., M_k\) of \(G\) and coefficients \(\alpha_1, ..., \alpha_k\) with the property that each edge is covered by the matchings in the following relaxed way

    \[\forall e \in E(G), \sum_{e \in M_i} \alpha_i \geq 1\]

    For more information, see the Wikipedia article on fractional coloring.

    ALGORITHM:

    The fractional chromatic index is computed through Linear Programming through its dual. The LP solved by sage is actually:

    \[\begin{split}\mbox{Maximize : }&\sum_{e\in E(G)} r_{e}\\ \mbox{Such that : }&\\ &\forall M\text{ matching }\subseteq G, \sum_{e\in M}r_{v}\leq 1\\\end{split}\]

    INPUT:

    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.

      Note

      If you want exact results, i.e. a rational number, use `solver="PPL"`. This may be slower, though.

    - `verbose_constraints` – whether to display which constraints are being generated.

    - `verbose` – level of verbosity required from the LP solver

    Note

    This implementation can be improved by computing matchings through a LP formulation, and not using the Python implementation of Edmonds’ algorithm (which requires to copy the graph, etc). It may be more efficient to write the matching problem as a LP, as we would then just have to update the weights on the edges between each call to `solve` (and so avoiding the generation of all the constraints).

    EXAMPLE:

    The fractional chromatic index of a \(C_5\) is \(5/2\):

        sage: g = graphs.CycleGraph(5)
        sage: g.fractional_chromatic_index()
        2.5

    With PPL:

        sage: g.fractional_chromatic_index(solver="PPL")
        5/2

  `gomory_hu_tree`(method='FF')

    Returns a Gomory-Hu tree of self.

    Given a tree \(T\) with labeled edges representing capacities, it is very easy to determine the maximal flow between any pair of vertices : it is the minimal label on the edges of the unique path between them.

    Given a graph \(G\), a Gomory-Hu tree \(T\) of \(G\) is a tree with the same set of vertices, and such that the maximal flow between any two vertices is the same in \(G\) as in \(T\). See the Wikipedia article on Gomory-Hu tree. Note that, in general, a graph admits more than one Gomory-Hu tree.

    INPUT:

    - `method` – There are currently two different implementations of this method :

      > - If `method = "FF"` (default), a Python implementation of the Ford-Fulkerson algorithm is used.
      > - If `method = "LP"`, the flow problems are solved using Linear Programming.

    OUTPUT:

    A graph with labeled edges

    EXAMPLE:

    Taking the Petersen graph:

        sage: g = graphs.PetersenGraph()
        sage: t = g.gomory_hu_tree()

    Obviously, this graph is a tree:

        sage: t.is_tree()
        True

    Note that if the original graph is not connected, then the Gomory-Hu tree is in fact a forest:

        sage: (2*g).gomory_hu_tree().is_forest()
        True
        sage: (2*g).gomory_hu_tree().is_connected()
        False

    On the other hand, such a tree has lost nothing of the initial graph connectedness:

        sage: all([ t.flow(u,v) == g.flow(u,v) for u,v in Subsets( g.vertices(), 2 ) ])
        True

    Just to make sure, we can check that the same is true for two vertices in a random graph:

        sage: g = graphs.RandomGNP(20,.3)
        sage: t = g.gomory_hu_tree()
        sage: g.flow(0,1) == t.flow(0,1)
        True

    And also the min cut:

        sage: g.edge_connectivity() == min(t.edge_labels())
        True

  `graph6_string`()

    Returns the graph6 representation of the graph as an ASCII string. Only valid for simple (no loops, multiple edges) graphs on 0 to 262143 vertices.

    EXAMPLES:

        sage: G = graphs.KrackhardtKiteGraph()
        sage: G.graph6_string()
        'IvUqwK@?G'

  `has_homomorphism_to`(H, core=False, solver=None, verbose=0)

    Checks whether there is a homomorphism between two graphs.

    A homomorphism from a graph \(G\) to a graph \(H\) is a function \(\phi:V(G)\mapsto V(H)\) such that for any edge \(uv \in E(G)\) the pair \(\phi(u)\phi(v)\) is an edge of \(H\).

    Saying that a graph can be \(k\)-colored is equivalent to saying that it has a homomorphism to \(K_k\), the complete graph on \(k\) elements.

    For more information, see the Wikipedia article on graph homomorphisms.

    INPUT:

    - `H` – the graph to which `self` should be sent.
    - `core` (boolean) – whether to minimize the size of the mapping’s image (see note below). This is set to `False` by default.
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet.

    Note

    One can compute the core of a graph (with respect to homomorphism) with this method

        sage: g = graphs.CycleGraph(10)
        sage: mapping = g.has_homomorphism_to(g, core = True)
        sage: print "The size of the core is",len(set(mapping.values()))
        The size of the core is 2

    OUTPUT:

    This method returns `False` when the homomorphism does not exist, and returns the homomorphism otherwise as a dictionnary associating a vertex of \(H\) to a vertex of \(G\).

    EXAMPLE:

    Is Petersen’s graph 3-colorable:

        sage: P = graphs.PetersenGraph()
        sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False
        True

    An odd cycle admits a homomorphism to a smaller odd cycle, but not to an even cycle:

        sage: g = graphs.CycleGraph(9)
        sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False
        True
        sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False
        True
        sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False
        False

  `ihara_zeta_function_inverse`()

    Compute the inverse of the Ihara zeta function of the graph

    This is a polynomial in one variable with integer coefficients. The Ihara zeta function itself is the inverse of this polynomial.

    See Wikipedia article Ihara zeta function

    ALGORITHM:

    This is computed here using the determinant of a square matrix of size twice the number of edges, related to the adjacency matrix of the line graph, see for example Proposition 9 in [ScottStorm].

    EXAMPLES:

        sage: G = graphs.CompleteGraph(4)
        sage: factor(G.ihara_zeta_function_inverse())
        (2*t - 1) * (t + 1)^2 * (t - 1)^3 * (2*t^2 + t + 1)^3

        sage: G = graphs.CompleteGraph(5)
        sage: factor(G.ihara_zeta_function_inverse())
        (-1) * (3*t - 1) * (t + 1)^5 * (t - 1)^6 * (3*t^2 + t + 1)^4

        sage: G = graphs.PetersenGraph()
        sage: factor(G.ihara_zeta_function_inverse())
        (-1) * (2*t - 1) * (t + 1)^5 * (t - 1)^6 * (2*t^2 + 2*t + 1)^4
        * (2*t^2 - t + 1)^5

        sage: G = graphs.RandomTree(10)
        sage: G.ihara_zeta_function_inverse()
        1

    REFERENCES:

    [HST] | Matthew D. Horton, H. M. Stark, and Audrey A. Terras, What are zeta functions of graphs and what are they good for? in Quantum graphs and their applications, 173-189, Contemp. Math., Vol. 415

    [Terras] | Audrey Terras, Zeta functions of graphs: a stroll through the garden, Cambridge Studies in Advanced Mathematics, Vol. 128

    [ScottStorm] | Geoffrey Scott and Christopher Storm, The coefficients of the Ihara zeta function, Involve (http://msp.org/involve/2008/1-2/involve-v1-n2-p08-p.pdf)

  `independent_set`(algorithm='Cliquer', value_only=False, reduction_rules=True, solver=None, verbosity=0)

    Returns a maximum independent set.

    An independent set of a graph is a set of pairwise non-adjacent vertices. A maximum independent set is an independent set of maximum cardinality. It induces an empty subgraph.

    Equivalently, an independent set is defined as the complement of a vertex cover.

    For more information, see the Wikipedia article Independent_set_(graph_theory) and the Wikipedia article Vertex_cover.

    INPUT:

    - `algorithm` – the algorithm to be used

      > > - If `algorithm = "Cliquer"` (default), the problem is solved using Cliquer [NisOst2003].

      > >   (see the `Cliquer modules`)

      > > - If `algorithm = "MILP"`, the problem is solved through a Mixed Integer Linear Program.

      > >   (see `MixedIntegerLinearProgram`)

      > - If `algorithm = "mcqd"` - Uses the MCQD solver (http://www.sicmm.org/~konc/maxclique/). Note that the MCQD package must be installed.

    - `value_only` – boolean (default: `False`). If set to `True`, only the size of a maximum independent set is returned. Otherwise, a maximum independent set is returned as a list of vertices.

    - `reduction_rules` – (default: `True`) Specify if the reductions rules from kernelization must be applied as pre-processing or not. See [ACFLSS04] for more details. Note that depending on the instance, it might be faster to disable reduction rules.

    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve()` of the class `MixedIntegerLinearProgram`.

    - `verbosity` – non-negative integer (default: `0`). Set the level of verbosity you want from the linear program solver. Since the problem of computing an independent set is \(NP\)-complete, its solving may take some time depending on the graph. A value of 0 means that there will be no message printed by the solver. This option is only useful if `algorithm="MILP"`.

    Note

    While Cliquer/MCAD are usually (and by far) the most efficient implementations, the MILP formulation sometimes proves faster on very “symmetrical” graphs.

    EXAMPLES:

    Using Cliquer:

        sage: C = graphs.PetersenGraph()
        sage: C.independent_set()
        [0, 3, 6, 7]

    As a linear program:

        sage: C = graphs.PetersenGraph()
        sage: len(C.independent_set(algorithm = "MILP"))
        4

  `independent_set_of_representatives`(family, solver=None, verbose=0)

    Returns an independent set of representatives.

    Given a graph \(G\) and and a family \(F=\{F_i:i\in [1,...,k]\}\) of subsets of `g.vertices()`, an Independent Set of Representatives (ISR) is an assignation of a vertex \(v_i\in F_i\) to each set \(F_i\) such that \(v_i != v_j\) if \(i<j\) (they are representatives) and the set \(\cup_{i}v_i\) is an independent set in \(G\).

    It generalizes, for example, graph coloring and graph list coloring.

    (See [AhaBerZiv07] for more information.)

    INPUT:

    - `family` – A list of lists defining the family \(F\) (actually, a Family of subsets of `G.vertices()`).
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet.

    OUTPUT:

    - A list whose \(i^{\mbox{th}}\) element is the representative of the \(i^{\mbox{th}}\) element of the `family` list. If there is no ISR, `None` is returned.

    EXAMPLES:

    For a bipartite graph missing one edge, the solution is as expected:

        sage: g = graphs.CompleteBipartiteGraph(3,3)
        sage: g.delete_edge(1,4)
        sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]])
        [1, 4]

    The Petersen Graph is 3-colorable, which can be expressed as an independent set of representatives problem : take 3 disjoint copies of the Petersen Graph, each one representing one color. Then take as a partition of the set of vertices the family defined by the three copies of each vertex. The ISR of such a family defines a 3-coloring:

        sage: g = 3 * graphs.PetersenGraph()
        sage: n = g.order()/3
        sage: f = [[i,i+n,i+2*n] for i in xrange(n)]
        sage: isr = g.independent_set_of_representatives(f)
        sage: c = [floor(i/n) for i in isr]
        sage: color_classes = [[],[],[]]
        sage: for v,i in enumerate(c):
        ...     color_classes[i].append(v)
        sage: for classs in color_classes:
        ...     g.subgraph(classs).size() == 0
        True
        True
        True

    REFERENCE:

    [AhaBerZiv07] | R. Aharoni and E. Berger and R. Ziv Independent systems of representatives in weighted graphs Combinatorica vol 27, num 3, p253–267 2007

  `is_arc_transitive`()

    Returns true if self is an arc-transitive graph

    A graph is arc-transitive if its automorphism group acts transitively on its pairs of adjacent vertices.

    Equivalently, if there exists for any pair of edges \(uv,u'v'\in E(G)\) an automorphism \(\phi_1\) of \(G\) such that \(\phi_1(u)=u'\) and \(\phi_1(v)=v'\), as well as another automorphism \(\phi_2\) of \(G\) such that \(\phi_2(u)=v'\) and \(\phi_2(v)=u'\)

    See the wikipedia article on arc-transitive graphs for more information.

    See also

    - `is_edge_transitive()`
    - `is_half_transitive()`
    - `is_semi_symmetric()`

    EXAMPLES:

        sage: P = graphs.PetersenGraph()
        sage: P.is_arc_transitive()
        True
        sage: G = graphs.GrayGraph()
        sage: G.is_arc_transitive()
        False

  `is_bipartite`(certificate=False)

    Returns `True` if graph \(G\) is bipartite, `False` if not.

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

    INPUT:

    - `certificate` – whether to return a certificate (`False` by default). If set to `True`, the certificate returned in a proper 2-coloring when \(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(100,100,0.7).is_bipartite()
        True

    A random graph is very rarely bipartite:

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

  `is_cartesian_product`(g, certificate=False, relabeling=False)

    Tests whether the graph is a cartesian product.

    INPUT:

    - `certificate` (boolean) – if `certificate = False` (default) the method only returns `True` or `False` answers. If `certificate = True`, the `True` answers are replaced by the list of the factors of the graph.

    - `relabeling` (boolean) – if `relabeling = True` (implies `certificate = True`), the method also returns a dictionary associating to each vertex its natural coordinates as a vertex of a product graph. If \(g\) is not a cartesian product, `None` is returned instead.

      This is set to `False` by default.

    See also

    - `sage.graphs.generic_graph.GenericGraph.cartesian_product()`
    - `graph_products` – a module on graph products.

    Note

    This algorithm may run faster whenever the graph’s vertices are integers (see `relabel()`). Give it a try if it is too slow !

    EXAMPLE:

    The Petersen graph is prime:

        sage: from sage.graphs.graph_decompositions.graph_products import is_cartesian_product
        sage: g = graphs.PetersenGraph()
        sage: is_cartesian_product(g)
        False

    A 2d grid is the product of paths:

        sage: g = graphs.Grid2dGraph(5,5)
        sage: p1, p2 = is_cartesian_product(g, certificate = True)
        sage: p1.is_isomorphic(graphs.PathGraph(5))
        True
        sage: p2.is_isomorphic(graphs.PathGraph(5))
        True

    Forgetting the graph’s labels, then finding them back:

        sage: g.relabel()
        sage: g.is_cartesian_product(g, relabeling = True)
        (True, {0: (0, 0), 1: (0, 1), 2: (0, 2), 3: (0, 3),
                4: (0, 4), 5: (5, 0), 6: (5, 1), 7: (5, 2),
                8: (5, 3), 9: (5, 4), 10: (10, 0), 11: (10, 1),
                12: (10, 2), 13: (10, 3), 14: (10, 4), 15: (15, 0),
                16: (15, 1), 17: (15, 2), 18: (15, 3), 19: (15, 4),
                20: (20, 0), 21: (20, 1), 22: (20, 2), 23: (20, 3),
                24: (20, 4)})

    And of course, we find the factors back when we build a graph from a product:

        sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
        sage: g1, g2 = is_cartesian_product(g, certificate = True)
        sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
        True
        sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
        True

    TESTS:

    Wagner’s Graph (trac ticket #13599):

        sage: g = graphs.WagnerGraph()
        sage: g.is_cartesian_product()
        False

  `is_directed`()

    Since graph is undirected, returns False.

    EXAMPLES:

        sage: Graph().is_directed()
        False

  `is_distance_regular`(G, parameters=False)

    Tests if the graph is distance-regular

    A graph \(G\) is distance-regular if for any integers \(j,k\) the value of \(|\{x:d_G(x,u)=j,x\in V(G)\} \cap \{y:d_G(y,v)=j,y\in V(G)\}|\) is constant for any two vertices \(u,v\in V(G)\) at distance \(i\) from each other. In particular \(G\) is regular, of degree \(b_0\) (see below), as one can take \(u=v\).

    Equivalently a graph is distance-regular if there exist integers \(b_i,c_i\) such that for any two vertices \(u,v\) at distance \(i\) we have

    - \(b_i = |\{x:d_G(x,u)=i+1,x\in V(G)\}\cap N_G(v)\}|, \ 0\leq i\leq d-1\)
    - \(c_i = |\{x:d_G(x,u)=i-1,x\in V(G)\}\cap N_G(v)\}|, \ 1\leq i\leq d,\)

    where \(d\) is the diameter of the graph. For more information on distance-regular graphs, see its associated wikipedia page.

    INPUT:

    - `parameters` (boolean) – if set to `True`, the function returns the pair `(b,c)` of lists of integers instead of `True` (see the definition above). Set to `False` by default.

    See also

    - `is_regular()`
    - `is_strongly_regular()`

    EXAMPLES:

        sage: g = graphs.PetersenGraph()
        sage: g.is_distance_regular()
        True
        sage: g.is_distance_regular(parameters = True)
        ([3, 2, None], [None, 1, 1])

    Cube graphs, which are not strongly regular, are a bit more interesting:

        sage: graphs.CubeGraph(4).is_distance_regular()
        True
        sage: graphs.OddGraph(5).is_distance_regular()
        True

    Disconnected graph:

        sage: (2*graphs.CubeGraph(4)).is_distance_regular()
        True

    TESTS:

        sage: graphs.PathGraph(2).is_distance_regular(parameters = True)
        ([1, None], [None, 1])
        sage: graphs.Tutte12Cage().is_distance_regular(parameters=True)
        ([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3])

  `is_edge_transitive`()

    Returns true if self is an edge transitive graph.

    A graph is edge-transitive if its automorphism group acts transitively on its edge set.

    Equivalently, if there exists for any pair of edges \(uv,u'v'\in E(G)\) an automorphism \(\phi\) of \(G\) such that \(\phi(uv)=u'v'\) (note this does not necessarily mean that \(\phi(u)=u'\) and \(\phi(v)=v'\)).

    See the wikipedia article on edge-transitive graphs for more information.

    See also

    - `is_arc_transitive()`
    - `is_half_transitive()`
    - `is_semi_symmetric()`

    EXAMPLES:

        sage: P = graphs.PetersenGraph()
        sage: P.is_edge_transitive()
        True
        sage: C = graphs.CubeGraph(3)
        sage: C.is_edge_transitive()
        True
        sage: G = graphs.GrayGraph()
        sage: G.is_edge_transitive()
        True
        sage: P = graphs.PathGraph(4)
        sage: P.is_edge_transitive()
        False

  `is_even_hole_free`(certificate=False)

    Tests whether `self` contains an induced even hole.

    A Hole is a cycle of length at least 4 (included). It is said to be even (resp. odd) if its length is even (resp. odd).

    Even-hole-free graphs always contain a bisimplicial vertex, which ensures that their chromatic number is at most twice their clique number [ABCHRS08].

    INPUT:

    - `certificate` (boolean) – When `certificate = False`, this method only returns `True` or `False`. If `certificate = True`, the subgraph found is returned instead of `False`.

    EXAMPLE:

    Is the Petersen Graph even-hole-free

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

    As any chordal graph is hole-free, interval graphs behave the same way:

        sage: g = graphs.RandomIntervalGraph(20)
        sage: g.is_even_hole_free()
        True

    It is clear, though, that a random Bipartite Graph which is not a forest has an even hole:

        sage: g = graphs.RandomBipartite(10, 10, .5)
        sage: g.is_even_hole_free() and not g.is_forest()
        False

    We can check the certificate returned is indeed an even cycle:

        sage: if not g.is_forest():
        ...      cycle = g.is_even_hole_free(certificate = True)
        ...      if cycle.order() % 2 == 1:
        ...          print "Error !"
        ...      if not cycle.is_isomorphic(
        ...             graphs.CycleGraph(cycle.order())):
        ...          print "Error !"
        ...
        sage: print "Everything is Fine !"
        Everything is Fine !

    TESTS:

    Bug reported in trac ticket #9925, and fixed by trac ticket #9420:

        sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', loops=False, multiedges=False)
        sage: g.is_even_hole_free()
        False
        sage: g.is_even_hole_free(certificate = True)
        Subgraph of (): Graph on 4 vertices

    Making sure there are no other counter-examples around

        sage: t = lambda x : (Graph(x).is_forest() or
        ...         isinstance(Graph(x).is_even_hole_free(certificate = True),Graph))
        sage: all( t(graphs.RandomBipartite(10,10,.5)) for i in range(100) )
        True

    REFERENCE:

    [ABCHRS08] | L. Addario-Berry, M. Chudnovsky, F. Havet, B. Reed, P. Seymour Bisimplicial vertices in even-hole-free graphs Journal of Combinatorial Theory, Series B vol 98, n.6 pp 1119-1164, 2008

  `is_forest`(certificate=False, output='vertex')

    Tests if the graph is a forest, i.e. a disjoint union of trees.

    INPUT:

    - `certificate` (boolean) – whether to return a certificate. The method only returns boolean answers when `certificate = False` (default). When it is set to `True`, it either answers `(True, None)` when the graph is a forest and `(False, cycle)` when it contains a cycle.
    - `output` (`'vertex'` (default) or `'edge'`) – whether the certificate is given as a list of vertices or a list of edges.

    EXAMPLES:

        sage: seven_acre_wood = sum(graphs.trees(7), Graph())
        sage: seven_acre_wood.is_forest()
        True

    With certificates:

        sage: g = graphs.RandomTree(30)
        sage: g.is_forest(certificate=True)
        (True, None)
        sage: (2*g + graphs.PetersenGraph() + g).is_forest(certificate=True)
        (False, [63, 62, 61, 60, 64])

  `is_half_transitive`()

    Returns true if self is a half-transitive graph.

    A graph is is half-transitive if it is both vertex and edge transitive but not arc-transitive.

    See the wikipedia article on half-transitive graphs for more information.

    See also

    - `is_edge_transitive()`
    - `is_arc_transitive()`
    - `is_semi_symmetric()`

    EXAMPLES:

    The Petersen Graph is not half-transitive:

        sage: P = graphs.PetersenGraph()
        sage: P.is_half_transitive()
        False

    The smallest half-transitive graph is the Holt Graph:

        sage: H = graphs.HoltGraph()
        sage: H.is_half_transitive()
        True

  `is_line_graph`(g, certificate=False)

    Tests wether the graph is a line graph.

    INPUT:

    - `certificate` (boolean) – whether to return a certificate along with the boolean result. Here is what happens when `certificate = True`:
      - If the graph is not a line graph, the method returns a pair `(b, subgraph)` where `b` is `False` and `subgraph` is a subgraph isomorphic to one of the 9 forbidden induced subgraphs of a line graph.
      - If the graph is a line graph, the method returns a triple `(b,R,isom)` where `b` is `True`, `R` is a graph whose line graph is the graph given as input, and `isom` is a map associating an edge of `R` to each vertex of the graph.

    Todo

    This method sequentially tests each of the forbidden subgraphs in order to know whether the graph is a line graph, which is a very slow method. It could eventually be replaced by `root_graph()` when this method will not require an exponential time to run on general graphs anymore (see its documentation for more information on this problem)... and if it can be improved to return negative certificates !

    Note

    This method wastes a bit of time when the input graph is not connected. If you have performance in mind, it is probably better to only feed it with connected graphs only.

    See also

    - The `line_graph` module.
    - `line_graph_forbidden_subgraphs()` – the forbidden subgraphs of a line graph.
    - `line_graph()`

    EXAMPLES:

    A complete graph is always the line graph of a star:

        sage: graphs.CompleteGraph(5).is_line_graph()
        True

    The Petersen Graph not being claw-free, it is not a line graph:

    > sage: graphs.PetersenGraph().is_line_graph() False

    This is indeed the subgraph returned:

        sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)[1]
        sage: C.is_isomorphic(graphs.ClawGraph())
        True

    The house graph is a line graph:

        sage: g = graphs.HouseGraph()
        sage: g.is_line_graph()
        True

    But what is the graph whose line graph is the house ?:

        sage: is_line, R, isom = g.is_line_graph(certificate = True)
        sage: R.sparse6_string()
        ':DaHI~'
        sage: R.show()
        sage: isom
        {0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)}

    TESTS:

    Disconnected graphs:

        sage: g = 2*graphs.CycleGraph(3)
        sage: gl = g.line_graph().relabel(inplace = False)
        sage: new_g = gl.is_line_graph(certificate = True)[1]
        sage: g.line_graph().is_isomorphic(gl)
        True

  `is_long_antihole_free`(g, certificate=False)

    Tests whether the given graph contains an induced subgraph that is isomorphic to the complement of a cycle of length at least 5.

    INPUT:

    - `certificate` – boolean (default: `False`)

      Whether to return a certificate. When `certificate = True`, then the function returns

      - `(False, Antihole)` if `g` contains an induced complement of a cycle of length at least 5 returned as `Antihole`.
      - `(True, [])` if `g` does not contain an induced complement of a cycle of length at least 5. For this case it is not known how to provide a certificate.

      When `certificate = False`, the function returns just `True` or `False` accordingly.

    ALGORITHM:

    This algorithm tries to find a cycle in the graph of all induced \(\overline{P_4}\) of \(g\), where two copies \(\overline{P}\) and \(\overline{P'}\) of \(\overline{P_4}\) are adjacent if there exists a (not necessarily induced) copy of \(\overline{P_5}=u_1u_2u_3u_4u_5\) such that \(\overline{P}=u_1u_2u_3u_4\) and \(\overline{P'}=u_2u_3u_4u_5\).

    This is done through a depth-first-search. For efficiency, the auxiliary graph is constructed on-the-fly and never stored in memory.

    The run time of this algorithm is \(O(m^2)\) [NikolopoulosPalios07] ( where \(m\) is the number of edges of the graph ) .

    EXAMPLES:

    The Petersen Graph contains an antihole:

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

    The complement of a cycle is an antihole:

        sage: g = graphs.CycleGraph(6).complement()
        sage: r,a = g.is_long_antihole_free(certificate=True)
        sage: r
        False
        sage: a.complement().is_isomorphic( graphs.CycleGraph(6) )
        True

    TESTS:

    Further tests:

        sage: g = Graph({0:[6,7],1:[7,8],2:[8,9],3:[9,10],4:[10,11],5:[11,6],6:[0,5,7],7:[0,1,6],8:[1,2,9],9:[2,3,8],10:[3,4,11],11:[4,5,10]}).complement()
        sage: r,a = g.is_long_antihole_free(certificate=True)
        sage: r
        False
        sage: a.complement().is_isomorphic( graphs.CycleGraph(9) )
        True

  `is_long_hole_free`(g, certificate=False)

    Tests whether `g` contains an induced cycle of length at least 5.

    INPUT:

    - `certificate` – boolean (default: `False`)

      Whether to return a certificate. When `certificate = True`, then the function returns

      - `(True, [])` if `g` does not contain such a cycle. For this case, it is not known how to provide a certificate.
      - `(False, Hole)` if `g` contains an induced cycle of length at least 5. `Hole` returns this cycle.

      If `certificate = False`, the function returns just `True` or `False` accordingly.

    ALGORITHM:

    This algorithm tries to find a cycle in the graph of all induced \(P_4\) of \(g\), where two copies \(P\) and \(P'\) of \(P_4\) are adjacent if there exists a (not necessarily induced) copy of \(P_5=u_1u_2u_3u_4u_5\) such that \(P=u_1u_2u_3u_4\) and \(P'=u_2u_3u_4u_5\).

    This is done through a depth-first-search. For efficiency, the auxiliary graph is constructed on-the-fly and never stored in memory.

    The run time of this algorithm is \(O(m^2)\) [NikolopoulosPalios07] ( where \(m\) is the number of edges of the graph ) .

    EXAMPLES:

    The Petersen Graph contains a hole:

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

    The following graph contains a hole, which we want to display:

        sage: g = graphs.FlowerSnark()
        sage: r,h = g.is_long_hole_free(certificate=True)
        sage: r
        False
        sage: Graph(h).is_isomorphic(graphs.CycleGraph(h.order()))
        True

    TESTS:

    Another graph with vertices 2, ..., 8, 10:

        sage: g = Graph({2:[3,8],3:[2,4],4:[3,8,10],5:[6,10],6:[5,7],7:[6,8],8:[2,4,7,10],10:[4,5,8]})
        sage: r,hole = g.is_long_hole_free(certificate=True)
        sage: r
        False
        sage: hole
        Subgraph of (): Graph on 5 vertices
        sage: hole.is_isomorphic(graphs.CycleGraph(hole.order()))
        True

  `is_odd_hole_free`(certificate=False)

    Tests whether `self` contains an induced odd hole.

    A Hole is a cycle of length at least 4 (included). It is said to be even (resp. odd) if its length is even (resp. odd).

    It is interesting to notice that while it is polynomial to check whether a graph has an odd hole or an odd antihole [CRST06], it is not known whether testing for one of these two cases independently is polynomial too.

    INPUT:

    - `certificate` (boolean) – When `certificate = False`, this method only returns `True` or `False`. If `certificate = True`, the subgraph found is returned instead of `False`.

    EXAMPLE:

    Is the Petersen Graph odd-hole-free

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

    Which was to be expected, as its girth is 5

        sage: g.girth()
        5

    We can check the certificate returned is indeed a 5-cycle:

        sage: cycle = g.is_odd_hole_free(certificate = True)
        sage: cycle.is_isomorphic(graphs.CycleGraph(5))
        True

    As any chordal graph is hole-free, no interval graph has an odd hole:

        sage: g = graphs.RandomIntervalGraph(20)
        sage: g.is_odd_hole_free()
        True

    REFERENCES:

    [CRST06] | M. Chudnovsky, G. Cornuejols, X. Liu, P. Seymour, K. Vuskovic Recognizing berge graphs Combinatorica vol 25, n 2, pages 143–186 2005

  `is_overfull`()

    Tests whether the current graph is overfull.

    A graph \(G\) on \(n\) vertices and \(m\) edges is said to be overfull if:

    - \(n\) is odd
    - It satisfies \(2m > (n-1)\Delta(G)\), where \(\Delta(G)\) denotes the maximum degree among all vertices in \(G\).

    An overfull graph must have a chromatic index of \(\Delta(G)+1\).

    EXAMPLES:

    A complete graph of order \(n > 1\) is overfull if and only if \(n\) is odd:

        sage: graphs.CompleteGraph(6).is_overfull()
        False
        sage: graphs.CompleteGraph(7).is_overfull()
        True
        sage: graphs.CompleteGraph(1).is_overfull()
        False

    The claw graph is not overfull:

        sage: from sage.graphs.graph_coloring import edge_coloring
        sage: g = graphs.ClawGraph()
        sage: g
        Claw graph: Graph on 4 vertices
        sage: edge_coloring(g, value_only=True)
        3
        sage: g.is_overfull()
        False

    The Holt graph is an example of a overfull graph:

        sage: G = graphs.HoltGraph()
        sage: G.is_overfull()
        True

    Checking that all complete graphs \(K_n\) for even \(0 \leq n \leq 100\) are not overfull:

        sage: def check_overfull_Kn_even(n):
        ...       i = 0
        ...       while i <= n:
        ...           if graphs.CompleteGraph(i).is_overfull():
        ...               print "A complete graph of even order cannot be overfull."
        ...               return
        ...           i += 2
        ...       print "Complete graphs of even order up to %s are not overfull." % n
        ...
        sage: check_overfull_Kn_even(100)  # long time
        Complete graphs of even order up to 100 are not overfull.

    The null graph, i.e. the graph with no vertices, is not overfull:

        sage: Graph().is_overfull()
        False
        sage: graphs.CompleteGraph(0).is_overfull()
        False

    Checking that all complete graphs \(K_n\) for odd \(1 < n \leq 100\) are overfull:

        sage: def check_overfull_Kn_odd(n):
        ...       i = 3
        ...       while i <= n:
        ...           if not graphs.CompleteGraph(i).is_overfull():
        ...               print "A complete graph of odd order > 1 must be overfull."
        ...               return
        ...           i += 2
        ...       print "Complete graphs of odd order > 1 up to %s are overfull." % n
        ...
        sage: check_overfull_Kn_odd(100)  # long time
        Complete graphs of odd order > 1 up to 100 are overfull.

    The Petersen Graph, though, is not overfull while its chromatic index is \(\Delta+1\):

        sage: g = graphs.PetersenGraph()
        sage: g.is_overfull()
        False
        sage: from sage.graphs.graph_coloring import edge_coloring
        sage: max(g.degree()) + 1 ==  edge_coloring(g, value_only=True)
        True

  `is_perfect`(certificate=False)

    Tests whether the graph is perfect.

    A graph \(G\) is said to be perfect if \(\chi(H)=\omega(H)\) hold for any induced subgraph \(H\subseteq_i G\) (and so for \(G\) itself, too), where \(\chi(H)\) represents the chromatic number of \(H\), and \(\omega(H)\) its clique number. The Strong Perfect Graph Theorem [SPGT] gives another characterization of perfect graphs:

    A graph is perfect if and only if it contains no odd hole (cycle on an odd number \(k\) of vertices, \(k>3\)) nor any odd antihole (complement of a hole) as an induced subgraph.

    INPUT:

    - `certificate` (boolean) – whether to return a certificate (default : `False`)

    OUTPUT:

    When `certificate = False`, this function returns a boolean value. When `certificate = True`, it returns a subgraph of `self` isomorphic to an odd hole or an odd antihole if any, and `None` otherwise.

    EXAMPLE:

    A Bipartite Graph is always perfect

        sage: g = graphs.RandomBipartite(8,4,.5)
        sage: g.is_perfect()
        True

    So is the line graph of a bipartite graph:

        sage: g = graphs.RandomBipartite(4,3,0.7)
        sage: g.line_graph().is_perfect() # long time
        True

    As well as the Cartesian product of two complete graphs:

        sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3))
        sage: g.is_perfect()
        True

    Interval Graphs, which are chordal graphs, too

        sage: g =  graphs.RandomIntervalGraph(7)
        sage: g.is_perfect()
        True

    The PetersenGraph, which is triangle-free and has chromatic number 3 is obviously not perfect:

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

    We can obtain an induced 5-cycle as a certificate:

        sage: g.is_perfect(certificate = True)
        Subgraph of (Petersen graph): Graph on 5 vertices

    TEST:

    Check that trac ticket #13546 has been fixed:

        sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect()
        False
        sage: g = Graph({0: [2, 3, 4, 5],
        ...              1: [3, 4, 5, 6],
        ...              2: [0, 4, 5, 6],
        ...              3: [0, 1, 5, 6],
        ...              4: [0, 1, 2, 6],
        ...              5: [0, 1, 2, 3],
        ...              6: [1, 2, 3, 4]})
        sage: g.is_perfect()
        False

    REFERENCES:

    [SPGT] | M. Chudnovsky, N. Robertson, P. Seymour, R. Thomas. The strong perfect graph theorem Annals of Mathematics vol 164, number 1, pages 51–230 2006

    TESTS:

        sage: Graph(':Ab').is_perfect()
        Traceback (most recent call last):
        ...
        ValueError: This method is only defined for simple graphs, and yours is not one of them !
        sage: g = Graph()
        sage: g.allow_loops(True)
        sage: g.add_edge(0,0)
        sage: g.edges()
        [(0, 0, None)]
        sage: g.is_perfect()
        Traceback (most recent call last):
        ...
        ValueError: This method is only defined for simple graphs, and yours is not one of them !

  `is_prime`()

    Tests whether the current graph is prime. A graph is prime if all its modules are trivial (i.e. empty, all of the graph or singletons)– see \(self.modular_decomposition?\).

    EXAMPLE:

    The Petersen Graph and the Bull Graph are both prime

        sage: graphs.PetersenGraph().is_prime()
        True
        sage: graphs.BullGraph().is_prime()
        True

    Though quite obviously, the disjoint union of them is not:

        sage: (graphs.PetersenGraph() + graphs.BullGraph()).is_prime()
        False

  `is_semi_symmetric`()

    Returns true if self is semi-symmetric.

    A graph is semi-symmetric if it is regular, edge-transitve but not vertex-transitive.

    See the wikipedia article on semi-symmetric graphs for more information.

    See also

    - `is_edge_transitive()`
    - `is_arc_transitive()`
    - `is_half_transitive()`

    EXAMPLES:

    The Petersen graph is not semi-symmetric:

        sage: P = graphs.PetersenGraph()
        sage: P.is_semi_symmetric()
        False

    The Gray graph is the smallest possible cubic semi-symmetric graph:

        sage: G = graphs.GrayGraph()
        sage: G.is_semi_symmetric()
        True

    Another well known semi-symmetric graph is the Ljubljana graph:

        sage: L = graphs.LjubljanaGraph()
        sage: L.is_semi_symmetric()
        True

  `is_split`()

    Returns `True` if the graph is a Split graph, `False` otherwise.

    A Graph \(G\) is said to be a split graph if its vertices \(V(G)\) can be partitioned into two sets \(K\) and \(I\) such that the vertices of \(K\) induce a complete graph, and those of \(I\) are an independent set.

    There is a simple test to check whether a graph is a split graph (see, for instance, the book “Graph Classes, a survey” [GraphClasses] page 203) :

    Given the degree sequence \(d_1 \geq ... \geq d_n\) of \(G\), a graph is a split graph if and only if :

    \[\sum_{i=1}^\omega d_i = \omega (\omega - 1) + \sum_{i=\omega + 1}^nd_i\]

    where \(\omega = max \{i:d_i\geq i-1\}\).

    EXAMPLES:

    Split graphs are, in particular, chordal graphs. Hence, The Petersen graph can not be split:

        sage: graphs.PetersenGraph().is_split()
        False

    We can easily build some “random” split graph by creating a complete graph, and adding vertices only connected to some random vertices of the clique:

        sage: g = graphs.CompleteGraph(10)
        sage: sets = Subsets(Set(range(10)))
        sage: for i in range(10, 25):
        ...      g.add_edges([(i,k) for k in sets.random_element()])
        sage: g.is_split()
        True

    Another caracterisation of split graph states that a graph is a split graph if and only if does not contain the 4-cycle, 5-cycle or 2K_2 as an induced subgraph. Hence for the above graph we have:

        sage: sum([g.subgraph_search_count(H,induced=True) for H in [graphs.CycleGraph(4),graphs.CycleGraph(5), 2*graphs.CompleteGraph(2)]])
        0

    REFERENCES:

    [GraphClasses] | A. Brandstadt, VB Le and JP Spinrad Graph classes: a survey SIAM Monographs on Discrete Mathematics and Applications}, 1999

  `is_strongly_regular`(g, parameters=False)

    Tests whether `self` is strongly regular.

    A simple graph \(G\) is said to be strongly regular with parameters \((n, k, \lambda, \mu)\) if and only if:

    > - \(G\) has \(n\) vertices.
    > - \(G\) is \(k\)-regular.
    > - Any two adjacent vertices of \(G\) have \(\lambda\) common neighbors.
    > - Any two non-adjacent vertices of \(G\) have \(\mu\) common neighbors.

    By convention, the complete graphs, the graphs with no edges and the empty graph are not strongly regular.

    See Wikipedia article Strongly regular graph

    INPUT:

    - `parameters` (boolean) – whether to return the quadruple \((n, k,\lambda,\mu)\). If `parameters = False` (default), this method only returns `True` and `False` answers. If `parameters=True`, the `True` answers are replaced by quadruples \((n, k,\lambda,\mu)\). See definition above.

    EXAMPLES:

    Petersen’s graph is strongly regular:

        sage: g = graphs.PetersenGraph()
        sage: g.is_strongly_regular()
        True
        sage: g.is_strongly_regular(parameters = True)
        (10, 3, 0, 1)

    And Clebsch’s graph is too:

        sage: g = graphs.ClebschGraph()
        sage: g.is_strongly_regular()
        True
        sage: g.is_strongly_regular(parameters = True)
        (16, 5, 0, 2)

    But Chvatal’s graph is not:

        sage: g = graphs.ChvatalGraph()
        sage: g.is_strongly_regular()
        False

    Complete graphs are not strongly regular. (trac ticket #14297)

        sage: g = graphs.CompleteGraph(5)
        sage: g.is_strongly_regular()
        False

    Completements of complete graphs are not strongly regular:

        sage: g = graphs.CompleteGraph(5).complement()
        sage: g.is_strongly_regular()
        False

    The empty graph is not strongly regular:

        sage: g = graphs.EmptyGraph()
        sage: g.is_strongly_regular()
        False

    If the input graph has loops or multiedges an exception is raised:

        sage: Graph([(1,1),(2,2)]).is_strongly_regular()
        Traceback (most recent call last):
        ...
        ValueError: This method is not known to work on graphs with
        loops. Perhaps this method can be updated to handle them, but in the
        meantime if you want to use it please disallow loops using
        allow_loops().
        sage: Graph([(1,2),(1,2)]).is_strongly_regular()
        Traceback (most recent call last):
        ...
        ValueError: This method is not known to work on graphs with
        multiedges. Perhaps this method can be updated to handle them, but in
        the meantime if you want to use it please disallow multiedges using
        allow_multiple_edges().

  `is_tree`(certificate=False, output='vertex')

    Tests if the graph is a tree

    INPUT:

    - `certificate` (boolean) – whether to return a certificate. The method only returns boolean answers when `certificate = False` (default). When it is set to `True`, it either answers `(True, None)` when the graph is a tree and `(False, cycle)` when it contains a cycle. It returns `(False, None)` when the graph is not connected.
    - `output` (`'vertex'` (default) or `'edge'`) – whether the certificate is given as a list of vertices or a list of edges.

    When the certificate cycle is given as a list of edges, the edges are given as \((v_i, v_{i+1}, l)\) where \(v_1, v_2, \dots, v_n\) are the vertices of the cycles (in their cyclic order).

    EXAMPLES:

        sage: all(T.is_tree() for T in graphs.trees(15))
        True

    The empty graph is not considered to be a tree:

        sage: graphs.EmptyGraph().is_tree()
        False

    With certificates:

        sage: g = graphs.RandomTree(30)
        sage: g.is_tree(certificate=True)
        (True, None)
        sage: g.add_edge(10,-1)
        sage: g.add_edge(11,-1)
        sage: isit, cycle = g.is_tree(certificate=True)
        sage: isit
        False
        sage: -1 in cycle
        True

    One can also ask for the certificate as a list of edges:

        sage: g = graphs.CycleGraph(4)
        sage: g.is_tree(certificate=True, output='edge')
        (False, [(3, 2, None), (2, 1, None), (1, 0, None), (0, 3, None)])

    This is useful for graphs with multiple edges:

        sage: G = Graph([(1, 2, 'a'), (1, 2, 'b')])
        sage: G.is_tree(certificate=True)
        (False, [1, 2])
        sage: G.is_tree(certificate=True, output='edge')
        (False, [(1, 2, 'a'), (2, 1, 'b')])

    TESTS:

    trac ticket #14434 is fixed:

        sage: g = Graph({0:[1,4,5],3:[4,8,9],4:[9],5:[7,8],7:[9]})
        sage: _,cycle = g.is_tree(certificate=True)
        sage: g.size()
        10
        sage: g.add_cycle(cycle)
        sage: g.size()
        10

  `is_triangle_free`(algorithm='bitset')

    Returns whether `self` is triangle-free

    INPUT:

    - `algorithm` – (default: `'bitset'`) specifies the algorithm to use among:

      > - `'matrix'` – tests if the trace of the adjacency matrix is positive.
      > - `'bitset'` – encodes adjacencies into bitsets and uses fast bitset operations to test if the input graph contains a triangle. This method is generaly faster than stantard matrix multiplication.

    EXAMPLE:

    The Petersen Graph is triangle-free:

        sage: g = graphs.PetersenGraph()
        sage: g.is_triangle_free()
        True

    or a complete Bipartite Graph:

        sage: G = graphs.CompleteBipartiteGraph(5,6)
        sage: G.is_triangle_free(algorithm='matrix')
        True
        sage: G.is_triangle_free(algorithm='bitset')
        True

    a tripartite graph, though, contains many triangles:

        sage: G = (3 * graphs.CompleteGraph(5)).complement()
        sage: G.is_triangle_free(algorithm='matrix')
        False
        sage: G.is_triangle_free(algorithm='bitset')
        False

    TESTS:

    Comparison of algorithms:

        sage: for i in xrange(10): # long test
        ...       G = graphs.RandomBarabasiAlbert(50,2)
        ...       bm = G.is_triangle_free(algorithm='matrix')
        ...       bb = G.is_triangle_free(algorithm='bitset')
        ...       if bm != bb:
        ...          print "That's not good!"

    Asking for an unknown algorithm::
      sage: g.is_triangle_free(algorithm=’tip top’) Traceback (most recent call last): ... ValueError: Algorithm ‘tip top’ not yet implemented. Please contribute.
  `is_weakly_chordal`(g, certificate=False)

    Tests whether the given graph is weakly chordal, i.e., the graph and its complement have no induced cycle of length at least 5.

    INPUT:

    - `certificate` – Boolean value (default: `False`) whether to return a certificate. If `certificate = False`, return `True` or `False` according to the graph. If `certificate = True`, return

      - `(False, forbidden_subgraph)` when the graph contains a forbidden subgraph H, this graph is returned.

      - `(True, [])` when the graph is weakly chordal.

          For this case, it is not known how to provide a certificate.

    ALGORITHM:

    This algorithm checks whether the graph `g` or its complement contain an induced cycle of length at least 5.

    Using is_long_hole_free() and is_long_antihole_free() yields a run time of \(O(m^2)\) (where \(m\) is the number of edges of the graph).

    EXAMPLES:

    The Petersen Graph is not weakly chordal and contains a hole:

        sage: g = graphs.PetersenGraph()
        sage: r,s = g.is_weakly_chordal(certificate = True)
        sage: r
        False
        sage: l = len(s.vertices())
        sage: s.is_isomorphic( graphs.CycleGraph(l) )
        True

  `join`(other, verbose_relabel=True)

    Returns the join of self and other.

    INPUT:

    - `verbose_relabel` - (defaults to True) If True, each vertex \(v\) in the first graph will be named ‘0,v’ and each vertex u in the second graph will be named‘1,u’ in the final graph. If False, the vertices of the first graph and the second graph will be relabeled with consecutive integers.

    See also

    - `union()`
    - `disjoint_union()`

    EXAMPLES:

        sage: G = graphs.CycleGraph(3)
        sage: H = Graph(2)
        sage: J = G.join(H); J
        Cycle graph join : Graph on 5 vertices
        sage: J.vertices()
        [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]
        sage: J = G.join(H, verbose_relabel=False); J
        Cycle graph join : Graph on 5 vertices
        sage: J.vertices()
        [0, 1, 2, 3, 4]
        sage: J.edges()
        [(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None), (1, 2, None), (1, 3, None), (1, 4, None), (2, 3, None), (2, 4, None)]

        sage: G = Graph(3)
        sage: G.name("Graph on 3 vertices")
        sage: H = Graph(2)
        sage: H.name("Graph on 2 vertices")
        sage: J = G.join(H); J
        Graph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices
        sage: J.vertices()
        [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1)]
        sage: J = G.join(H, verbose_relabel=False); J
        Graph on 3 vertices join Graph on 2 vertices: Graph on 5 vertices
        sage: J.edges()
        [(0, 3, None), (0, 4, None), (1, 3, None), (1, 4, None), (2, 3, None), (2, 4, None)]

  `kirchhoff_symanzik_polynomial`(name='t')

    Return the Kirchhoff-Symanzik polynomial of a graph.

    This is a polynomial in variables \(t_e\) (each of them representing an edge of the graph \(G\)) defined as a sum over all spanning trees:

    \[\Psi_G(t) = \sum_{T\subseteq V\atop{\text{a spanning tree}}} \prod_{e \not\in E(T)} t_e\]

    This is also called the first Symanzik polynomial or the Kirchhoff polynomial.

    INPUT:

    - `name`: name of the variables (default: `'t'`)

    OUTPUT:

    - a polynomial with integer coefficients

    ALGORITHM:

    > This is computed here using a determinant, as explained in Section 3.1 of [Marcolli2009].

    > As an intermediate step, one computes a cycle basis \(\mathcal C\) of \(G\) and a rectangular \(|\mathcal C| \times |E(G)|\) matrix with entries in \(\{-1,0,1\}\), which describes which edge belong to which cycle of \(\mathcal C\) and their respective orientations.

    > More precisely, after fixing an arbitrary orientation for each edge \(e\in E(G)\) and each cycle \(C\in\mathcal C\), one gets a sign for every incident pair (edge, cycle) which is \(1\) if the orientation coincide and \(-1\) otherwise.

    EXAMPLES:

    For the cycle of length 5:

        sage: G = graphs.CycleGraph(5)
        sage: G.kirchhoff_symanzik_polynomial()
        t0 + t1 + t2 + t3 + t4

    One can use another letter for variables:

        sage: G.kirchhoff_symanzik_polynomial(name='u')
        u0 + u1 + u2 + u3 + u4

    For the ‘coffee bean’ graph:

        sage: G = Graph([(0,1,'a'),(0,1,'b'),(0,1,'c')])
        sage: G.kirchhoff_symanzik_polynomial()
        t0*t1 + t0*t2 + t1*t2

    For the ‘parachute’ graph:

        sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')])
        sage: G.kirchhoff_symanzik_polynomial()
        t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3

    For the complete graph with 4 vertices:

        sage: G = graphs.CompleteGraph(4)
        sage: G.kirchhoff_symanzik_polynomial()
        t0*t1*t3 + t0*t2*t3 + t1*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4
        + t1*t3*t4 + t2*t3*t4 + t0*t1*t5 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5
        + t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5

    REFERENCES:

    [Marcolli2009] | Matilde Marcolli, Feynman Motives, Chapter 3, Feynman integrals and algebraic varieties, http://www.its.caltech.edu/~matilde/LectureN3.pdf

    [Brown2011] | Francis Brown, Multiple zeta values and periods: From moduli spaces to Feynman integrals, in Contemporary Mathematics vol 539

  `matching`(value_only=False, algorithm='Edmonds', use_edge_labels=True, solver=None, verbose=0)

    Returns a maximum weighted matching of the graph represented by the list of its edges. For more information, see the Wikipedia article on matchings.

    Given a graph \(G\) such that each edge \(e\) has a weight \(w_e\), a maximum matching is a subset \(S\) of the edges of \(G\) of maximum weight such that no two edges of \(S\) are incident with each other.

    As an optimization problem, it can be expressed as:

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

    INPUT:

    - `value_only` – boolean (default: `False`). When set to `True`, only the cardinal (or the weight) of the matching is returned.
    - `algorithm` – string (default: `"Edmonds"`)
      - `"Edmonds"` selects Edmonds’ algorithm as implemented in NetworkX
      - `"LP"` uses a Linear Program formulation of the matching problem
    - `use_edge_labels` – boolean (default: `False`)
      - When set to `True`, computes a weighted matching where each edge is weighted by its label. (If an edge has no label, \(1\) is assumed.)
      - When set to `False`, each edge has weight \(1\).
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet. Only useful when `algorithm == "LP"`.

    ALGORITHM:

    The problem is solved using Edmond’s algorithm implemented in NetworkX, or using Linear Programming depending on the value of `algorithm`.

    EXAMPLES:

    Maximum matching in a Pappus Graph:

        sage: g = graphs.PappusGraph()
        sage: g.matching(value_only=True)
        9.0

    Same test with the Linear Program formulation:

        sage: g = graphs.PappusGraph()
        sage: g.matching(algorithm="LP", value_only=True)
        9.0

    TESTS:

    If `algorithm` is set to anything different from `"Edmonds"` or `"LP"`, an exception is raised:

        sage: g = graphs.PappusGraph()
        sage: g.matching(algorithm="somethingdifferent")
        Traceback (most recent call last):
        ...
        ValueError: algorithm must be set to either "Edmonds" or "LP"

  `matching_polynomial`(G, complement=True, name=None)

    Computes the matching polynomial of the graph \(G\).

    If \(p(G, k)\) denotes the number of \(k\)-matchings (matchings with \(k\) edges) in \(G\), then the matching polynomial is defined as [Godsil93]:

    \[\mu(x)=\sum_{k \geq 0} (-1)^k p(G,k) x^{n-2k}\]

    INPUT:

    - `complement` - (default: `True`) whether to use Godsil’s duality theorem to compute the matching polynomial from that of the graphs complement (see ALGORITHM).
    - `name` - optional string for the variable name in the polynomial

    Note

    The `complement` option uses matching polynomials of complete graphs, which are cached. So if you are crazy enough to try computing the matching polynomial on a graph with millions of vertices, you might not want to use this option, since it will end up caching millions of polynomials of degree in the millions.

    ALGORITHM:

    The algorithm used is a recursive one, based on the following observation [Godsil93]:

    - If \(e\) is an edge of \(G\), \(G'\) is the result of deleting the edge \(e\), and \(G''\) is the result of deleting each vertex in \(e\), then the matching polynomial of \(G\) is equal to that of \(G'\) minus that of \(G''\).

      (the algorithm actually computes the signless matching polynomial, for which the recursion is the same when one replaces the substraction by an addition. It is then converted into the matching polynomial and returned)

    Depending on the value of `complement`, Godsil’s duality theorem [Godsil93] can also be used to compute \(\mu(x)\) :

    \[\mu(\overline{G}, x) = \sum_{k \geq 0} p(G,k) \mu( K_{n-2k}, x)\]

    Where \(\overline{G}\) is the complement of \(G\), and \(K_n\) the complete graph on \(n\) vertices.

    EXAMPLES:

        sage: g = graphs.PetersenGraph()
        sage: g.matching_polynomial()
        x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6
        sage: g.matching_polynomial(complement=False)
        x^10 - 15*x^8 + 75*x^6 - 145*x^4 + 90*x^2 - 6
        sage: g.matching_polynomial(name='tom')
        tom^10 - 15*tom^8 + 75*tom^6 - 145*tom^4 + 90*tom^2 - 6
        sage: g = Graph()
        sage: L = [graphs.RandomGNP(8, .3) for i in range(1, 6)]
        sage: prod([h.matching_polynomial() for h in L]) == sum(L, g).matching_polynomial()  # long time (up to 10s on sage.math, 2011)
        True

        sage: for i in range(1, 12):  # long time (10s on sage.math, 2011)
        ....:     for t in graphs.trees(i):
        ....:         if t.matching_polynomial() != t.characteristic_polynomial():
        ....:             raise RuntimeError('bug for a tree A of size {0}'.format(i))
        ....:         c = t.complement()
        ....:         if c.matching_polynomial(complement=False) != c.matching_polynomial():
        ....:             raise RuntimeError('bug for a tree B of size {0}'.format(i))

        sage: from sage.graphs.matchpoly import matching_polynomial
        sage: matching_polynomial(graphs.CompleteGraph(0))
        1
        sage: matching_polynomial(graphs.CompleteGraph(1))
        x
        sage: matching_polynomial(graphs.CompleteGraph(2))
        x^2 - 1
        sage: matching_polynomial(graphs.CompleteGraph(3))
        x^3 - 3*x
        sage: matching_polynomial(graphs.CompleteGraph(4))
        x^4 - 6*x^2 + 3
        sage: matching_polynomial(graphs.CompleteGraph(5))
        x^5 - 10*x^3 + 15*x
        sage: matching_polynomial(graphs.CompleteGraph(6))
        x^6 - 15*x^4 + 45*x^2 - 15
        sage: matching_polynomial(graphs.CompleteGraph(7))
        x^7 - 21*x^5 + 105*x^3 - 105*x
        sage: matching_polynomial(graphs.CompleteGraph(8))
        x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105
        sage: matching_polynomial(graphs.CompleteGraph(9))
        x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x
        sage: matching_polynomial(graphs.CompleteGraph(10))
        x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945
        sage: matching_polynomial(graphs.CompleteGraph(11))
        x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x
        sage: matching_polynomial(graphs.CompleteGraph(12))
        x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395
        sage: matching_polynomial(graphs.CompleteGraph(13))
        x^13 - 78*x^11 + 2145*x^9 - 25740*x^7 + 135135*x^5 - 270270*x^3 + 135135*x

        sage: G = Graph({0:[1,2], 1:[2]})
        sage: matching_polynomial(G)
        x^3 - 3*x
        sage: G = Graph({0:[1,2]})
        sage: matching_polynomial(G)
        x^3 - 2*x
        sage: G = Graph({0:[1], 2:[]})
        sage: matching_polynomial(G)
        x^3 - x
        sage: G = Graph({0:[], 1:[], 2:[]})
        sage: matching_polynomial(G)
        x^3

        sage: matching_polynomial(graphs.CompleteGraph(0), complement=False)
        1
        sage: matching_polynomial(graphs.CompleteGraph(1), complement=False)
        x
        sage: matching_polynomial(graphs.CompleteGraph(2), complement=False)
        x^2 - 1
        sage: matching_polynomial(graphs.CompleteGraph(3), complement=False)
        x^3 - 3*x
        sage: matching_polynomial(graphs.CompleteGraph(4), complement=False)
        x^4 - 6*x^2 + 3
        sage: matching_polynomial(graphs.CompleteGraph(5), complement=False)
        x^5 - 10*x^3 + 15*x
        sage: matching_polynomial(graphs.CompleteGraph(6), complement=False)
        x^6 - 15*x^4 + 45*x^2 - 15
        sage: matching_polynomial(graphs.CompleteGraph(7), complement=False)
        x^7 - 21*x^5 + 105*x^3 - 105*x
        sage: matching_polynomial(graphs.CompleteGraph(8), complement=False)
        x^8 - 28*x^6 + 210*x^4 - 420*x^2 + 105
        sage: matching_polynomial(graphs.CompleteGraph(9), complement=False)
        x^9 - 36*x^7 + 378*x^5 - 1260*x^3 + 945*x
        sage: matching_polynomial(graphs.CompleteGraph(10), complement=False)
        x^10 - 45*x^8 + 630*x^6 - 3150*x^4 + 4725*x^2 - 945
        sage: matching_polynomial(graphs.CompleteGraph(11), complement=False)
        x^11 - 55*x^9 + 990*x^7 - 6930*x^5 + 17325*x^3 - 10395*x
        sage: matching_polynomial(graphs.CompleteGraph(12), complement=False)
        x^12 - 66*x^10 + 1485*x^8 - 13860*x^6 + 51975*x^4 - 62370*x^2 + 10395
        sage: matching_polynomial(graphs.CompleteGraph(13), complement=False)
        x^13 - 78*x^11 + 2145*x^9 - 25740*x^7 + 135135*x^5 - 270270*x^3 + 135135*x

    TESTS:

    Non-integer labels should work, (trac ticket #15545):

        sage: G = Graph(10);
        sage: G.add_vertex((0,1))
        sage: G.add_vertex('X')
        sage: G.matching_polynomial()
        x^12

  `maximum_average_degree`(value_only=True, solver=None, verbose=0)

    Returns the Maximum Average Degree (MAD) of the current graph.

    The Maximum Average Degree (MAD) of a graph is defined as the average degree of its densest subgraph. More formally, `Mad(G) = \max_{H\subseteq G} Ad(H)`, where \(Ad(G)\) denotes the average degree of \(G\).

    This can be computed in polynomial time.

    INPUT:

    - `value_only` (boolean) – `True` by default

      > - If `value_only=True`, only the numerical value of the \(MAD\) is returned.
      > - Else, the subgraph of \(G\) realizing the \(MAD\) is returned.

    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.

    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet.

    EXAMPLES:

    In any graph, the \(Mad\) is always larger than the average degree:

        sage: g = graphs.RandomGNP(20,.3)
        sage: mad_g = g.maximum_average_degree()
        sage: g.average_degree() <= mad_g
        True

    Unlike the average degree, the \(Mad\) of the disjoint union of two graphs is the maximum of the \(Mad\) of each graphs:

        sage: h = graphs.RandomGNP(20,.3)
        sage: mad_h = h.maximum_average_degree()
        sage: (g+h).maximum_average_degree() == max(mad_g, mad_h)
        True

    The subgraph of a regular graph realizing the maximum average degree is always the whole graph

        sage: g = graphs.CompleteGraph(5)
        sage: mad_g = g.maximum_average_degree(value_only=False)
        sage: g.is_isomorphic(mad_g)
        True

    This also works for complete bipartite graphs

        sage: g = graphs.CompleteBipartiteGraph(3,4)
        sage: mad_g = g.maximum_average_degree(value_only=False)
        sage: g.is_isomorphic(mad_g)
        True

  `minimum_outdegree_orientation`(use_edge_labels=False, solver=None, verbose=0)

    Returns an orientation of `self` with the smallest possible maximum outdegree.

    Given a Graph \(G\), is is polynomial to compute an orientation \(D\) of the edges of \(G\) such that the maximum out-degree in \(D\) is minimized. This problem, though, is NP-complete in the weighted case [AMOZ06].

    INPUT:

    - `use_edge_labels` – boolean (default: `False`)
      - When set to `True`, uses edge labels as weights to compute the orientation and assumes a weight of \(1\) when there is no value available for a given edge.
      - When set to `False` (default), gives a weight of 1 to all the edges.
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet.

    EXAMPLE:

    Given a complete bipartite graph \(K_{n,m}\), the maximum out-degree of an optimal orientation is \(\left\lceil \frac {nm} {n+m}\right\rceil\):

        sage: g = graphs.CompleteBipartiteGraph(3,4)
        sage: o = g.minimum_outdegree_orientation()
        sage: max(o.out_degree()) == ceil((4*3)/(3+4))
        True

    REFERENCES:

    [AMOZ06] | Asahiro, Y. and Miyano, E. and Ono, H. and Zenmyo, K. Graph orientation algorithms to minimize the maximum outdegree Proceedings of the 12th Computing: The Australasian Theory Symposium Volume 51, page 20 Australian Computer Society, Inc. 2006

  `minor`(H, solver=None, verbose=0)

    Returns the vertices of a minor isomorphic to \(H\) in the current graph.

    We say that a graph \(G\) has a \(H\)-minor (or that it has a graph isomorphic to \(H\) as a minor), if for all \(h\in H\), there exist disjoint sets \(S_h \subseteq V(G)\) such that once the vertices of each \(S_h\) have been merged to create a new graph \(G'\), this new graph contains \(H\) as a subgraph.

    For more information, see the Wikipedia article on graph minor.

    INPUT:

    - `H` – The minor to find for in the current graph.
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet.

    OUTPUT:

    A dictionary associating to each vertex of \(H\) the set of vertices in the current graph representing it.

    ALGORITHM:

    Mixed Integer Linear Programming

    COMPLEXITY:

    Theoretically, when \(H\) is fixed, testing for the existence of a \(H\)-minor is polynomial. The known algorithms are highly exponential in \(H\), though.

    Note

    This function can be expected to be very slow, especially where the minor does not exist.

    EXAMPLES:

    Trying to find a minor isomorphic to \(K_4\) in the \(4\times 4\) grid:

        sage: g = graphs.GridGraph([4,4])
        sage: h = graphs.CompleteGraph(4)
        sage: L = g.minor(h)
        sage: gg = g.subgraph(flatten(L.values(), max_level = 1))
        sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1]
        sage: gg.is_isomorphic(h)
        True

    We can also try to prove this way that the Petersen graph is not planar, as it has a \(K_5\) minor:

        sage: g = graphs.PetersenGraph()
        sage: K5_minor = g.minor(graphs.CompleteGraph(5))                    # long time

    And even a \(K_{3,3}\) minor:

        sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3))        # long time

    (It is much faster to use the linear-time test of planarity in this situation, though.)

    As there is no cycle in a tree, looking for a \(K_3\) minor is useless. This function will raise an exception in this case:

        sage: g = graphs.RandomGNP(20,.5)
        sage: g = g.subgraph(edges = g.min_spanning_tree())
        sage: g.is_tree()
        True
        sage: L = g.minor(graphs.CompleteGraph(3))
        Traceback (most recent call last):
        ...
        ValueError: This graph has no minor isomorphic to H !

  `modular_decomposition`()

    Returns the modular decomposition of the current graph.

    Crash course on modular decomposition:

    A module \(M\) of a graph \(G\) is a proper subset of its vertices such that for all \(u \in V(G)-M, v,w\in M\) the relation \(u \sim v \Leftrightarrow u \sim w\) holds, where \(\sim\) denotes the adjacency relation in \(G\). Equivalently, \(M \subset V(G)\) is a module if all its vertices have the same adjacency relations with each vertex outside of the module (vertex by vertex).

    Hence, for a set like a module, it is very easy to encode the information of the adjacencies between the vertices inside and outside the module – we can actually add a new vertex \(v_M\) to our graph representing our module \(M\), and let \(v_M\) be adjacent to \(u\in V(G)-M\) if and only if some \(v\in M\) (and hence all the vertices contained in the module) is adjacent to \(u\). We can now independently (and recursively) study the structure of our module \(M\) and the new graph \(G-M+\{v_M\}\), without any loss of information.

    Here are two very simple modules :

    > - A connected component \(C\) (or the union of some –but not all– of them) of a disconnected graph \(G\), for instance, is a module, as no vertex of \(C\) has a neighbor outside of it.
    > - An anticomponent \(C\) (or the union of some –but not all– of them) of an non-anticonnected graph \(G\), for the same reason (it is just the complement of the previous graph !).

    These modules being of special interest, the disjoint union of graphs is called a Parallel composition, and the complement of a disjoint union is called a Parallel composition. A graph whose only modules are singletons is called Prime.

    For more information on modular decomposition, in particular for an explanation of the terms “Parallel,” “Prime” and “Serie,” see the Wikipedia article on modular decomposition.

    You may also be interested in the survey from Michel Habib and Christophe Paul entitled “A survey on Algorithmic aspects of modular decomposition” [HabPau10].

    OUTPUT:

    A pair of two values (recursively encoding the decomposition) :

    > - The type of the current module :

    >   > - `"Parallel"`
    >   > - `"Prime"`
    >   > - `"Serie"`

    > - The list of submodules (as list of pairs `(type, list)`, recursively...) or the vertex’s name if the module is a singleton.

    EXAMPLES:

    The Bull Graph is prime:

        sage: graphs.BullGraph().modular_decomposition()
        ('Prime', [3, 4, 0, 1, 2])

    The Petersen Graph too:

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

    This a clique on 5 vertices with 2 pendant edges, though, has a more interesting decomposition

        sage: g = graphs.CompleteGraph(5)
        sage: g.add_edge(0,5)
        sage: g.add_edge(0,6)
        sage: g.modular_decomposition()
        ('Serie', [0, ('Parallel', [5, ('Serie', [1, 4, 3, 2]), 6])])

    ALGORITHM:

    This function uses a C implementation of a 2-step algorithm implemented by Fabien de Montgolfier [FMDec] :

    > - Computation of a factorizing permutation [HabibViennot1999].
    > - Computation of the tree itself [CapHabMont02].

    See also

    - `is_prime()` – Tests whether a graph is prime.

    REFERENCE:

    [FMDec] | Fabien de Montgolfier http://www.liafa.jussieu.fr/~fm/algos/index.html

    [HabibViennot1999] | Michel Habib, Christiphe Paul, Laurent Viennot Partition refinement techniques: An interesting algorithmic tool kit International Journal of Foundations of Computer Science vol. 10 n2 pp.147–170, 1999

    [CapHabMont02] | C. Capelle, M. Habib et F. de Montgolfier Graph decomposition and Factorising Permutations Discrete Mathematics and Theoretical Computer Sciences, vol 5 no. 1 , 2002.

    [HabPau10] | Michel Habib and Christophe Paul A survey of the algorithmic aspects of modular decomposition Computer Science Review vol 4, number 1, pages 41–59, 2010 http://www.lirmm.fr/~paul/md-survey.pdf

  `odd_girth`()

    Returns the odd girth of self.

    The odd girth of a graph is defined as the smallest cycle of odd length.

    OUTPUT:

    The odd girth of `self`.

    EXAMPLES:

    The McGee graph has girth 7 and therefore its odd girth is 7 as well.

        sage: G = graphs.McGeeGraph()
        sage: G.odd_girth()
        7

    Any complete graph on more than 2 vertices contains a triangle and has thus odd girth 3.

        sage: G = graphs.CompleteGraph(10)
        sage: G.odd_girth()
        3

    Every bipartite graph has no odd cycles and consequently odd girth of infinity.

        sage: G = graphs.CompleteBipartiteGraph(100,100)
        sage: G.odd_girth()
        +Infinity

    See also

    - `girth()` – computes the girth of a graph.

    REFERENCES:

    The property relating the odd girth to the coefficients of the characteristic polynomial is an old result from algebraic graph theory see

    [Har62] | Harary, F (1962). The determinant of the adjacency matrix of a graph, SIAM Review 4, 202-210

    [Biggs93] | Biggs, N. L. Algebraic Graph Theory, 2nd ed. Cambridge, England: Cambridge University Press, pp. 45, 1993.

    TESTS:

        sage: graphs.CycleGraph(5).odd_girth()
        5
        sage: graphs.CycleGraph(11).odd_girth()
        11

  `random_spanning_tree`(output_as_graph=False)

    Return a random spanning tree of the graph.

    This uses the Aldous-Broder algorithm ([Broder89], [Aldous90]) to generate a random spanning tree with the uniform distribution, as follows.

    Start from any vertex. Perform a random walk by choosing at every step one neighbor uniformly at random. Every time a new vertex \(j\) is met, add the edge \((i, j)\) to the spanning tree, where \(i\) is the previous vertex in the random walk.

    INPUT:

    - `output_as_graph` – boolean (default: `False`) whether to return a list of edges or a graph.

    See also

    `spanning_trees_count()` and `spanning_trees()`

    EXAMPLES:

        sage: G = graphs.TietzeGraph()
        sage: G.random_spanning_tree(output_as_graph=True)
        Graph on 12 vertices
        sage: rg = G.random_spanning_tree(); rg # random
        [(0, 9),
        (9, 11),
        (0, 8),
        (8, 7),
        (7, 6),
        (7, 2),
        (2, 1),
        (1, 5),
        (9, 10),
        (5, 4),
        (2, 3)]
        sage: Graph(rg).is_tree()
        True

    A visual example for the grid graph:

        sage: G = graphs.Grid2dGraph(6, 6)
        sage: pos = G.get_pos()
        sage: T = G.random_spanning_tree(True)
        sage: T.set_pos(pos)
        sage: T.show(vertex_labels=False)

    TESTS:

        sage: G = Graph()
        sage: G.random_spanning_tree()
        Traceback (most recent call last):
        ...
        ValueError: works only for non-empty connected graphs

        sage: G = graphs.CompleteGraph(3).complement()
        sage: G.random_spanning_tree()
        Traceback (most recent call last):
        ...
        ValueError: works only for non-empty connected graphs

  `rank_decomposition`(G, verbose=False)

    Computes an optimal rank-decomposition of the given graph.

    This function is available as a method of the `Graph` class. See `rank_decomposition`.

    INPUT:

    - `verbose` (boolean) – whether to display progress information while computing the decomposition.

    OUTPUT:

    A pair `(rankwidth, decomposition_tree)`, where `rankwidth` is a numerical value and `decomposition_tree` is a ternary tree describing the decomposition (cf. the module’s documentation).

    EXAMPLE:

        sage: from sage.graphs.graph_decompositions.rankwidth import rank_decomposition
        sage: g = graphs.PetersenGraph()
        sage: rank_decomposition(g)
        (3, Graph on 19 vertices)

    On more than 32 vertices:

        sage: g = graphs.RandomGNP(40, .5)
        sage: rank_decomposition(g)
        Traceback (most recent call last):
        ...
        RuntimeError: the rank decomposition cannot be computed on graphs of >= 32 vertices

    The empty graph:

        sage: g = Graph()
        sage: rank_decomposition(g)
        (0, Graph on 0 vertices)

  `spanning_trees`()

    Returns a list of all spanning trees.

    If the graph is disconnected, returns the empty list.

    Uses the Read-Tarjan backtracking algorithm [RT75].

    EXAMPLES:

        sage: G = Graph([(1,2),(1,2),(1,3),(1,3),(2,3),(1,4)])
        sage: len(G.spanning_trees())
        8
        sage: G.spanning_trees_count()
        8
        sage: G = Graph([(1,2),(2,3),(3,1),(3,4),(4,5),(4,5),(4,6)])
        sage: len(G.spanning_trees())
        6
        sage: G.spanning_trees_count()
        6

    See also

    - `spanning_trees_count()` – counts the number of spanning trees.
    - `random_spanning_tree()` – returns a random spanning tree.

    REFERENCES:

    [RT75] | Read, R. C. and Tarjan, R. E. Bounds on Backtrack Algoritms for Listing Cycles, Paths, and Spanning Trees Networks, Volume 5 (1975), numer 3, pages 237-252.

  `sparse6_string`()

    Returns the sparse6 representation of the graph as an ASCII string. Only valid for undirected graphs on 0 to 262143 vertices, but loops and multiple edges are permitted.

    EXAMPLES:

        sage: G = graphs.BullGraph()
        sage: G.sparse6_string()
        ':Da@en'

        sage: G = Graph()
        sage: G.sparse6_string()
        ':?'

        sage: G = Graph(loops=True, multiedges=True,data_structure="sparse")
        sage: Graph(':?',data_structure="sparse") == G
        True

  `strong_orientation`()

    Returns a strongly connected orientation of the current graph. See also the Wikipedia article Strongly_connected_component.

    An orientation of an undirected graph is a digraph obtained by giving an unique direction to each of its edges. An orientation is said to be strong if there is a directed path between each pair of vertices.

    If the graph is 2-edge-connected, a strongly connected orientation can be found in linear time. If the given graph is not 2-connected, the orientation returned will ensure that each 2-connected component has a strongly connected orientation.

    OUTPUT:

    A digraph representing an orientation of the current graph.

    Note

    - This method assumes the graph is connected.
    - This algorithm works in O(m).

    EXAMPLE:

    For a 2-regular graph, a strong orientation gives to each vertex an out-degree equal to 1:

        sage: g = graphs.CycleGraph(5)
        sage: g.strong_orientation().out_degree()
        [1, 1, 1, 1, 1]

    The Petersen Graph is 2-edge connected. It then has a strongly connected orientation:

        sage: g = graphs.PetersenGraph()
        sage: o = g.strong_orientation()
        sage: len(o.strongly_connected_components())
        1

    The same goes for the CubeGraph in any dimension

        sage: all(len(graphs.CubeGraph(i).strong_orientation().strongly_connected_components()) == 1 for i in xrange(2,6))
        True

    A multigraph also has a strong orientation

        sage: g = Graph([(1,2),(1,2)])
        sage: g.strong_orientation()
        Multi-digraph on 2 vertices

  `to_directed`(implementation='c_graph', data_structure=None, sparse=None)

    Returns a directed version of the graph. A single edge becomes two edges, one in each direction.

    INPUT:

    > - `implementation` - string (default: ‘networkx’) the implementation goes here. Current options are only ‘networkx’ or ‘c_graph’.
    > - `data_structure` – one of `"sparse"`, `"static_sparse"`, or `"dense"`. See the documentation of `Graph` or `DiGraph`.
    > - `sparse` (boolean) – `sparse=True` is an alias for `data_structure="sparse"`, and `sparse=False` is an alias for `data_structure="dense"`.

    EXAMPLES:

        sage: graphs.PetersenGraph().to_directed()
        Petersen graph: Digraph on 10 vertices

    TESTS:

    Immutable graphs yield immutable graphs:

        sage: Graph([[1, 2]], immutable=True).to_directed()._backend
        <class 'sage.graphs.base.static_sparse_backend.StaticSparseBackend'>

  `to_partition`()

    Return the partition of connected components of `self`.

    EXAMPLES:

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

  `to_undirected`()

    Since the graph is already undirected, simply returns a copy of itself.

    EXAMPLES:

        sage: graphs.PetersenGraph().to_undirected()
        Petersen graph: Graph on 10 vertices

  `topological_minor`(H, vertices=False, paths=False, solver=None, verbose=0)

    Returns a topological \(H\)-minor from `self` if one exists.

    We say that a graph \(G\) has a topological \(H\)-minor (or that it has a graph isomorphic to \(H\) as a topological minor), if \(G\) contains a subdivision of a graph isomorphic to \(H\) (= obtained from \(H\) through arbitrary subdivision of its edges) as a subgraph.

    For more information, see the \(Wikipedia article on graph minor :wikipedia:`Minor_(graph_theory)\).

    INPUT:

    - `H` – The topological minor to find in the current graph.
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbose` – integer (default: `0`). Sets the level of verbosity. Set to 0 by default, which means quiet.

    OUTPUT:

    The topological \(H\)-minor found is returned as a subgraph \(M\) of `self`, such that the vertex \(v\) of \(M\) that represents a vertex \(h\in H\) has `h` as a label (see `get_vertex` and `set_vertex`), and such that every edge of \(M\) has as a label the edge of \(H\) it (partially) represents.

    If no topological minor is found, this method returns `False`.

    ALGORITHM:

    Mixed Integer Linear Programming.

    COMPLEXITY:

    Theoretically, when \(H\) is fixed, testing for the existence of a topological \(H\)-minor is polynomial. The known algorithms are highly exponential in \(H\), though.

    Note

    This function can be expected to be very slow, especially where the topological minor does not exist.

    (CPLEX seems to be much more efficient than GLPK on this kind of problem)

    EXAMPLES:

    Petersen’s graph has a topological \(K_4\)-minor:

        sage: g = graphs.PetersenGraph()
        sage: g.topological_minor(graphs.CompleteGraph(4))
        Subgraph of (Petersen graph): Graph on ...

    And a topological \(K_{3,3}\)-minor:

        sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3))
        Subgraph of (Petersen graph): Graph on ...

    And of course, a tree has no topological \(C_3\)-minor:

        sage: g = graphs.RandomGNP(15,.3)
        sage: g = g.subgraph(edges = g.min_spanning_tree())
        sage: g.topological_minor(graphs.CycleGraph(3))
        False

  `treewidth`(k=None, certificate=False)

    Computes the tree-width of \(G\) (and provides a decomposition)

    INPUT:

    - `k` (integer) – the width to be considered. When `k` is an integer, the method checks that the graph has treewidth \(\leq k\). If `k` is `None` (default), the method computes the optimal tree-width.
    - `certificate` – whether to return the tree-decomposition itself.

    OUTPUT:

    > `g.treewidth()` returns the treewidth of `g`. When `k` is
    >   specified, it returns `False` when no tree-decomposition of width \(\leq k\) exists or `True` otherwise. When `certificate=True`, the tree-decomposition is also returned.

    ALGORITHM:

    > This function virtually explores the graph of all pairs `(vertex_cut,cc)`, where `vertex_cut` is a vertex cut of the graph of cardinality \(\leq k+1\), and `connected_component` is a connected component of the graph induced by `G-vertex_cut`.

    > We deduce that the pair `(vertex_cut,cc)` is feasible with tree-width \(k\) if `cc` is empty, or if a vertex `v` from `vertex_cut` can be replaced with a vertex from `cc`, such that the pair `(vertex_cut+v,cc-v)` is feasible.

    Note

    The implementation would be much faster if `cc`, the argument of the recursive function, was a bitset. It would also be very nice to not copy the graph in order to compute connected components, for this is really a waste of time.

    See also

    `path_decomposition()` computes the pathwidth of a graph. See also the `vertex_separation` module.

    EXAMPLES:

    The PetersenGraph has treewidth 4:

        sage: graphs.PetersenGraph().treewidth()
        4
        sage: graphs.PetersenGraph().treewidth(certificate=True)
        Graph on 7 vertices

    The treewidth of a 2d grid is its smallest side:

        sage: graphs.Grid2dGraph(2,5).treewidth()
        2
        sage: graphs.Grid2dGraph(3,5).treewidth()
        3

    TESTS:

        sage: g = graphs.PathGraph(3)
        sage: g.treewidth()
        1
        sage: g = 2*graphs.PathGraph(3)
        sage: g.treewidth()
        1
        sage: g.treewidth(certificate=True)
        Graph on 6 vertices
        sage: g.treewidth(2)
        True
        sage: g.treewidth(1)
        True
        sage: Graph(1).treewidth()
        1
        sage: Graph(0).treewidth()
        0
        sage: graphs.PetersenGraph().treewidth(k=2)
        False
        sage: graphs.PetersenGraph().treewidth(k=6)
        True
        sage: graphs.PetersenGraph().treewidth(certificate=True).is_tree()
        True
        sage: graphs.PetersenGraph().treewidth(k=3,certificate=True)
        False
        sage: graphs.PetersenGraph().treewidth(k=4,certificate=True)
        Graph on 7 vertices

  `tutte_polynomial`(G, edge_selector=None, cache=None)

    Return the Tutte polynomial of the graph \(G\).

    INPUT:

    - `edge_selector` (optional; method) this argument allows the user to specify his own heuristic for selecting edges used in the deletion contraction recurrence
    - `cache` – (optional; dict) a dictionary to cache the Tutte polynomials generated in the recursive process. One will be created automatically if not provided.

    EXAMPLES:

    The Tutte polynomial of any tree of order \(n\) is \(x^{n-1}\):

        sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10))
        True

    The Tutte polynomial of the Petersen graph is:

        sage: P = graphs.PetersenGraph()
        sage: P.tutte_polynomial()
        x^9 + 6*x^8 + 21*x^7 + 56*x^6 + 12*x^5*y + y^6 + 114*x^5 + 70*x^4*y
        + 30*x^3*y^2 + 15*x^2*y^3 + 10*x*y^4 + 9*y^5 + 170*x^4 + 170*x^3*y
        + 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2
        + 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y

    The Tutte polynomial of \(G\) evaluated at (1,1) is the number of spanning trees of \(G\):

        sage: G = graphs.RandomGNP(10,0.6)
        sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count()
        True

    Given that \(T(x,y)\) is the Tutte polynomial of a graph \(G\) with \(n\) vertices and \(c\) connected components, then \((-1)^{n-c} x^k T(1-x,0)\) is the chromatic polynomial of \(G\).

        sage: G = graphs.OctahedralGraph()
        sage: T = G.tutte_polynomial()
        sage: R = PolynomialRing(ZZ, 'x')
        sage: R((-1)^5*x*T(1-x,0)).factor()
        (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
        sage: G.chromatic_polynomial().factor()
        (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)

    TESTS:

    Providing an external cache:

        sage: cache = {}
        sage: _ = graphs.RandomGNP(7,.5).tutte_polynomial(cache=cache)
        sage: len(cache) > 0
        True

  `two_factor_petersen`()

    Returns a decomposition of the graph into 2-factors.

    Petersen’s 2-factor decomposition theorem asserts that any \(2r\)-regular graph \(G\) can be decomposed into 2-factors. Equivalently, it means that the edges of any \(2r\)-regular graphs can be partitionned in \(r\) sets \(C_1,\dots,C_r\) such that for all \(i\), the set \(C_i\) is a disjoint union of cycles ( a 2-regular graph ).

    As any graph of maximal degree \(\Delta\) can be completed into a regular graph of degree \(2\lceil\frac\Delta 2\rceil\), this result also means that the edges of any graph of degree \(\Delta\) can be partitionned in \(r=2\lceil\frac\Delta 2\rceil\) sets \(C_1,\dots,C_r\) such that for all \(i\), the set \(C_i\) is a graph of maximal degree \(2\) ( a disjoint union of paths and cycles ).

    EXAMPLE:

    The Complete Graph on \(7\) vertices is a \(6\)-regular graph, so it can be edge-partitionned into \(2\)-regular graphs:

        sage: g = graphs.CompleteGraph(7)
        sage: classes = g.two_factor_petersen()
        sage: for c in classes:
        ...     gg = Graph()
        ...     gg.add_edges(c)
        ...     print max(gg.degree())<=2
        True
        True
        True
        sage: Set(set(classes[0]) | set(classes[1]) | set(classes[2])).cardinality() == g.size()
        True

        sage: g = graphs.CirculantGraph(24, [7, 11])
        sage: cl = g.two_factor_petersen()
        sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]})
        Graphics object consisting of 73 graphics primitives

  `vertex_cover`(algorithm='Cliquer', value_only=False, reduction_rules=True, solver=None, verbosity=0)

    Returns a minimum vertex cover of self represented by a set of vertices.

    A minimum vertex cover of a graph is a set \(S\) of vertices such that each edge is incident to at least one element of \(S\), and such that \(S\) is of minimum cardinality. For more information, see the Wikipedia article on vertex cover.

    Equivalently, a vertex cover is defined as the complement of an independent set.

    As an optimization problem, it can be expressed as follows:

    \[\begin{split}\mbox{Minimize : }&\sum_{v\in G} b_v\\ \mbox{Such that : }&\forall (u,v) \in G.edges(), b_u+b_v\geq 1\\ &\forall x\in G, b_x\mbox{ is a binary variable}\end{split}\]

    INPUT:

    - `algorithm` – string (default: `"Cliquer"`). Indicating which algorithm to use. It can be one of those two values.
      - `"Cliquer"` will compute a minimum vertex cover using the Cliquer package.
      - `"MILP"` will compute a minimum vertex cover through a mixed integer linear program.
      - If `algorithm = "mcqd"` - Uses the MCQD solver (http://www.sicmm.org/~konc/maxclique/). Note that the MCQD package must be installed.
    - `value_only` – boolean (default: `False`). If set to `True`, only the size of a minimum vertex cover is returned. Otherwise, a minimum vertex cover is returned as a list of vertices.
    - `reduction_rules` – (default: `True`) Specify if the reductions rules from kernelization must be applied as pre-processing or not. See [ACFLSS04] for more details. Note that depending on the instance, it might be faster to disable reduction rules.
    - `solver` – (default: `None`) Specify a Linear Program (LP) solver to be used. If set to `None`, the default one is used. For more information on LP solvers and which default solver is used, see the method `solve` of the class `MixedIntegerLinearProgram`.
    - `verbosity` – non-negative integer (default: `0`). Set the level of verbosity you want from the linear program solver. Since the problem of computing a vertex cover is \(NP\)-complete, its solving may take some time depending on the graph. A value of 0 means that there will be no message printed by the solver. This option is only useful if `algorithm="MILP"`.

    EXAMPLES:

    On the Pappus graph:

        sage: g = graphs.PappusGraph()
        sage: g.vertex_cover(value_only=True)
        9

    TESTS:

    The two algorithms should return the same result:

        sage: g = graphs.RandomGNP(10,.5)
        sage: vc1 = g.vertex_cover(algorithm="MILP")
        sage: vc2 = g.vertex_cover(algorithm="Cliquer")
        sage: len(vc1) == len(vc2)
        True

    The cardinality of the vertex cover is unchanged when reduction rules are used. First for trees:

        sage: for i in range(20):
        ...       g = graphs.RandomTree(20)
        ...       vc1_set = g.vertex_cover()
        ...       vc1 = len(vc1_set)
        ...       vc2 = g.vertex_cover(value_only = True, reduction_rules = False)
        ...       if vc1 != vc2:
        ...           print "Error :", vc1, vc2
        ...           print "With reduction rules :", vc1
        ...           print "Without reduction rules :", vc2
        ...           break
        ...       g.delete_vertices(vc1_set)
        ...       if g.size() != 0:
        ...           print "This thing is not a vertex cover !"

    Then for random GNP graphs:

        sage: for i in range(20):
        ...       g = graphs.RandomGNP(50,4/50)
        ...       vc1_set = g.vertex_cover()
        ...       vc1 = len(vc1_set)
        ...       vc2 = g.vertex_cover(value_only = True, reduction_rules = False)
        ...       if vc1 != vc2:
        ...           print "Error :", vc1, vc2
        ...           print "With reduction rules :", vc1
        ...           print "Without reduction rules :", vc2
        ...           break
        ...       g.delete_vertices(vc1_set)
        ...       if g.size() != 0:
        ...           print "This thing is not a vertex cover !"

    Testing mcqd:

        sage: graphs.PetersenGraph().vertex_cover(algorithm="mcqd",value_only=True) # optional - mcqd
        6

    Given a wrong algorithm:

        sage: graphs.PetersenGraph().vertex_cover(algorithm = "guess")
        Traceback (most recent call last):
        ...
        ValueError: The algorithm must be "Cliquer" "MILP" or "mcqd".

    REFERENCE:

    [ACFLSS04] | (1, 2) F. N. Abu-Khzam, R. L. Collins, M. R. Fellows, M. A. Langston, W. H. Suters, and C. T. Symons: Kernelization Algorithm for the Vertex Cover Problem: Theory and Experiments. SIAM ALENEX/ANALCO 2004: 62-69.

  `write_to_eps`(filename, **options)

    Writes a plot of the graph to `filename` in `eps` format.

    INPUT:

    > - `filename` – a string
    > - `**options` – same layout options as `layout()`

    EXAMPLES:

        sage: P = graphs.PetersenGraph()
        sage: P.write_to_eps(tmp_filename(ext='.eps'))

    It is relatively simple to include this file in a LaTeX document. `\usepackagegraphics` must appear in the preamble, and `\includegraphics{filename.eps}` will include the file. To compile the document to `pdf` with `pdflatex` the file needs first to be converted to `pdf`, for example with `ps2pdf filename.eps filename.pdf`.

### Navigation

- index
- modules |
- next |
- previous |
- Graph Theory »