-
Notifications
You must be signed in to change notification settings - Fork 21
Rewrite test_metis.py to test exposed functions #44
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
import itertools | ||
import nose.tools | ||
|
||
import networkx as nx | ||
|
||
import nxmetis | ||
from nxmetis import exceptions | ||
from nxmetis import _metis | ||
from nxmetis import types | ||
|
@@ -17,59 +20,81 @@ def make_cycle(n): | |
|
||
class TestMetis(object): | ||
|
||
def test_node_nd(self): | ||
n = 16 | ||
xadj, adjncy = make_cycle(n) | ||
perm, iperm = _metis.node_nd(xadj, adjncy) | ||
nose.tools.assert_equal(set(perm), set(range(n))) | ||
nose.tools.assert_equal(abs(perm[-1] - perm[-2]), n // 2) | ||
nose.tools.ok_(set(range(min(perm[-2:]) + 1, max(perm[-2:]))) in | ||
(set(perm[0:n // 2 - 1]), set(perm[n // 2 - 1:-2]))) | ||
nose.tools.ok_(all(i == perm[iperm[i]] for i in range(n))) | ||
|
||
def test_selfloops(self): | ||
n = 16 | ||
xadj = list(range(0, 3 * n + 1, 3)) | ||
adjncy = list( | ||
itertools.chain.from_iterable( | ||
zip(itertools.chain([n - 1], range(n - 1)), | ||
range(n), | ||
itertools.chain(range(1, n), [0])))) | ||
perm, iperm = _metis.node_nd(xadj, adjncy) | ||
nose.tools.assert_equal(set(perm), set(range(n))) | ||
nose.tools.assert_equal(abs(perm[-1] - perm[-2]), n // 2) | ||
nose.tools.ok_(set(range(min(perm[-2:]) + 1, max(perm[-2:]))) in | ||
(set(perm[0:n // 2 - 1]), set(perm[n // 2 - 1:-2]))) | ||
nose.tools.ok_(all(i == perm[iperm[i]] for i in range(n))) | ||
|
||
def test_part_graph(self): | ||
n = 16 | ||
xadj, adjncy = make_cycle(n) | ||
for recursive in (False, True): | ||
objval, part = _metis.part_graph( | ||
xadj, adjncy, 2, recursive=recursive) | ||
nose.tools.assert_equal(objval, 2) | ||
nose.tools.assert_equal(set(part), set(range(2))) | ||
it = itertools.dropwhile(lambda x: x == 0, itertools.cycle(part)) | ||
nose.tools.assert_equal( | ||
list(itertools.takewhile(lambda x: x == 1, it)), [1] * (n // 2)) | ||
|
||
def test_compute_vertex_separator(self): | ||
n = 16 | ||
xadj, adjncy = make_cycle(n) | ||
sepsize, part = _metis.compute_vertex_separator(xadj, adjncy) | ||
nose.tools.assert_equal(sepsize, 2) | ||
nose.tools.assert_equal(len(part), n) | ||
part1, part2, sep = (list(filter(lambda i: part[i] == k, range(n))) | ||
for k in range(3)) | ||
nose.tools.assert_equal(sorted(part1 + part2 + sep), list(range(n))) | ||
def setUp(self): | ||
self.node_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', | ||
1, 2, 3, 4, 5, 6] | ||
self.G = nx.Graph() | ||
self.G.add_path(self.node_list) | ||
self.G.add_edge(self.node_list[-1], self.node_list[0]) | ||
|
||
def test_node_nested_dissection_unweighted(self): | ||
node_ordering = nxmetis.node_nested_dissection(self.G) | ||
nose.tools.assert_equal(len(self.G), len(node_ordering)) | ||
nose.tools.assert_equal(set(self.G), set(node_ordering)) | ||
|
||
# Tests for exercising package's ability to handle self-loops | ||
# METIS crashes on self loops. networkx-metis should not | ||
self.G.add_edge(1, 1) | ||
self.G.add_edge('a', 'a') | ||
node_ordering = nxmetis.node_nested_dissection(self.G) | ||
nose.tools.assert_equal(len(self.G), len(node_ordering)) | ||
nose.tools.assert_equal(set(self.G), set(node_ordering)) | ||
|
||
def test_partition(self): | ||
partition = nxmetis.partition(self.G, 4) | ||
# When we choose one node from one part of the partitioned Graph, | ||
# It must be adjacent to one or more of the nodes in the same part. | ||
# This is to verify the continuity of the chain of nodes. | ||
parts = partition[1] # List containing partitioned node lists | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please keep this loops as the underlying METIS functions are different. |
||
|
||
nose.tools.assert_equal(list(partition)[0], 4) | ||
|
||
for part in parts: | ||
nose.tools.assert_not_equal(0, len(part)) # Non-empty set | ||
nose.tools.assert_equal(len(part), len(set(part))) # Duplicate-free | ||
nose.tools.ok_(nx.is_connected(self.G.subgraph(part))) # Connected | ||
|
||
# Disjoint sets | ||
for part1, part2 in itertools.combinations(parts, 2): | ||
nose.tools.assert_equal(set(), set(part1) & set(part2)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about exhaustiveness? |
||
|
||
# These parts must be exhaustive with the node list of the Graph | ||
parts_combined = parts[0] + parts[1] + parts[2] + parts[3] | ||
nose.tools.assert_equal(set(parts_combined), set(self.G)) | ||
|
||
def test_vertex_separator(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simplify this test the same way as |
||
bisection = nxmetis.vertex_separator(self.G) | ||
sep, part1, part2 = nxmetis.vertex_separator(self.G) | ||
|
||
# The two separator nodes must not be present in the | ||
# two bisected chains | ||
nose.tools.ok_(sep[0] not in part1) | ||
nose.tools.ok_(sep[0] not in part2) | ||
nose.tools.ok_(sep[1] not in part1) | ||
nose.tools.ok_(sep[1] not in part2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to first check that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
# There should be two different separator nodes | ||
nose.tools.assert_equal(len(sep), 2) | ||
nose.tools.assert_equal(abs(sep[1] - sep[0]), n // 2) | ||
nose.tools.assert_equal( | ||
sorted(map(sorted, [part1, part2])), | ||
sorted(map(sorted, | ||
[[(sep[0] + i) % n for i in range(1, n // 2)], | ||
[(sep[1] + i) % n for i in range(1, n // 2)]]))) | ||
nose.tools.assert_not_equal(sep[0], sep[1]) | ||
|
||
# The lists should be exhaustive with the node list of the Graph | ||
nose.tools.assert_equal(set(sep) | set(part1) | set(part2), | ||
set(self.G)) | ||
|
||
# The parts must be disjoint sets | ||
nose.tools.assert_equal(set(), set(part1) & set(part2)) | ||
|
||
# Non-empty set | ||
nose.tools.assert_not_equal(len(part1), 0) | ||
nose.tools.assert_not_equal(len(part2), 0) | ||
|
||
# Duplicate-free | ||
nose.tools.assert_equal(len(part1), len(set(part1))) | ||
nose.tools.assert_equal(len(part2), len(set(part2))) | ||
|
||
# Connected | ||
nose.tools.ok_(nx.is_connected(self.G.subgraph(part1))) | ||
nose.tools.ok_(nx.is_connected(self.G.subgraph(part2))) | ||
|
||
def test_MetisOptions(self): | ||
n = 16 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test that exercises the package's ability to handle self loops. IIRC, METIS crashes when you have self loops in graphs.