Test coverage of verification routine
This commit is contained in:
parent
4dc7befd9d
commit
8f81154169
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import unittest
|
import unittest
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
import max_weight_matching
|
||||||
from max_weight_matching import (
|
from max_weight_matching import (
|
||||||
maximum_weight_matching as mwm,
|
maximum_weight_matching as mwm,
|
||||||
adjust_weights_for_maximum_cardinality_matching as adj,
|
adjust_weights_for_maximum_cardinality_matching as adj)
|
||||||
_GraphInfo)
|
|
||||||
|
|
||||||
|
|
||||||
class TestMaximumWeightMatching(unittest.TestCase):
|
class TestMaximumWeightMatching(unittest.TestCase):
|
||||||
|
@ -267,12 +268,150 @@ class TestGraphInfo(unittest.TestCase):
|
||||||
"""Test _GraphInfo helper class."""
|
"""Test _GraphInfo helper class."""
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
graph = _GraphInfo([])
|
graph = max_weight_matching._GraphInfo([])
|
||||||
self.assertEqual(graph.num_vertex, 0)
|
self.assertEqual(graph.num_vertex, 0)
|
||||||
self.assertEqual(graph.edges, [])
|
self.assertEqual(graph.edges, [])
|
||||||
self.assertEqual(graph.adjacent_edges, [])
|
self.assertEqual(graph.adjacent_edges, [])
|
||||||
|
|
||||||
|
|
||||||
|
class TestVerificationFail(unittest.TestCase):
|
||||||
|
"""Test failure handling in verification routine."""
|
||||||
|
|
||||||
|
def _make_context(
|
||||||
|
self,
|
||||||
|
edges,
|
||||||
|
vertex_mate,
|
||||||
|
vertex_dual_2x,
|
||||||
|
nontrivial_blossom):
|
||||||
|
ctx = Mock(spec=max_weight_matching._MatchingContext)
|
||||||
|
ctx.graph = max_weight_matching._GraphInfo(edges)
|
||||||
|
ctx.vertex_mate = vertex_mate
|
||||||
|
ctx.vertex_dual_2x = vertex_dual_2x
|
||||||
|
ctx.nontrivial_blossom = nontrivial_blossom
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
def test_success(self):
|
||||||
|
edges = [(0,1,10), (1,2,11)]
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[-1, 2, 1],
|
||||||
|
vertex_dual_2x=[0, 20, 2],
|
||||||
|
nontrivial_blossom=[])
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_asymmetric_matching(self):
|
||||||
|
edges = [(0,1,10), (1,2,11)]
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[-1, 2, 0],
|
||||||
|
vertex_dual_2x=[0, 20, 2],
|
||||||
|
nontrivial_blossom=[])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_nonexistent_matched_edge(self):
|
||||||
|
edges = [(0,1,10), (1,2,11)]
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[2, -1, 0],
|
||||||
|
vertex_dual_2x=[11, 11, 11],
|
||||||
|
nontrivial_blossom=[])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_negative_vertex_dual(self):
|
||||||
|
edges = [(0,1,10), (1,2,11)]
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[-1, 2, 1],
|
||||||
|
vertex_dual_2x=[-2, 22, 0],
|
||||||
|
nontrivial_blossom=[])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_unmatched_nonzero_dual(self):
|
||||||
|
edges = [(0,1,10), (1,2,11)]
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[-1, 2, 1],
|
||||||
|
vertex_dual_2x=[9, 11, 11],
|
||||||
|
nontrivial_blossom=[])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_negative_edge_slack(self):
|
||||||
|
edges = [(0,1,10), (1,2,11)]
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[-1, 2, 1],
|
||||||
|
vertex_dual_2x=[0, 11, 11],
|
||||||
|
nontrivial_blossom=[])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_matched_edge_slack(self):
|
||||||
|
edges = [(0,1,10), (1,2,11)]
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[-1, 2, 1],
|
||||||
|
vertex_dual_2x=[0, 20, 11],
|
||||||
|
nontrivial_blossom=[])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_negative_blossom_dual(self):
|
||||||
|
#
|
||||||
|
# [0]--7--[1]--9--[2]--6--[3]
|
||||||
|
# \ /
|
||||||
|
# \----8-----/
|
||||||
|
#
|
||||||
|
edges = [(0,1,7), (0,2,8), (1,2,9), (2,3,6)]
|
||||||
|
blossom = max_weight_matching._NonTrivialBlossom(
|
||||||
|
subblossoms=[
|
||||||
|
max_weight_matching._Blossom(0),
|
||||||
|
max_weight_matching._Blossom(1),
|
||||||
|
max_weight_matching._Blossom(2)],
|
||||||
|
edges=[0,2,1])
|
||||||
|
for sub in blossom.subblossoms:
|
||||||
|
sub.parent = blossom
|
||||||
|
blossom.dual_var = -1
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[1, 0, 3, 2],
|
||||||
|
vertex_dual_2x=[4, 6, 8, 4],
|
||||||
|
nontrivial_blossom=[blossom])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
def test_blossom_not_full(self):
|
||||||
|
#
|
||||||
|
# [3] [4]
|
||||||
|
# | |
|
||||||
|
# 8 8
|
||||||
|
# | |
|
||||||
|
# [0]--7--[1]--5--[2]
|
||||||
|
# \ /
|
||||||
|
# \----2-----/
|
||||||
|
#
|
||||||
|
edges = [(0,1,7), (0,2,2), (1,2,5), (0,3,8), (1,4,8)]
|
||||||
|
blossom = max_weight_matching._NonTrivialBlossom(
|
||||||
|
subblossoms=[
|
||||||
|
max_weight_matching._Blossom(0),
|
||||||
|
max_weight_matching._Blossom(1),
|
||||||
|
max_weight_matching._Blossom(2)],
|
||||||
|
edges=[0,2,1])
|
||||||
|
for sub in blossom.subblossoms:
|
||||||
|
sub.parent = blossom
|
||||||
|
blossom.dual_var = 2
|
||||||
|
ctx = self._make_context(
|
||||||
|
edges,
|
||||||
|
vertex_mate=[3, 4, -1, 0, 1],
|
||||||
|
vertex_dual_2x=[4, 10, 0, 12, 6],
|
||||||
|
nontrivial_blossom=[blossom])
|
||||||
|
with self.assertRaises(max_weight_matching.MatchingError):
|
||||||
|
max_weight_matching._verify_optimum(ctx)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue