mirror of
https://github.com/boostorg/graph.git
synced 2026-01-19 04:12:11 +00:00
Update maximum_weighted_matching documentation
This commit is contained in:
@@ -453,6 +453,11 @@ Journal of the ACM (JACM), 23(2): 221-234, 1976.
|
||||
<em>Data Structures for Weighted Matching and Nearest Common Ancestors with Linking</em><br>
|
||||
Proceedings of the First Annual ACM-SIAM Symposium on Discrete Algorithms, pp. 434-443, 1990.
|
||||
|
||||
<p></p><dt><a name="galil86">77</a>
|
||||
<dd>Zvi Galil<br>
|
||||
<em><a href="https://dl.acm.org/doi/pdf/10.1145/6462.6502">Efficient Algorithms for Finding Maximum Matching in Graphs</a></em><br>
|
||||
ACM Computing Surveys (CSUR), 18(1), 23-38, 1986.
|
||||
|
||||
</dl>
|
||||
|
||||
<br>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<html><head><!--
|
||||
Copyright 2018 Yi Ji
|
||||
Copyright 2025 Joris van Rantwijk
|
||||
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -20,6 +21,9 @@ void maximum_weighted_matching(const Graph& g, MateMap mate);
|
||||
template <typename Graph, typename MateMap, typename VertexIndexMap>
|
||||
void maximum_weighted_matching(const Graph& g, MateMap mate, VertexIndexMap vm);
|
||||
|
||||
template <typename Graph, typename MateMap, typename VertexIndexMap, typename EdgeWeightMap, bool Verify = true>
|
||||
void maximum_weighted_matching(const Graph& g, MateMap mate, VertexIndexMap vm, EdgeWeightMap weights);
|
||||
|
||||
template <typename Graph, typename MateMap>
|
||||
void brute_force_maximum_weighted_matching(const Graph& g, MateMap mate);
|
||||
|
||||
@@ -56,77 +60,109 @@ maximum weighted matching in any undirected graph. The matching is returned in a
|
||||
<a href="../../property_map/doc/ReadWritePropertyMap.html">ReadWritePropertyMap</a>
|
||||
that maps vertices to vertices. In the mapping returned, each vertex is either mapped
|
||||
to the vertex it's matched to, or to <tt>graph_traits<Graph>::null_vertex()</tt> if it
|
||||
doesn't participate in the matching. If no <tt>VertexIndexMap</tt> is provided, both functions
|
||||
assume that the <tt>VertexIndexMap</tt> is provided as an internal graph property accessible
|
||||
by calling <tt>get(vertex_index, g)</tt>.
|
||||
doesn't participate in the matching.
|
||||
</p>
|
||||
|
||||
<h3>Algorithm Description</h3>
|
||||
|
||||
<p>
|
||||
The maximum weighted matching problem was solved by Edmonds in [<a href="bibliography.html#edmonds65:_max_weighted_match">74</a>].
|
||||
The implementation of <tt>maximum_weighted_matching</tt> followed Chapter 6, Section 10 of [<a href="bibliography.html#lawler76:_comb_opt">20</a>] and
|
||||
was written in a consistent style with <tt>edmonds_maximum_cardinality_matching</tt> because of their algorithmic similarity.
|
||||
In addition, a brute-force verifier <tt>brute_force_maximum_weighted_matching</tt> simply searches all possible matchings in any graph and selects one with the maximum weight sum.
|
||||
|
||||
</p><h3>Algorithm Description</h3>
|
||||
|
||||
Primal-dual method in linear programming is introduced to solve weighted matching problems. Edmonds proved that for any graph,
|
||||
the maximum number of edges in a matching is equal to the minimum capacity of an odd-set cover; this further enable us to prove a max-min duality theorem for weighted matching.
|
||||
Let <i>H<sub>k-1</sub></i> denote any graph obtained from G by contracting odd sets of three or more nodes and deleting single nodes,
|
||||
where the capacity of the family of odd sets (not necessarily a cover of G) is <i>k-1</i>. Let <i>X<sub>k</sub></i> denote any matching containing <i>k</i> edges.
|
||||
Each edge <i>(i, j)</i> has a weight <i>w<sub>ij</sub></i>. We have:
|
||||
<math>
|
||||
max<i><sub>X<sub>k</sub></sub></i> min {<i>w<sub>ij</sub>|(i, j) ϵ X<sub>k</sub></i>} = min<i><sub>H<sub>k-1</sub></sub></i> max {<i>w<sub>ij</sub>|(i, j) ϵ H<sub>k-1</sub></i>}.
|
||||
</math>
|
||||
This matching duality theorem gives an indication of how the matching problem should be formulated as a linear programming problem. That is,
|
||||
the theorem suggests a set of linear inequalities which are satisfied by any matching, and it is anticipated that these inequalities describe a convex polyhedron
|
||||
with integer vertices corresponding to feasible matchings.
|
||||
The maximum weighted matching problem was solved by Edmonds in
|
||||
[<a href="bibliography.html#edmonds65:_max_weighted_match">74</a>].
|
||||
Subsequently, Gabow [<a href="bibliography.html#gabow76">75</a>] and
|
||||
Lawler [<a href="bibliography.html#lawler76:_comb_opt">20</a>] developed methods
|
||||
to reduce the run time from <i>O(V<sup>4</sup>)</i> to <i>O(V<sup>3</sup>)</i>.
|
||||
The implementation of <tt>maximum_weighted_matching</tt> follows a description
|
||||
of the <i>O(V<sup>3</sup>)</i> algorithm by Galil [<a href="bibliography.html#galil86">77</a>].
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For <tt>maximum_weighted_matching</tt>, the management of blossoms is much more involved than in the case of <tt>max_cardinality_matching</tt>.
|
||||
It is not sufficient to record only the outermost blossoms. When an outermost blossom is expanded,
|
||||
it is necessary to know which blossom are nested immediately with it, so that these blossoms can be restored to the status of the outermost blossoms.
|
||||
When augmentation occurs, blossoms with strictly positive dual variables must be maintained for use in the next application of the labeling procedure.
|
||||
Starting from an empty matching, the algorithm repeatedly augments the matching until no further improvement is possible.
|
||||
Alternating trees and blossoms are used to find an augmenting path, in a way that is similar to maximum cardinality matching.
|
||||
A linear programming technique is used to ensure that the selected augmenting path has maximum weight.
|
||||
This involves assigning dual variables to vertices and blossoms, and computing slack values for edges.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The outline of the algorithm is as follow:
|
||||
The outline of the algorithm is as follows:
|
||||
</p>
|
||||
|
||||
<ol start="0">
|
||||
<li>Start with an empty matching and initialize dual variables as a half of maximum edge weight.</li>
|
||||
<li>(Labeling) Root an alternate tree at each exposed node, and proceed to construct alternate trees by labeling, using only edges with zero slack value.
|
||||
<li>Start with an empty matching and initialize dual variables to half of the maximum edge weight.</li>
|
||||
<li>(Labeling) Root an alternate tree at each non-matched vertex, and proceed to construct alternate trees by labeling, using only edges with zero slack value.
|
||||
If an augmenting path is found, go to step 2. If a blossom is formed, go to step 3. Otherwise, go to step 4. </li>
|
||||
<li>(Augmentation) Find the augmenting path, tracing the path through shrunken blossoms. Augment the matching,
|
||||
correct labels on nodes in the augmenting path, expand blossoms with zero dual variables and remove labels from all base nodes. Go to step 1.</li>
|
||||
<li>(Blossoming) Determine the membership and base node of the new blossom and supply missing labels for all non-base nodes in the blossom.
|
||||
<li>(Augmentation) Find the augmenting path, tracing the path through shrunken blossoms. Augment the matching.
|
||||
Deconstruct and unlabel the alternating trees traversed by the augmenting path.
|
||||
Go to step 1.</li>
|
||||
<li>(Blossoming) Identify the blossoms in the alternating cycle and shrink these into a newly formed blossom.
|
||||
Return to step 1.</li>
|
||||
<li>(Revision of Dual Solution) Adjust the dual variables based on the primal-dual method. Go to step 1 or halt, accordingly.</li>
|
||||
<li>(Updating dual variables) Adjust the dual variables based on the primal-dual method.
|
||||
If this enables further growth of the alternating trees, return to step 1.
|
||||
Otherwise, halt the algorithm; the matching has maximum weight.</li>
|
||||
</ol>
|
||||
|
||||
Note that in <tt>maximum_weighted_matching</tt>, all edge weights are multiplied by 4, so that all dual variables always remain as integers if all edge weights are integers.
|
||||
Unlike <tt>max_cardinality_matching</tt>, the initial matching and augmenting path finder are not parameterized,
|
||||
because the algorithm maintains blossoms, dual variables and node labels across all augmentations.
|
||||
<p>
|
||||
The implementation deviates from the description in [<a href="bibliography.html#galil86">77</a>] on a few points:
|
||||
</p>
|
||||
|
||||
The algorithm's time complexity is reduced from <i>O(V<sup>4</sup>)</i> (naive implementation of [<a href="bibliography.html#edmonds65:_max_weighted_match">74</a>])
|
||||
to <i>O(V<sup>3</sup>)</i>, by a delicate labeling procedure [<a href="bibliography.html#gabow76">75</a>] to avoid re-scanning labels after revision of the dual solution.
|
||||
Special variables <i>pi, tau, gamma</i> and two arrays <i>critical_edge, tau_idx</i> are introduced for this purpose.
|
||||
Please refer to [<a href="bibliography.html#lawler76:_comb_opt">20</a>] and code comments for more implementation details.
|
||||
<ul>
|
||||
<li>After augmenting the matching, blossoms with zero dual are not expanded right away.
|
||||
Expanding such blossoms is correct, but potentially unnecessary.
|
||||
If expansion is required, it will eventually happen by assigning label T and going through a zero-delta dual update.</li>
|
||||
<li>After augmenting, labels and alternating trees are reused for the next round.
|
||||
Labels are erased only from the two alternating trees that are touched by the augmenting path.
|
||||
Although this strategy does not change the worst-case time complexity of the algorithm, it appears to provide a significant speedup for random graphs.</li>
|
||||
<li>The algorithm keeps track of the minimum-slack edge <i>e<sub>k,l</sub></i> for each pair of blossoms.
|
||||
Storing these edges in a 2-dimensional array would increase the space complexity to <i>O(V<sup>2</sup>)</i>.
|
||||
This is avoided by storing each row of the array as a list <tt>best_edge_set</tt> that contains only the non-empty elements.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If edge weights are integers, the algorithm uses only integer computations.
|
||||
This is achieved by internally multiplying edge weights by 2, which ensures that all dual variables are also integers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
After computing the maximum matching, a verification step may be performed to check that the matching is optimal.
|
||||
The verification step is simpler and faster (<i>O(V<sup>2</sup>)</i>) than the search for the matching.
|
||||
It always succeeds unless there is a bug in the matching algorithm.
|
||||
Since verification checks for exact optimality, it can only be used if edge weights are integers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In addition, a brute-force implementation <tt>brute_force_maximum_weighted_matching</tt> is provided.
|
||||
This algorithm simply searches all possible matchings and selects one with the maximum weight sum.
|
||||
</p>
|
||||
|
||||
</p><h3>Where Defined</h3>
|
||||
|
||||
<p>
|
||||
<a href="../../../boost/graph/maximum_weighted_matching.hpp"><tt>boost/graph/maximum_weighted_matching.hpp</tt></a>
|
||||
</p>
|
||||
|
||||
</p><h3>Parameters</h3>
|
||||
<h3>Parameters</h3>
|
||||
|
||||
IN: <tt>const Graph& g</tt>
|
||||
<blockquote>
|
||||
An undirected graph. The graph type must be a model of
|
||||
<a href="VertexAndEdgeListGraph.html">Vertex and Edge List Graph</a> and
|
||||
<a href="IncidenceGraph.html">Incidence Graph</a>.
|
||||
The edge property of the graph <tt>property_map<Graph, edge_weight_t></tt> must exist and have numeric value type.<br>
|
||||
The graph may not contain parallel edges.
|
||||
</blockquote>
|
||||
|
||||
IN: <tt>VertexIndexMap vm</tt>
|
||||
<blockquote>
|
||||
Must be a model of <a href="../../property_map/doc/ReadablePropertyMap.html">ReadablePropertyMap</a>, mapping vertices to integer indices.
|
||||
Must be a model of <a href="../../property_map/doc/ReadablePropertyMap.html">ReadablePropertyMap</a>,
|
||||
mapping vertices to integer indices in the range <tt>[0, num_vertices(g))</tt>.
|
||||
If this parameter is not explicitly specified, it is obtained from the internal vertex property of the graph
|
||||
by calling <tt>get(vertex_index, g)</tt>.
|
||||
</blockquote>
|
||||
|
||||
IN: <tt>EdgeWeightMap weights</tt>
|
||||
<blockquote>
|
||||
Must be a model of <a href="../../property_map/doc/ReadablePropertyMap.html">ReadablePropertyMap</a>, mapping edges to weights.
|
||||
Edge weights must be integers or floating point values.
|
||||
If this parameter is not explicitly specified, it is obtained from the internal edge property of the graph
|
||||
by calling <tt>get(edge_weight, g)</tt>.
|
||||
</blockquote>
|
||||
|
||||
OUT: <tt>MateMap mate</tt>
|
||||
@@ -140,24 +176,29 @@ vertices to vertices. For any vertex v in the graph, <tt>get(mate,v)</tt> will b
|
||||
|
||||
<p>
|
||||
Let <i>m</i> and <i>n</i> be the number of edges and vertices in the input graph, respectively. Assuming the
|
||||
<tt>VertexIndexMap</tt> supplied allows constant-time lookup, the time complexity for
|
||||
<tt>maximum_weighted_matching</tt> is <i>O(n<sup>3</sup>)</i>. For <tt>brute_force_maximum_weighted_matching</tt>, the time complexity is exponential of <i>m</i>.
|
||||
<tt>VertexIndexMap</tt> and <tt>EdgeWeightMap</tt> both provide constant-time lookup, the time complexity for
|
||||
<tt>maximum_weighted_matching</tt> is <i>O(n<sup>3</sup>)</i>.
|
||||
For <tt>brute_force_maximum_weighted_matching</tt>, the time complexity is exponential of <i>m</i>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that the best known time complexity for maximum weighted matching in general graph
|
||||
is <i>O(nm+n<sup>2</sup>log(n))</i> by [<a href="bibliography.html#gabow90">76</a>], but relies on an
|
||||
efficient algorithm for solving nearest ancestor problem on trees, which is not provided in Boost C++ libraries.
|
||||
</p><p>
|
||||
</p>
|
||||
|
||||
</p><h3>Example</h3>
|
||||
<h3>Example</h3>
|
||||
|
||||
<p> The file <a href="../example/weighted_matching_example.cpp"><tt>example/weighted_matching_example.cpp</tt></a>
|
||||
<p>The file <a href="../example/weighted_matching_example.cpp"><tt>example/weighted_matching_example.cpp</tt></a>
|
||||
contains an example.
|
||||
</p>
|
||||
|
||||
<br>
|
||||
</p><hr>
|
||||
<hr>
|
||||
<table>
|
||||
<tbody><tr valign="top">
|
||||
<td nowrap="nowrap">Copyright © 2018</td><td>
|
||||
Yi Ji (<a href="mailto:jiy@pku.edu.cn">jiy@pku.edu.cn</a>)<br>
|
||||
<td nowrap="nowrap">Copyright © 2018, 2025</td><td>
|
||||
Yi Ji (<a href="mailto:jiy@pku.edu.cn">jiy@pku.edu.cn</a>),
|
||||
Joris van Rantwijk
|
||||
</td></tr></tbody></table>
|
||||
|
||||
</body></html>
|
||||
|
||||
Reference in New Issue
Block a user