Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/algorithms/bipartite/basic.py: 21%

77 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-20 07:00 +0000

1""" 

2========================== 

3Bipartite Graph Algorithms 

4========================== 

5""" 

6import networkx as nx 

7from networkx.algorithms.components import connected_components 

8from networkx.exception import AmbiguousSolution 

9 

10__all__ = [ 

11 "is_bipartite", 

12 "is_bipartite_node_set", 

13 "color", 

14 "sets", 

15 "density", 

16 "degrees", 

17] 

18 

19 

20@nx._dispatch 

21def color(G): 

22 """Returns a two-coloring of the graph. 

23 

24 Raises an exception if the graph is not bipartite. 

25 

26 Parameters 

27 ---------- 

28 G : NetworkX graph 

29 

30 Returns 

31 ------- 

32 color : dictionary 

33 A dictionary keyed by node with a 1 or 0 as data for each node color. 

34 

35 Raises 

36 ------ 

37 NetworkXError 

38 If the graph is not two-colorable. 

39 

40 Examples 

41 -------- 

42 >>> from networkx.algorithms import bipartite 

43 >>> G = nx.path_graph(4) 

44 >>> c = bipartite.color(G) 

45 >>> print(c) 

46 {0: 1, 1: 0, 2: 1, 3: 0} 

47 

48 You can use this to set a node attribute indicating the bipartite set: 

49 

50 >>> nx.set_node_attributes(G, c, "bipartite") 

51 >>> print(G.nodes[0]["bipartite"]) 

52 1 

53 >>> print(G.nodes[1]["bipartite"]) 

54 0 

55 """ 

56 if G.is_directed(): 

57 import itertools 

58 

59 def neighbors(v): 

60 return itertools.chain.from_iterable([G.predecessors(v), G.successors(v)]) 

61 

62 else: 

63 neighbors = G.neighbors 

64 

65 color = {} 

66 for n in G: # handle disconnected graphs 

67 if n in color or len(G[n]) == 0: # skip isolates 

68 continue 

69 queue = [n] 

70 color[n] = 1 # nodes seen with color (1 or 0) 

71 while queue: 

72 v = queue.pop() 

73 c = 1 - color[v] # opposite color of node v 

74 for w in neighbors(v): 

75 if w in color: 

76 if color[w] == color[v]: 

77 raise nx.NetworkXError("Graph is not bipartite.") 

78 else: 

79 color[w] = c 

80 queue.append(w) 

81 # color isolates with 0 

82 color.update(dict.fromkeys(nx.isolates(G), 0)) 

83 return color 

84 

85 

86@nx._dispatch 

87def is_bipartite(G): 

88 """Returns True if graph G is bipartite, False if not. 

89 

90 Parameters 

91 ---------- 

92 G : NetworkX graph 

93 

94 Examples 

95 -------- 

96 >>> from networkx.algorithms import bipartite 

97 >>> G = nx.path_graph(4) 

98 >>> print(bipartite.is_bipartite(G)) 

99 True 

100 

101 See Also 

102 -------- 

103 color, is_bipartite_node_set 

104 """ 

105 try: 

106 color(G) 

107 return True 

108 except nx.NetworkXError: 

109 return False 

110 

111 

112@nx._dispatch 

113def is_bipartite_node_set(G, nodes): 

114 """Returns True if nodes and G/nodes are a bipartition of G. 

115 

116 Parameters 

117 ---------- 

118 G : NetworkX graph 

119 

120 nodes: list or container 

121 Check if nodes are a one of a bipartite set. 

122 

123 Examples 

124 -------- 

125 >>> from networkx.algorithms import bipartite 

126 >>> G = nx.path_graph(4) 

127 >>> X = set([1, 3]) 

128 >>> bipartite.is_bipartite_node_set(G, X) 

129 True 

130 

131 Notes 

132 ----- 

133 An exception is raised if the input nodes are not distinct, because in this 

134 case some bipartite algorithms will yield incorrect results. 

135 For connected graphs the bipartite sets are unique. This function handles 

136 disconnected graphs. 

137 """ 

138 S = set(nodes) 

139 

140 if len(S) < len(nodes): 

141 # this should maybe just return False? 

142 raise AmbiguousSolution( 

143 "The input node set contains duplicates.\n" 

144 "This may lead to incorrect results when using it in bipartite algorithms.\n" 

145 "Consider using set(nodes) as the input" 

146 ) 

147 

148 for CC in (G.subgraph(c).copy() for c in connected_components(G)): 

149 X, Y = sets(CC) 

150 if not ( 

151 (X.issubset(S) and Y.isdisjoint(S)) or (Y.issubset(S) and X.isdisjoint(S)) 

152 ): 

153 return False 

154 return True 

155 

156 

157@nx._dispatch 

158def sets(G, top_nodes=None): 

159 """Returns bipartite node sets of graph G. 

160 

161 Raises an exception if the graph is not bipartite or if the input 

162 graph is disconnected and thus more than one valid solution exists. 

163 See :mod:`bipartite documentation <networkx.algorithms.bipartite>` 

164 for further details on how bipartite graphs are handled in NetworkX. 

165 

166 Parameters 

167 ---------- 

168 G : NetworkX graph 

169 

170 top_nodes : container, optional 

171 Container with all nodes in one bipartite node set. If not supplied 

172 it will be computed. But if more than one solution exists an exception 

173 will be raised. 

174 

175 Returns 

176 ------- 

177 X : set 

178 Nodes from one side of the bipartite graph. 

179 Y : set 

180 Nodes from the other side. 

181 

182 Raises 

183 ------ 

184 AmbiguousSolution 

185 Raised if the input bipartite graph is disconnected and no container 

186 with all nodes in one bipartite set is provided. When determining 

187 the nodes in each bipartite set more than one valid solution is 

188 possible if the input graph is disconnected. 

189 NetworkXError 

190 Raised if the input graph is not bipartite. 

191 

192 Examples 

193 -------- 

194 >>> from networkx.algorithms import bipartite 

195 >>> G = nx.path_graph(4) 

196 >>> X, Y = bipartite.sets(G) 

197 >>> list(X) 

198 [0, 2] 

199 >>> list(Y) 

200 [1, 3] 

201 

202 See Also 

203 -------- 

204 color 

205 

206 """ 

207 if G.is_directed(): 

208 is_connected = nx.is_weakly_connected 

209 else: 

210 is_connected = nx.is_connected 

211 if top_nodes is not None: 

212 X = set(top_nodes) 

213 Y = set(G) - X 

214 else: 

215 if not is_connected(G): 

216 msg = "Disconnected graph: Ambiguous solution for bipartite sets." 

217 raise nx.AmbiguousSolution(msg) 

218 c = color(G) 

219 X = {n for n, is_top in c.items() if is_top} 

220 Y = {n for n, is_top in c.items() if not is_top} 

221 return (X, Y) 

222 

223 

224@nx._dispatch(graphs="B") 

225def density(B, nodes): 

226 """Returns density of bipartite graph B. 

227 

228 Parameters 

229 ---------- 

230 B : NetworkX graph 

231 

232 nodes: list or container 

233 Nodes in one node set of the bipartite graph. 

234 

235 Returns 

236 ------- 

237 d : float 

238 The bipartite density 

239 

240 Examples 

241 -------- 

242 >>> from networkx.algorithms import bipartite 

243 >>> G = nx.complete_bipartite_graph(3, 2) 

244 >>> X = set([0, 1, 2]) 

245 >>> bipartite.density(G, X) 

246 1.0 

247 >>> Y = set([3, 4]) 

248 >>> bipartite.density(G, Y) 

249 1.0 

250 

251 Notes 

252 ----- 

253 The container of nodes passed as argument must contain all nodes 

254 in one of the two bipartite node sets to avoid ambiguity in the 

255 case of disconnected graphs. 

256 See :mod:`bipartite documentation <networkx.algorithms.bipartite>` 

257 for further details on how bipartite graphs are handled in NetworkX. 

258 

259 See Also 

260 -------- 

261 color 

262 """ 

263 n = len(B) 

264 m = nx.number_of_edges(B) 

265 nb = len(nodes) 

266 nt = n - nb 

267 if m == 0: # includes cases n==0 and n==1 

268 d = 0.0 

269 else: 

270 if B.is_directed(): 

271 d = m / (2 * nb * nt) 

272 else: 

273 d = m / (nb * nt) 

274 return d 

275 

276 

277@nx._dispatch(graphs="B", edge_attrs="weight") 

278def degrees(B, nodes, weight=None): 

279 """Returns the degrees of the two node sets in the bipartite graph B. 

280 

281 Parameters 

282 ---------- 

283 B : NetworkX graph 

284 

285 nodes: list or container 

286 Nodes in one node set of the bipartite graph. 

287 

288 weight : string or None, optional (default=None) 

289 The edge attribute that holds the numerical value used as a weight. 

290 If None, then each edge has weight 1. 

291 The degree is the sum of the edge weights adjacent to the node. 

292 

293 Returns 

294 ------- 

295 (degX,degY) : tuple of dictionaries 

296 The degrees of the two bipartite sets as dictionaries keyed by node. 

297 

298 Examples 

299 -------- 

300 >>> from networkx.algorithms import bipartite 

301 >>> G = nx.complete_bipartite_graph(3, 2) 

302 >>> Y = set([3, 4]) 

303 >>> degX, degY = bipartite.degrees(G, Y) 

304 >>> dict(degX) 

305 {0: 2, 1: 2, 2: 2} 

306 

307 Notes 

308 ----- 

309 The container of nodes passed as argument must contain all nodes 

310 in one of the two bipartite node sets to avoid ambiguity in the 

311 case of disconnected graphs. 

312 See :mod:`bipartite documentation <networkx.algorithms.bipartite>` 

313 for further details on how bipartite graphs are handled in NetworkX. 

314 

315 See Also 

316 -------- 

317 color, density 

318 """ 

319 bottom = set(nodes) 

320 top = set(B) - bottom 

321 return (B.degree(top, weight), B.degree(bottom, weight))