test_function.py 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. import random
  2. import pytest
  3. import networkx as nx
  4. from networkx.utils import edges_equal, nodes_equal
  5. def test_degree_histogram_empty():
  6. G = nx.Graph()
  7. assert nx.degree_histogram(G) == []
  8. class TestFunction:
  9. def setup_method(self):
  10. self.G = nx.Graph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}, name="Test")
  11. self.Gdegree = {0: 3, 1: 2, 2: 2, 3: 1, 4: 0}
  12. self.Gnodes = list(range(5))
  13. self.Gedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
  14. self.DG = nx.DiGraph({0: [1, 2, 3], 1: [1, 2, 0], 4: []})
  15. self.DGin_degree = {0: 1, 1: 2, 2: 2, 3: 1, 4: 0}
  16. self.DGout_degree = {0: 3, 1: 3, 2: 0, 3: 0, 4: 0}
  17. self.DGnodes = list(range(5))
  18. self.DGedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
  19. def test_describe_info_dict(self):
  20. info_dict = nx.classes.function._create_describe_info_dict(self.G)
  21. assert info_dict["Name of Graph"] == "Test"
  22. assert not info_dict["Directed"]
  23. assert not info_dict["Multigraph"]
  24. assert info_dict["Number of nodes"] == 5
  25. assert info_dict["Number of edges"] == 5
  26. assert info_dict["Average degree (min, max)"] == "2.00 (0, 4)"
  27. assert info_dict["Number of connected components"] == 2
  28. def test_nodes(self):
  29. assert nodes_equal(self.G.nodes(), list(nx.nodes(self.G)))
  30. assert nodes_equal(self.DG.nodes(), list(nx.nodes(self.DG)))
  31. def test_edges(self):
  32. assert edges_equal(self.G.edges(), list(nx.edges(self.G)))
  33. assert sorted(self.DG.edges()) == sorted(nx.edges(self.DG))
  34. assert edges_equal(
  35. self.G.edges(nbunch=[0, 1, 3]), list(nx.edges(self.G, nbunch=[0, 1, 3]))
  36. )
  37. assert sorted(self.DG.edges(nbunch=[0, 1, 3])) == sorted(
  38. nx.edges(self.DG, nbunch=[0, 1, 3])
  39. )
  40. def test_degree(self):
  41. assert edges_equal(self.G.degree(), list(nx.degree(self.G)))
  42. assert sorted(self.DG.degree()) == sorted(nx.degree(self.DG))
  43. assert edges_equal(
  44. self.G.degree(nbunch=[0, 1]), list(nx.degree(self.G, nbunch=[0, 1]))
  45. )
  46. assert sorted(self.DG.degree(nbunch=[0, 1])) == sorted(
  47. nx.degree(self.DG, nbunch=[0, 1])
  48. )
  49. assert edges_equal(
  50. self.G.degree(weight="weight"), list(nx.degree(self.G, weight="weight"))
  51. )
  52. assert sorted(self.DG.degree(weight="weight")) == sorted(
  53. nx.degree(self.DG, weight="weight")
  54. )
  55. def test_neighbors(self):
  56. assert list(self.G.neighbors(1)) == list(nx.neighbors(self.G, 1))
  57. assert list(self.DG.neighbors(1)) == list(nx.neighbors(self.DG, 1))
  58. def test_number_of_nodes(self):
  59. assert self.G.number_of_nodes() == nx.number_of_nodes(self.G)
  60. assert self.DG.number_of_nodes() == nx.number_of_nodes(self.DG)
  61. def test_number_of_edges(self):
  62. assert self.G.number_of_edges() == nx.number_of_edges(self.G)
  63. assert self.DG.number_of_edges() == nx.number_of_edges(self.DG)
  64. def test_is_directed(self):
  65. assert self.G.is_directed() == nx.is_directed(self.G)
  66. assert self.DG.is_directed() == nx.is_directed(self.DG)
  67. def test_add_star(self):
  68. G = self.G.copy()
  69. nlist = [12, 13, 14, 15]
  70. nx.add_star(G, nlist)
  71. assert edges_equal(G.edges(nlist), [(12, 13), (12, 14), (12, 15)])
  72. G = self.G.copy()
  73. nx.add_star(G, nlist, weight=2.0)
  74. assert edges_equal(
  75. G.edges(nlist, data=True),
  76. [
  77. (12, 13, {"weight": 2.0}),
  78. (12, 14, {"weight": 2.0}),
  79. (12, 15, {"weight": 2.0}),
  80. ],
  81. )
  82. G = self.G.copy()
  83. nlist = [12]
  84. nx.add_star(G, nlist)
  85. assert nodes_equal(G, list(self.G) + nlist)
  86. G = self.G.copy()
  87. nlist = []
  88. nx.add_star(G, nlist)
  89. assert nodes_equal(G.nodes, self.Gnodes)
  90. assert edges_equal(G.edges, self.G.edges)
  91. def test_add_path(self):
  92. G = self.G.copy()
  93. nlist = [12, 13, 14, 15]
  94. nx.add_path(G, nlist)
  95. assert edges_equal(G.edges(nlist), [(12, 13), (13, 14), (14, 15)])
  96. G = self.G.copy()
  97. nx.add_path(G, nlist, weight=2.0)
  98. assert edges_equal(
  99. G.edges(nlist, data=True),
  100. [
  101. (12, 13, {"weight": 2.0}),
  102. (13, 14, {"weight": 2.0}),
  103. (14, 15, {"weight": 2.0}),
  104. ],
  105. )
  106. G = self.G.copy()
  107. nlist = ["node"]
  108. nx.add_path(G, nlist)
  109. assert edges_equal(G.edges(nlist), [])
  110. assert nodes_equal(G, list(self.G) + ["node"])
  111. G = self.G.copy()
  112. nlist = iter(["node"])
  113. nx.add_path(G, nlist)
  114. assert edges_equal(G.edges(["node"]), [])
  115. assert nodes_equal(G, list(self.G) + ["node"])
  116. G = self.G.copy()
  117. nlist = [12]
  118. nx.add_path(G, nlist)
  119. assert edges_equal(G.edges(nlist), [])
  120. assert nodes_equal(G, list(self.G) + [12])
  121. G = self.G.copy()
  122. nlist = iter([12])
  123. nx.add_path(G, nlist)
  124. assert edges_equal(G.edges([12]), [])
  125. assert nodes_equal(G, list(self.G) + [12])
  126. G = self.G.copy()
  127. nlist = []
  128. nx.add_path(G, nlist)
  129. assert edges_equal(G.edges, self.G.edges)
  130. assert nodes_equal(G, list(self.G))
  131. G = self.G.copy()
  132. nlist = iter([])
  133. nx.add_path(G, nlist)
  134. assert edges_equal(G.edges, self.G.edges)
  135. assert nodes_equal(G, list(self.G))
  136. def test_add_cycle(self):
  137. G = self.G.copy()
  138. nlist = [12, 13, 14, 15]
  139. oklists = [
  140. [(12, 13), (12, 15), (13, 14), (14, 15)],
  141. [(12, 13), (13, 14), (14, 15), (15, 12)],
  142. ]
  143. nx.add_cycle(G, nlist)
  144. assert sorted(G.edges(nlist)) in oklists
  145. G = self.G.copy()
  146. oklists = [
  147. [
  148. (12, 13, {"weight": 1.0}),
  149. (12, 15, {"weight": 1.0}),
  150. (13, 14, {"weight": 1.0}),
  151. (14, 15, {"weight": 1.0}),
  152. ],
  153. [
  154. (12, 13, {"weight": 1.0}),
  155. (13, 14, {"weight": 1.0}),
  156. (14, 15, {"weight": 1.0}),
  157. (15, 12, {"weight": 1.0}),
  158. ],
  159. ]
  160. nx.add_cycle(G, nlist, weight=1.0)
  161. assert sorted(G.edges(nlist, data=True)) in oklists
  162. G = self.G.copy()
  163. nlist = [12]
  164. nx.add_cycle(G, nlist)
  165. assert nodes_equal(G, list(self.G) + nlist)
  166. G = self.G.copy()
  167. nlist = []
  168. nx.add_cycle(G, nlist)
  169. assert nodes_equal(G.nodes, self.Gnodes)
  170. assert edges_equal(G.edges, self.G.edges)
  171. def test_subgraph(self):
  172. assert (
  173. self.G.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.G, [0, 1, 2, 4]).adj
  174. )
  175. assert (
  176. self.DG.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.DG, [0, 1, 2, 4]).adj
  177. )
  178. assert (
  179. self.G.subgraph([0, 1, 2, 4]).adj
  180. == nx.induced_subgraph(self.G, [0, 1, 2, 4]).adj
  181. )
  182. assert (
  183. self.DG.subgraph([0, 1, 2, 4]).adj
  184. == nx.induced_subgraph(self.DG, [0, 1, 2, 4]).adj
  185. )
  186. # subgraph-subgraph chain is allowed in function interface
  187. H = nx.induced_subgraph(self.G.subgraph([0, 1, 2, 4]), [0, 1, 4])
  188. assert H._graph is not self.G
  189. assert H.adj == self.G.subgraph([0, 1, 4]).adj
  190. def test_edge_subgraph(self):
  191. assert (
  192. self.G.edge_subgraph([(1, 2), (0, 3)]).adj
  193. == nx.edge_subgraph(self.G, [(1, 2), (0, 3)]).adj
  194. )
  195. assert (
  196. self.DG.edge_subgraph([(1, 2), (0, 3)]).adj
  197. == nx.edge_subgraph(self.DG, [(1, 2), (0, 3)]).adj
  198. )
  199. def test_create_empty_copy(self):
  200. G = nx.create_empty_copy(self.G, with_data=False)
  201. assert nodes_equal(G, list(self.G))
  202. assert G.graph == {}
  203. assert G._node == {}.fromkeys(self.G.nodes(), {})
  204. assert G._adj == {}.fromkeys(self.G.nodes(), {})
  205. G = nx.create_empty_copy(self.G)
  206. assert nodes_equal(G, list(self.G))
  207. assert G.graph == self.G.graph
  208. assert G._node == self.G._node
  209. assert G._adj == {}.fromkeys(self.G.nodes(), {})
  210. def test_degree_histogram(self):
  211. assert nx.degree_histogram(self.G) == [1, 1, 1, 1, 1]
  212. def test_density(self):
  213. assert nx.density(self.G) == 0.5
  214. assert nx.density(self.DG) == 0.3
  215. G = nx.Graph()
  216. G.add_node(1)
  217. assert nx.density(G) == 0.0
  218. def test_density_selfloop(self):
  219. G = nx.Graph()
  220. G.add_edge(1, 1)
  221. assert nx.density(G) == 0.0
  222. G.add_edge(1, 2)
  223. assert nx.density(G) == 2.0
  224. def test_freeze(self):
  225. G = nx.freeze(self.G)
  226. assert G.frozen
  227. pytest.raises(nx.NetworkXError, G.add_node, 1)
  228. pytest.raises(nx.NetworkXError, G.add_nodes_from, [1])
  229. pytest.raises(nx.NetworkXError, G.remove_node, 1)
  230. pytest.raises(nx.NetworkXError, G.remove_nodes_from, [1])
  231. pytest.raises(nx.NetworkXError, G.add_edge, 1, 2)
  232. pytest.raises(nx.NetworkXError, G.add_edges_from, [(1, 2)])
  233. pytest.raises(nx.NetworkXError, G.remove_edge, 1, 2)
  234. pytest.raises(nx.NetworkXError, G.remove_edges_from, [(1, 2)])
  235. pytest.raises(nx.NetworkXError, G.clear_edges)
  236. pytest.raises(nx.NetworkXError, G.clear)
  237. def test_is_frozen(self):
  238. assert not nx.is_frozen(self.G)
  239. G = nx.freeze(self.G)
  240. assert G.frozen == nx.is_frozen(self.G)
  241. assert G.frozen
  242. def test_node_attributes_are_still_mutable_on_frozen_graph(self):
  243. G = nx.freeze(nx.path_graph(3))
  244. node = G.nodes[0]
  245. node["node_attribute"] = True
  246. assert node["node_attribute"] is True
  247. def test_edge_attributes_are_still_mutable_on_frozen_graph(self):
  248. G = nx.freeze(nx.path_graph(3))
  249. edge = G.edges[(0, 1)]
  250. edge["edge_attribute"] = True
  251. assert edge["edge_attribute"] is True
  252. def test_neighbors_complete_graph(self):
  253. graph = nx.complete_graph(100)
  254. pop = random.sample(list(graph), 1)
  255. nbors = list(nx.neighbors(graph, pop[0]))
  256. # should be all the other vertices in the graph
  257. assert len(nbors) == len(graph) - 1
  258. graph = nx.path_graph(100)
  259. node = random.sample(list(graph), 1)[0]
  260. nbors = list(nx.neighbors(graph, node))
  261. # should be all the other vertices in the graph
  262. if node != 0 and node != 99:
  263. assert len(nbors) == 2
  264. else:
  265. assert len(nbors) == 1
  266. # create a star graph with 99 outer nodes
  267. graph = nx.star_graph(99)
  268. nbors = list(nx.neighbors(graph, 0))
  269. assert len(nbors) == 99
  270. def test_non_neighbors(self):
  271. graph = nx.complete_graph(100)
  272. pop = random.sample(list(graph), 1)
  273. nbors = nx.non_neighbors(graph, pop[0])
  274. # should be all the other vertices in the graph
  275. assert len(nbors) == 0
  276. graph = nx.path_graph(100)
  277. node = random.sample(list(graph), 1)[0]
  278. nbors = nx.non_neighbors(graph, node)
  279. # should be all the other vertices in the graph
  280. if node != 0 and node != 99:
  281. assert len(nbors) == 97
  282. else:
  283. assert len(nbors) == 98
  284. # create a star graph with 99 outer nodes
  285. graph = nx.star_graph(99)
  286. nbors = nx.non_neighbors(graph, 0)
  287. assert len(nbors) == 0
  288. # disconnected graph
  289. graph = nx.Graph()
  290. graph.add_nodes_from(range(10))
  291. nbors = nx.non_neighbors(graph, 0)
  292. assert len(nbors) == 9
  293. def test_non_edges(self):
  294. # All possible edges exist
  295. graph = nx.complete_graph(5)
  296. nedges = list(nx.non_edges(graph))
  297. assert len(nedges) == 0
  298. graph = nx.path_graph(4)
  299. expected = [(0, 2), (0, 3), (1, 3)]
  300. nedges = list(nx.non_edges(graph))
  301. for u, v in expected:
  302. assert (u, v) in nedges or (v, u) in nedges
  303. graph = nx.star_graph(4)
  304. expected = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
  305. nedges = list(nx.non_edges(graph))
  306. for u, v in expected:
  307. assert (u, v) in nedges or (v, u) in nedges
  308. # Directed graphs
  309. graph = nx.DiGraph()
  310. graph.add_edges_from([(0, 2), (2, 0), (2, 1)])
  311. expected = [(0, 1), (1, 0), (1, 2)]
  312. nedges = list(nx.non_edges(graph))
  313. for e in expected:
  314. assert e in nedges
  315. def test_is_weighted(self):
  316. G = nx.Graph()
  317. assert not nx.is_weighted(G)
  318. G = nx.path_graph(4)
  319. assert not nx.is_weighted(G)
  320. assert not nx.is_weighted(G, (2, 3))
  321. G.add_node(4)
  322. G.add_edge(3, 4, weight=4)
  323. assert not nx.is_weighted(G)
  324. assert nx.is_weighted(G, (3, 4))
  325. G = nx.DiGraph()
  326. G.add_weighted_edges_from(
  327. [
  328. ("0", "3", 3),
  329. ("0", "1", -5),
  330. ("1", "0", -5),
  331. ("0", "2", 2),
  332. ("1", "2", 4),
  333. ("2", "3", 1),
  334. ]
  335. )
  336. assert nx.is_weighted(G)
  337. assert nx.is_weighted(G, ("1", "0"))
  338. G = G.to_undirected()
  339. assert nx.is_weighted(G)
  340. assert nx.is_weighted(G, ("1", "0"))
  341. pytest.raises(nx.NetworkXError, nx.is_weighted, G, (1, 2))
  342. def test_is_negatively_weighted(self):
  343. G = nx.Graph()
  344. assert not nx.is_negatively_weighted(G)
  345. G.add_node(1)
  346. G.add_nodes_from([2, 3, 4, 5])
  347. assert not nx.is_negatively_weighted(G)
  348. G.add_edge(1, 2, weight=4)
  349. assert not nx.is_negatively_weighted(G, (1, 2))
  350. G.add_edges_from([(1, 3), (2, 4), (2, 6)])
  351. G[1][3]["color"] = "blue"
  352. assert not nx.is_negatively_weighted(G)
  353. assert not nx.is_negatively_weighted(G, (1, 3))
  354. G[2][4]["weight"] = -2
  355. assert nx.is_negatively_weighted(G, (2, 4))
  356. assert nx.is_negatively_weighted(G)
  357. G = nx.DiGraph()
  358. G.add_weighted_edges_from(
  359. [
  360. ("0", "3", 3),
  361. ("0", "1", -5),
  362. ("1", "0", -2),
  363. ("0", "2", 2),
  364. ("1", "2", -3),
  365. ("2", "3", 1),
  366. ]
  367. )
  368. assert nx.is_negatively_weighted(G)
  369. assert not nx.is_negatively_weighted(G, ("0", "3"))
  370. assert nx.is_negatively_weighted(G, ("1", "0"))
  371. pytest.raises(nx.NetworkXError, nx.is_negatively_weighted, G, (1, 4))
  372. class TestCommonNeighbors:
  373. @classmethod
  374. def setup_class(cls):
  375. cls.func = staticmethod(nx.common_neighbors)
  376. def test_func(G, u, v, expected):
  377. result = sorted(cls.func(G, u, v))
  378. assert result == expected
  379. cls.test = staticmethod(test_func)
  380. def test_K5(self):
  381. G = nx.complete_graph(5)
  382. self.test(G, 0, 1, [2, 3, 4])
  383. def test_P3(self):
  384. G = nx.path_graph(3)
  385. self.test(G, 0, 2, [1])
  386. def test_S4(self):
  387. G = nx.star_graph(4)
  388. self.test(G, 1, 2, [0])
  389. def test_digraph(self):
  390. with pytest.raises(nx.NetworkXNotImplemented):
  391. G = nx.DiGraph()
  392. G.add_edges_from([(0, 1), (1, 2)])
  393. self.func(G, 0, 2)
  394. def test_nonexistent_nodes(self):
  395. G = nx.complete_graph(5)
  396. pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 4)
  397. pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 4, 5)
  398. pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 6)
  399. def test_custom1(self):
  400. """Case of no common neighbors."""
  401. G = nx.Graph()
  402. G.add_nodes_from([0, 1])
  403. self.test(G, 0, 1, [])
  404. def test_custom2(self):
  405. """Case of equal nodes."""
  406. G = nx.complete_graph(4)
  407. self.test(G, 0, 0, [1, 2, 3])
  408. @pytest.mark.parametrize(
  409. "graph_type", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
  410. )
  411. def test_set_node_attributes(graph_type):
  412. # Test single value
  413. G = nx.path_graph(3, create_using=graph_type)
  414. vals = 100
  415. attr = "hello"
  416. nx.set_node_attributes(G, vals, attr)
  417. assert G.nodes[0][attr] == vals
  418. assert G.nodes[1][attr] == vals
  419. assert G.nodes[2][attr] == vals
  420. # Test dictionary
  421. G = nx.path_graph(3, create_using=graph_type)
  422. vals = dict(zip(sorted(G.nodes()), range(len(G))))
  423. attr = "hi"
  424. nx.set_node_attributes(G, vals, attr)
  425. assert G.nodes[0][attr] == 0
  426. assert G.nodes[1][attr] == 1
  427. assert G.nodes[2][attr] == 2
  428. # Test dictionary of dictionaries
  429. G = nx.path_graph(3, create_using=graph_type)
  430. d = {"hi": 0, "hello": 200}
  431. vals = dict.fromkeys(G.nodes(), d)
  432. vals.pop(0)
  433. nx.set_node_attributes(G, vals)
  434. assert G.nodes[0] == {}
  435. assert G.nodes[1]["hi"] == 0
  436. assert G.nodes[2]["hello"] == 200
  437. @pytest.mark.parametrize(
  438. ("values", "name"),
  439. (
  440. ({0: "red", 1: "blue"}, "color"), # values dictionary
  441. ({0: {"color": "red"}, 1: {"color": "blue"}}, None), # dict-of-dict
  442. ),
  443. )
  444. def test_set_node_attributes_ignores_extra_nodes(values, name):
  445. """
  446. When `values` is a dict or dict-of-dict keyed by nodes, ensure that keys
  447. that correspond to nodes not in G are ignored.
  448. """
  449. G = nx.Graph()
  450. G.add_node(0)
  451. nx.set_node_attributes(G, values, name)
  452. assert G.nodes[0]["color"] == "red"
  453. assert 1 not in G.nodes
  454. @pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
  455. def test_set_edge_attributes(graph_type):
  456. # Test single value
  457. G = nx.path_graph(3, create_using=graph_type)
  458. attr = "hello"
  459. vals = 3
  460. nx.set_edge_attributes(G, vals, attr)
  461. assert G[0][1][attr] == vals
  462. assert G[1][2][attr] == vals
  463. # Test multiple values
  464. G = nx.path_graph(3, create_using=graph_type)
  465. attr = "hi"
  466. edges = [(0, 1), (1, 2)]
  467. vals = dict(zip(edges, range(len(edges))))
  468. nx.set_edge_attributes(G, vals, attr)
  469. assert G[0][1][attr] == 0
  470. assert G[1][2][attr] == 1
  471. # Test dictionary of dictionaries
  472. G = nx.path_graph(3, create_using=graph_type)
  473. d = {"hi": 0, "hello": 200}
  474. edges = [(0, 1)]
  475. vals = dict.fromkeys(edges, d)
  476. nx.set_edge_attributes(G, vals)
  477. assert G[0][1]["hi"] == 0
  478. assert G[0][1]["hello"] == 200
  479. assert G[1][2] == {}
  480. @pytest.mark.parametrize(
  481. ("values", "name"),
  482. (
  483. ({(0, 1): 1.0, (0, 2): 2.0}, "weight"), # values dict
  484. ({(0, 1): {"weight": 1.0}, (0, 2): {"weight": 2.0}}, None), # values dod
  485. ),
  486. )
  487. def test_set_edge_attributes_ignores_extra_edges(values, name):
  488. """If `values` is a dict or dict-of-dicts containing edges that are not in
  489. G, data associate with these edges should be ignored.
  490. """
  491. G = nx.Graph([(0, 1)])
  492. nx.set_edge_attributes(G, values, name)
  493. assert G[0][1]["weight"] == 1.0
  494. assert (0, 2) not in G.edges
  495. @pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph))
  496. def test_set_edge_attributes_multi(graph_type):
  497. # Test single value
  498. G = nx.path_graph(3, create_using=graph_type)
  499. attr = "hello"
  500. vals = 3
  501. nx.set_edge_attributes(G, vals, attr)
  502. assert G[0][1][0][attr] == vals
  503. assert G[1][2][0][attr] == vals
  504. # Test multiple values
  505. G = nx.path_graph(3, create_using=graph_type)
  506. attr = "hi"
  507. edges = [(0, 1, 0), (1, 2, 0)]
  508. vals = dict(zip(edges, range(len(edges))))
  509. nx.set_edge_attributes(G, vals, attr)
  510. assert G[0][1][0][attr] == 0
  511. assert G[1][2][0][attr] == 1
  512. # Test dictionary of dictionaries
  513. G = nx.path_graph(3, create_using=graph_type)
  514. d = {"hi": 0, "hello": 200}
  515. edges = [(0, 1, 0)]
  516. vals = dict.fromkeys(edges, d)
  517. nx.set_edge_attributes(G, vals)
  518. assert G[0][1][0]["hi"] == 0
  519. assert G[0][1][0]["hello"] == 200
  520. assert G[1][2][0] == {}
  521. @pytest.mark.parametrize(
  522. ("values", "name"),
  523. (
  524. ({(0, 1, 0): 1.0, (0, 2, 0): 2.0}, "weight"), # values dict
  525. ({(0, 1, 0): {"weight": 1.0}, (0, 2, 0): {"weight": 2.0}}, None), # values dod
  526. ),
  527. )
  528. def test_set_edge_attributes_multi_ignores_extra_edges(values, name):
  529. """If `values` is a dict or dict-of-dicts containing edges that are not in
  530. G, data associate with these edges should be ignored.
  531. """
  532. G = nx.MultiGraph([(0, 1, 0), (0, 1, 1)])
  533. nx.set_edge_attributes(G, values, name)
  534. assert G[0][1][0]["weight"] == 1.0
  535. assert G[0][1][1] == {}
  536. assert (0, 2) not in G.edges()
  537. def test_get_node_attributes():
  538. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  539. for G in graphs:
  540. G = nx.path_graph(3, create_using=G)
  541. attr = "hello"
  542. vals = 100
  543. nx.set_node_attributes(G, vals, attr)
  544. attrs = nx.get_node_attributes(G, attr)
  545. assert attrs[0] == vals
  546. assert attrs[1] == vals
  547. assert attrs[2] == vals
  548. default_val = 1
  549. G.add_node(4)
  550. attrs = nx.get_node_attributes(G, attr, default=default_val)
  551. assert attrs[4] == default_val
  552. def test_get_edge_attributes():
  553. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  554. for G in graphs:
  555. G = nx.path_graph(3, create_using=G)
  556. attr = "hello"
  557. vals = 100
  558. nx.set_edge_attributes(G, vals, attr)
  559. attrs = nx.get_edge_attributes(G, attr)
  560. assert len(attrs) == 2
  561. for edge in G.edges:
  562. assert attrs[edge] == vals
  563. default_val = vals
  564. G.add_edge(4, 5)
  565. deafult_attrs = nx.get_edge_attributes(G, attr, default=default_val)
  566. assert len(deafult_attrs) == 3
  567. for edge in G.edges:
  568. assert deafult_attrs[edge] == vals
  569. @pytest.mark.parametrize(
  570. "graph_type", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
  571. )
  572. def test_remove_node_attributes(graph_type):
  573. # Test removing single attribute
  574. G = nx.path_graph(3, create_using=graph_type)
  575. vals = 100
  576. attr = "hello"
  577. nx.set_node_attributes(G, vals, attr)
  578. nx.remove_node_attributes(G, attr)
  579. assert attr not in G.nodes[0]
  580. assert attr not in G.nodes[1]
  581. assert attr not in G.nodes[2]
  582. # Test removing single attribute when multiple present
  583. G = nx.path_graph(3, create_using=graph_type)
  584. other_vals = 200
  585. other_attr = "other"
  586. nx.set_node_attributes(G, vals, attr)
  587. nx.set_node_attributes(G, other_vals, other_attr)
  588. nx.remove_node_attributes(G, attr)
  589. assert attr not in G.nodes[0]
  590. assert G.nodes[0][other_attr] == other_vals
  591. assert attr not in G.nodes[1]
  592. assert G.nodes[1][other_attr] == other_vals
  593. assert attr not in G.nodes[2]
  594. assert G.nodes[2][other_attr] == other_vals
  595. # Test removing multiple attributes
  596. G = nx.path_graph(3, create_using=graph_type)
  597. nx.set_node_attributes(G, vals, attr)
  598. nx.set_node_attributes(G, other_vals, other_attr)
  599. nx.remove_node_attributes(G, attr, other_attr)
  600. assert attr not in G.nodes[0] and other_attr not in G.nodes[0]
  601. assert attr not in G.nodes[1] and other_attr not in G.nodes[1]
  602. assert attr not in G.nodes[2] and other_attr not in G.nodes[2]
  603. # Test removing multiple (but not all) attributes
  604. G = nx.path_graph(3, create_using=graph_type)
  605. third_vals = 300
  606. third_attr = "three"
  607. nx.set_node_attributes(
  608. G,
  609. {
  610. n: {attr: vals, other_attr: other_vals, third_attr: third_vals}
  611. for n in G.nodes()
  612. },
  613. )
  614. nx.remove_node_attributes(G, other_attr, third_attr)
  615. assert other_attr not in G.nodes[0] and third_attr not in G.nodes[0]
  616. assert other_attr not in G.nodes[1] and third_attr not in G.nodes[1]
  617. assert other_attr not in G.nodes[2] and third_attr not in G.nodes[2]
  618. assert G.nodes[0][attr] == vals
  619. assert G.nodes[1][attr] == vals
  620. assert G.nodes[2][attr] == vals
  621. # Test incomplete node attributes
  622. G = nx.path_graph(3, create_using=graph_type)
  623. nx.set_node_attributes(
  624. G,
  625. {
  626. 1: {attr: vals, other_attr: other_vals},
  627. 2: {attr: vals, other_attr: other_vals},
  628. },
  629. )
  630. nx.remove_node_attributes(G, attr)
  631. assert attr not in G.nodes[0]
  632. assert attr not in G.nodes[1]
  633. assert attr not in G.nodes[2]
  634. assert G.nodes[1][other_attr] == other_vals
  635. assert G.nodes[2][other_attr] == other_vals
  636. # Test removing on a subset of nodes
  637. G = nx.path_graph(3, create_using=graph_type)
  638. nx.set_node_attributes(
  639. G,
  640. {
  641. n: {attr: vals, other_attr: other_vals, third_attr: third_vals}
  642. for n in G.nodes()
  643. },
  644. )
  645. nx.remove_node_attributes(G, attr, other_attr, nbunch=[0, 1])
  646. assert attr not in G.nodes[0] and other_attr not in G.nodes[0]
  647. assert attr not in G.nodes[1] and other_attr not in G.nodes[1]
  648. assert attr in G.nodes[2] and other_attr in G.nodes[2]
  649. assert third_attr in G.nodes[0] and G.nodes[0][third_attr] == third_vals
  650. assert third_attr in G.nodes[1] and G.nodes[1][third_attr] == third_vals
  651. @pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
  652. def test_remove_edge_attributes(graph_type):
  653. # Test removing single attribute
  654. G = nx.path_graph(3, create_using=graph_type)
  655. attr = "hello"
  656. vals = 100
  657. nx.set_edge_attributes(G, vals, attr)
  658. nx.remove_edge_attributes(G, attr)
  659. assert len(nx.get_edge_attributes(G, attr)) == 0
  660. # Test removing only some attributes
  661. G = nx.path_graph(3, create_using=graph_type)
  662. other_attr = "other"
  663. other_vals = 200
  664. nx.set_edge_attributes(G, vals, attr)
  665. nx.set_edge_attributes(G, other_vals, other_attr)
  666. nx.remove_edge_attributes(G, attr)
  667. assert attr not in G[0][1]
  668. assert attr not in G[1][2]
  669. assert G[0][1][other_attr] == 200
  670. assert G[1][2][other_attr] == 200
  671. # Test removing multiple attributes
  672. G = nx.path_graph(3, create_using=graph_type)
  673. nx.set_edge_attributes(G, vals, attr)
  674. nx.set_edge_attributes(G, other_vals, other_attr)
  675. nx.remove_edge_attributes(G, attr, other_attr)
  676. assert attr not in G[0][1] and other_attr not in G[0][1]
  677. assert attr not in G[1][2] and other_attr not in G[1][2]
  678. # Test removing multiple (not all) attributes
  679. G = nx.path_graph(3, create_using=graph_type)
  680. third_attr = "third"
  681. third_vals = 300
  682. nx.set_edge_attributes(
  683. G,
  684. {
  685. (u, v): {attr: vals, other_attr: other_vals, third_attr: third_vals}
  686. for u, v in G.edges()
  687. },
  688. )
  689. nx.remove_edge_attributes(G, other_attr, third_attr)
  690. assert other_attr not in G[0][1] and third_attr not in G[0][1]
  691. assert other_attr not in G[1][2] and third_attr not in G[1][2]
  692. assert G[0][1][attr] == vals
  693. assert G[1][2][attr] == vals
  694. # Test removing incomplete edge attributes
  695. G = nx.path_graph(3, create_using=graph_type)
  696. nx.set_edge_attributes(G, {(0, 1): {attr: vals, other_attr: other_vals}})
  697. nx.remove_edge_attributes(G, other_attr)
  698. assert other_attr not in G[0][1] and G[0][1][attr] == vals
  699. assert other_attr not in G[1][2]
  700. # Test removing subset of edge attributes
  701. G = nx.path_graph(3, create_using=graph_type)
  702. nx.set_edge_attributes(
  703. G,
  704. {
  705. (u, v): {attr: vals, other_attr: other_vals, third_attr: third_vals}
  706. for u, v in G.edges()
  707. },
  708. )
  709. nx.remove_edge_attributes(G, other_attr, third_attr, ebunch=[(0, 1)])
  710. assert other_attr not in G[0][1] and third_attr not in G[0][1]
  711. assert other_attr in G[1][2] and third_attr in G[1][2]
  712. @pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph))
  713. def test_remove_multi_edge_attributes(graph_type):
  714. # Test removing single attribute
  715. G = nx.path_graph(3, create_using=graph_type)
  716. G.add_edge(1, 2)
  717. attr = "hello"
  718. vals = 100
  719. nx.set_edge_attributes(G, vals, attr)
  720. nx.remove_edge_attributes(G, attr)
  721. assert attr not in G[0][1][0]
  722. assert attr not in G[1][2][0]
  723. assert attr not in G[1][2][1]
  724. # Test removing only some attributes
  725. G = nx.path_graph(3, create_using=graph_type)
  726. G.add_edge(1, 2)
  727. other_attr = "other"
  728. other_vals = 200
  729. nx.set_edge_attributes(G, vals, attr)
  730. nx.set_edge_attributes(G, other_vals, other_attr)
  731. nx.remove_edge_attributes(G, attr)
  732. assert attr not in G[0][1][0]
  733. assert attr not in G[1][2][0]
  734. assert attr not in G[1][2][1]
  735. assert G[0][1][0][other_attr] == other_vals
  736. assert G[1][2][0][other_attr] == other_vals
  737. assert G[1][2][1][other_attr] == other_vals
  738. # Test removing multiple attributes
  739. G = nx.path_graph(3, create_using=graph_type)
  740. G.add_edge(1, 2)
  741. nx.set_edge_attributes(G, vals, attr)
  742. nx.set_edge_attributes(G, other_vals, other_attr)
  743. nx.remove_edge_attributes(G, attr, other_attr)
  744. assert attr not in G[0][1][0] and other_attr not in G[0][1][0]
  745. assert attr not in G[1][2][0] and other_attr not in G[1][2][0]
  746. assert attr not in G[1][2][1] and other_attr not in G[1][2][1]
  747. # Test removing multiple (not all) attributes
  748. G = nx.path_graph(3, create_using=graph_type)
  749. G.add_edge(1, 2)
  750. third_attr = "third"
  751. third_vals = 300
  752. nx.set_edge_attributes(
  753. G,
  754. {
  755. (u, v, k): {attr: vals, other_attr: other_vals, third_attr: third_vals}
  756. for u, v, k in G.edges(keys=True)
  757. },
  758. )
  759. nx.remove_edge_attributes(G, other_attr, third_attr)
  760. assert other_attr not in G[0][1][0] and third_attr not in G[0][1][0]
  761. assert other_attr not in G[1][2][0] and other_attr not in G[1][2][0]
  762. assert other_attr not in G[1][2][1] and other_attr not in G[1][2][1]
  763. assert G[0][1][0][attr] == vals
  764. assert G[1][2][0][attr] == vals
  765. assert G[1][2][1][attr] == vals
  766. # Test removing incomplete edge attributes
  767. G = nx.path_graph(3, create_using=graph_type)
  768. G.add_edge(1, 2)
  769. nx.set_edge_attributes(
  770. G,
  771. {
  772. (0, 1, 0): {attr: vals, other_attr: other_vals},
  773. (1, 2, 1): {attr: vals, other_attr: other_vals},
  774. },
  775. )
  776. nx.remove_edge_attributes(G, other_attr)
  777. assert other_attr not in G[0][1][0] and G[0][1][0][attr] == vals
  778. assert other_attr not in G[1][2][0]
  779. assert other_attr not in G[1][2][1]
  780. # Test removing subset of edge attributes
  781. G = nx.path_graph(3, create_using=graph_type)
  782. G.add_edge(1, 2)
  783. nx.set_edge_attributes(
  784. G,
  785. {
  786. (0, 1, 0): {attr: vals, other_attr: other_vals},
  787. (1, 2, 0): {attr: vals, other_attr: other_vals},
  788. (1, 2, 1): {attr: vals, other_attr: other_vals},
  789. },
  790. )
  791. nx.remove_edge_attributes(G, attr, ebunch=[(0, 1, 0), (1, 2, 0)])
  792. assert attr not in G[0][1][0] and other_attr in G[0][1][0]
  793. assert attr not in G[1][2][0] and other_attr in G[1][2][0]
  794. assert attr in G[1][2][1] and other_attr in G[1][2][1]
  795. def test_is_empty():
  796. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  797. for G in graphs:
  798. assert nx.is_empty(G)
  799. G.add_nodes_from(range(5))
  800. assert nx.is_empty(G)
  801. G.add_edges_from([(1, 2), (3, 4)])
  802. assert not nx.is_empty(G)
  803. @pytest.mark.parametrize(
  804. "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
  805. )
  806. def test_selfloops(graph_type):
  807. G = nx.complete_graph(3, create_using=graph_type)
  808. G.add_edge(0, 0)
  809. assert nodes_equal(nx.nodes_with_selfloops(G), [0])
  810. assert edges_equal(nx.selfloop_edges(G), [(0, 0)])
  811. assert edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})])
  812. assert nx.number_of_selfloops(G) == 1
  813. @pytest.mark.parametrize(
  814. "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
  815. )
  816. def test_selfloop_edges_attr(graph_type):
  817. G = nx.complete_graph(3, create_using=graph_type)
  818. G.add_edge(0, 0)
  819. G.add_edge(1, 1, weight=2)
  820. assert edges_equal(
  821. nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})]
  822. )
  823. assert edges_equal(nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)])
  824. def test_selfloop_edges_multi_with_data_and_keys():
  825. G = nx.complete_graph(3, create_using=nx.MultiGraph)
  826. G.add_edge(0, 0, weight=10)
  827. G.add_edge(0, 0, weight=100)
  828. assert edges_equal(
  829. nx.selfloop_edges(G, data="weight", keys=True), [(0, 0, 0, 10), (0, 0, 1, 100)]
  830. )
  831. @pytest.mark.parametrize("graph_type", [nx.Graph, nx.DiGraph])
  832. def test_selfloops_removal(graph_type):
  833. G = nx.complete_graph(3, create_using=graph_type)
  834. G.add_edge(0, 0)
  835. G.remove_edges_from(nx.selfloop_edges(G, keys=True))
  836. G.add_edge(0, 0)
  837. G.remove_edges_from(nx.selfloop_edges(G, data=True))
  838. G.add_edge(0, 0)
  839. G.remove_edges_from(nx.selfloop_edges(G, keys=True, data=True))
  840. @pytest.mark.parametrize("graph_type", [nx.MultiGraph, nx.MultiDiGraph])
  841. def test_selfloops_removal_multi(graph_type):
  842. """test removing selfloops behavior vis-a-vis altering a dict while iterating.
  843. cf. gh-4068"""
  844. G = nx.complete_graph(3, create_using=graph_type)
  845. # Defaults - see gh-4080
  846. G.add_edge(0, 0)
  847. G.add_edge(0, 0)
  848. G.remove_edges_from(nx.selfloop_edges(G))
  849. assert (0, 0) not in G.edges()
  850. # With keys
  851. G.add_edge(0, 0)
  852. G.add_edge(0, 0)
  853. with pytest.raises(RuntimeError):
  854. G.remove_edges_from(nx.selfloop_edges(G, keys=True))
  855. # With data
  856. G.add_edge(0, 0)
  857. G.add_edge(0, 0)
  858. with pytest.raises(TypeError):
  859. G.remove_edges_from(nx.selfloop_edges(G, data=True))
  860. # With keys and data
  861. G.add_edge(0, 0)
  862. G.add_edge(0, 0)
  863. with pytest.raises(RuntimeError):
  864. G.remove_edges_from(nx.selfloop_edges(G, data=True, keys=True))
  865. def test_pathweight():
  866. valid_path = [1, 2, 3]
  867. invalid_path = [1, 3, 2]
  868. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  869. edges = [
  870. (1, 2, {"cost": 5, "dist": 6}),
  871. (2, 3, {"cost": 3, "dist": 4}),
  872. (1, 2, {"cost": 1, "dist": 2}),
  873. ]
  874. for graph in graphs:
  875. graph.add_edges_from(edges)
  876. assert nx.path_weight(graph, valid_path, "cost") == 4
  877. assert nx.path_weight(graph, valid_path, "dist") == 6
  878. pytest.raises(nx.NetworkXNoPath, nx.path_weight, graph, invalid_path, "cost")
  879. @pytest.mark.parametrize(
  880. "G", (nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph())
  881. )
  882. def test_ispath(G):
  883. G.add_edges_from([(1, 2), (2, 3), (1, 2), (3, 4)])
  884. valid_path = [1, 2, 3, 4]
  885. invalid_path = [1, 2, 4, 3] # wrong node order
  886. another_invalid_path = [1, 2, 3, 4, 5] # contains node not in G
  887. assert nx.is_path(G, valid_path)
  888. assert not nx.is_path(G, invalid_path)
  889. assert not nx.is_path(G, another_invalid_path)
  890. @pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
  891. def test_restricted_view(G):
  892. G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)])
  893. G.add_node(4)
  894. H = nx.restricted_view(G, [0, 2, 5], [(1, 2), (3, 4)])
  895. assert set(H.nodes()) == {1, 3, 4}
  896. assert set(H.edges()) == {(1, 1)}
  897. @pytest.mark.parametrize("G", (nx.MultiGraph(), nx.MultiDiGraph()))
  898. def test_restricted_view_multi(G):
  899. G.add_edges_from(
  900. [(0, 1, 0), (0, 2, 0), (0, 3, 0), (0, 1, 1), (1, 0, 0), (1, 1, 0), (1, 2, 0)]
  901. )
  902. G.add_node(4)
  903. H = nx.restricted_view(G, [0, 2, 5], [(1, 2, 0), (3, 4, 0)])
  904. assert set(H.nodes()) == {1, 3, 4}
  905. assert set(H.edges()) == {(1, 1)}