Chromatic polynomial

AUTHORS:

  • Gordon Royle - original C implementation

  • Robert Miller - transplant

REFERENCE:

See [Rea1968] and the Wikipedia article Chromatic_polynomial for more details on this notion in graphs.

sage.graphs.chrompoly.chromatic_polynomial(G, return_tree_basis=False, algorithm='C', cache=None)

Compute the chromatic polynomial of the graph G.

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

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

INPUT:

  • G – a Sage graph

  • return_tree_basis – boolean (default: False); not used yet

  • algorithm – string (default: 'C'); the algorithm to use among

    • 'C', an implementation in C by Robert Miller and Gordon Royle.

    • 'Python', an implementation in Python using caching to avoid recomputing the chromatic polynomial of a graph that has already been seen. This seems faster on some dense graphs.

  • cache – dictionary (default: None); this parameter is used only for algorithm 'Python'. It is a dictionary keyed by canonical labelings of graphs and used to cache the chromatic polynomials of the graphs generated by the algorithm. In other words, it avoids computing twice the chromatic polynomial of isometric graphs. One will be created automatically if not provided.

EXAMPLES:

sage: graphs.CycleGraph(4).chromatic_polynomial()
x^4 - 4*x^3 + 6*x^2 - 3*x
sage: graphs.CycleGraph(3).chromatic_polynomial()
x^3 - 3*x^2 + 2*x
sage: graphs.CubeGraph(3).chromatic_polynomial()
x^8 - 12*x^7 + 66*x^6 - 214*x^5 + 441*x^4 - 572*x^3 + 423*x^2 - 133*x
sage: graphs.PetersenGraph().chromatic_polynomial()
x^10 - 15*x^9 + 105*x^8 - 455*x^7 + 1353*x^6 - 2861*x^5 + 4275*x^4 - 4305*x^3 + 2606*x^2 - 704*x
sage: graphs.CompleteBipartiteGraph(3,3).chromatic_polynomial()
x^6 - 9*x^5 + 36*x^4 - 75*x^3 + 78*x^2 - 31*x
sage: for i in range(2,7):
....:     graphs.CompleteGraph(i).chromatic_polynomial().factor()
(x - 1) * x
(x - 2) * (x - 1) * x
(x - 3) * (x - 2) * (x - 1) * x
(x - 4) * (x - 3) * (x - 2) * (x - 1) * x
(x - 5) * (x - 4) * (x - 3) * (x - 2) * (x - 1) * x
sage: graphs.CycleGraph(5).chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^2 - 2*x + 2)
sage: graphs.OctahedralGraph().chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
sage: graphs.WheelGraph(5).chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^2 - 5*x + 7)
sage: graphs.WheelGraph(6).chromatic_polynomial().factor()
(x - 3) * (x - 2) * (x - 1) * x * (x^2 - 4*x + 5)
sage: C(x)=graphs.LCFGraph(24, [12,7,-7], 8).chromatic_polynomial()  # long time (6s on sage.math, 2011)
sage: C(2)  # long time
0
>>> from sage.all import *
>>> graphs.CycleGraph(Integer(4)).chromatic_polynomial()
x^4 - 4*x^3 + 6*x^2 - 3*x
>>> graphs.CycleGraph(Integer(3)).chromatic_polynomial()
x^3 - 3*x^2 + 2*x
>>> graphs.CubeGraph(Integer(3)).chromatic_polynomial()
x^8 - 12*x^7 + 66*x^6 - 214*x^5 + 441*x^4 - 572*x^3 + 423*x^2 - 133*x
>>> graphs.PetersenGraph().chromatic_polynomial()
x^10 - 15*x^9 + 105*x^8 - 455*x^7 + 1353*x^6 - 2861*x^5 + 4275*x^4 - 4305*x^3 + 2606*x^2 - 704*x
>>> graphs.CompleteBipartiteGraph(Integer(3),Integer(3)).chromatic_polynomial()
x^6 - 9*x^5 + 36*x^4 - 75*x^3 + 78*x^2 - 31*x
>>> for i in range(Integer(2),Integer(7)):
...     graphs.CompleteGraph(i).chromatic_polynomial().factor()
(x - 1) * x
(x - 2) * (x - 1) * x
(x - 3) * (x - 2) * (x - 1) * x
(x - 4) * (x - 3) * (x - 2) * (x - 1) * x
(x - 5) * (x - 4) * (x - 3) * (x - 2) * (x - 1) * x
>>> graphs.CycleGraph(Integer(5)).chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^2 - 2*x + 2)
>>> graphs.OctahedralGraph().chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32)
>>> graphs.WheelGraph(Integer(5)).chromatic_polynomial().factor()
(x - 2) * (x - 1) * x * (x^2 - 5*x + 7)
>>> graphs.WheelGraph(Integer(6)).chromatic_polynomial().factor()
(x - 3) * (x - 2) * (x - 1) * x * (x^2 - 4*x + 5)
>>> __tmp__=var("x"); C = symbolic_expression(graphs.LCFGraph(Integer(24), [Integer(12),Integer(7),-Integer(7)], Integer(8)).chromatic_polynomial()  ).function(x)# long time (6s on sage.math, 2011)
>>> C(Integer(2))  # long 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 range(11) if P(i) > 0) == G.chromatic_number()
True

sage: G = graphs.RandomGNP(10,0.7)
sage: P = G.chromatic_polynomial()
sage: min(i for i in range(11) if P(i) > 0) == G.chromatic_number()
True
>>> from sage.all import *
>>> G = graphs.PetersenGraph()
>>> P = G.chromatic_polynomial()
>>> min(i for i in range(Integer(11)) if P(i) > Integer(0)) == G.chromatic_number()
True

>>> G = graphs.RandomGNP(Integer(10),RealNumber('0.7'))
>>> P = G.chromatic_polynomial()
>>> min(i for i in range(Integer(11)) if P(i) > Integer(0)) == G.chromatic_number()
True

Check that algorithms 'C' and 'Python' return the same results:

sage: G = graphs.RandomGNP(8, randint(1, 9)*0.1)
sage: c = G.chromatic_polynomial(algorithm='C')
sage: p = G.chromatic_polynomial(algorithm='Python')
sage: c == p
True
>>> from sage.all import *
>>> G = graphs.RandomGNP(Integer(8), randint(Integer(1), Integer(9))*RealNumber('0.1'))
>>> c = G.chromatic_polynomial(algorithm='C')
>>> p = G.chromatic_polynomial(algorithm='Python')
>>> c == p
True
sage.graphs.chrompoly.chromatic_polynomial_with_cache(G, cache=None)

Return the chromatic polynomial of the graph G.

The algorithm used is here is the non recursive version of a recursive algorithm 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''\).

  • If \(G\) is not connected, its the chromatic polynomial is the product of the chromatic polynomials of its connected components.

Since this method makes extensive use of canonical labelings, it is recommended to install optional package bliss.

INPUT:

  • G – a Sage graph

  • cache – dictionary (default: None); dictionary keyed by canonical labelings of graphs and used to cache the chromatic polynomials of the graphs generated by the algorithm. In other words, it avoids computing twice the chromatic polynomial of isometric graphs. One will be created automatically if not provided.

EXAMPLES:

sage: from sage.graphs.chrompoly import chromatic_polynomial_with_cache
sage: chromatic_polynomial_with_cache(graphs.CycleGraph(4))
x^4 - 4*x^3 + 6*x^2 - 3*x
sage: chromatic_polynomial_with_cache(graphs.CycleGraph(3))
x^3 - 3*x^2 + 2*x
sage: chromatic_polynomial_with_cache(graphs.CubeGraph(3))
x^8 - 12*x^7 + 66*x^6 - 214*x^5 + 441*x^4 - 572*x^3 + 423*x^2 - 133*x
sage: chromatic_polynomial_with_cache(graphs.PetersenGraph())
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: chromatic_polynomial_with_cache(graphs.CompleteBipartiteGraph(3,3))
x^6 - 9*x^5 + 36*x^4 - 75*x^3 + 78*x^2 - 31*x
>>> from sage.all import *
>>> from sage.graphs.chrompoly import chromatic_polynomial_with_cache
>>> chromatic_polynomial_with_cache(graphs.CycleGraph(Integer(4)))
x^4 - 4*x^3 + 6*x^2 - 3*x
>>> chromatic_polynomial_with_cache(graphs.CycleGraph(Integer(3)))
x^3 - 3*x^2 + 2*x
>>> chromatic_polynomial_with_cache(graphs.CubeGraph(Integer(3)))
x^8 - 12*x^7 + 66*x^6 - 214*x^5 + 441*x^4 - 572*x^3 + 423*x^2 - 133*x
>>> chromatic_polynomial_with_cache(graphs.PetersenGraph())
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
>>> chromatic_polynomial_with_cache(graphs.CompleteBipartiteGraph(Integer(3),Integer(3)))
x^6 - 9*x^5 + 36*x^4 - 75*x^3 + 78*x^2 - 31*x

If a cache is provided, it is fed:

sage: cache = {}
sage: G = graphs.CycleGraph(4)
sage: p = chromatic_polynomial_with_cache(graphs.CycleGraph(4), cache=cache)
sage: key = frozenset(G.canonical_label().edges(labels=False, sort=False))
sage: cache[key]
x^4 - 4*x^3 + 6*x^2 - 3*x
>>> from sage.all import *
>>> cache = {}
>>> G = graphs.CycleGraph(Integer(4))
>>> p = chromatic_polynomial_with_cache(graphs.CycleGraph(Integer(4)), cache=cache)
>>> key = frozenset(G.canonical_label().edges(labels=False, sort=False))
>>> cache[key]
x^4 - 4*x^3 + 6*x^2 - 3*x