From 4c6115fb2fc4c225a1ea4750f89084d0ae580b66 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Sun, 30 Jun 2024 21:38:12 +0200 Subject: [PATCH] Improve comments and docstrings --- python/mwmatching.py | 56 +++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/python/mwmatching.py b/python/mwmatching.py index 874331c..d49b95f 100644 --- a/python/mwmatching.py +++ b/python/mwmatching.py @@ -371,13 +371,13 @@ class _Blossom: # vertex in the blossom. self.base_vertex: int = base_vertex - # A top-level blossom that are part of an alternating tree, - # has labels S or T. Unlabeled top-level blossoms are not (yet) - # part of any alternating tree. + # A top-level blossom that is part of an alternating tree, + # has label S or T. An unlabeled top-level blossom is not part + # of any alternating tree. self.label: int = _LABEL_NONE - # Labeled top-level blossoms keep track of the edge through which - # they are attached to an alternating tree. + # A labeled top-level blossoms keeps track of the edge through which + # it is attached to the alternating tree. # # "tree_edge = (x, y)" if the blossom is attached to an alternating # tree via edge "(x, y)" and vertex "y" is contained in the blossom. @@ -401,7 +401,8 @@ class _Blossom: # queue. self.delta2_node: Optional[PriorityQueue.Node] = None - # Support variable for lazy updating of vertex dual variables. + # This variable holds pending lazy updates to the dual variables + # of the vertices inside the blossom. self.vertex_dual_offset: float = 0 # "marker" is a temporary variable used to discover common @@ -556,7 +557,7 @@ class _MatchingContext: # "vertex_set_node[x]" represents the vertex "x" inside the # union-find datastructure of its top-level blossom. # - # Initially, each vertex belongs to its owwn trivial top-level blossom. + # Initially, each vertex belongs to its own trivial top-level blossom. self.vertex_set_node = [b.vertex_set.insert(i, math.inf) for (i, b) in enumerate(self.trivial_blossom)] @@ -754,7 +755,7 @@ class _MatchingContext: It is assumed that the blossom containing "x" has already been disabled for delta2 tracking. - This function takes time O(k * log(n)), + This function takes time O(k + log(n)), where "k" is the number of edges incident on "x". """ self.vertex_sedge_queue[x].clear() @@ -861,7 +862,14 @@ class _MatchingContext: # def assign_blossom_label_s(self, blossom: _Blossom) -> None: - """Change an unlabeled top-level blossom into an S-blossom.""" + """Change an unlabeled top-level blossom into an S-blossom. + + For a blossom with "j" vertices and "k" incident edges, + this function takes time O(j * log(n) + k). + + This function is called at most once per blossom per stage. + It therefore takes total time O(n * log(n) + m) per stage. + """ assert blossom.parent is None assert blossom.label == _LABEL_NONE @@ -911,7 +919,10 @@ class _MatchingContext: self.scan_queue.extend(vertices) def assign_blossom_label_t(self, blossom: _Blossom) -> None: - """Change an unlabeled top-level blossom into a T-blossom.""" + """Change an unlabeled top-level blossom into a T-blossom. + + This function takes time O(log(n)). + """ assert blossom.parent is None assert blossom.label == _LABEL_NONE @@ -1005,7 +1016,10 @@ class _MatchingContext: self.delta2_remove_edge(e, y, by) def remove_blossom_label_t(self, blossom: _Blossom) -> None: - """Change a top-level T-blossom into an unlabeled blossom.""" + """Change a top-level T-blossom into an unlabeled blossom. + + This function takes time O(log(n)). + """ assert blossom.parent is None assert blossom.label == _LABEL_T @@ -1028,7 +1042,10 @@ class _MatchingContext: self.delta2_enable_blossom(blossom) def change_s_blossom_to_subblossom(self, blossom: _Blossom) -> None: - """Change a top-level S-blossom into an S-subblossom.""" + """Change a top-level S-blossom into an S-subblossom. + + This function takes time O(1). + """ assert blossom.parent is None assert blossom.label == _LABEL_S @@ -1180,7 +1197,7 @@ class _MatchingContext: Assign label S to the new blossom. Relabel all T-sub-blossoms as S and add their vertices to the queue. - This function takes total time O(n * log(n)) per stage. + This function takes total time O((n + m) * log(n)) per stage. """ # Check that the path is odd-length. @@ -1273,7 +1290,7 @@ class _MatchingContext: def expand_unlabeled_blossom(self, blossom: _NonTrivialBlossom) -> None: """Expand the specified unlabeled blossom. - This function takes total time O(n*log(n)) per stage. + This function takes total time O(n * log(n)) per stage. """ assert blossom.parent is None @@ -1305,7 +1322,7 @@ class _MatchingContext: def expand_t_blossom(self, blossom: _NonTrivialBlossom) -> None: """Expand the specified T-blossom. - This function takes total time O(n*log(n)) per stage. + This function takes total time O(n * log(n) + m) per stage. """ assert blossom.parent is None @@ -1713,8 +1730,9 @@ class _MatchingContext: where "k" is the number of intra-blossom edges removed from the delta3 queue. - Since each edge can be inserted into the delta3 queue at most - once per stage, this function takes total time O((n + m) * log(n)) + At most O(n) delta steps can occur during a stage. + Each edge can be inserted into the delta3 queue at most once per stage. + Therefore, this function takes total time O((n + m) * log(n)) per stage. Returns: @@ -1770,7 +1788,7 @@ class _MatchingContext: Assign label S to all vertices and add them to the scan queue. - This function takes time O(n). + This function takes time O(n + m). It is called once, at the beginning of the algorithm. """ for x in range(self.graph.num_vertex): @@ -1857,7 +1875,7 @@ class _MatchingContext: Also applies delayed updates to dual variables. Also resets tracking of least-slack edges. - This function takes time O(n * log(n)). + This function takes time O((n + m) * log(n)). It is called once, at the end of the algorithm. """