Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/networkx/algorithms/polynomials.py: 21%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

52 statements  

1"""Provides algorithms supporting the computation of graph polynomials. 

2 

3Graph polynomials are polynomial-valued graph invariants that encode a wide 

4variety of structural information. Examples include the Tutte polynomial, 

5chromatic polynomial, characteristic polynomial, and matching polynomial. An 

6extensive treatment is provided in [1]_. 

7 

8For a simple example, the `~sympy.matrices.matrices.MatrixDeterminant.charpoly` 

9method can be used to compute the characteristic polynomial from the adjacency 

10matrix of a graph. Consider the complete graph ``K_4``: 

11 

12>>> import sympy 

13>>> x = sympy.Symbol("x") 

14>>> G = nx.complete_graph(4) 

15>>> A = nx.to_numpy_array(G, dtype=int) 

16>>> M = sympy.SparseMatrix(A) 

17>>> M.charpoly(x).as_expr() 

18x**4 - 6*x**2 - 8*x - 3 

19 

20 

21.. [1] Y. Shi, M. Dehmer, X. Li, I. Gutman, 

22 "Graph Polynomials" 

23""" 

24 

25from collections import deque 

26 

27import networkx as nx 

28from networkx.utils import not_implemented_for 

29 

30__all__ = ["tutte_polynomial", "chromatic_polynomial"] 

31 

32 

33@not_implemented_for("directed") 

34@nx._dispatchable 

35def tutte_polynomial(G): 

36 r"""Returns the Tutte polynomial of `G` 

37 

38 This function computes the Tutte polynomial via an iterative version of 

39 the deletion-contraction algorithm. 

40 

41 The Tutte polynomial `T_G(x, y)` is a fundamental graph polynomial invariant in 

42 two variables. It encodes a wide array of information related to the 

43 edge-connectivity of a graph; "Many problems about graphs can be reduced to 

44 problems of finding and evaluating the Tutte polynomial at certain values" [1]_. 

45 In fact, every deletion-contraction-expressible feature of a graph is a 

46 specialization of the Tutte polynomial [2]_ (see Notes for examples). 

47 

48 There are several equivalent definitions; here are three: 

49 

50 Def 1 (rank-nullity expansion): For `G` an undirected graph, `n(G)` the 

51 number of vertices of `G`, `E` the edge set of `G`, `V` the vertex set of 

52 `G`, and `c(A)` the number of connected components of the graph with vertex 

53 set `V` and edge set `A` [3]_: 

54 

55 .. math:: 

56 

57 T_G(x, y) = \sum_{A \in E} (x-1)^{c(A) - c(E)} (y-1)^{c(A) + |A| - n(G)} 

58 

59 Def 2 (spanning tree expansion): Let `G` be an undirected graph, `T` a spanning 

60 tree of `G`, and `E` the edge set of `G`. Let `E` have an arbitrary strict 

61 linear order `L`. Let `B_e` be the unique minimal nonempty edge cut of 

62 $E \setminus T \cup {e}$. An edge `e` is internally active with respect to 

63 `T` and `L` if `e` is the least edge in `B_e` according to the linear order 

64 `L`. The internal activity of `T` (denoted `i(T)`) is the number of edges 

65 in $E \setminus T$ that are internally active with respect to `T` and `L`. 

66 Let `P_e` be the unique path in $T \cup {e}$ whose source and target vertex 

67 are the same. An edge `e` is externally active with respect to `T` and `L` 

68 if `e` is the least edge in `P_e` according to the linear order `L`. The 

69 external activity of `T` (denoted `e(T)`) is the number of edges in 

70 $E \setminus T$ that are externally active with respect to `T` and `L`. 

71 Then [4]_ [5]_: 

72 

73 .. math:: 

74 

75 T_G(x, y) = \sum_{T \text{ a spanning tree of } G} x^{i(T)} y^{e(T)} 

76 

77 Def 3 (deletion-contraction recurrence): For `G` an undirected graph, `G-e` 

78 the graph obtained from `G` by deleting edge `e`, `G/e` the graph obtained 

79 from `G` by contracting edge `e`, `k(G)` the number of cut-edges of `G`, 

80 and `l(G)` the number of self-loops of `G`: 

81 

82 .. math:: 

83 T_G(x, y) = \begin{cases} 

84 x^{k(G)} y^{l(G)}, & \text{if all edges are cut-edges or self-loops} \\ 

85 T_{G-e}(x, y) + T_{G/e}(x, y), & \text{otherwise, for an arbitrary edge $e$ not a cut-edge or loop} 

86 \end{cases} 

87 

88 Parameters 

89 ---------- 

90 G : NetworkX graph 

91 

92 Returns 

93 ------- 

94 instance of `sympy.core.add.Add` 

95 A Sympy expression representing the Tutte polynomial for `G`. 

96 

97 Examples 

98 -------- 

99 >>> C = nx.cycle_graph(5) 

100 >>> nx.tutte_polynomial(C) 

101 x**4 + x**3 + x**2 + x + y 

102 

103 >>> D = nx.diamond_graph() 

104 >>> nx.tutte_polynomial(D) 

105 x**3 + 2*x**2 + 2*x*y + x + y**2 + y 

106 

107 Notes 

108 ----- 

109 Some specializations of the Tutte polynomial: 

110 

111 - `T_G(1, 1)` counts the number of spanning trees of `G` 

112 - `T_G(1, 2)` counts the number of connected spanning subgraphs of `G` 

113 - `T_G(2, 1)` counts the number of spanning forests in `G` 

114 - `T_G(0, 2)` counts the number of strong orientations of `G` 

115 - `T_G(2, 0)` counts the number of acyclic orientations of `G` 

116 

117 Edge contraction is defined and deletion-contraction is introduced in [6]_. 

118 Combinatorial meaning of the coefficients is introduced in [7]_. 

119 Universality, properties, and applications are discussed in [8]_. 

120 

121 Practically, up-front computation of the Tutte polynomial may be useful when 

122 users wish to repeatedly calculate edge-connectivity-related information 

123 about one or more graphs. 

124 

125 References 

126 ---------- 

127 .. [1] M. Brandt, 

128 "The Tutte Polynomial." 

129 Talking About Combinatorial Objects Seminar, 2015 

130 https://math.berkeley.edu/~brandtm/talks/tutte.pdf 

131 .. [2] A. Björklund, T. Husfeldt, P. Kaski, M. Koivisto, 

132 "Computing the Tutte polynomial in vertex-exponential time" 

133 49th Annual IEEE Symposium on Foundations of Computer Science, 2008 

134 https://ieeexplore.ieee.org/abstract/document/4691000 

135 .. [3] Y. Shi, M. Dehmer, X. Li, I. Gutman, 

136 "Graph Polynomials," p. 14 

137 .. [4] Y. Shi, M. Dehmer, X. Li, I. Gutman, 

138 "Graph Polynomials," p. 46 

139 .. [5] A. Nešetril, J. Goodall, 

140 "Graph invariants, homomorphisms, and the Tutte polynomial" 

141 https://iuuk.mff.cuni.cz/~andrew/Tutte.pdf 

142 .. [6] D. B. West, 

143 "Introduction to Graph Theory," p. 84 

144 .. [7] G. Coutinho, 

145 "A brief introduction to the Tutte polynomial" 

146 Structural Analysis of Complex Networks, 2011 

147 https://homepages.dcc.ufmg.br/~gabriel/seminars/coutinho_tuttepolynomial_seminar.pdf 

148 .. [8] J. A. Ellis-Monaghan, C. Merino, 

149 "Graph polynomials and their applications I: The Tutte polynomial" 

150 Structural Analysis of Complex Networks, 2011 

151 https://arxiv.org/pdf/0803.3079.pdf 

152 """ 

153 import sympy 

154 

155 x = sympy.Symbol("x") 

156 y = sympy.Symbol("y") 

157 stack = deque() 

158 stack.append(nx.MultiGraph(G)) 

159 

160 polynomial = 0 

161 while stack: 

162 G = stack.pop() 

163 bridges = set(nx.bridges(G)) 

164 

165 e = None 

166 for i in G.edges: 

167 if (i[0], i[1]) not in bridges and i[0] != i[1]: 

168 e = i 

169 break 

170 if not e: 

171 loops = list(nx.selfloop_edges(G, keys=True)) 

172 polynomial += x ** len(bridges) * y ** len(loops) 

173 else: 

174 # deletion-contraction 

175 C = nx.contracted_edge(G, e, self_loops=True) 

176 C.remove_edge(e[0], e[0]) 

177 G.remove_edge(*e) 

178 stack.append(G) 

179 stack.append(C) 

180 return sympy.simplify(polynomial) 

181 

182 

183@not_implemented_for("directed") 

184@nx._dispatchable 

185def chromatic_polynomial(G): 

186 r"""Returns the chromatic polynomial of `G` 

187 

188 This function computes the chromatic polynomial via an iterative version of 

189 the deletion-contraction algorithm. 

190 

191 The chromatic polynomial `X_G(x)` is a fundamental graph polynomial 

192 invariant in one variable. Evaluating `X_G(k)` for an natural number `k` 

193 enumerates the proper k-colorings of `G`. 

194 

195 There are several equivalent definitions; here are three: 

196 

197 Def 1 (explicit formula): 

198 For `G` an undirected graph, `c(G)` the number of connected components of 

199 `G`, `E` the edge set of `G`, and `G(S)` the spanning subgraph of `G` with 

200 edge set `S` [1]_: 

201 

202 .. math:: 

203 

204 X_G(x) = \sum_{S \subseteq E} (-1)^{|S|} x^{c(G(S))} 

205 

206 

207 Def 2 (interpolating polynomial): 

208 For `G` an undirected graph, `n(G)` the number of vertices of `G`, `k_0 = 0`, 

209 and `k_i` the number of distinct ways to color the vertices of `G` with `i` 

210 unique colors (for `i` a natural number at most `n(G)`), `X_G(x)` is the 

211 unique Lagrange interpolating polynomial of degree `n(G)` through the points 

212 `(0, k_0), (1, k_1), \dots, (n(G), k_{n(G)})` [2]_. 

213 

214 

215 Def 3 (chromatic recurrence): 

216 For `G` an undirected graph, `G-e` the graph obtained from `G` by deleting 

217 edge `e`, `G/e` the graph obtained from `G` by contracting edge `e`, `n(G)` 

218 the number of vertices of `G`, and `e(G)` the number of edges of `G` [3]_: 

219 

220 .. math:: 

221 X_G(x) = \begin{cases} 

222 x^{n(G)}, & \text{if $e(G)=0$} \\ 

223 X_{G-e}(x) - X_{G/e}(x), & \text{otherwise, for an arbitrary edge $e$} 

224 \end{cases} 

225 

226 This formulation is also known as the Fundamental Reduction Theorem [4]_. 

227 

228 

229 Parameters 

230 ---------- 

231 G : NetworkX graph 

232 

233 Returns 

234 ------- 

235 instance of `sympy.core.add.Add` 

236 A Sympy expression representing the chromatic polynomial for `G`. 

237 

238 Examples 

239 -------- 

240 >>> C = nx.cycle_graph(5) 

241 >>> nx.chromatic_polynomial(C) 

242 x**5 - 5*x**4 + 10*x**3 - 10*x**2 + 4*x 

243 

244 >>> G = nx.complete_graph(4) 

245 >>> nx.chromatic_polynomial(G) 

246 x**4 - 6*x**3 + 11*x**2 - 6*x 

247 

248 Notes 

249 ----- 

250 Interpretation of the coefficients is discussed in [5]_. Several special 

251 cases are listed in [2]_. 

252 

253 The chromatic polynomial is a specialization of the Tutte polynomial; in 

254 particular, ``X_G(x) = T_G(x, 0)`` [6]_. 

255 

256 The chromatic polynomial may take negative arguments, though evaluations 

257 may not have chromatic interpretations. For instance, ``X_G(-1)`` enumerates 

258 the acyclic orientations of `G` [7]_. 

259 

260 References 

261 ---------- 

262 .. [1] D. B. West, 

263 "Introduction to Graph Theory," p. 222 

264 .. [2] E. W. Weisstein 

265 "Chromatic Polynomial" 

266 MathWorld--A Wolfram Web Resource 

267 https://mathworld.wolfram.com/ChromaticPolynomial.html 

268 .. [3] D. B. West, 

269 "Introduction to Graph Theory," p. 221 

270 .. [4] J. Zhang, J. Goodall, 

271 "An Introduction to Chromatic Polynomials" 

272 https://math.mit.edu/~apost/courses/18.204_2018/Julie_Zhang_paper.pdf 

273 .. [5] R. C. Read, 

274 "An Introduction to Chromatic Polynomials" 

275 Journal of Combinatorial Theory, 1968 

276 https://math.berkeley.edu/~mrklug/ReadChromatic.pdf 

277 .. [6] W. T. Tutte, 

278 "Graph-polynomials" 

279 Advances in Applied Mathematics, 2004 

280 https://www.sciencedirect.com/science/article/pii/S0196885803000411 

281 .. [7] R. P. Stanley, 

282 "Acyclic orientations of graphs" 

283 Discrete Mathematics, 2006 

284 https://math.mit.edu/~rstan/pubs/pubfiles/18.pdf 

285 """ 

286 import sympy 

287 

288 x = sympy.Symbol("x") 

289 stack = deque() 

290 stack.append(nx.MultiGraph(G, contraction_idx=0)) 

291 

292 polynomial = 0 

293 while stack: 

294 G = stack.pop() 

295 edges = list(G.edges) 

296 if not edges: 

297 polynomial += (-1) ** G.graph["contraction_idx"] * x ** len(G) 

298 else: 

299 e = edges[0] 

300 C = nx.contracted_edge(G, e, self_loops=True) 

301 C.graph["contraction_idx"] = G.graph["contraction_idx"] + 1 

302 C.remove_edge(e[0], e[0]) 

303 G.remove_edge(*e) 

304 stack.append(G) 

305 stack.append(C) 

306 return polynomial