From 0e79e1d2f6f3dd79e03f3a6e77ccb06b890601d2 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Thu, 6 Apr 2023 20:50:06 +0200 Subject: [PATCH] Use FIFO queue for S-vertices --- python/mwmatching.py | 8 ++++---- python/test_mwmatching.py | 35 ++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/python/mwmatching.py b/python/mwmatching.py index 5ec7880..4fee51b 100644 --- a/python/mwmatching.py +++ b/python/mwmatching.py @@ -6,6 +6,7 @@ from __future__ import annotations import sys import math +import collections from collections.abc import Sequence from typing import NamedTuple, Optional @@ -545,9 +546,8 @@ class _MatchingContext: # between "x" and any S-vertex, or -1 if no such edge has been found. self.vertex_best_edge: list[int] = num_vertex * [-1] - # "queue" is a list of S-vertices that must be scanned. - # We call it a queue, but it is actually a stack. - self.queue: list[int] = [] + # Queue of S-vertices to be scanned. + self.queue: collections.deque[int] = collections.deque() def edge_slack_2x(self, e: int) -> int|float: """Return 2 times the slack of the edge with index "e". @@ -1361,7 +1361,7 @@ class _MatchingContext: while self.queue: # Take a vertex from the queue. - x = self.queue.pop() + x = self.queue.popleft() # Double-check that "x" is an S-vertex. bx = self.vertex_top_blossom[x] diff --git a/python/test_mwmatching.py b/python/test_mwmatching.py index 07b50d7..b3340ab 100644 --- a/python/test_mwmatching.py +++ b/python/test_mwmatching.py @@ -194,22 +194,22 @@ class TestMaximumWeightMatching(unittest.TestCase): def test46_expand_unlabeled_blossom(self): """expand blossom before assigning label T""" # - # 5--[2]--3--[4] - # / | - # [0]--5--[1] 5 - # \ | - # 5--[3]--3--[5] + # 3--[1] + # / | + # [2]--1--[4] 7 + # \ | + # 5--[3]--5--[5] # - self.assertEqual( - mwm([(0,1,5), (1,2,5), (1,3,5), (2,3,5), (2,4,3), (3,5,3)]), - [(0,1), (2,4), (3,5)]) + self.assertIn( + mwm([(1,3,7), (1,4,3), (2,4,1), (3,4,5), (3,5,5)]), + ([(1,3), (2,4)], [(1,4), (3,5)])) def test47_expand_unlabeled_outer(self): """expand outer blossom before assigning label T""" # # [3]--10--[1]--15--[2]--12--[5] # _/ \_ | | - # 11 16_ 8 15 + # 11 16_ 8 15 # / \ | | # [4] [6]---7--[7] # @@ -217,6 +217,19 @@ class TestMaximumWeightMatching(unittest.TestCase): mwm([(1,2,15), (1,3,10), (1,4,11), (1,6,17), (2,5,12), (2,6,8), (5,7,15), (6,7,7)]), [(1,4), (2,6), (5,7)]) + def test48_expand_unlabeled_nested(self): + """expand nested blossom before assigning label T""" + # + # [5]--11--[1]--11 14--[3] + # | \ / | + # 12 [4] 14 + # | / \ | + # [6]--11--[2]--12 11--[7] + # + self.assertEqual( + mwm([(1,2,12), (1,4,11), (1,5,11), (2,4,12), (2,6,11), (3,4,14), (3,7,14), (4,7,11)]), + [(1,5), (2,4), (3,7)]) + def test_fail_bad_input(self): """bad input values""" with self.assertRaises(TypeError): @@ -315,6 +328,10 @@ class TestCornerCases(unittest.TestCase): pairs = mwm([(0,2,13), (1,2,11), (2,3,39), (2,4,17), (3,4,35)]) self.assertEqual(pairs, [(0,2), (3,4)]) + def test17(self): + pairs = mwm([(0,1,48), (0,2,44), (0,4,48), (1,4,36), (3,4,31)]) + self.assertEqual(pairs, [(0,2), (1,4)]) + class TestAdjustWeightForMaxCardinality(unittest.TestCase): """Test adjust_weights_for_maximum_cardinality_matching() function."""