123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- import collections
- import pytest
- import networkx as nx
- class TestIsEulerian:
- def test_is_eulerian(self):
- assert nx.is_eulerian(nx.complete_graph(5))
- assert nx.is_eulerian(nx.complete_graph(7))
- assert nx.is_eulerian(nx.hypercube_graph(4))
- assert nx.is_eulerian(nx.hypercube_graph(6))
- assert not nx.is_eulerian(nx.complete_graph(4))
- assert not nx.is_eulerian(nx.complete_graph(6))
- assert not nx.is_eulerian(nx.hypercube_graph(3))
- assert not nx.is_eulerian(nx.hypercube_graph(5))
- assert not nx.is_eulerian(nx.petersen_graph())
- assert not nx.is_eulerian(nx.path_graph(4))
- def test_is_eulerian2(self):
- # not connected
- G = nx.Graph()
- G.add_nodes_from([1, 2, 3])
- assert not nx.is_eulerian(G)
- # not strongly connected
- G = nx.DiGraph()
- G.add_nodes_from([1, 2, 3])
- assert not nx.is_eulerian(G)
- G = nx.MultiDiGraph()
- G.add_edge(1, 2)
- G.add_edge(2, 3)
- G.add_edge(2, 3)
- G.add_edge(3, 1)
- assert not nx.is_eulerian(G)
- class TestEulerianCircuit:
- def test_eulerian_circuit_cycle(self):
- G = nx.cycle_graph(4)
- edges = list(nx.eulerian_circuit(G, source=0))
- nodes = [u for u, v in edges]
- assert nodes == [0, 3, 2, 1]
- assert edges == [(0, 3), (3, 2), (2, 1), (1, 0)]
- edges = list(nx.eulerian_circuit(G, source=1))
- nodes = [u for u, v in edges]
- assert nodes == [1, 2, 3, 0]
- assert edges == [(1, 2), (2, 3), (3, 0), (0, 1)]
- G = nx.complete_graph(3)
- edges = list(nx.eulerian_circuit(G, source=0))
- nodes = [u for u, v in edges]
- assert nodes == [0, 2, 1]
- assert edges == [(0, 2), (2, 1), (1, 0)]
- edges = list(nx.eulerian_circuit(G, source=1))
- nodes = [u for u, v in edges]
- assert nodes == [1, 2, 0]
- assert edges == [(1, 2), (2, 0), (0, 1)]
- def test_eulerian_circuit_digraph(self):
- G = nx.DiGraph()
- nx.add_cycle(G, [0, 1, 2, 3])
- edges = list(nx.eulerian_circuit(G, source=0))
- nodes = [u for u, v in edges]
- assert nodes == [0, 1, 2, 3]
- assert edges == [(0, 1), (1, 2), (2, 3), (3, 0)]
- edges = list(nx.eulerian_circuit(G, source=1))
- nodes = [u for u, v in edges]
- assert nodes == [1, 2, 3, 0]
- assert edges == [(1, 2), (2, 3), (3, 0), (0, 1)]
- def test_multigraph(self):
- G = nx.MultiGraph()
- nx.add_cycle(G, [0, 1, 2, 3])
- G.add_edge(1, 2)
- G.add_edge(1, 2)
- edges = list(nx.eulerian_circuit(G, source=0))
- nodes = [u for u, v in edges]
- assert nodes == [0, 3, 2, 1, 2, 1]
- assert edges == [(0, 3), (3, 2), (2, 1), (1, 2), (2, 1), (1, 0)]
- def test_multigraph_with_keys(self):
- G = nx.MultiGraph()
- nx.add_cycle(G, [0, 1, 2, 3])
- G.add_edge(1, 2)
- G.add_edge(1, 2)
- edges = list(nx.eulerian_circuit(G, source=0, keys=True))
- nodes = [u for u, v, k in edges]
- assert nodes == [0, 3, 2, 1, 2, 1]
- assert edges[:2] == [(0, 3, 0), (3, 2, 0)]
- assert collections.Counter(edges[2:5]) == collections.Counter(
- [(2, 1, 0), (1, 2, 1), (2, 1, 2)]
- )
- assert edges[5:] == [(1, 0, 0)]
- def test_not_eulerian(self):
- with pytest.raises(nx.NetworkXError):
- f = list(nx.eulerian_circuit(nx.complete_graph(4)))
- class TestIsSemiEulerian:
- def test_is_semieulerian(self):
- # Test graphs with Eulerian paths but no cycles return True.
- assert nx.is_semieulerian(nx.path_graph(4))
- G = nx.path_graph(6, create_using=nx.DiGraph)
- assert nx.is_semieulerian(G)
- # Test graphs with Eulerian cycles return False.
- assert not nx.is_semieulerian(nx.complete_graph(5))
- assert not nx.is_semieulerian(nx.complete_graph(7))
- assert not nx.is_semieulerian(nx.hypercube_graph(4))
- assert not nx.is_semieulerian(nx.hypercube_graph(6))
- class TestHasEulerianPath:
- def test_has_eulerian_path_cyclic(self):
- # Test graphs with Eulerian cycles return True.
- assert nx.has_eulerian_path(nx.complete_graph(5))
- assert nx.has_eulerian_path(nx.complete_graph(7))
- assert nx.has_eulerian_path(nx.hypercube_graph(4))
- assert nx.has_eulerian_path(nx.hypercube_graph(6))
- def test_has_eulerian_path_non_cyclic(self):
- # Test graphs with Eulerian paths but no cycles return True.
- assert nx.has_eulerian_path(nx.path_graph(4))
- G = nx.path_graph(6, create_using=nx.DiGraph)
- assert nx.has_eulerian_path(G)
- def test_has_eulerian_path_directed_graph(self):
- # Test directed graphs and returns False
- G = nx.DiGraph()
- G.add_edges_from([(0, 1), (1, 2), (0, 2)])
- assert not nx.has_eulerian_path(G)
- # Test directed graphs without isolated node returns True
- G = nx.DiGraph()
- G.add_edges_from([(0, 1), (1, 2), (2, 0)])
- assert nx.has_eulerian_path(G)
- # Test directed graphs with isolated node returns False
- G.add_node(3)
- assert not nx.has_eulerian_path(G)
- @pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
- def test_has_eulerian_path_not_weakly_connected(self, G):
- G.add_edges_from([(0, 1), (2, 3), (3, 2)])
- assert not nx.has_eulerian_path(G)
- @pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
- def test_has_eulerian_path_unbalancedins_more_than_one(self, G):
- G.add_edges_from([(0, 1), (2, 3)])
- assert not nx.has_eulerian_path(G)
- class TestFindPathStart:
- def testfind_path_start(self):
- find_path_start = nx.algorithms.euler._find_path_start
- # Test digraphs return correct starting node.
- G = nx.path_graph(6, create_using=nx.DiGraph)
- assert find_path_start(G) == 0
- edges = [(0, 1), (1, 2), (2, 0), (4, 0)]
- assert find_path_start(nx.DiGraph(edges)) == 4
- # Test graph with no Eulerian path return None.
- edges = [(0, 1), (1, 2), (2, 3), (2, 4)]
- assert find_path_start(nx.DiGraph(edges)) is None
- class TestEulerianPath:
- def test_eulerian_path(self):
- x = [(4, 0), (0, 1), (1, 2), (2, 0)]
- for e1, e2 in zip(x, nx.eulerian_path(nx.DiGraph(x))):
- assert e1 == e2
- def test_eulerian_path_straight_link(self):
- G = nx.DiGraph()
- result = [(1, 2), (2, 3), (3, 4), (4, 5)]
- G.add_edges_from(result)
- assert result == list(nx.eulerian_path(G))
- assert result == list(nx.eulerian_path(G, source=1))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=3))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=4))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=5))
- def test_eulerian_path_multigraph(self):
- G = nx.MultiDiGraph()
- result = [(2, 1), (1, 2), (2, 1), (1, 2), (2, 3), (3, 4), (4, 3)]
- G.add_edges_from(result)
- assert result == list(nx.eulerian_path(G))
- assert result == list(nx.eulerian_path(G, source=2))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=3))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=4))
- def test_eulerian_path_eulerian_circuit(self):
- G = nx.DiGraph()
- result = [(1, 2), (2, 3), (3, 4), (4, 1)]
- result2 = [(2, 3), (3, 4), (4, 1), (1, 2)]
- result3 = [(3, 4), (4, 1), (1, 2), (2, 3)]
- G.add_edges_from(result)
- assert result == list(nx.eulerian_path(G))
- assert result == list(nx.eulerian_path(G, source=1))
- assert result2 == list(nx.eulerian_path(G, source=2))
- assert result3 == list(nx.eulerian_path(G, source=3))
- def test_eulerian_path_undirected(self):
- G = nx.Graph()
- result = [(1, 2), (2, 3), (3, 4), (4, 5)]
- result2 = [(5, 4), (4, 3), (3, 2), (2, 1)]
- G.add_edges_from(result)
- assert list(nx.eulerian_path(G)) in (result, result2)
- assert result == list(nx.eulerian_path(G, source=1))
- assert result2 == list(nx.eulerian_path(G, source=5))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=3))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=2))
- def test_eulerian_path_multigraph_undirected(self):
- G = nx.MultiGraph()
- result = [(2, 1), (1, 2), (2, 1), (1, 2), (2, 3), (3, 4)]
- G.add_edges_from(result)
- assert result == list(nx.eulerian_path(G))
- assert result == list(nx.eulerian_path(G, source=2))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=3))
- with pytest.raises(nx.NetworkXError):
- list(nx.eulerian_path(G, source=1))
- class TestEulerize:
- def test_disconnected(self):
- with pytest.raises(nx.NetworkXError):
- G = nx.from_edgelist([(0, 1), (2, 3)])
- nx.eulerize(G)
- def test_null_graph(self):
- with pytest.raises(nx.NetworkXPointlessConcept):
- nx.eulerize(nx.Graph())
- def test_null_multigraph(self):
- with pytest.raises(nx.NetworkXPointlessConcept):
- nx.eulerize(nx.MultiGraph())
- def test_on_empty_graph(self):
- with pytest.raises(nx.NetworkXError):
- nx.eulerize(nx.empty_graph(3))
- def test_on_eulerian(self):
- G = nx.cycle_graph(3)
- H = nx.eulerize(G)
- assert nx.is_isomorphic(G, H)
- def test_on_eulerian_multigraph(self):
- G = nx.MultiGraph(nx.cycle_graph(3))
- G.add_edge(0, 1)
- H = nx.eulerize(G)
- assert nx.is_eulerian(H)
- def test_on_complete_graph(self):
- G = nx.complete_graph(4)
- assert nx.is_eulerian(nx.eulerize(G))
- assert nx.is_eulerian(nx.eulerize(nx.MultiGraph(G)))
- def test_on_non_eulerian_graph(self):
- G = nx.cycle_graph(18)
- G.add_edge(0, 18)
- G.add_edge(18, 19)
- G.add_edge(17, 19)
- G.add_edge(4, 20)
- G.add_edge(20, 21)
- G.add_edge(21, 22)
- G.add_edge(22, 23)
- G.add_edge(23, 24)
- G.add_edge(24, 25)
- G.add_edge(25, 26)
- G.add_edge(26, 27)
- G.add_edge(27, 28)
- G.add_edge(28, 13)
- assert not nx.is_eulerian(G)
- G = nx.eulerize(G)
- assert nx.is_eulerian(G)
- assert nx.number_of_edges(G) == 39
|