test_function.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. import random
  2. import pytest
  3. import networkx as nx
  4. from networkx.utils import edges_equal, nodes_equal
  5. class TestFunction:
  6. def setup_method(self):
  7. self.G = nx.Graph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}, name="Test")
  8. self.Gdegree = {0: 3, 1: 2, 2: 2, 3: 1, 4: 0}
  9. self.Gnodes = list(range(5))
  10. self.Gedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
  11. self.DG = nx.DiGraph({0: [1, 2, 3], 1: [1, 2, 0], 4: []})
  12. self.DGin_degree = {0: 1, 1: 2, 2: 2, 3: 1, 4: 0}
  13. self.DGout_degree = {0: 3, 1: 3, 2: 0, 3: 0, 4: 0}
  14. self.DGnodes = list(range(5))
  15. self.DGedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
  16. def test_nodes(self):
  17. assert nodes_equal(self.G.nodes(), list(nx.nodes(self.G)))
  18. assert nodes_equal(self.DG.nodes(), list(nx.nodes(self.DG)))
  19. def test_edges(self):
  20. assert edges_equal(self.G.edges(), list(nx.edges(self.G)))
  21. assert sorted(self.DG.edges()) == sorted(nx.edges(self.DG))
  22. assert edges_equal(
  23. self.G.edges(nbunch=[0, 1, 3]), list(nx.edges(self.G, nbunch=[0, 1, 3]))
  24. )
  25. assert sorted(self.DG.edges(nbunch=[0, 1, 3])) == sorted(
  26. nx.edges(self.DG, nbunch=[0, 1, 3])
  27. )
  28. def test_degree(self):
  29. assert edges_equal(self.G.degree(), list(nx.degree(self.G)))
  30. assert sorted(self.DG.degree()) == sorted(nx.degree(self.DG))
  31. assert edges_equal(
  32. self.G.degree(nbunch=[0, 1]), list(nx.degree(self.G, nbunch=[0, 1]))
  33. )
  34. assert sorted(self.DG.degree(nbunch=[0, 1])) == sorted(
  35. nx.degree(self.DG, nbunch=[0, 1])
  36. )
  37. assert edges_equal(
  38. self.G.degree(weight="weight"), list(nx.degree(self.G, weight="weight"))
  39. )
  40. assert sorted(self.DG.degree(weight="weight")) == sorted(
  41. nx.degree(self.DG, weight="weight")
  42. )
  43. def test_neighbors(self):
  44. assert list(self.G.neighbors(1)) == list(nx.neighbors(self.G, 1))
  45. assert list(self.DG.neighbors(1)) == list(nx.neighbors(self.DG, 1))
  46. def test_number_of_nodes(self):
  47. assert self.G.number_of_nodes() == nx.number_of_nodes(self.G)
  48. assert self.DG.number_of_nodes() == nx.number_of_nodes(self.DG)
  49. def test_number_of_edges(self):
  50. assert self.G.number_of_edges() == nx.number_of_edges(self.G)
  51. assert self.DG.number_of_edges() == nx.number_of_edges(self.DG)
  52. def test_is_directed(self):
  53. assert self.G.is_directed() == nx.is_directed(self.G)
  54. assert self.DG.is_directed() == nx.is_directed(self.DG)
  55. def test_add_star(self):
  56. G = self.G.copy()
  57. nlist = [12, 13, 14, 15]
  58. nx.add_star(G, nlist)
  59. assert edges_equal(G.edges(nlist), [(12, 13), (12, 14), (12, 15)])
  60. G = self.G.copy()
  61. nx.add_star(G, nlist, weight=2.0)
  62. assert edges_equal(
  63. G.edges(nlist, data=True),
  64. [
  65. (12, 13, {"weight": 2.0}),
  66. (12, 14, {"weight": 2.0}),
  67. (12, 15, {"weight": 2.0}),
  68. ],
  69. )
  70. G = self.G.copy()
  71. nlist = [12]
  72. nx.add_star(G, nlist)
  73. assert nodes_equal(G, list(self.G) + nlist)
  74. G = self.G.copy()
  75. nlist = []
  76. nx.add_star(G, nlist)
  77. assert nodes_equal(G.nodes, self.Gnodes)
  78. assert edges_equal(G.edges, self.G.edges)
  79. def test_add_path(self):
  80. G = self.G.copy()
  81. nlist = [12, 13, 14, 15]
  82. nx.add_path(G, nlist)
  83. assert edges_equal(G.edges(nlist), [(12, 13), (13, 14), (14, 15)])
  84. G = self.G.copy()
  85. nx.add_path(G, nlist, weight=2.0)
  86. assert edges_equal(
  87. G.edges(nlist, data=True),
  88. [
  89. (12, 13, {"weight": 2.0}),
  90. (13, 14, {"weight": 2.0}),
  91. (14, 15, {"weight": 2.0}),
  92. ],
  93. )
  94. G = self.G.copy()
  95. nlist = ["node"]
  96. nx.add_path(G, nlist)
  97. assert edges_equal(G.edges(nlist), [])
  98. assert nodes_equal(G, list(self.G) + ["node"])
  99. G = self.G.copy()
  100. nlist = iter(["node"])
  101. nx.add_path(G, nlist)
  102. assert edges_equal(G.edges(["node"]), [])
  103. assert nodes_equal(G, list(self.G) + ["node"])
  104. G = self.G.copy()
  105. nlist = [12]
  106. nx.add_path(G, nlist)
  107. assert edges_equal(G.edges(nlist), [])
  108. assert nodes_equal(G, list(self.G) + [12])
  109. G = self.G.copy()
  110. nlist = iter([12])
  111. nx.add_path(G, nlist)
  112. assert edges_equal(G.edges([12]), [])
  113. assert nodes_equal(G, list(self.G) + [12])
  114. G = self.G.copy()
  115. nlist = []
  116. nx.add_path(G, nlist)
  117. assert edges_equal(G.edges, self.G.edges)
  118. assert nodes_equal(G, list(self.G))
  119. G = self.G.copy()
  120. nlist = iter([])
  121. nx.add_path(G, nlist)
  122. assert edges_equal(G.edges, self.G.edges)
  123. assert nodes_equal(G, list(self.G))
  124. def test_add_cycle(self):
  125. G = self.G.copy()
  126. nlist = [12, 13, 14, 15]
  127. oklists = [
  128. [(12, 13), (12, 15), (13, 14), (14, 15)],
  129. [(12, 13), (13, 14), (14, 15), (15, 12)],
  130. ]
  131. nx.add_cycle(G, nlist)
  132. assert sorted(G.edges(nlist)) in oklists
  133. G = self.G.copy()
  134. oklists = [
  135. [
  136. (12, 13, {"weight": 1.0}),
  137. (12, 15, {"weight": 1.0}),
  138. (13, 14, {"weight": 1.0}),
  139. (14, 15, {"weight": 1.0}),
  140. ],
  141. [
  142. (12, 13, {"weight": 1.0}),
  143. (13, 14, {"weight": 1.0}),
  144. (14, 15, {"weight": 1.0}),
  145. (15, 12, {"weight": 1.0}),
  146. ],
  147. ]
  148. nx.add_cycle(G, nlist, weight=1.0)
  149. assert sorted(G.edges(nlist, data=True)) in oklists
  150. G = self.G.copy()
  151. nlist = [12]
  152. nx.add_cycle(G, nlist)
  153. assert nodes_equal(G, list(self.G) + nlist)
  154. G = self.G.copy()
  155. nlist = []
  156. nx.add_cycle(G, nlist)
  157. assert nodes_equal(G.nodes, self.Gnodes)
  158. assert edges_equal(G.edges, self.G.edges)
  159. def test_subgraph(self):
  160. assert (
  161. self.G.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.G, [0, 1, 2, 4]).adj
  162. )
  163. assert (
  164. self.DG.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.DG, [0, 1, 2, 4]).adj
  165. )
  166. assert (
  167. self.G.subgraph([0, 1, 2, 4]).adj
  168. == nx.induced_subgraph(self.G, [0, 1, 2, 4]).adj
  169. )
  170. assert (
  171. self.DG.subgraph([0, 1, 2, 4]).adj
  172. == nx.induced_subgraph(self.DG, [0, 1, 2, 4]).adj
  173. )
  174. # subgraph-subgraph chain is allowed in function interface
  175. H = nx.induced_subgraph(self.G.subgraph([0, 1, 2, 4]), [0, 1, 4])
  176. assert H._graph is not self.G
  177. assert H.adj == self.G.subgraph([0, 1, 4]).adj
  178. def test_edge_subgraph(self):
  179. assert (
  180. self.G.edge_subgraph([(1, 2), (0, 3)]).adj
  181. == nx.edge_subgraph(self.G, [(1, 2), (0, 3)]).adj
  182. )
  183. assert (
  184. self.DG.edge_subgraph([(1, 2), (0, 3)]).adj
  185. == nx.edge_subgraph(self.DG, [(1, 2), (0, 3)]).adj
  186. )
  187. def test_create_empty_copy(self):
  188. G = nx.create_empty_copy(self.G, with_data=False)
  189. assert nodes_equal(G, list(self.G))
  190. assert G.graph == {}
  191. assert G._node == {}.fromkeys(self.G.nodes(), {})
  192. assert G._adj == {}.fromkeys(self.G.nodes(), {})
  193. G = nx.create_empty_copy(self.G)
  194. assert nodes_equal(G, list(self.G))
  195. assert G.graph == self.G.graph
  196. assert G._node == self.G._node
  197. assert G._adj == {}.fromkeys(self.G.nodes(), {})
  198. def test_degree_histogram(self):
  199. assert nx.degree_histogram(self.G) == [1, 1, 1, 1, 1]
  200. def test_density(self):
  201. assert nx.density(self.G) == 0.5
  202. assert nx.density(self.DG) == 0.3
  203. G = nx.Graph()
  204. G.add_node(1)
  205. assert nx.density(G) == 0.0
  206. def test_density_selfloop(self):
  207. G = nx.Graph()
  208. G.add_edge(1, 1)
  209. assert nx.density(G) == 0.0
  210. G.add_edge(1, 2)
  211. assert nx.density(G) == 2.0
  212. def test_freeze(self):
  213. G = nx.freeze(self.G)
  214. assert G.frozen
  215. pytest.raises(nx.NetworkXError, G.add_node, 1)
  216. pytest.raises(nx.NetworkXError, G.add_nodes_from, [1])
  217. pytest.raises(nx.NetworkXError, G.remove_node, 1)
  218. pytest.raises(nx.NetworkXError, G.remove_nodes_from, [1])
  219. pytest.raises(nx.NetworkXError, G.add_edge, 1, 2)
  220. pytest.raises(nx.NetworkXError, G.add_edges_from, [(1, 2)])
  221. pytest.raises(nx.NetworkXError, G.remove_edge, 1, 2)
  222. pytest.raises(nx.NetworkXError, G.remove_edges_from, [(1, 2)])
  223. pytest.raises(nx.NetworkXError, G.clear_edges)
  224. pytest.raises(nx.NetworkXError, G.clear)
  225. def test_is_frozen(self):
  226. assert not nx.is_frozen(self.G)
  227. G = nx.freeze(self.G)
  228. assert G.frozen == nx.is_frozen(self.G)
  229. assert G.frozen
  230. def test_node_attributes_are_still_mutable_on_frozen_graph(self):
  231. G = nx.freeze(nx.path_graph(3))
  232. node = G.nodes[0]
  233. node["node_attribute"] = True
  234. assert node["node_attribute"] == True
  235. def test_edge_attributes_are_still_mutable_on_frozen_graph(self):
  236. G = nx.freeze(nx.path_graph(3))
  237. edge = G.edges[(0, 1)]
  238. edge["edge_attribute"] = True
  239. assert edge["edge_attribute"] == True
  240. def test_neighbors_complete_graph(self):
  241. graph = nx.complete_graph(100)
  242. pop = random.sample(list(graph), 1)
  243. nbors = list(nx.neighbors(graph, pop[0]))
  244. # should be all the other vertices in the graph
  245. assert len(nbors) == len(graph) - 1
  246. graph = nx.path_graph(100)
  247. node = random.sample(list(graph), 1)[0]
  248. nbors = list(nx.neighbors(graph, node))
  249. # should be all the other vertices in the graph
  250. if node != 0 and node != 99:
  251. assert len(nbors) == 2
  252. else:
  253. assert len(nbors) == 1
  254. # create a star graph with 99 outer nodes
  255. graph = nx.star_graph(99)
  256. nbors = list(nx.neighbors(graph, 0))
  257. assert len(nbors) == 99
  258. def test_non_neighbors(self):
  259. graph = nx.complete_graph(100)
  260. pop = random.sample(list(graph), 1)
  261. nbors = list(nx.non_neighbors(graph, pop[0]))
  262. # should be all the other vertices in the graph
  263. assert len(nbors) == 0
  264. graph = nx.path_graph(100)
  265. node = random.sample(list(graph), 1)[0]
  266. nbors = list(nx.non_neighbors(graph, node))
  267. # should be all the other vertices in the graph
  268. if node != 0 and node != 99:
  269. assert len(nbors) == 97
  270. else:
  271. assert len(nbors) == 98
  272. # create a star graph with 99 outer nodes
  273. graph = nx.star_graph(99)
  274. nbors = list(nx.non_neighbors(graph, 0))
  275. assert len(nbors) == 0
  276. # disconnected graph
  277. graph = nx.Graph()
  278. graph.add_nodes_from(range(10))
  279. nbors = list(nx.non_neighbors(graph, 0))
  280. assert len(nbors) == 9
  281. def test_non_edges(self):
  282. # All possible edges exist
  283. graph = nx.complete_graph(5)
  284. nedges = list(nx.non_edges(graph))
  285. assert len(nedges) == 0
  286. graph = nx.path_graph(4)
  287. expected = [(0, 2), (0, 3), (1, 3)]
  288. nedges = list(nx.non_edges(graph))
  289. for u, v in expected:
  290. assert (u, v) in nedges or (v, u) in nedges
  291. graph = nx.star_graph(4)
  292. expected = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
  293. nedges = list(nx.non_edges(graph))
  294. for u, v in expected:
  295. assert (u, v) in nedges or (v, u) in nedges
  296. # Directed graphs
  297. graph = nx.DiGraph()
  298. graph.add_edges_from([(0, 2), (2, 0), (2, 1)])
  299. expected = [(0, 1), (1, 0), (1, 2)]
  300. nedges = list(nx.non_edges(graph))
  301. for e in expected:
  302. assert e in nedges
  303. def test_is_weighted(self):
  304. G = nx.Graph()
  305. assert not nx.is_weighted(G)
  306. G = nx.path_graph(4)
  307. assert not nx.is_weighted(G)
  308. assert not nx.is_weighted(G, (2, 3))
  309. G.add_node(4)
  310. G.add_edge(3, 4, weight=4)
  311. assert not nx.is_weighted(G)
  312. assert nx.is_weighted(G, (3, 4))
  313. G = nx.DiGraph()
  314. G.add_weighted_edges_from(
  315. [
  316. ("0", "3", 3),
  317. ("0", "1", -5),
  318. ("1", "0", -5),
  319. ("0", "2", 2),
  320. ("1", "2", 4),
  321. ("2", "3", 1),
  322. ]
  323. )
  324. assert nx.is_weighted(G)
  325. assert nx.is_weighted(G, ("1", "0"))
  326. G = G.to_undirected()
  327. assert nx.is_weighted(G)
  328. assert nx.is_weighted(G, ("1", "0"))
  329. pytest.raises(nx.NetworkXError, nx.is_weighted, G, (1, 2))
  330. def test_is_negatively_weighted(self):
  331. G = nx.Graph()
  332. assert not nx.is_negatively_weighted(G)
  333. G.add_node(1)
  334. G.add_nodes_from([2, 3, 4, 5])
  335. assert not nx.is_negatively_weighted(G)
  336. G.add_edge(1, 2, weight=4)
  337. assert not nx.is_negatively_weighted(G, (1, 2))
  338. G.add_edges_from([(1, 3), (2, 4), (2, 6)])
  339. G[1][3]["color"] = "blue"
  340. assert not nx.is_negatively_weighted(G)
  341. assert not nx.is_negatively_weighted(G, (1, 3))
  342. G[2][4]["weight"] = -2
  343. assert nx.is_negatively_weighted(G, (2, 4))
  344. assert nx.is_negatively_weighted(G)
  345. G = nx.DiGraph()
  346. G.add_weighted_edges_from(
  347. [
  348. ("0", "3", 3),
  349. ("0", "1", -5),
  350. ("1", "0", -2),
  351. ("0", "2", 2),
  352. ("1", "2", -3),
  353. ("2", "3", 1),
  354. ]
  355. )
  356. assert nx.is_negatively_weighted(G)
  357. assert not nx.is_negatively_weighted(G, ("0", "3"))
  358. assert nx.is_negatively_weighted(G, ("1", "0"))
  359. pytest.raises(nx.NetworkXError, nx.is_negatively_weighted, G, (1, 4))
  360. class TestCommonNeighbors:
  361. @classmethod
  362. def setup_class(cls):
  363. cls.func = staticmethod(nx.common_neighbors)
  364. def test_func(G, u, v, expected):
  365. result = sorted(cls.func(G, u, v))
  366. assert result == expected
  367. cls.test = staticmethod(test_func)
  368. def test_K5(self):
  369. G = nx.complete_graph(5)
  370. self.test(G, 0, 1, [2, 3, 4])
  371. def test_P3(self):
  372. G = nx.path_graph(3)
  373. self.test(G, 0, 2, [1])
  374. def test_S4(self):
  375. G = nx.star_graph(4)
  376. self.test(G, 1, 2, [0])
  377. def test_digraph(self):
  378. with pytest.raises(nx.NetworkXNotImplemented):
  379. G = nx.DiGraph()
  380. G.add_edges_from([(0, 1), (1, 2)])
  381. self.func(G, 0, 2)
  382. def test_nonexistent_nodes(self):
  383. G = nx.complete_graph(5)
  384. pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 4)
  385. pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 4, 5)
  386. pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 6)
  387. def test_custom1(self):
  388. """Case of no common neighbors."""
  389. G = nx.Graph()
  390. G.add_nodes_from([0, 1])
  391. self.test(G, 0, 1, [])
  392. def test_custom2(self):
  393. """Case of equal nodes."""
  394. G = nx.complete_graph(4)
  395. self.test(G, 0, 0, [1, 2, 3])
  396. @pytest.mark.parametrize(
  397. "graph_type", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
  398. )
  399. def test_set_node_attributes(graph_type):
  400. # Test single value
  401. G = nx.path_graph(3, create_using=graph_type)
  402. vals = 100
  403. attr = "hello"
  404. nx.set_node_attributes(G, vals, attr)
  405. assert G.nodes[0][attr] == vals
  406. assert G.nodes[1][attr] == vals
  407. assert G.nodes[2][attr] == vals
  408. # Test dictionary
  409. G = nx.path_graph(3, create_using=graph_type)
  410. vals = dict(zip(sorted(G.nodes()), range(len(G))))
  411. attr = "hi"
  412. nx.set_node_attributes(G, vals, attr)
  413. assert G.nodes[0][attr] == 0
  414. assert G.nodes[1][attr] == 1
  415. assert G.nodes[2][attr] == 2
  416. # Test dictionary of dictionaries
  417. G = nx.path_graph(3, create_using=graph_type)
  418. d = {"hi": 0, "hello": 200}
  419. vals = dict.fromkeys(G.nodes(), d)
  420. vals.pop(0)
  421. nx.set_node_attributes(G, vals)
  422. assert G.nodes[0] == {}
  423. assert G.nodes[1]["hi"] == 0
  424. assert G.nodes[2]["hello"] == 200
  425. @pytest.mark.parametrize(
  426. ("values", "name"),
  427. (
  428. ({0: "red", 1: "blue"}, "color"), # values dictionary
  429. ({0: {"color": "red"}, 1: {"color": "blue"}}, None), # dict-of-dict
  430. ),
  431. )
  432. def test_set_node_attributes_ignores_extra_nodes(values, name):
  433. """
  434. When `values` is a dict or dict-of-dict keyed by nodes, ensure that keys
  435. that correspond to nodes not in G are ignored.
  436. """
  437. G = nx.Graph()
  438. G.add_node(0)
  439. nx.set_node_attributes(G, values, name)
  440. assert G.nodes[0]["color"] == "red"
  441. assert 1 not in G.nodes
  442. @pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
  443. def test_set_edge_attributes(graph_type):
  444. # Test single value
  445. G = nx.path_graph(3, create_using=graph_type)
  446. attr = "hello"
  447. vals = 3
  448. nx.set_edge_attributes(G, vals, attr)
  449. assert G[0][1][attr] == vals
  450. assert G[1][2][attr] == vals
  451. # Test multiple values
  452. G = nx.path_graph(3, create_using=graph_type)
  453. attr = "hi"
  454. edges = [(0, 1), (1, 2)]
  455. vals = dict(zip(edges, range(len(edges))))
  456. nx.set_edge_attributes(G, vals, attr)
  457. assert G[0][1][attr] == 0
  458. assert G[1][2][attr] == 1
  459. # Test dictionary of dictionaries
  460. G = nx.path_graph(3, create_using=graph_type)
  461. d = {"hi": 0, "hello": 200}
  462. edges = [(0, 1)]
  463. vals = dict.fromkeys(edges, d)
  464. nx.set_edge_attributes(G, vals)
  465. assert G[0][1]["hi"] == 0
  466. assert G[0][1]["hello"] == 200
  467. assert G[1][2] == {}
  468. @pytest.mark.parametrize(
  469. ("values", "name"),
  470. (
  471. ({(0, 1): 1.0, (0, 2): 2.0}, "weight"), # values dict
  472. ({(0, 1): {"weight": 1.0}, (0, 2): {"weight": 2.0}}, None), # values dod
  473. ),
  474. )
  475. def test_set_edge_attributes_ignores_extra_edges(values, name):
  476. """If `values` is a dict or dict-of-dicts containing edges that are not in
  477. G, data associate with these edges should be ignored.
  478. """
  479. G = nx.Graph([(0, 1)])
  480. nx.set_edge_attributes(G, values, name)
  481. assert G[0][1]["weight"] == 1.0
  482. assert (0, 2) not in G.edges
  483. @pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph))
  484. def test_set_edge_attributes_multi(graph_type):
  485. # Test single value
  486. G = nx.path_graph(3, create_using=graph_type)
  487. attr = "hello"
  488. vals = 3
  489. nx.set_edge_attributes(G, vals, attr)
  490. assert G[0][1][0][attr] == vals
  491. assert G[1][2][0][attr] == vals
  492. # Test multiple values
  493. G = nx.path_graph(3, create_using=graph_type)
  494. attr = "hi"
  495. edges = [(0, 1, 0), (1, 2, 0)]
  496. vals = dict(zip(edges, range(len(edges))))
  497. nx.set_edge_attributes(G, vals, attr)
  498. assert G[0][1][0][attr] == 0
  499. assert G[1][2][0][attr] == 1
  500. # Test dictionary of dictionaries
  501. G = nx.path_graph(3, create_using=graph_type)
  502. d = {"hi": 0, "hello": 200}
  503. edges = [(0, 1, 0)]
  504. vals = dict.fromkeys(edges, d)
  505. nx.set_edge_attributes(G, vals)
  506. assert G[0][1][0]["hi"] == 0
  507. assert G[0][1][0]["hello"] == 200
  508. assert G[1][2][0] == {}
  509. @pytest.mark.parametrize(
  510. ("values", "name"),
  511. (
  512. ({(0, 1, 0): 1.0, (0, 2, 0): 2.0}, "weight"), # values dict
  513. ({(0, 1, 0): {"weight": 1.0}, (0, 2, 0): {"weight": 2.0}}, None), # values dod
  514. ),
  515. )
  516. def test_set_edge_attributes_multi_ignores_extra_edges(values, name):
  517. """If `values` is a dict or dict-of-dicts containing edges that are not in
  518. G, data associate with these edges should be ignored.
  519. """
  520. G = nx.MultiGraph([(0, 1, 0), (0, 1, 1)])
  521. nx.set_edge_attributes(G, values, name)
  522. assert G[0][1][0]["weight"] == 1.0
  523. assert G[0][1][1] == {}
  524. assert (0, 2) not in G.edges()
  525. def test_get_node_attributes():
  526. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  527. for G in graphs:
  528. G = nx.path_graph(3, create_using=G)
  529. attr = "hello"
  530. vals = 100
  531. nx.set_node_attributes(G, vals, attr)
  532. attrs = nx.get_node_attributes(G, attr)
  533. assert attrs[0] == vals
  534. assert attrs[1] == vals
  535. assert attrs[2] == vals
  536. def test_get_edge_attributes():
  537. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  538. for G in graphs:
  539. G = nx.path_graph(3, create_using=G)
  540. attr = "hello"
  541. vals = 100
  542. nx.set_edge_attributes(G, vals, attr)
  543. attrs = nx.get_edge_attributes(G, attr)
  544. assert len(attrs) == 2
  545. if G.is_multigraph():
  546. keys = [(0, 1, 0), (1, 2, 0)]
  547. for u, v, k in keys:
  548. try:
  549. assert attrs[(u, v, k)] == 100
  550. except KeyError:
  551. assert attrs[(v, u, k)] == 100
  552. else:
  553. keys = [(0, 1), (1, 2)]
  554. for u, v in keys:
  555. try:
  556. assert attrs[(u, v)] == 100
  557. except KeyError:
  558. assert attrs[(v, u)] == 100
  559. def test_is_empty():
  560. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  561. for G in graphs:
  562. assert nx.is_empty(G)
  563. G.add_nodes_from(range(5))
  564. assert nx.is_empty(G)
  565. G.add_edges_from([(1, 2), (3, 4)])
  566. assert not nx.is_empty(G)
  567. @pytest.mark.parametrize(
  568. "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
  569. )
  570. def test_selfloops(graph_type):
  571. G = nx.complete_graph(3, create_using=graph_type)
  572. G.add_edge(0, 0)
  573. assert nodes_equal(nx.nodes_with_selfloops(G), [0])
  574. assert edges_equal(nx.selfloop_edges(G), [(0, 0)])
  575. assert edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})])
  576. assert nx.number_of_selfloops(G) == 1
  577. @pytest.mark.parametrize(
  578. "graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
  579. )
  580. def test_selfloop_edges_attr(graph_type):
  581. G = nx.complete_graph(3, create_using=graph_type)
  582. G.add_edge(0, 0)
  583. G.add_edge(1, 1, weight=2)
  584. assert edges_equal(
  585. nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})]
  586. )
  587. assert edges_equal(nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)])
  588. def test_selfloop_edges_multi_with_data_and_keys():
  589. G = nx.complete_graph(3, create_using=nx.MultiGraph)
  590. G.add_edge(0, 0, weight=10)
  591. G.add_edge(0, 0, weight=100)
  592. assert edges_equal(
  593. nx.selfloop_edges(G, data="weight", keys=True), [(0, 0, 0, 10), (0, 0, 1, 100)]
  594. )
  595. @pytest.mark.parametrize("graph_type", [nx.Graph, nx.DiGraph])
  596. def test_selfloops_removal(graph_type):
  597. G = nx.complete_graph(3, create_using=graph_type)
  598. G.add_edge(0, 0)
  599. G.remove_edges_from(nx.selfloop_edges(G, keys=True))
  600. G.add_edge(0, 0)
  601. G.remove_edges_from(nx.selfloop_edges(G, data=True))
  602. G.add_edge(0, 0)
  603. G.remove_edges_from(nx.selfloop_edges(G, keys=True, data=True))
  604. @pytest.mark.parametrize("graph_type", [nx.MultiGraph, nx.MultiDiGraph])
  605. def test_selfloops_removal_multi(graph_type):
  606. """test removing selfloops behavior vis-a-vis altering a dict while iterating.
  607. cf. gh-4068"""
  608. G = nx.complete_graph(3, create_using=graph_type)
  609. # Defaults - see gh-4080
  610. G.add_edge(0, 0)
  611. G.add_edge(0, 0)
  612. G.remove_edges_from(nx.selfloop_edges(G))
  613. assert (0, 0) not in G.edges()
  614. # With keys
  615. G.add_edge(0, 0)
  616. G.add_edge(0, 0)
  617. with pytest.raises(RuntimeError):
  618. G.remove_edges_from(nx.selfloop_edges(G, keys=True))
  619. # With data
  620. G.add_edge(0, 0)
  621. G.add_edge(0, 0)
  622. with pytest.raises(TypeError):
  623. G.remove_edges_from(nx.selfloop_edges(G, data=True))
  624. # With keys and data
  625. G.add_edge(0, 0)
  626. G.add_edge(0, 0)
  627. with pytest.raises(RuntimeError):
  628. G.remove_edges_from(nx.selfloop_edges(G, data=True, keys=True))
  629. def test_pathweight():
  630. valid_path = [1, 2, 3]
  631. invalid_path = [1, 3, 2]
  632. graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
  633. edges = [
  634. (1, 2, {"cost": 5, "dist": 6}),
  635. (2, 3, {"cost": 3, "dist": 4}),
  636. (1, 2, {"cost": 1, "dist": 2}),
  637. ]
  638. for graph in graphs:
  639. graph.add_edges_from(edges)
  640. assert nx.path_weight(graph, valid_path, "cost") == 4
  641. assert nx.path_weight(graph, valid_path, "dist") == 6
  642. pytest.raises(nx.NetworkXNoPath, nx.path_weight, graph, invalid_path, "cost")
  643. @pytest.mark.parametrize(
  644. "G", (nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph())
  645. )
  646. def test_ispath(G):
  647. G.add_edges_from([(1, 2), (2, 3), (1, 2), (3, 4)])
  648. valid_path = [1, 2, 3, 4]
  649. invalid_path = [1, 2, 4, 3] # wrong node order
  650. another_invalid_path = [1, 2, 3, 4, 5] # contains node not in G
  651. assert nx.is_path(G, valid_path)
  652. assert not nx.is_path(G, invalid_path)
  653. assert not nx.is_path(G, another_invalid_path)
  654. @pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
  655. def test_restricted_view(G):
  656. G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)])
  657. G.add_node(4)
  658. H = nx.restricted_view(G, [0, 2, 5], [(1, 2), (3, 4)])
  659. assert set(H.nodes()) == {1, 3, 4}
  660. assert set(H.edges()) == {(1, 1)}
  661. @pytest.mark.parametrize("G", (nx.MultiGraph(), nx.MultiDiGraph()))
  662. def test_restricted_view_multi(G):
  663. G.add_edges_from(
  664. [(0, 1, 0), (0, 2, 0), (0, 3, 0), (0, 1, 1), (1, 0, 0), (1, 1, 0), (1, 2, 0)]
  665. )
  666. G.add_node(4)
  667. H = nx.restricted_view(G, [0, 2, 5], [(1, 2, 0), (3, 4, 0)])
  668. assert set(H.nodes()) == {1, 3, 4}
  669. assert set(H.edges()) == {(1, 1)}