Fixed database typo and removed unnecessary class identifier.

This commit is contained in:
Batuhan Berk Başoğlu 2020-10-14 10:10:37 -04:00
parent 00ad49a143
commit 45fb349a7d
5098 changed files with 952558 additions and 85 deletions

View file

@ -0,0 +1,27 @@
"""Unit tests for the beam search functions."""
import networkx as nx
def identity(x):
return x
class TestBeamSearch:
"""Unit tests for the beam search function."""
def test_narrow(self):
"""Tests that a narrow beam width may cause an incomplete search."""
# In this search, we enqueue only the neighbor 3 at the first
# step, then only the neighbor 2 at the second step. Once at
# node 2, the search chooses node 3, since it has a higher value
# that node 1, but node 3 has already been visited, so the
# search terminates.
G = nx.cycle_graph(4)
edges = nx.bfs_beam_edges(G, 0, identity, width=1)
assert list(edges) == [(0, 3), (3, 2)]
def test_wide(self):
G = nx.cycle_graph(4)
edges = nx.bfs_beam_edges(G, 0, identity, width=2)
assert list(edges) == [(0, 3), (0, 1), (3, 2)]

View file

@ -0,0 +1,100 @@
from functools import partial
import networkx as nx
class TestBFS:
@classmethod
def setup_class(cls):
# simple graph
G = nx.Graph()
G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)])
cls.G = G
def test_successor(self):
assert dict(nx.bfs_successors(self.G, source=0)) == {0: [1], 1: [2, 3], 2: [4]}
def test_predecessor(self):
assert dict(nx.bfs_predecessors(self.G, source=0)) == {1: 0, 2: 1, 3: 1, 4: 2}
def test_bfs_tree(self):
T = nx.bfs_tree(self.G, source=0)
assert sorted(T.nodes()) == sorted(self.G.nodes())
assert sorted(T.edges()) == [(0, 1), (1, 2), (1, 3), (2, 4)]
def test_bfs_edges(self):
edges = nx.bfs_edges(self.G, source=0)
assert list(edges) == [(0, 1), (1, 2), (1, 3), (2, 4)]
def test_bfs_edges_reverse(self):
D = nx.DiGraph()
D.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)])
edges = nx.bfs_edges(D, source=4, reverse=True)
assert list(edges) == [(4, 2), (4, 3), (2, 1), (1, 0)]
def test_bfs_edges_sorting(self):
D = nx.DiGraph()
D.add_edges_from([(0, 1), (0, 2), (1, 4), (1, 3), (2, 5)])
sort_desc = partial(sorted, reverse=True)
edges_asc = nx.bfs_edges(D, source=0, sort_neighbors=sorted)
edges_desc = nx.bfs_edges(D, source=0, sort_neighbors=sort_desc)
assert list(edges_asc) == [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5)]
assert list(edges_desc) == [(0, 2), (0, 1), (2, 5), (1, 4), (1, 3)]
def test_bfs_tree_isolates(self):
G = nx.Graph()
G.add_node(1)
G.add_node(2)
T = nx.bfs_tree(G, source=1)
assert sorted(T.nodes()) == [1]
assert sorted(T.edges()) == []
class TestBreadthLimitedSearch:
@classmethod
def setup_class(cls):
# a tree
G = nx.Graph()
nx.add_path(G, [0, 1, 2, 3, 4, 5, 6])
nx.add_path(G, [2, 7, 8, 9, 10])
cls.G = G
# a disconnected graph
D = nx.Graph()
D.add_edges_from([(0, 1), (2, 3)])
nx.add_path(D, [2, 7, 8, 9, 10])
cls.D = D
def test_limited_bfs_successor(self):
assert dict(nx.bfs_successors(self.G, source=1, depth_limit=3)) == {
1: [0, 2],
2: [3, 7],
3: [4],
7: [8],
}
result = {
n: sorted(s) for n, s in nx.bfs_successors(self.D, source=7, depth_limit=2)
}
assert result == {8: [9], 2: [3], 7: [2, 8]}
def test_limited_bfs_predecessor(self):
assert dict(nx.bfs_predecessors(self.G, source=1, depth_limit=3)) == {
0: 1,
2: 1,
3: 2,
4: 3,
7: 2,
8: 7,
}
assert dict(nx.bfs_predecessors(self.D, source=7, depth_limit=2)) == {
2: 7,
3: 2,
8: 7,
9: 8,
}
def test_limited_bfs_tree(self):
T = nx.bfs_tree(self.G, source=3, depth_limit=1)
assert sorted(T.edges()) == [(3, 2), (3, 4)]
def test_limited_bfs_edges(self):
edges = nx.bfs_edges(self.G, source=9, depth_limit=4)
assert list(edges) == [(9, 8), (9, 10), (8, 7), (7, 2), (2, 1), (2, 3)]

View file

@ -0,0 +1,148 @@
import networkx as nx
class TestDFS:
@classmethod
def setup_class(cls):
# simple graph
G = nx.Graph()
G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)])
cls.G = G
# simple graph, disconnected
D = nx.Graph()
D.add_edges_from([(0, 1), (2, 3)])
cls.D = D
def test_preorder_nodes(self):
assert list(nx.dfs_preorder_nodes(self.G, source=0)) == [0, 1, 2, 4, 3]
assert list(nx.dfs_preorder_nodes(self.D)) == [0, 1, 2, 3]
def test_postorder_nodes(self):
assert list(nx.dfs_postorder_nodes(self.G, source=0)) == [3, 4, 2, 1, 0]
assert list(nx.dfs_postorder_nodes(self.D)) == [1, 0, 3, 2]
def test_successor(self):
assert nx.dfs_successors(self.G, source=0) == {0: [1], 1: [2], 2: [4], 4: [3]}
assert nx.dfs_successors(self.D) == {0: [1], 2: [3]}
def test_predecessor(self):
assert nx.dfs_predecessors(self.G, source=0) == {1: 0, 2: 1, 3: 4, 4: 2}
assert nx.dfs_predecessors(self.D) == {1: 0, 3: 2}
def test_dfs_tree(self):
exp_nodes = sorted(self.G.nodes())
exp_edges = [(0, 1), (1, 2), (2, 4), (4, 3)]
# Search from first node
T = nx.dfs_tree(self.G, source=0)
assert sorted(T.nodes()) == exp_nodes
assert sorted(T.edges()) == exp_edges
# Check source=None
T = nx.dfs_tree(self.G, source=None)
assert sorted(T.nodes()) == exp_nodes
assert sorted(T.edges()) == exp_edges
# Check source=None is the default
T = nx.dfs_tree(self.G)
assert sorted(T.nodes()) == exp_nodes
assert sorted(T.edges()) == exp_edges
def test_dfs_edges(self):
edges = nx.dfs_edges(self.G, source=0)
assert list(edges) == [(0, 1), (1, 2), (2, 4), (4, 3)]
edges = nx.dfs_edges(self.D)
assert list(edges) == [(0, 1), (2, 3)]
def test_dfs_labeled_edges(self):
edges = list(nx.dfs_labeled_edges(self.G, source=0))
forward = [(u, v) for (u, v, d) in edges if d == "forward"]
assert forward == [(0, 0), (0, 1), (1, 2), (2, 4), (4, 3)]
def test_dfs_labeled_disconnected_edges(self):
edges = list(nx.dfs_labeled_edges(self.D))
forward = [(u, v) for (u, v, d) in edges if d == "forward"]
assert forward == [(0, 0), (0, 1), (2, 2), (2, 3)]
def test_dfs_tree_isolates(self):
G = nx.Graph()
G.add_node(1)
G.add_node(2)
T = nx.dfs_tree(G, source=1)
assert sorted(T.nodes()) == [1]
assert sorted(T.edges()) == []
T = nx.dfs_tree(G, source=None)
assert sorted(T.nodes()) == [1, 2]
assert sorted(T.edges()) == []
class TestDepthLimitedSearch:
@classmethod
def setup_class(cls):
# a tree
G = nx.Graph()
nx.add_path(G, [0, 1, 2, 3, 4, 5, 6])
nx.add_path(G, [2, 7, 8, 9, 10])
cls.G = G
# a disconnected graph
D = nx.Graph()
D.add_edges_from([(0, 1), (2, 3)])
nx.add_path(D, [2, 7, 8, 9, 10])
cls.D = D
def test_dls_preorder_nodes(self):
assert list(nx.dfs_preorder_nodes(self.G, source=0, depth_limit=2)) == [0, 1, 2]
assert list(nx.dfs_preorder_nodes(self.D, source=1, depth_limit=2)) == ([1, 0])
def test_dls_postorder_nodes(self):
assert list(nx.dfs_postorder_nodes(self.G, source=3, depth_limit=3)) == [
1,
7,
2,
5,
4,
3,
]
assert list(nx.dfs_postorder_nodes(self.D, source=2, depth_limit=2)) == (
[3, 7, 2]
)
def test_dls_successor(self):
result = nx.dfs_successors(self.G, source=4, depth_limit=3)
assert {n: set(v) for n, v in result.items()} == {
2: {1, 7},
3: {2},
4: {3, 5},
5: {6},
}
result = nx.dfs_successors(self.D, source=7, depth_limit=2)
assert {n: set(v) for n, v in result.items()} == {8: {9}, 2: {3}, 7: {8, 2}}
def test_dls_predecessor(self):
assert nx.dfs_predecessors(self.G, source=0, depth_limit=3) == {
1: 0,
2: 1,
3: 2,
7: 2,
}
assert nx.dfs_predecessors(self.D, source=2, depth_limit=3) == {
8: 7,
9: 8,
3: 2,
7: 2,
}
def test_dls_tree(self):
T = nx.dfs_tree(self.G, source=3, depth_limit=1)
assert sorted(T.edges()) == [(3, 2), (3, 4)]
def test_dls_edges(self):
edges = nx.dfs_edges(self.G, source=9, depth_limit=4)
assert list(edges) == [(9, 8), (8, 7), (7, 2), (2, 1), (2, 3), (9, 10)]
def test_dls_labeled_edges(self):
edges = list(nx.dfs_labeled_edges(self.G, source=5, depth_limit=1))
forward = [(u, v) for (u, v, d) in edges if d == "forward"]
assert forward == [(5, 5), (5, 4), (5, 6)]
def test_dls_labeled_disconnected_edges(self):
edges = list(nx.dfs_labeled_edges(self.G, source=6, depth_limit=2))
forward = [(u, v) for (u, v, d) in edges if d == "forward"]
assert forward == [(6, 6), (6, 5), (5, 4)]

View file

@ -0,0 +1,151 @@
import pytest
import networkx as nx
edge_bfs = nx.edge_bfs
FORWARD = nx.algorithms.edgedfs.FORWARD
REVERSE = nx.algorithms.edgedfs.REVERSE
class TestEdgeBFS:
@classmethod
def setup_class(cls):
cls.nodes = [0, 1, 2, 3]
cls.edges = [(0, 1), (1, 0), (1, 0), (2, 0), (2, 1), (3, 1)]
def test_empty(self):
G = nx.Graph()
edges = list(edge_bfs(G))
assert edges == []
def test_graph_single_source(self):
G = nx.Graph(self.edges)
G.add_edge(4, 5)
x = list(edge_bfs(G, [0]))
x_ = [(0, 1), (0, 2), (1, 2), (1, 3)]
assert x == x_
def test_graph(self):
G = nx.Graph(self.edges)
x = list(edge_bfs(G, self.nodes))
x_ = [(0, 1), (0, 2), (1, 2), (1, 3)]
assert x == x_
def test_digraph(self):
G = nx.DiGraph(self.edges)
x = list(edge_bfs(G, self.nodes))
x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)]
assert x == x_
def test_digraph_orientation_invalid(self):
G = nx.DiGraph(self.edges)
edge_iterator = edge_bfs(G, self.nodes, orientation="hello")
pytest.raises(nx.NetworkXError, list, edge_iterator)
def test_digraph_orientation_none(self):
G = nx.DiGraph(self.edges)
x = list(edge_bfs(G, self.nodes, orientation=None))
x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)]
assert x == x_
def test_digraph_orientation_original(self):
G = nx.DiGraph(self.edges)
x = list(edge_bfs(G, self.nodes, orientation="original"))
x_ = [
(0, 1, FORWARD),
(1, 0, FORWARD),
(2, 0, FORWARD),
(2, 1, FORWARD),
(3, 1, FORWARD),
]
assert x == x_
def test_digraph2(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
x = list(edge_bfs(G, [0]))
x_ = [(0, 1), (1, 2), (2, 3)]
assert x == x_
def test_digraph_rev(self):
G = nx.DiGraph(self.edges)
x = list(edge_bfs(G, self.nodes, orientation="reverse"))
x_ = [
(1, 0, REVERSE),
(2, 0, REVERSE),
(0, 1, REVERSE),
(2, 1, REVERSE),
(3, 1, REVERSE),
]
assert x == x_
def test_digraph_rev2(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
x = list(edge_bfs(G, [3], orientation="reverse"))
x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)]
assert x == x_
def test_multigraph(self):
G = nx.MultiGraph(self.edges)
x = list(edge_bfs(G, self.nodes))
x_ = [(0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (1, 2, 0), (1, 3, 0)]
# This is an example of where hash randomization can break.
# There are 3! * 2 alternative outputs, such as:
# [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)]
# But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k)
# edges. So the algorithm only guarantees a partial order. A total
# order is guaranteed only if the graph data structures are ordered.
assert x == x_
def test_multidigraph(self):
G = nx.MultiDiGraph(self.edges)
x = list(edge_bfs(G, self.nodes))
x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0), (3, 1, 0)]
assert x == x_
def test_multidigraph_rev(self):
G = nx.MultiDiGraph(self.edges)
x = list(edge_bfs(G, self.nodes, orientation="reverse"))
x_ = [
(1, 0, 0, REVERSE),
(1, 0, 1, REVERSE),
(2, 0, 0, REVERSE),
(0, 1, 0, REVERSE),
(2, 1, 0, REVERSE),
(3, 1, 0, REVERSE),
]
assert x == x_
def test_digraph_ignore(self):
G = nx.DiGraph(self.edges)
x = list(edge_bfs(G, self.nodes, orientation="ignore"))
x_ = [
(0, 1, FORWARD),
(1, 0, REVERSE),
(2, 0, REVERSE),
(2, 1, REVERSE),
(3, 1, REVERSE),
]
assert x == x_
def test_digraph_ignore2(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
x = list(edge_bfs(G, [0], orientation="ignore"))
x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)]
assert x == x_
def test_multidigraph_ignore(self):
G = nx.MultiDiGraph(self.edges)
x = list(edge_bfs(G, self.nodes, orientation="ignore"))
x_ = [
(0, 1, 0, FORWARD),
(1, 0, 0, REVERSE),
(1, 0, 1, REVERSE),
(2, 0, 0, REVERSE),
(2, 1, 0, REVERSE),
(3, 1, 0, REVERSE),
]
assert x == x_

View file

@ -0,0 +1,134 @@
import pytest
import networkx as nx
edge_dfs = nx.algorithms.edge_dfs
FORWARD = nx.algorithms.edgedfs.FORWARD
REVERSE = nx.algorithms.edgedfs.REVERSE
# These tests can fail with hash randomization. The easiest and clearest way
# to write these unit tests is for the edges to be output in an expected total
# order, but we cannot guarantee the order amongst outgoing edges from a node,
# unless each class uses an ordered data structure for neighbors. This is
# painful to do with the current API. The alternative is that the tests are
# written (IMO confusingly) so that there is not a total order over the edges,
# but only a partial order. Due to the small size of the graphs, hopefully
# failures due to hash randomization will not occur. For an example of how
# this can fail, see TestEdgeDFS.test_multigraph.
class TestEdgeDFS:
@classmethod
def setup_class(cls):
cls.nodes = [0, 1, 2, 3]
cls.edges = [(0, 1), (1, 0), (1, 0), (2, 1), (3, 1)]
def test_empty(self):
G = nx.Graph()
edges = list(edge_dfs(G))
assert edges == []
def test_graph(self):
G = nx.Graph(self.edges)
x = list(edge_dfs(G, self.nodes))
x_ = [(0, 1), (1, 2), (1, 3)]
assert x == x_
def test_digraph(self):
G = nx.DiGraph(self.edges)
x = list(edge_dfs(G, self.nodes))
x_ = [(0, 1), (1, 0), (2, 1), (3, 1)]
assert x == x_
def test_digraph_orientation_invalid(self):
G = nx.DiGraph(self.edges)
edge_iterator = edge_dfs(G, self.nodes, orientation="hello")
pytest.raises(nx.NetworkXError, list, edge_iterator)
def test_digraph_orientation_none(self):
G = nx.DiGraph(self.edges)
x = list(edge_dfs(G, self.nodes, orientation=None))
x_ = [(0, 1), (1, 0), (2, 1), (3, 1)]
assert x == x_
def test_digraph_orientation_original(self):
G = nx.DiGraph(self.edges)
x = list(edge_dfs(G, self.nodes, orientation="original"))
x_ = [(0, 1, FORWARD), (1, 0, FORWARD), (2, 1, FORWARD), (3, 1, FORWARD)]
assert x == x_
def test_digraph2(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
x = list(edge_dfs(G, [0]))
x_ = [(0, 1), (1, 2), (2, 3)]
assert x == x_
def test_digraph_rev(self):
G = nx.DiGraph(self.edges)
x = list(edge_dfs(G, self.nodes, orientation="reverse"))
x_ = [(1, 0, REVERSE), (0, 1, REVERSE), (2, 1, REVERSE), (3, 1, REVERSE)]
assert x == x_
def test_digraph_rev2(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
x = list(edge_dfs(G, [3], orientation="reverse"))
x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)]
assert x == x_
def test_multigraph(self):
G = nx.MultiGraph(self.edges)
x = list(edge_dfs(G, self.nodes))
x_ = [(0, 1, 0), (1, 0, 1), (0, 1, 2), (1, 2, 0), (1, 3, 0)]
# This is an example of where hash randomization can break.
# There are 3! * 2 alternative outputs, such as:
# [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)]
# But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k)
# edges. So the algorithm only guarantees a partial order. A total
# order is guaranteed only if the graph data structures are ordered.
assert x == x_
def test_multidigraph(self):
G = nx.MultiDiGraph(self.edges)
x = list(edge_dfs(G, self.nodes))
x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 1, 0), (3, 1, 0)]
assert x == x_
def test_multidigraph_rev(self):
G = nx.MultiDiGraph(self.edges)
x = list(edge_dfs(G, self.nodes, orientation="reverse"))
x_ = [
(1, 0, 0, REVERSE),
(0, 1, 0, REVERSE),
(1, 0, 1, REVERSE),
(2, 1, 0, REVERSE),
(3, 1, 0, REVERSE),
]
assert x == x_
def test_digraph_ignore(self):
G = nx.DiGraph(self.edges)
x = list(edge_dfs(G, self.nodes, orientation="ignore"))
x_ = [(0, 1, FORWARD), (1, 0, FORWARD), (2, 1, REVERSE), (3, 1, REVERSE)]
assert x == x_
def test_digraph_ignore2(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
x = list(edge_dfs(G, [0], orientation="ignore"))
x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)]
assert x == x_
def test_multidigraph_ignore(self):
G = nx.MultiDiGraph(self.edges)
x = list(edge_dfs(G, self.nodes, orientation="ignore"))
x_ = [
(0, 1, 0, FORWARD),
(1, 0, 0, FORWARD),
(1, 0, 1, REVERSE),
(2, 1, 0, REVERSE),
(3, 1, 0, REVERSE),
]
assert x == x_