lemongraph 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +8 -0
- data/LICENSE +674 -0
- data/README.md +6 -0
- data/ext/lemon-1.3.1/AUTHORS +26 -0
- data/ext/lemon-1.3.1/CMakeLists.txt +371 -0
- data/ext/lemon-1.3.1/INSTALL +167 -0
- data/ext/lemon-1.3.1/LICENSE +32 -0
- data/ext/lemon-1.3.1/NEWS +337 -0
- data/ext/lemon-1.3.1/README +50 -0
- data/ext/lemon-1.3.1/cmake/FindCOIN.cmake +110 -0
- data/ext/lemon-1.3.1/cmake/FindGLPK.cmake +55 -0
- data/ext/lemon-1.3.1/cmake/FindGhostscript.cmake +10 -0
- data/ext/lemon-1.3.1/cmake/FindILOG.cmake +102 -0
- data/ext/lemon-1.3.1/cmake/FindSOPLEX.cmake +23 -0
- data/ext/lemon-1.3.1/cmake/LEMONConfig.cmake.in +13 -0
- data/ext/lemon-1.3.1/cmake/nsis/lemon.ico +0 -0
- data/ext/lemon-1.3.1/cmake/nsis/uninstall.ico +0 -0
- data/ext/lemon-1.3.1/cmake/version.cmake +1 -0
- data/ext/lemon-1.3.1/cmake/version.cmake.in +1 -0
- data/ext/lemon-1.3.1/contrib/CMakeLists.txt +19 -0
- data/ext/lemon-1.3.1/lemon/CMakeLists.txt +91 -0
- data/ext/lemon-1.3.1/lemon/adaptors.h +3638 -0
- data/ext/lemon-1.3.1/lemon/arg_parser.cc +474 -0
- data/ext/lemon-1.3.1/lemon/arg_parser.h +440 -0
- data/ext/lemon-1.3.1/lemon/assert.h +214 -0
- data/ext/lemon-1.3.1/lemon/base.cc +37 -0
- data/ext/lemon-1.3.1/lemon/bellman_ford.h +1116 -0
- data/ext/lemon-1.3.1/lemon/bfs.h +1754 -0
- data/ext/lemon-1.3.1/lemon/bin_heap.h +347 -0
- data/ext/lemon-1.3.1/lemon/binomial_heap.h +445 -0
- data/ext/lemon-1.3.1/lemon/bits/alteration_notifier.h +472 -0
- data/ext/lemon-1.3.1/lemon/bits/array_map.h +351 -0
- data/ext/lemon-1.3.1/lemon/bits/bezier.h +174 -0
- data/ext/lemon-1.3.1/lemon/bits/default_map.h +182 -0
- data/ext/lemon-1.3.1/lemon/bits/edge_set_extender.h +627 -0
- data/ext/lemon-1.3.1/lemon/bits/enable_if.h +131 -0
- data/ext/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h +401 -0
- data/ext/lemon-1.3.1/lemon/bits/graph_extender.h +1332 -0
- data/ext/lemon-1.3.1/lemon/bits/lock.h +65 -0
- data/ext/lemon-1.3.1/lemon/bits/map_extender.h +332 -0
- data/ext/lemon-1.3.1/lemon/bits/path_dump.h +177 -0
- data/ext/lemon-1.3.1/lemon/bits/solver_bits.h +194 -0
- data/ext/lemon-1.3.1/lemon/bits/traits.h +388 -0
- data/ext/lemon-1.3.1/lemon/bits/variant.h +494 -0
- data/ext/lemon-1.3.1/lemon/bits/vector_map.h +244 -0
- data/ext/lemon-1.3.1/lemon/bits/windows.cc +166 -0
- data/ext/lemon-1.3.1/lemon/bits/windows.h +44 -0
- data/ext/lemon-1.3.1/lemon/bucket_heap.h +594 -0
- data/ext/lemon-1.3.1/lemon/capacity_scaling.h +1014 -0
- data/ext/lemon-1.3.1/lemon/cbc.cc +460 -0
- data/ext/lemon-1.3.1/lemon/cbc.h +129 -0
- data/ext/lemon-1.3.1/lemon/christofides_tsp.h +254 -0
- data/ext/lemon-1.3.1/lemon/circulation.h +807 -0
- data/ext/lemon-1.3.1/lemon/clp.cc +464 -0
- data/ext/lemon-1.3.1/lemon/clp.h +164 -0
- data/ext/lemon-1.3.1/lemon/color.cc +44 -0
- data/ext/lemon-1.3.1/lemon/color.h +204 -0
- data/ext/lemon-1.3.1/lemon/concept_check.h +77 -0
- data/ext/lemon-1.3.1/lemon/concepts/bpgraph.h +1029 -0
- data/ext/lemon-1.3.1/lemon/concepts/digraph.h +491 -0
- data/ext/lemon-1.3.1/lemon/concepts/graph.h +788 -0
- data/ext/lemon-1.3.1/lemon/concepts/graph_components.h +2134 -0
- data/ext/lemon-1.3.1/lemon/concepts/heap.h +324 -0
- data/ext/lemon-1.3.1/lemon/concepts/maps.h +223 -0
- data/ext/lemon-1.3.1/lemon/concepts/path.h +312 -0
- data/ext/lemon-1.3.1/lemon/config.h.in +22 -0
- data/ext/lemon-1.3.1/lemon/connectivity.h +1688 -0
- data/ext/lemon-1.3.1/lemon/core.h +2506 -0
- data/ext/lemon-1.3.1/lemon/cost_scaling.h +1607 -0
- data/ext/lemon-1.3.1/lemon/counter.h +249 -0
- data/ext/lemon-1.3.1/lemon/cplex.cc +994 -0
- data/ext/lemon-1.3.1/lemon/cplex.h +292 -0
- data/ext/lemon-1.3.1/lemon/cycle_canceling.h +1230 -0
- data/ext/lemon-1.3.1/lemon/dfs.h +1637 -0
- data/ext/lemon-1.3.1/lemon/dheap.h +352 -0
- data/ext/lemon-1.3.1/lemon/dijkstra.h +1303 -0
- data/ext/lemon-1.3.1/lemon/dim2.h +726 -0
- data/ext/lemon-1.3.1/lemon/dimacs.h +448 -0
- data/ext/lemon-1.3.1/lemon/edge_set.h +1420 -0
- data/ext/lemon-1.3.1/lemon/edmonds_karp.h +556 -0
- data/ext/lemon-1.3.1/lemon/elevator.h +982 -0
- data/ext/lemon-1.3.1/lemon/error.h +276 -0
- data/ext/lemon-1.3.1/lemon/euler.h +287 -0
- data/ext/lemon-1.3.1/lemon/fib_heap.h +475 -0
- data/ext/lemon-1.3.1/lemon/fractional_matching.h +2139 -0
- data/ext/lemon-1.3.1/lemon/full_graph.h +1082 -0
- data/ext/lemon-1.3.1/lemon/glpk.cc +1012 -0
- data/ext/lemon-1.3.1/lemon/glpk.h +263 -0
- data/ext/lemon-1.3.1/lemon/gomory_hu.h +568 -0
- data/ext/lemon-1.3.1/lemon/graph_to_eps.h +1186 -0
- data/ext/lemon-1.3.1/lemon/greedy_tsp.h +251 -0
- data/ext/lemon-1.3.1/lemon/grid_graph.h +699 -0
- data/ext/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h +840 -0
- data/ext/lemon-1.3.1/lemon/hao_orlin.h +1015 -0
- data/ext/lemon-1.3.1/lemon/hartmann_orlin_mmc.h +654 -0
- data/ext/lemon-1.3.1/lemon/howard_mmc.h +651 -0
- data/ext/lemon-1.3.1/lemon/hypercube_graph.h +459 -0
- data/ext/lemon-1.3.1/lemon/insertion_tsp.h +533 -0
- data/ext/lemon-1.3.1/lemon/karp_mmc.h +590 -0
- data/ext/lemon-1.3.1/lemon/kruskal.h +324 -0
- data/ext/lemon-1.3.1/lemon/lemon.pc.in +10 -0
- data/ext/lemon-1.3.1/lemon/lgf_reader.h +3854 -0
- data/ext/lemon-1.3.1/lemon/lgf_writer.h +2687 -0
- data/ext/lemon-1.3.1/lemon/list_graph.h +2510 -0
- data/ext/lemon-1.3.1/lemon/lp.h +95 -0
- data/ext/lemon-1.3.1/lemon/lp_base.cc +30 -0
- data/ext/lemon-1.3.1/lemon/lp_base.h +2147 -0
- data/ext/lemon-1.3.1/lemon/lp_skeleton.cc +143 -0
- data/ext/lemon-1.3.1/lemon/lp_skeleton.h +234 -0
- data/ext/lemon-1.3.1/lemon/maps.h +4057 -0
- data/ext/lemon-1.3.1/lemon/matching.h +3505 -0
- data/ext/lemon-1.3.1/lemon/math.h +77 -0
- data/ext/lemon-1.3.1/lemon/max_cardinality_search.h +794 -0
- data/ext/lemon-1.3.1/lemon/min_cost_arborescence.h +808 -0
- data/ext/lemon-1.3.1/lemon/nagamochi_ibaraki.h +702 -0
- data/ext/lemon-1.3.1/lemon/nauty_reader.h +113 -0
- data/ext/lemon-1.3.1/lemon/nearest_neighbor_tsp.h +238 -0
- data/ext/lemon-1.3.1/lemon/network_simplex.h +1659 -0
- data/ext/lemon-1.3.1/lemon/opt2_tsp.h +367 -0
- data/ext/lemon-1.3.1/lemon/pairing_heap.h +474 -0
- data/ext/lemon-1.3.1/lemon/path.h +1164 -0
- data/ext/lemon-1.3.1/lemon/planarity.h +2754 -0
- data/ext/lemon-1.3.1/lemon/preflow.h +985 -0
- data/ext/lemon-1.3.1/lemon/quad_heap.h +343 -0
- data/ext/lemon-1.3.1/lemon/radix_heap.h +438 -0
- data/ext/lemon-1.3.1/lemon/radix_sort.h +487 -0
- data/ext/lemon-1.3.1/lemon/random.cc +29 -0
- data/ext/lemon-1.3.1/lemon/random.h +1005 -0
- data/ext/lemon-1.3.1/lemon/smart_graph.h +1344 -0
- data/ext/lemon-1.3.1/lemon/soplex.cc +465 -0
- data/ext/lemon-1.3.1/lemon/soplex.h +158 -0
- data/ext/lemon-1.3.1/lemon/static_graph.h +476 -0
- data/ext/lemon-1.3.1/lemon/suurballe.h +776 -0
- data/ext/lemon-1.3.1/lemon/time_measure.h +610 -0
- data/ext/lemon-1.3.1/lemon/tolerance.h +242 -0
- data/ext/lemon-1.3.1/lemon/unionfind.h +1824 -0
- data/ext/lemon-1.3.1/scripts/unify-sources.sh +390 -0
- data/ext/lemon-1.3.1/scripts/valgrind-wrapper.sh +22 -0
- data/ext/lemongraph/arc_map.cc +1007 -0
- data/ext/lemongraph/digraph.cc +282 -0
- data/ext/lemongraph/digraph_arc.cc +153 -0
- data/ext/lemongraph/digraph_node.cc +277 -0
- data/ext/lemongraph/edge_map.cc +770 -0
- data/ext/lemongraph/extconf.rb +53 -0
- data/ext/lemongraph/graph.cc +351 -0
- data/ext/lemongraph/graph_arc.cc +95 -0
- data/ext/lemongraph/graph_edge.cc +153 -0
- data/ext/lemongraph/graph_item.cc +76 -0
- data/ext/lemongraph/graph_node.cc +321 -0
- data/ext/lemongraph/lemongraph.cc +260 -0
- data/ext/lemongraph/lemongraph.hh +295 -0
- data/ext/lemongraph/lemongraph.map +6 -0
- data/ext/lemongraph/lemongraph_export.hh +31 -0
- data/ext/lemongraph/node_map.cc +1011 -0
- data/lemongraph.gemspec +176 -0
- data/lib/lemongraph/graphviz.rb +240 -0
- data/lib/lemongraph/version.rb +4 -0
- data/lib/lemongraph.rb +21 -0
- data/samples/lemondeps.rb +38 -0
- metadata +202 -0
|
@@ -0,0 +1,3505 @@
|
|
|
1
|
+
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
|
2
|
+
*
|
|
3
|
+
* This file is a part of LEMON, a generic C++ optimization library.
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2003-2013
|
|
6
|
+
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
|
7
|
+
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
|
8
|
+
*
|
|
9
|
+
* Permission to use, modify and distribute this software is granted
|
|
10
|
+
* provided that this copyright notice appears in all copies. For
|
|
11
|
+
* precise terms see the accompanying LICENSE file.
|
|
12
|
+
*
|
|
13
|
+
* This software is provided "AS IS" with no warranty of any kind,
|
|
14
|
+
* express or implied, and with no claim as to its suitability for any
|
|
15
|
+
* purpose.
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#ifndef LEMON_MATCHING_H
|
|
20
|
+
#define LEMON_MATCHING_H
|
|
21
|
+
|
|
22
|
+
#include <vector>
|
|
23
|
+
#include <queue>
|
|
24
|
+
#include <set>
|
|
25
|
+
#include <limits>
|
|
26
|
+
|
|
27
|
+
#include <lemon/core.h>
|
|
28
|
+
#include <lemon/unionfind.h>
|
|
29
|
+
#include <lemon/bin_heap.h>
|
|
30
|
+
#include <lemon/maps.h>
|
|
31
|
+
#include <lemon/fractional_matching.h>
|
|
32
|
+
|
|
33
|
+
///\ingroup matching
|
|
34
|
+
///\file
|
|
35
|
+
///\brief Maximum matching algorithms in general graphs.
|
|
36
|
+
|
|
37
|
+
namespace lemon {
|
|
38
|
+
|
|
39
|
+
/// \ingroup matching
|
|
40
|
+
///
|
|
41
|
+
/// \brief Maximum cardinality matching in general graphs
|
|
42
|
+
///
|
|
43
|
+
/// This class implements Edmonds' alternating forest matching algorithm
|
|
44
|
+
/// for finding a maximum cardinality matching in a general undirected graph.
|
|
45
|
+
/// It can be started from an arbitrary initial matching
|
|
46
|
+
/// (the default is the empty one).
|
|
47
|
+
///
|
|
48
|
+
/// The dual solution of the problem is a map of the nodes to
|
|
49
|
+
/// \ref MaxMatching::Status "Status", having values \c EVEN (or \c D),
|
|
50
|
+
/// \c ODD (or \c A) and \c MATCHED (or \c C) defining the Gallai-Edmonds
|
|
51
|
+
/// decomposition of the graph. The nodes in \c EVEN/D induce a subgraph
|
|
52
|
+
/// with factor-critical components, the nodes in \c ODD/A form the
|
|
53
|
+
/// canonical barrier, and the nodes in \c MATCHED/C induce a graph having
|
|
54
|
+
/// a perfect matching. The number of the factor-critical components
|
|
55
|
+
/// minus the number of barrier nodes is a lower bound on the
|
|
56
|
+
/// unmatched nodes, and the matching is optimal if and only if this bound is
|
|
57
|
+
/// tight. This decomposition can be obtained using \ref status() or
|
|
58
|
+
/// \ref statusMap() after running the algorithm.
|
|
59
|
+
///
|
|
60
|
+
/// \tparam GR The undirected graph type the algorithm runs on.
|
|
61
|
+
template <typename GR>
|
|
62
|
+
class MaxMatching {
|
|
63
|
+
public:
|
|
64
|
+
|
|
65
|
+
/// The graph type of the algorithm
|
|
66
|
+
typedef GR Graph;
|
|
67
|
+
/// The type of the matching map
|
|
68
|
+
typedef typename Graph::template NodeMap<typename Graph::Arc>
|
|
69
|
+
MatchingMap;
|
|
70
|
+
|
|
71
|
+
///\brief Status constants for Gallai-Edmonds decomposition.
|
|
72
|
+
///
|
|
73
|
+
///These constants are used for indicating the Gallai-Edmonds
|
|
74
|
+
///decomposition of a graph. The nodes with status \c EVEN (or \c D)
|
|
75
|
+
///induce a subgraph with factor-critical components, the nodes with
|
|
76
|
+
///status \c ODD (or \c A) form the canonical barrier, and the nodes
|
|
77
|
+
///with status \c MATCHED (or \c C) induce a subgraph having a
|
|
78
|
+
///perfect matching.
|
|
79
|
+
enum Status {
|
|
80
|
+
EVEN = 1, ///< = 1. (\c D is an alias for \c EVEN.)
|
|
81
|
+
D = 1,
|
|
82
|
+
MATCHED = 0, ///< = 0. (\c C is an alias for \c MATCHED.)
|
|
83
|
+
C = 0,
|
|
84
|
+
ODD = -1, ///< = -1. (\c A is an alias for \c ODD.)
|
|
85
|
+
A = -1,
|
|
86
|
+
UNMATCHED = -2 ///< = -2.
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/// The type of the status map
|
|
90
|
+
typedef typename Graph::template NodeMap<Status> StatusMap;
|
|
91
|
+
|
|
92
|
+
private:
|
|
93
|
+
|
|
94
|
+
TEMPLATE_GRAPH_TYPEDEFS(Graph);
|
|
95
|
+
|
|
96
|
+
typedef UnionFindEnum<IntNodeMap> BlossomSet;
|
|
97
|
+
typedef ExtendFindEnum<IntNodeMap> TreeSet;
|
|
98
|
+
typedef RangeMap<Node> NodeIntMap;
|
|
99
|
+
typedef MatchingMap EarMap;
|
|
100
|
+
typedef std::vector<Node> NodeQueue;
|
|
101
|
+
|
|
102
|
+
const Graph& _graph;
|
|
103
|
+
MatchingMap* _matching;
|
|
104
|
+
StatusMap* _status;
|
|
105
|
+
|
|
106
|
+
EarMap* _ear;
|
|
107
|
+
|
|
108
|
+
IntNodeMap* _blossom_set_index;
|
|
109
|
+
BlossomSet* _blossom_set;
|
|
110
|
+
NodeIntMap* _blossom_rep;
|
|
111
|
+
|
|
112
|
+
IntNodeMap* _tree_set_index;
|
|
113
|
+
TreeSet* _tree_set;
|
|
114
|
+
|
|
115
|
+
NodeQueue _node_queue;
|
|
116
|
+
int _process, _postpone, _last;
|
|
117
|
+
|
|
118
|
+
int _node_num;
|
|
119
|
+
|
|
120
|
+
private:
|
|
121
|
+
|
|
122
|
+
void createStructures() {
|
|
123
|
+
_node_num = countNodes(_graph);
|
|
124
|
+
if (!_matching) {
|
|
125
|
+
_matching = new MatchingMap(_graph);
|
|
126
|
+
}
|
|
127
|
+
if (!_status) {
|
|
128
|
+
_status = new StatusMap(_graph);
|
|
129
|
+
}
|
|
130
|
+
if (!_ear) {
|
|
131
|
+
_ear = new EarMap(_graph);
|
|
132
|
+
}
|
|
133
|
+
if (!_blossom_set) {
|
|
134
|
+
_blossom_set_index = new IntNodeMap(_graph);
|
|
135
|
+
_blossom_set = new BlossomSet(*_blossom_set_index);
|
|
136
|
+
}
|
|
137
|
+
if (!_blossom_rep) {
|
|
138
|
+
_blossom_rep = new NodeIntMap(_node_num);
|
|
139
|
+
}
|
|
140
|
+
if (!_tree_set) {
|
|
141
|
+
_tree_set_index = new IntNodeMap(_graph);
|
|
142
|
+
_tree_set = new TreeSet(*_tree_set_index);
|
|
143
|
+
}
|
|
144
|
+
_node_queue.resize(_node_num);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
void destroyStructures() {
|
|
148
|
+
if (_matching) {
|
|
149
|
+
delete _matching;
|
|
150
|
+
}
|
|
151
|
+
if (_status) {
|
|
152
|
+
delete _status;
|
|
153
|
+
}
|
|
154
|
+
if (_ear) {
|
|
155
|
+
delete _ear;
|
|
156
|
+
}
|
|
157
|
+
if (_blossom_set) {
|
|
158
|
+
delete _blossom_set;
|
|
159
|
+
delete _blossom_set_index;
|
|
160
|
+
}
|
|
161
|
+
if (_blossom_rep) {
|
|
162
|
+
delete _blossom_rep;
|
|
163
|
+
}
|
|
164
|
+
if (_tree_set) {
|
|
165
|
+
delete _tree_set_index;
|
|
166
|
+
delete _tree_set;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
void processDense(const Node& n) {
|
|
171
|
+
_process = _postpone = _last = 0;
|
|
172
|
+
_node_queue[_last++] = n;
|
|
173
|
+
|
|
174
|
+
while (_process != _last) {
|
|
175
|
+
Node u = _node_queue[_process++];
|
|
176
|
+
for (OutArcIt a(_graph, u); a != INVALID; ++a) {
|
|
177
|
+
Node v = _graph.target(a);
|
|
178
|
+
if ((*_status)[v] == MATCHED) {
|
|
179
|
+
extendOnArc(a);
|
|
180
|
+
} else if ((*_status)[v] == UNMATCHED) {
|
|
181
|
+
augmentOnArc(a);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
while (_postpone != _last) {
|
|
188
|
+
Node u = _node_queue[_postpone++];
|
|
189
|
+
|
|
190
|
+
for (OutArcIt a(_graph, u); a != INVALID ; ++a) {
|
|
191
|
+
Node v = _graph.target(a);
|
|
192
|
+
|
|
193
|
+
if ((*_status)[v] == EVEN) {
|
|
194
|
+
if (_blossom_set->find(u) != _blossom_set->find(v)) {
|
|
195
|
+
shrinkOnEdge(a);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
while (_process != _last) {
|
|
200
|
+
Node w = _node_queue[_process++];
|
|
201
|
+
for (OutArcIt b(_graph, w); b != INVALID; ++b) {
|
|
202
|
+
Node x = _graph.target(b);
|
|
203
|
+
if ((*_status)[x] == MATCHED) {
|
|
204
|
+
extendOnArc(b);
|
|
205
|
+
} else if ((*_status)[x] == UNMATCHED) {
|
|
206
|
+
augmentOnArc(b);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
void processSparse(const Node& n) {
|
|
216
|
+
_process = _last = 0;
|
|
217
|
+
_node_queue[_last++] = n;
|
|
218
|
+
while (_process != _last) {
|
|
219
|
+
Node u = _node_queue[_process++];
|
|
220
|
+
for (OutArcIt a(_graph, u); a != INVALID; ++a) {
|
|
221
|
+
Node v = _graph.target(a);
|
|
222
|
+
|
|
223
|
+
if ((*_status)[v] == EVEN) {
|
|
224
|
+
if (_blossom_set->find(u) != _blossom_set->find(v)) {
|
|
225
|
+
shrinkOnEdge(a);
|
|
226
|
+
}
|
|
227
|
+
} else if ((*_status)[v] == MATCHED) {
|
|
228
|
+
extendOnArc(a);
|
|
229
|
+
} else if ((*_status)[v] == UNMATCHED) {
|
|
230
|
+
augmentOnArc(a);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
void shrinkOnEdge(const Edge& e) {
|
|
238
|
+
Node nca = INVALID;
|
|
239
|
+
|
|
240
|
+
{
|
|
241
|
+
std::set<Node> left_set, right_set;
|
|
242
|
+
|
|
243
|
+
Node left = (*_blossom_rep)[_blossom_set->find(_graph.u(e))];
|
|
244
|
+
left_set.insert(left);
|
|
245
|
+
|
|
246
|
+
Node right = (*_blossom_rep)[_blossom_set->find(_graph.v(e))];
|
|
247
|
+
right_set.insert(right);
|
|
248
|
+
|
|
249
|
+
while (true) {
|
|
250
|
+
if ((*_matching)[left] == INVALID) break;
|
|
251
|
+
left = _graph.target((*_matching)[left]);
|
|
252
|
+
left = (*_blossom_rep)[_blossom_set->
|
|
253
|
+
find(_graph.target((*_ear)[left]))];
|
|
254
|
+
if (right_set.find(left) != right_set.end()) {
|
|
255
|
+
nca = left;
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
left_set.insert(left);
|
|
259
|
+
|
|
260
|
+
if ((*_matching)[right] == INVALID) break;
|
|
261
|
+
right = _graph.target((*_matching)[right]);
|
|
262
|
+
right = (*_blossom_rep)[_blossom_set->
|
|
263
|
+
find(_graph.target((*_ear)[right]))];
|
|
264
|
+
if (left_set.find(right) != left_set.end()) {
|
|
265
|
+
nca = right;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
right_set.insert(right);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (nca == INVALID) {
|
|
272
|
+
if ((*_matching)[left] == INVALID) {
|
|
273
|
+
nca = right;
|
|
274
|
+
while (left_set.find(nca) == left_set.end()) {
|
|
275
|
+
nca = _graph.target((*_matching)[nca]);
|
|
276
|
+
nca =(*_blossom_rep)[_blossom_set->
|
|
277
|
+
find(_graph.target((*_ear)[nca]))];
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
nca = left;
|
|
281
|
+
while (right_set.find(nca) == right_set.end()) {
|
|
282
|
+
nca = _graph.target((*_matching)[nca]);
|
|
283
|
+
nca = (*_blossom_rep)[_blossom_set->
|
|
284
|
+
find(_graph.target((*_ear)[nca]))];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
{
|
|
291
|
+
|
|
292
|
+
Node node = _graph.u(e);
|
|
293
|
+
Arc arc = _graph.direct(e, true);
|
|
294
|
+
Node base = (*_blossom_rep)[_blossom_set->find(node)];
|
|
295
|
+
|
|
296
|
+
while (base != nca) {
|
|
297
|
+
(*_ear)[node] = arc;
|
|
298
|
+
|
|
299
|
+
Node n = node;
|
|
300
|
+
while (n != base) {
|
|
301
|
+
n = _graph.target((*_matching)[n]);
|
|
302
|
+
Arc a = (*_ear)[n];
|
|
303
|
+
n = _graph.target(a);
|
|
304
|
+
(*_ear)[n] = _graph.oppositeArc(a);
|
|
305
|
+
}
|
|
306
|
+
node = _graph.target((*_matching)[base]);
|
|
307
|
+
_tree_set->erase(base);
|
|
308
|
+
_tree_set->erase(node);
|
|
309
|
+
_blossom_set->insert(node, _blossom_set->find(base));
|
|
310
|
+
(*_status)[node] = EVEN;
|
|
311
|
+
_node_queue[_last++] = node;
|
|
312
|
+
arc = _graph.oppositeArc((*_ear)[node]);
|
|
313
|
+
node = _graph.target((*_ear)[node]);
|
|
314
|
+
base = (*_blossom_rep)[_blossom_set->find(node)];
|
|
315
|
+
_blossom_set->join(_graph.target(arc), base);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
(*_blossom_rep)[_blossom_set->find(nca)] = nca;
|
|
320
|
+
|
|
321
|
+
{
|
|
322
|
+
|
|
323
|
+
Node node = _graph.v(e);
|
|
324
|
+
Arc arc = _graph.direct(e, false);
|
|
325
|
+
Node base = (*_blossom_rep)[_blossom_set->find(node)];
|
|
326
|
+
|
|
327
|
+
while (base != nca) {
|
|
328
|
+
(*_ear)[node] = arc;
|
|
329
|
+
|
|
330
|
+
Node n = node;
|
|
331
|
+
while (n != base) {
|
|
332
|
+
n = _graph.target((*_matching)[n]);
|
|
333
|
+
Arc a = (*_ear)[n];
|
|
334
|
+
n = _graph.target(a);
|
|
335
|
+
(*_ear)[n] = _graph.oppositeArc(a);
|
|
336
|
+
}
|
|
337
|
+
node = _graph.target((*_matching)[base]);
|
|
338
|
+
_tree_set->erase(base);
|
|
339
|
+
_tree_set->erase(node);
|
|
340
|
+
_blossom_set->insert(node, _blossom_set->find(base));
|
|
341
|
+
(*_status)[node] = EVEN;
|
|
342
|
+
_node_queue[_last++] = node;
|
|
343
|
+
arc = _graph.oppositeArc((*_ear)[node]);
|
|
344
|
+
node = _graph.target((*_ear)[node]);
|
|
345
|
+
base = (*_blossom_rep)[_blossom_set->find(node)];
|
|
346
|
+
_blossom_set->join(_graph.target(arc), base);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
(*_blossom_rep)[_blossom_set->find(nca)] = nca;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
void extendOnArc(const Arc& a) {
|
|
354
|
+
Node base = _graph.source(a);
|
|
355
|
+
Node odd = _graph.target(a);
|
|
356
|
+
|
|
357
|
+
(*_ear)[odd] = _graph.oppositeArc(a);
|
|
358
|
+
Node even = _graph.target((*_matching)[odd]);
|
|
359
|
+
(*_blossom_rep)[_blossom_set->insert(even)] = even;
|
|
360
|
+
(*_status)[odd] = ODD;
|
|
361
|
+
(*_status)[even] = EVEN;
|
|
362
|
+
int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(base)]);
|
|
363
|
+
_tree_set->insert(odd, tree);
|
|
364
|
+
_tree_set->insert(even, tree);
|
|
365
|
+
_node_queue[_last++] = even;
|
|
366
|
+
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
void augmentOnArc(const Arc& a) {
|
|
370
|
+
Node even = _graph.source(a);
|
|
371
|
+
Node odd = _graph.target(a);
|
|
372
|
+
|
|
373
|
+
int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(even)]);
|
|
374
|
+
|
|
375
|
+
(*_matching)[odd] = _graph.oppositeArc(a);
|
|
376
|
+
(*_status)[odd] = MATCHED;
|
|
377
|
+
|
|
378
|
+
Arc arc = (*_matching)[even];
|
|
379
|
+
(*_matching)[even] = a;
|
|
380
|
+
|
|
381
|
+
while (arc != INVALID) {
|
|
382
|
+
odd = _graph.target(arc);
|
|
383
|
+
arc = (*_ear)[odd];
|
|
384
|
+
even = _graph.target(arc);
|
|
385
|
+
(*_matching)[odd] = arc;
|
|
386
|
+
arc = (*_matching)[even];
|
|
387
|
+
(*_matching)[even] = _graph.oppositeArc((*_matching)[odd]);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
for (typename TreeSet::ItemIt it(*_tree_set, tree);
|
|
391
|
+
it != INVALID; ++it) {
|
|
392
|
+
if ((*_status)[it] == ODD) {
|
|
393
|
+
(*_status)[it] = MATCHED;
|
|
394
|
+
} else {
|
|
395
|
+
int blossom = _blossom_set->find(it);
|
|
396
|
+
for (typename BlossomSet::ItemIt jt(*_blossom_set, blossom);
|
|
397
|
+
jt != INVALID; ++jt) {
|
|
398
|
+
(*_status)[jt] = MATCHED;
|
|
399
|
+
}
|
|
400
|
+
_blossom_set->eraseClass(blossom);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
_tree_set->eraseClass(tree);
|
|
404
|
+
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
public:
|
|
408
|
+
|
|
409
|
+
/// \brief Constructor
|
|
410
|
+
///
|
|
411
|
+
/// Constructor.
|
|
412
|
+
MaxMatching(const Graph& graph)
|
|
413
|
+
: _graph(graph), _matching(0), _status(0), _ear(0),
|
|
414
|
+
_blossom_set_index(0), _blossom_set(0), _blossom_rep(0),
|
|
415
|
+
_tree_set_index(0), _tree_set(0) {}
|
|
416
|
+
|
|
417
|
+
~MaxMatching() {
|
|
418
|
+
destroyStructures();
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/// \name Execution Control
|
|
422
|
+
/// The simplest way to execute the algorithm is to use the
|
|
423
|
+
/// \c run() member function.\n
|
|
424
|
+
/// If you need better control on the execution, you have to call
|
|
425
|
+
/// one of the functions \ref init(), \ref greedyInit() or
|
|
426
|
+
/// \ref matchingInit() first, then you can start the algorithm with
|
|
427
|
+
/// \ref startSparse() or \ref startDense().
|
|
428
|
+
|
|
429
|
+
///@{
|
|
430
|
+
|
|
431
|
+
/// \brief Set the initial matching to the empty matching.
|
|
432
|
+
///
|
|
433
|
+
/// This function sets the initial matching to the empty matching.
|
|
434
|
+
void init() {
|
|
435
|
+
createStructures();
|
|
436
|
+
for(NodeIt n(_graph); n != INVALID; ++n) {
|
|
437
|
+
(*_matching)[n] = INVALID;
|
|
438
|
+
(*_status)[n] = UNMATCHED;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/// \brief Find an initial matching in a greedy way.
|
|
443
|
+
///
|
|
444
|
+
/// This function finds an initial matching in a greedy way.
|
|
445
|
+
void greedyInit() {
|
|
446
|
+
createStructures();
|
|
447
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
448
|
+
(*_matching)[n] = INVALID;
|
|
449
|
+
(*_status)[n] = UNMATCHED;
|
|
450
|
+
}
|
|
451
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
452
|
+
if ((*_matching)[n] == INVALID) {
|
|
453
|
+
for (OutArcIt a(_graph, n); a != INVALID ; ++a) {
|
|
454
|
+
Node v = _graph.target(a);
|
|
455
|
+
if ((*_matching)[v] == INVALID && v != n) {
|
|
456
|
+
(*_matching)[n] = a;
|
|
457
|
+
(*_status)[n] = MATCHED;
|
|
458
|
+
(*_matching)[v] = _graph.oppositeArc(a);
|
|
459
|
+
(*_status)[v] = MATCHED;
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
/// \brief Initialize the matching from a map.
|
|
469
|
+
///
|
|
470
|
+
/// This function initializes the matching from a \c bool valued edge
|
|
471
|
+
/// map. This map should have the property that there are no two incident
|
|
472
|
+
/// edges with \c true value, i.e. it really contains a matching.
|
|
473
|
+
/// \return \c true if the map contains a matching.
|
|
474
|
+
template <typename MatchingMap>
|
|
475
|
+
bool matchingInit(const MatchingMap& matching) {
|
|
476
|
+
createStructures();
|
|
477
|
+
|
|
478
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
479
|
+
(*_matching)[n] = INVALID;
|
|
480
|
+
(*_status)[n] = UNMATCHED;
|
|
481
|
+
}
|
|
482
|
+
for(EdgeIt e(_graph); e!=INVALID; ++e) {
|
|
483
|
+
if (matching[e]) {
|
|
484
|
+
|
|
485
|
+
Node u = _graph.u(e);
|
|
486
|
+
if ((*_matching)[u] != INVALID) return false;
|
|
487
|
+
(*_matching)[u] = _graph.direct(e, true);
|
|
488
|
+
(*_status)[u] = MATCHED;
|
|
489
|
+
|
|
490
|
+
Node v = _graph.v(e);
|
|
491
|
+
if ((*_matching)[v] != INVALID) return false;
|
|
492
|
+
(*_matching)[v] = _graph.direct(e, false);
|
|
493
|
+
(*_status)[v] = MATCHED;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/// \brief Start Edmonds' algorithm
|
|
500
|
+
///
|
|
501
|
+
/// This function runs the original Edmonds' algorithm.
|
|
502
|
+
///
|
|
503
|
+
/// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be
|
|
504
|
+
/// called before using this function.
|
|
505
|
+
void startSparse() {
|
|
506
|
+
for(NodeIt n(_graph); n != INVALID; ++n) {
|
|
507
|
+
if ((*_status)[n] == UNMATCHED) {
|
|
508
|
+
(*_blossom_rep)[_blossom_set->insert(n)] = n;
|
|
509
|
+
_tree_set->insert(n);
|
|
510
|
+
(*_status)[n] = EVEN;
|
|
511
|
+
processSparse(n);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/// \brief Start Edmonds' algorithm with a heuristic improvement
|
|
517
|
+
/// for dense graphs
|
|
518
|
+
///
|
|
519
|
+
/// This function runs Edmonds' algorithm with a heuristic of postponing
|
|
520
|
+
/// shrinks, therefore resulting in a faster algorithm for dense graphs.
|
|
521
|
+
///
|
|
522
|
+
/// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be
|
|
523
|
+
/// called before using this function.
|
|
524
|
+
void startDense() {
|
|
525
|
+
for(NodeIt n(_graph); n != INVALID; ++n) {
|
|
526
|
+
if ((*_status)[n] == UNMATCHED) {
|
|
527
|
+
(*_blossom_rep)[_blossom_set->insert(n)] = n;
|
|
528
|
+
_tree_set->insert(n);
|
|
529
|
+
(*_status)[n] = EVEN;
|
|
530
|
+
processDense(n);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
/// \brief Run Edmonds' algorithm
|
|
537
|
+
///
|
|
538
|
+
/// This function runs Edmonds' algorithm. An additional heuristic of
|
|
539
|
+
/// postponing shrinks is used for relatively dense graphs
|
|
540
|
+
/// (for which <tt>m>=2*n</tt> holds).
|
|
541
|
+
void run() {
|
|
542
|
+
if (countEdges(_graph) < 2 * countNodes(_graph)) {
|
|
543
|
+
greedyInit();
|
|
544
|
+
startSparse();
|
|
545
|
+
} else {
|
|
546
|
+
init();
|
|
547
|
+
startDense();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/// @}
|
|
552
|
+
|
|
553
|
+
/// \name Primal Solution
|
|
554
|
+
/// Functions to get the primal solution, i.e. the maximum matching.
|
|
555
|
+
|
|
556
|
+
/// @{
|
|
557
|
+
|
|
558
|
+
/// \brief Return the size (cardinality) of the matching.
|
|
559
|
+
///
|
|
560
|
+
/// This function returns the size (cardinality) of the current matching.
|
|
561
|
+
/// After run() it returns the size of the maximum matching in the graph.
|
|
562
|
+
int matchingSize() const {
|
|
563
|
+
int size = 0;
|
|
564
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
565
|
+
if ((*_matching)[n] != INVALID) {
|
|
566
|
+
++size;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return size / 2;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/// \brief Return \c true if the given edge is in the matching.
|
|
573
|
+
///
|
|
574
|
+
/// This function returns \c true if the given edge is in the current
|
|
575
|
+
/// matching.
|
|
576
|
+
bool matching(const Edge& edge) const {
|
|
577
|
+
return edge == (*_matching)[_graph.u(edge)];
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/// \brief Return the matching arc (or edge) incident to the given node.
|
|
581
|
+
///
|
|
582
|
+
/// This function returns the matching arc (or edge) incident to the
|
|
583
|
+
/// given node in the current matching or \c INVALID if the node is
|
|
584
|
+
/// not covered by the matching.
|
|
585
|
+
Arc matching(const Node& n) const {
|
|
586
|
+
return (*_matching)[n];
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/// \brief Return a const reference to the matching map.
|
|
590
|
+
///
|
|
591
|
+
/// This function returns a const reference to a node map that stores
|
|
592
|
+
/// the matching arc (or edge) incident to each node.
|
|
593
|
+
const MatchingMap& matchingMap() const {
|
|
594
|
+
return *_matching;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/// \brief Return the mate of the given node.
|
|
598
|
+
///
|
|
599
|
+
/// This function returns the mate of the given node in the current
|
|
600
|
+
/// matching or \c INVALID if the node is not covered by the matching.
|
|
601
|
+
Node mate(const Node& n) const {
|
|
602
|
+
return (*_matching)[n] != INVALID ?
|
|
603
|
+
_graph.target((*_matching)[n]) : INVALID;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/// @}
|
|
607
|
+
|
|
608
|
+
/// \name Dual Solution
|
|
609
|
+
/// Functions to get the dual solution, i.e. the Gallai-Edmonds
|
|
610
|
+
/// decomposition.
|
|
611
|
+
|
|
612
|
+
/// @{
|
|
613
|
+
|
|
614
|
+
/// \brief Return the status of the given node in the Edmonds-Gallai
|
|
615
|
+
/// decomposition.
|
|
616
|
+
///
|
|
617
|
+
/// This function returns the \ref Status "status" of the given node
|
|
618
|
+
/// in the Edmonds-Gallai decomposition.
|
|
619
|
+
Status status(const Node& n) const {
|
|
620
|
+
return (*_status)[n];
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/// \brief Return a const reference to the status map, which stores
|
|
624
|
+
/// the Edmonds-Gallai decomposition.
|
|
625
|
+
///
|
|
626
|
+
/// This function returns a const reference to a node map that stores the
|
|
627
|
+
/// \ref Status "status" of each node in the Edmonds-Gallai decomposition.
|
|
628
|
+
const StatusMap& statusMap() const {
|
|
629
|
+
return *_status;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/// \brief Return \c true if the given node is in the barrier.
|
|
633
|
+
///
|
|
634
|
+
/// This function returns \c true if the given node is in the barrier.
|
|
635
|
+
bool barrier(const Node& n) const {
|
|
636
|
+
return (*_status)[n] == ODD;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/// @}
|
|
640
|
+
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
/// \ingroup matching
|
|
644
|
+
///
|
|
645
|
+
/// \brief Weighted matching in general graphs
|
|
646
|
+
///
|
|
647
|
+
/// This class provides an efficient implementation of Edmond's
|
|
648
|
+
/// maximum weighted matching algorithm. The implementation is based
|
|
649
|
+
/// on extensive use of priority queues and provides
|
|
650
|
+
/// \f$O(nm\log n)\f$ time complexity.
|
|
651
|
+
///
|
|
652
|
+
/// The maximum weighted matching problem is to find a subset of the
|
|
653
|
+
/// edges in an undirected graph with maximum overall weight for which
|
|
654
|
+
/// each node has at most one incident edge.
|
|
655
|
+
/// It can be formulated with the following linear program.
|
|
656
|
+
/// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f]
|
|
657
|
+
/** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2}
|
|
658
|
+
\quad \forall B\in\mathcal{O}\f] */
|
|
659
|
+
/// \f[x_e \ge 0\quad \forall e\in E\f]
|
|
660
|
+
/// \f[\max \sum_{e\in E}x_ew_e\f]
|
|
661
|
+
/// where \f$\delta(X)\f$ is the set of edges incident to a node in
|
|
662
|
+
/// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in
|
|
663
|
+
/// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality
|
|
664
|
+
/// subsets of the nodes.
|
|
665
|
+
///
|
|
666
|
+
/// The algorithm calculates an optimal matching and a proof of the
|
|
667
|
+
/// optimality. The solution of the dual problem can be used to check
|
|
668
|
+
/// the result of the algorithm. The dual linear problem is the
|
|
669
|
+
/// following.
|
|
670
|
+
/** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)}
|
|
671
|
+
z_B \ge w_{uv} \quad \forall uv\in E\f] */
|
|
672
|
+
/// \f[y_u \ge 0 \quad \forall u \in V\f]
|
|
673
|
+
/// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f]
|
|
674
|
+
/** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}}
|
|
675
|
+
\frac{\vert B \vert - 1}{2}z_B\f] */
|
|
676
|
+
///
|
|
677
|
+
/// The algorithm can be executed with the run() function.
|
|
678
|
+
/// After it the matching (the primal solution) and the dual solution
|
|
679
|
+
/// can be obtained using the query functions and the
|
|
680
|
+
/// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class,
|
|
681
|
+
/// which is able to iterate on the nodes of a blossom.
|
|
682
|
+
/// If the value type is integer, then the dual solution is multiplied
|
|
683
|
+
/// by \ref MaxWeightedMatching::dualScale "4".
|
|
684
|
+
///
|
|
685
|
+
/// \tparam GR The undirected graph type the algorithm runs on.
|
|
686
|
+
/// \tparam WM The type edge weight map. The default type is
|
|
687
|
+
/// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
|
|
688
|
+
#ifdef DOXYGEN
|
|
689
|
+
template <typename GR, typename WM>
|
|
690
|
+
#else
|
|
691
|
+
template <typename GR,
|
|
692
|
+
typename WM = typename GR::template EdgeMap<int> >
|
|
693
|
+
#endif
|
|
694
|
+
class MaxWeightedMatching {
|
|
695
|
+
public:
|
|
696
|
+
|
|
697
|
+
/// The graph type of the algorithm
|
|
698
|
+
typedef GR Graph;
|
|
699
|
+
/// The type of the edge weight map
|
|
700
|
+
typedef WM WeightMap;
|
|
701
|
+
/// The value type of the edge weights
|
|
702
|
+
typedef typename WeightMap::Value Value;
|
|
703
|
+
|
|
704
|
+
/// The type of the matching map
|
|
705
|
+
typedef typename Graph::template NodeMap<typename Graph::Arc>
|
|
706
|
+
MatchingMap;
|
|
707
|
+
|
|
708
|
+
/// \brief Scaling factor for dual solution
|
|
709
|
+
///
|
|
710
|
+
/// Scaling factor for dual solution. It is equal to 4 or 1
|
|
711
|
+
/// according to the value type.
|
|
712
|
+
static const int dualScale =
|
|
713
|
+
std::numeric_limits<Value>::is_integer ? 4 : 1;
|
|
714
|
+
|
|
715
|
+
private:
|
|
716
|
+
|
|
717
|
+
TEMPLATE_GRAPH_TYPEDEFS(Graph);
|
|
718
|
+
|
|
719
|
+
typedef typename Graph::template NodeMap<Value> NodePotential;
|
|
720
|
+
typedef std::vector<Node> BlossomNodeList;
|
|
721
|
+
|
|
722
|
+
struct BlossomVariable {
|
|
723
|
+
int begin, end;
|
|
724
|
+
Value value;
|
|
725
|
+
|
|
726
|
+
BlossomVariable(int _begin, int _end, Value _value)
|
|
727
|
+
: begin(_begin), end(_end), value(_value) {}
|
|
728
|
+
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
typedef std::vector<BlossomVariable> BlossomPotential;
|
|
732
|
+
|
|
733
|
+
const Graph& _graph;
|
|
734
|
+
const WeightMap& _weight;
|
|
735
|
+
|
|
736
|
+
MatchingMap* _matching;
|
|
737
|
+
|
|
738
|
+
NodePotential* _node_potential;
|
|
739
|
+
|
|
740
|
+
BlossomPotential _blossom_potential;
|
|
741
|
+
BlossomNodeList _blossom_node_list;
|
|
742
|
+
|
|
743
|
+
int _node_num;
|
|
744
|
+
int _blossom_num;
|
|
745
|
+
|
|
746
|
+
typedef RangeMap<int> IntIntMap;
|
|
747
|
+
|
|
748
|
+
enum Status {
|
|
749
|
+
EVEN = -1, MATCHED = 0, ODD = 1
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
typedef HeapUnionFind<Value, IntNodeMap> BlossomSet;
|
|
753
|
+
struct BlossomData {
|
|
754
|
+
int tree;
|
|
755
|
+
Status status;
|
|
756
|
+
Arc pred, next;
|
|
757
|
+
Value pot, offset;
|
|
758
|
+
Node base;
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
IntNodeMap *_blossom_index;
|
|
762
|
+
BlossomSet *_blossom_set;
|
|
763
|
+
RangeMap<BlossomData>* _blossom_data;
|
|
764
|
+
|
|
765
|
+
IntNodeMap *_node_index;
|
|
766
|
+
IntArcMap *_node_heap_index;
|
|
767
|
+
|
|
768
|
+
struct NodeData {
|
|
769
|
+
|
|
770
|
+
NodeData(IntArcMap& node_heap_index)
|
|
771
|
+
: heap(node_heap_index) {}
|
|
772
|
+
|
|
773
|
+
int blossom;
|
|
774
|
+
Value pot;
|
|
775
|
+
BinHeap<Value, IntArcMap> heap;
|
|
776
|
+
std::map<int, Arc> heap_index;
|
|
777
|
+
|
|
778
|
+
int tree;
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
RangeMap<NodeData>* _node_data;
|
|
782
|
+
|
|
783
|
+
typedef ExtendFindEnum<IntIntMap> TreeSet;
|
|
784
|
+
|
|
785
|
+
IntIntMap *_tree_set_index;
|
|
786
|
+
TreeSet *_tree_set;
|
|
787
|
+
|
|
788
|
+
IntNodeMap *_delta1_index;
|
|
789
|
+
BinHeap<Value, IntNodeMap> *_delta1;
|
|
790
|
+
|
|
791
|
+
IntIntMap *_delta2_index;
|
|
792
|
+
BinHeap<Value, IntIntMap> *_delta2;
|
|
793
|
+
|
|
794
|
+
IntEdgeMap *_delta3_index;
|
|
795
|
+
BinHeap<Value, IntEdgeMap> *_delta3;
|
|
796
|
+
|
|
797
|
+
IntIntMap *_delta4_index;
|
|
798
|
+
BinHeap<Value, IntIntMap> *_delta4;
|
|
799
|
+
|
|
800
|
+
Value _delta_sum;
|
|
801
|
+
int _unmatched;
|
|
802
|
+
|
|
803
|
+
typedef MaxWeightedFractionalMatching<Graph, WeightMap> FractionalMatching;
|
|
804
|
+
FractionalMatching *_fractional;
|
|
805
|
+
|
|
806
|
+
void createStructures() {
|
|
807
|
+
_node_num = countNodes(_graph);
|
|
808
|
+
_blossom_num = _node_num * 3 / 2;
|
|
809
|
+
|
|
810
|
+
if (!_matching) {
|
|
811
|
+
_matching = new MatchingMap(_graph);
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
if (!_node_potential) {
|
|
815
|
+
_node_potential = new NodePotential(_graph);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (!_blossom_set) {
|
|
819
|
+
_blossom_index = new IntNodeMap(_graph);
|
|
820
|
+
_blossom_set = new BlossomSet(*_blossom_index);
|
|
821
|
+
_blossom_data = new RangeMap<BlossomData>(_blossom_num);
|
|
822
|
+
} else if (_blossom_data->size() != _blossom_num) {
|
|
823
|
+
delete _blossom_data;
|
|
824
|
+
_blossom_data = new RangeMap<BlossomData>(_blossom_num);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (!_node_index) {
|
|
828
|
+
_node_index = new IntNodeMap(_graph);
|
|
829
|
+
_node_heap_index = new IntArcMap(_graph);
|
|
830
|
+
_node_data = new RangeMap<NodeData>(_node_num,
|
|
831
|
+
NodeData(*_node_heap_index));
|
|
832
|
+
} else {
|
|
833
|
+
delete _node_data;
|
|
834
|
+
_node_data = new RangeMap<NodeData>(_node_num,
|
|
835
|
+
NodeData(*_node_heap_index));
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
if (!_tree_set) {
|
|
839
|
+
_tree_set_index = new IntIntMap(_blossom_num);
|
|
840
|
+
_tree_set = new TreeSet(*_tree_set_index);
|
|
841
|
+
} else {
|
|
842
|
+
_tree_set_index->resize(_blossom_num);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (!_delta1) {
|
|
846
|
+
_delta1_index = new IntNodeMap(_graph);
|
|
847
|
+
_delta1 = new BinHeap<Value, IntNodeMap>(*_delta1_index);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (!_delta2) {
|
|
851
|
+
_delta2_index = new IntIntMap(_blossom_num);
|
|
852
|
+
_delta2 = new BinHeap<Value, IntIntMap>(*_delta2_index);
|
|
853
|
+
} else {
|
|
854
|
+
_delta2_index->resize(_blossom_num);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
if (!_delta3) {
|
|
858
|
+
_delta3_index = new IntEdgeMap(_graph);
|
|
859
|
+
_delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (!_delta4) {
|
|
863
|
+
_delta4_index = new IntIntMap(_blossom_num);
|
|
864
|
+
_delta4 = new BinHeap<Value, IntIntMap>(*_delta4_index);
|
|
865
|
+
} else {
|
|
866
|
+
_delta4_index->resize(_blossom_num);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
void destroyStructures() {
|
|
871
|
+
if (_matching) {
|
|
872
|
+
delete _matching;
|
|
873
|
+
}
|
|
874
|
+
if (_node_potential) {
|
|
875
|
+
delete _node_potential;
|
|
876
|
+
}
|
|
877
|
+
if (_blossom_set) {
|
|
878
|
+
delete _blossom_index;
|
|
879
|
+
delete _blossom_set;
|
|
880
|
+
delete _blossom_data;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (_node_index) {
|
|
884
|
+
delete _node_index;
|
|
885
|
+
delete _node_heap_index;
|
|
886
|
+
delete _node_data;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
if (_tree_set) {
|
|
890
|
+
delete _tree_set_index;
|
|
891
|
+
delete _tree_set;
|
|
892
|
+
}
|
|
893
|
+
if (_delta1) {
|
|
894
|
+
delete _delta1_index;
|
|
895
|
+
delete _delta1;
|
|
896
|
+
}
|
|
897
|
+
if (_delta2) {
|
|
898
|
+
delete _delta2_index;
|
|
899
|
+
delete _delta2;
|
|
900
|
+
}
|
|
901
|
+
if (_delta3) {
|
|
902
|
+
delete _delta3_index;
|
|
903
|
+
delete _delta3;
|
|
904
|
+
}
|
|
905
|
+
if (_delta4) {
|
|
906
|
+
delete _delta4_index;
|
|
907
|
+
delete _delta4;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
void matchedToEven(int blossom, int tree) {
|
|
912
|
+
if (_delta2->state(blossom) == _delta2->IN_HEAP) {
|
|
913
|
+
_delta2->erase(blossom);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
917
|
+
(*_blossom_data)[blossom].pot -=
|
|
918
|
+
2 * (_delta_sum - (*_blossom_data)[blossom].offset);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
|
|
922
|
+
n != INVALID; ++n) {
|
|
923
|
+
|
|
924
|
+
_blossom_set->increase(n, std::numeric_limits<Value>::max());
|
|
925
|
+
int ni = (*_node_index)[n];
|
|
926
|
+
|
|
927
|
+
(*_node_data)[ni].heap.clear();
|
|
928
|
+
(*_node_data)[ni].heap_index.clear();
|
|
929
|
+
|
|
930
|
+
(*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset;
|
|
931
|
+
|
|
932
|
+
_delta1->push(n, (*_node_data)[ni].pot);
|
|
933
|
+
|
|
934
|
+
for (InArcIt e(_graph, n); e != INVALID; ++e) {
|
|
935
|
+
Node v = _graph.source(e);
|
|
936
|
+
int vb = _blossom_set->find(v);
|
|
937
|
+
int vi = (*_node_index)[v];
|
|
938
|
+
|
|
939
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
940
|
+
dualScale * _weight[e];
|
|
941
|
+
|
|
942
|
+
if ((*_blossom_data)[vb].status == EVEN) {
|
|
943
|
+
if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
|
|
944
|
+
_delta3->push(e, rw / 2);
|
|
945
|
+
}
|
|
946
|
+
} else {
|
|
947
|
+
typename std::map<int, Arc>::iterator it =
|
|
948
|
+
(*_node_data)[vi].heap_index.find(tree);
|
|
949
|
+
|
|
950
|
+
if (it != (*_node_data)[vi].heap_index.end()) {
|
|
951
|
+
if ((*_node_data)[vi].heap[it->second] > rw) {
|
|
952
|
+
(*_node_data)[vi].heap.replace(it->second, e);
|
|
953
|
+
(*_node_data)[vi].heap.decrease(e, rw);
|
|
954
|
+
it->second = e;
|
|
955
|
+
}
|
|
956
|
+
} else {
|
|
957
|
+
(*_node_data)[vi].heap.push(e, rw);
|
|
958
|
+
(*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
|
|
962
|
+
_blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
|
|
963
|
+
|
|
964
|
+
if ((*_blossom_data)[vb].status == MATCHED) {
|
|
965
|
+
if (_delta2->state(vb) != _delta2->IN_HEAP) {
|
|
966
|
+
_delta2->push(vb, _blossom_set->classPrio(vb) -
|
|
967
|
+
(*_blossom_data)[vb].offset);
|
|
968
|
+
} else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
|
|
969
|
+
(*_blossom_data)[vb].offset) {
|
|
970
|
+
_delta2->decrease(vb, _blossom_set->classPrio(vb) -
|
|
971
|
+
(*_blossom_data)[vb].offset);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
void matchedToOdd(int blossom) {
|
|
982
|
+
if (_delta2->state(blossom) == _delta2->IN_HEAP) {
|
|
983
|
+
_delta2->erase(blossom);
|
|
984
|
+
}
|
|
985
|
+
(*_blossom_data)[blossom].offset += _delta_sum;
|
|
986
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
987
|
+
_delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 +
|
|
988
|
+
(*_blossom_data)[blossom].offset);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
void evenToMatched(int blossom, int tree) {
|
|
993
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
994
|
+
(*_blossom_data)[blossom].pot += 2 * _delta_sum;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
|
|
998
|
+
n != INVALID; ++n) {
|
|
999
|
+
int ni = (*_node_index)[n];
|
|
1000
|
+
(*_node_data)[ni].pot -= _delta_sum;
|
|
1001
|
+
|
|
1002
|
+
_delta1->erase(n);
|
|
1003
|
+
|
|
1004
|
+
for (InArcIt e(_graph, n); e != INVALID; ++e) {
|
|
1005
|
+
Node v = _graph.source(e);
|
|
1006
|
+
int vb = _blossom_set->find(v);
|
|
1007
|
+
int vi = (*_node_index)[v];
|
|
1008
|
+
|
|
1009
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
1010
|
+
dualScale * _weight[e];
|
|
1011
|
+
|
|
1012
|
+
if (vb == blossom) {
|
|
1013
|
+
if (_delta3->state(e) == _delta3->IN_HEAP) {
|
|
1014
|
+
_delta3->erase(e);
|
|
1015
|
+
}
|
|
1016
|
+
} else if ((*_blossom_data)[vb].status == EVEN) {
|
|
1017
|
+
|
|
1018
|
+
if (_delta3->state(e) == _delta3->IN_HEAP) {
|
|
1019
|
+
_delta3->erase(e);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
int vt = _tree_set->find(vb);
|
|
1023
|
+
|
|
1024
|
+
if (vt != tree) {
|
|
1025
|
+
|
|
1026
|
+
Arc r = _graph.oppositeArc(e);
|
|
1027
|
+
|
|
1028
|
+
typename std::map<int, Arc>::iterator it =
|
|
1029
|
+
(*_node_data)[ni].heap_index.find(vt);
|
|
1030
|
+
|
|
1031
|
+
if (it != (*_node_data)[ni].heap_index.end()) {
|
|
1032
|
+
if ((*_node_data)[ni].heap[it->second] > rw) {
|
|
1033
|
+
(*_node_data)[ni].heap.replace(it->second, r);
|
|
1034
|
+
(*_node_data)[ni].heap.decrease(r, rw);
|
|
1035
|
+
it->second = r;
|
|
1036
|
+
}
|
|
1037
|
+
} else {
|
|
1038
|
+
(*_node_data)[ni].heap.push(r, rw);
|
|
1039
|
+
(*_node_data)[ni].heap_index.insert(std::make_pair(vt, r));
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) {
|
|
1043
|
+
_blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
|
|
1044
|
+
|
|
1045
|
+
if (_delta2->state(blossom) != _delta2->IN_HEAP) {
|
|
1046
|
+
_delta2->push(blossom, _blossom_set->classPrio(blossom) -
|
|
1047
|
+
(*_blossom_data)[blossom].offset);
|
|
1048
|
+
} else if ((*_delta2)[blossom] >
|
|
1049
|
+
_blossom_set->classPrio(blossom) -
|
|
1050
|
+
(*_blossom_data)[blossom].offset){
|
|
1051
|
+
_delta2->decrease(blossom, _blossom_set->classPrio(blossom) -
|
|
1052
|
+
(*_blossom_data)[blossom].offset);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
} else {
|
|
1057
|
+
|
|
1058
|
+
typename std::map<int, Arc>::iterator it =
|
|
1059
|
+
(*_node_data)[vi].heap_index.find(tree);
|
|
1060
|
+
|
|
1061
|
+
if (it != (*_node_data)[vi].heap_index.end()) {
|
|
1062
|
+
(*_node_data)[vi].heap.erase(it->second);
|
|
1063
|
+
(*_node_data)[vi].heap_index.erase(it);
|
|
1064
|
+
if ((*_node_data)[vi].heap.empty()) {
|
|
1065
|
+
_blossom_set->increase(v, std::numeric_limits<Value>::max());
|
|
1066
|
+
} else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) {
|
|
1067
|
+
_blossom_set->increase(v, (*_node_data)[vi].heap.prio());
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
if ((*_blossom_data)[vb].status == MATCHED) {
|
|
1071
|
+
if (_blossom_set->classPrio(vb) ==
|
|
1072
|
+
std::numeric_limits<Value>::max()) {
|
|
1073
|
+
_delta2->erase(vb);
|
|
1074
|
+
} else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) -
|
|
1075
|
+
(*_blossom_data)[vb].offset) {
|
|
1076
|
+
_delta2->increase(vb, _blossom_set->classPrio(vb) -
|
|
1077
|
+
(*_blossom_data)[vb].offset);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
void oddToMatched(int blossom) {
|
|
1087
|
+
(*_blossom_data)[blossom].offset -= _delta_sum;
|
|
1088
|
+
|
|
1089
|
+
if (_blossom_set->classPrio(blossom) !=
|
|
1090
|
+
std::numeric_limits<Value>::max()) {
|
|
1091
|
+
_delta2->push(blossom, _blossom_set->classPrio(blossom) -
|
|
1092
|
+
(*_blossom_data)[blossom].offset);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
1096
|
+
_delta4->erase(blossom);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
void oddToEven(int blossom, int tree) {
|
|
1101
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
1102
|
+
_delta4->erase(blossom);
|
|
1103
|
+
(*_blossom_data)[blossom].pot -=
|
|
1104
|
+
2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
|
|
1108
|
+
n != INVALID; ++n) {
|
|
1109
|
+
int ni = (*_node_index)[n];
|
|
1110
|
+
|
|
1111
|
+
_blossom_set->increase(n, std::numeric_limits<Value>::max());
|
|
1112
|
+
|
|
1113
|
+
(*_node_data)[ni].heap.clear();
|
|
1114
|
+
(*_node_data)[ni].heap_index.clear();
|
|
1115
|
+
(*_node_data)[ni].pot +=
|
|
1116
|
+
2 * _delta_sum - (*_blossom_data)[blossom].offset;
|
|
1117
|
+
|
|
1118
|
+
_delta1->push(n, (*_node_data)[ni].pot);
|
|
1119
|
+
|
|
1120
|
+
for (InArcIt e(_graph, n); e != INVALID; ++e) {
|
|
1121
|
+
Node v = _graph.source(e);
|
|
1122
|
+
int vb = _blossom_set->find(v);
|
|
1123
|
+
int vi = (*_node_index)[v];
|
|
1124
|
+
|
|
1125
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
1126
|
+
dualScale * _weight[e];
|
|
1127
|
+
|
|
1128
|
+
if ((*_blossom_data)[vb].status == EVEN) {
|
|
1129
|
+
if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
|
|
1130
|
+
_delta3->push(e, rw / 2);
|
|
1131
|
+
}
|
|
1132
|
+
} else {
|
|
1133
|
+
|
|
1134
|
+
typename std::map<int, Arc>::iterator it =
|
|
1135
|
+
(*_node_data)[vi].heap_index.find(tree);
|
|
1136
|
+
|
|
1137
|
+
if (it != (*_node_data)[vi].heap_index.end()) {
|
|
1138
|
+
if ((*_node_data)[vi].heap[it->second] > rw) {
|
|
1139
|
+
(*_node_data)[vi].heap.replace(it->second, e);
|
|
1140
|
+
(*_node_data)[vi].heap.decrease(e, rw);
|
|
1141
|
+
it->second = e;
|
|
1142
|
+
}
|
|
1143
|
+
} else {
|
|
1144
|
+
(*_node_data)[vi].heap.push(e, rw);
|
|
1145
|
+
(*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
|
|
1149
|
+
_blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
|
|
1150
|
+
|
|
1151
|
+
if ((*_blossom_data)[vb].status == MATCHED) {
|
|
1152
|
+
if (_delta2->state(vb) != _delta2->IN_HEAP) {
|
|
1153
|
+
_delta2->push(vb, _blossom_set->classPrio(vb) -
|
|
1154
|
+
(*_blossom_data)[vb].offset);
|
|
1155
|
+
} else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
|
|
1156
|
+
(*_blossom_data)[vb].offset) {
|
|
1157
|
+
_delta2->decrease(vb, _blossom_set->classPrio(vb) -
|
|
1158
|
+
(*_blossom_data)[vb].offset);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
void alternatePath(int even, int tree) {
|
|
1169
|
+
int odd;
|
|
1170
|
+
|
|
1171
|
+
evenToMatched(even, tree);
|
|
1172
|
+
(*_blossom_data)[even].status = MATCHED;
|
|
1173
|
+
|
|
1174
|
+
while ((*_blossom_data)[even].pred != INVALID) {
|
|
1175
|
+
odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred));
|
|
1176
|
+
(*_blossom_data)[odd].status = MATCHED;
|
|
1177
|
+
oddToMatched(odd);
|
|
1178
|
+
(*_blossom_data)[odd].next = (*_blossom_data)[odd].pred;
|
|
1179
|
+
|
|
1180
|
+
even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred));
|
|
1181
|
+
(*_blossom_data)[even].status = MATCHED;
|
|
1182
|
+
evenToMatched(even, tree);
|
|
1183
|
+
(*_blossom_data)[even].next =
|
|
1184
|
+
_graph.oppositeArc((*_blossom_data)[odd].pred);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
void destroyTree(int tree) {
|
|
1190
|
+
for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) {
|
|
1191
|
+
if ((*_blossom_data)[b].status == EVEN) {
|
|
1192
|
+
(*_blossom_data)[b].status = MATCHED;
|
|
1193
|
+
evenToMatched(b, tree);
|
|
1194
|
+
} else if ((*_blossom_data)[b].status == ODD) {
|
|
1195
|
+
(*_blossom_data)[b].status = MATCHED;
|
|
1196
|
+
oddToMatched(b);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
_tree_set->eraseClass(tree);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
void unmatchNode(const Node& node) {
|
|
1204
|
+
int blossom = _blossom_set->find(node);
|
|
1205
|
+
int tree = _tree_set->find(blossom);
|
|
1206
|
+
|
|
1207
|
+
alternatePath(blossom, tree);
|
|
1208
|
+
destroyTree(tree);
|
|
1209
|
+
|
|
1210
|
+
(*_blossom_data)[blossom].base = node;
|
|
1211
|
+
(*_blossom_data)[blossom].next = INVALID;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
void augmentOnEdge(const Edge& edge) {
|
|
1215
|
+
|
|
1216
|
+
int left = _blossom_set->find(_graph.u(edge));
|
|
1217
|
+
int right = _blossom_set->find(_graph.v(edge));
|
|
1218
|
+
|
|
1219
|
+
int left_tree = _tree_set->find(left);
|
|
1220
|
+
alternatePath(left, left_tree);
|
|
1221
|
+
destroyTree(left_tree);
|
|
1222
|
+
|
|
1223
|
+
int right_tree = _tree_set->find(right);
|
|
1224
|
+
alternatePath(right, right_tree);
|
|
1225
|
+
destroyTree(right_tree);
|
|
1226
|
+
|
|
1227
|
+
(*_blossom_data)[left].next = _graph.direct(edge, true);
|
|
1228
|
+
(*_blossom_data)[right].next = _graph.direct(edge, false);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
void augmentOnArc(const Arc& arc) {
|
|
1232
|
+
|
|
1233
|
+
int left = _blossom_set->find(_graph.source(arc));
|
|
1234
|
+
int right = _blossom_set->find(_graph.target(arc));
|
|
1235
|
+
|
|
1236
|
+
(*_blossom_data)[left].status = MATCHED;
|
|
1237
|
+
|
|
1238
|
+
int right_tree = _tree_set->find(right);
|
|
1239
|
+
alternatePath(right, right_tree);
|
|
1240
|
+
destroyTree(right_tree);
|
|
1241
|
+
|
|
1242
|
+
(*_blossom_data)[left].next = arc;
|
|
1243
|
+
(*_blossom_data)[right].next = _graph.oppositeArc(arc);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
void extendOnArc(const Arc& arc) {
|
|
1247
|
+
int base = _blossom_set->find(_graph.target(arc));
|
|
1248
|
+
int tree = _tree_set->find(base);
|
|
1249
|
+
|
|
1250
|
+
int odd = _blossom_set->find(_graph.source(arc));
|
|
1251
|
+
_tree_set->insert(odd, tree);
|
|
1252
|
+
(*_blossom_data)[odd].status = ODD;
|
|
1253
|
+
matchedToOdd(odd);
|
|
1254
|
+
(*_blossom_data)[odd].pred = arc;
|
|
1255
|
+
|
|
1256
|
+
int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next));
|
|
1257
|
+
(*_blossom_data)[even].pred = (*_blossom_data)[even].next;
|
|
1258
|
+
_tree_set->insert(even, tree);
|
|
1259
|
+
(*_blossom_data)[even].status = EVEN;
|
|
1260
|
+
matchedToEven(even, tree);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
void shrinkOnEdge(const Edge& edge, int tree) {
|
|
1264
|
+
int nca = -1;
|
|
1265
|
+
std::vector<int> left_path, right_path;
|
|
1266
|
+
|
|
1267
|
+
{
|
|
1268
|
+
std::set<int> left_set, right_set;
|
|
1269
|
+
int left = _blossom_set->find(_graph.u(edge));
|
|
1270
|
+
left_path.push_back(left);
|
|
1271
|
+
left_set.insert(left);
|
|
1272
|
+
|
|
1273
|
+
int right = _blossom_set->find(_graph.v(edge));
|
|
1274
|
+
right_path.push_back(right);
|
|
1275
|
+
right_set.insert(right);
|
|
1276
|
+
|
|
1277
|
+
while (true) {
|
|
1278
|
+
|
|
1279
|
+
if ((*_blossom_data)[left].pred == INVALID) break;
|
|
1280
|
+
|
|
1281
|
+
left =
|
|
1282
|
+
_blossom_set->find(_graph.target((*_blossom_data)[left].pred));
|
|
1283
|
+
left_path.push_back(left);
|
|
1284
|
+
left =
|
|
1285
|
+
_blossom_set->find(_graph.target((*_blossom_data)[left].pred));
|
|
1286
|
+
left_path.push_back(left);
|
|
1287
|
+
|
|
1288
|
+
left_set.insert(left);
|
|
1289
|
+
|
|
1290
|
+
if (right_set.find(left) != right_set.end()) {
|
|
1291
|
+
nca = left;
|
|
1292
|
+
break;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
if ((*_blossom_data)[right].pred == INVALID) break;
|
|
1296
|
+
|
|
1297
|
+
right =
|
|
1298
|
+
_blossom_set->find(_graph.target((*_blossom_data)[right].pred));
|
|
1299
|
+
right_path.push_back(right);
|
|
1300
|
+
right =
|
|
1301
|
+
_blossom_set->find(_graph.target((*_blossom_data)[right].pred));
|
|
1302
|
+
right_path.push_back(right);
|
|
1303
|
+
|
|
1304
|
+
right_set.insert(right);
|
|
1305
|
+
|
|
1306
|
+
if (left_set.find(right) != left_set.end()) {
|
|
1307
|
+
nca = right;
|
|
1308
|
+
break;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
if (nca == -1) {
|
|
1314
|
+
if ((*_blossom_data)[left].pred == INVALID) {
|
|
1315
|
+
nca = right;
|
|
1316
|
+
while (left_set.find(nca) == left_set.end()) {
|
|
1317
|
+
nca =
|
|
1318
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
1319
|
+
right_path.push_back(nca);
|
|
1320
|
+
nca =
|
|
1321
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
1322
|
+
right_path.push_back(nca);
|
|
1323
|
+
}
|
|
1324
|
+
} else {
|
|
1325
|
+
nca = left;
|
|
1326
|
+
while (right_set.find(nca) == right_set.end()) {
|
|
1327
|
+
nca =
|
|
1328
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
1329
|
+
left_path.push_back(nca);
|
|
1330
|
+
nca =
|
|
1331
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
1332
|
+
left_path.push_back(nca);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
std::vector<int> subblossoms;
|
|
1339
|
+
Arc prev;
|
|
1340
|
+
|
|
1341
|
+
prev = _graph.direct(edge, true);
|
|
1342
|
+
for (int i = 0; left_path[i] != nca; i += 2) {
|
|
1343
|
+
subblossoms.push_back(left_path[i]);
|
|
1344
|
+
(*_blossom_data)[left_path[i]].next = prev;
|
|
1345
|
+
_tree_set->erase(left_path[i]);
|
|
1346
|
+
|
|
1347
|
+
subblossoms.push_back(left_path[i + 1]);
|
|
1348
|
+
(*_blossom_data)[left_path[i + 1]].status = EVEN;
|
|
1349
|
+
oddToEven(left_path[i + 1], tree);
|
|
1350
|
+
_tree_set->erase(left_path[i + 1]);
|
|
1351
|
+
prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
int k = 0;
|
|
1355
|
+
while (right_path[k] != nca) ++k;
|
|
1356
|
+
|
|
1357
|
+
subblossoms.push_back(nca);
|
|
1358
|
+
(*_blossom_data)[nca].next = prev;
|
|
1359
|
+
|
|
1360
|
+
for (int i = k - 2; i >= 0; i -= 2) {
|
|
1361
|
+
subblossoms.push_back(right_path[i + 1]);
|
|
1362
|
+
(*_blossom_data)[right_path[i + 1]].status = EVEN;
|
|
1363
|
+
oddToEven(right_path[i + 1], tree);
|
|
1364
|
+
_tree_set->erase(right_path[i + 1]);
|
|
1365
|
+
|
|
1366
|
+
(*_blossom_data)[right_path[i + 1]].next =
|
|
1367
|
+
(*_blossom_data)[right_path[i + 1]].pred;
|
|
1368
|
+
|
|
1369
|
+
subblossoms.push_back(right_path[i]);
|
|
1370
|
+
_tree_set->erase(right_path[i]);
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
int surface =
|
|
1374
|
+
_blossom_set->join(subblossoms.begin(), subblossoms.end());
|
|
1375
|
+
|
|
1376
|
+
for (int i = 0; i < int(subblossoms.size()); ++i) {
|
|
1377
|
+
if (!_blossom_set->trivial(subblossoms[i])) {
|
|
1378
|
+
(*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum;
|
|
1379
|
+
}
|
|
1380
|
+
(*_blossom_data)[subblossoms[i]].status = MATCHED;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
(*_blossom_data)[surface].pot = -2 * _delta_sum;
|
|
1384
|
+
(*_blossom_data)[surface].offset = 0;
|
|
1385
|
+
(*_blossom_data)[surface].status = EVEN;
|
|
1386
|
+
(*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred;
|
|
1387
|
+
(*_blossom_data)[surface].next = (*_blossom_data)[nca].pred;
|
|
1388
|
+
|
|
1389
|
+
_tree_set->insert(surface, tree);
|
|
1390
|
+
_tree_set->erase(nca);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
void splitBlossom(int blossom) {
|
|
1394
|
+
Arc next = (*_blossom_data)[blossom].next;
|
|
1395
|
+
Arc pred = (*_blossom_data)[blossom].pred;
|
|
1396
|
+
|
|
1397
|
+
int tree = _tree_set->find(blossom);
|
|
1398
|
+
|
|
1399
|
+
(*_blossom_data)[blossom].status = MATCHED;
|
|
1400
|
+
oddToMatched(blossom);
|
|
1401
|
+
if (_delta2->state(blossom) == _delta2->IN_HEAP) {
|
|
1402
|
+
_delta2->erase(blossom);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
std::vector<int> subblossoms;
|
|
1406
|
+
_blossom_set->split(blossom, std::back_inserter(subblossoms));
|
|
1407
|
+
|
|
1408
|
+
Value offset = (*_blossom_data)[blossom].offset;
|
|
1409
|
+
int b = _blossom_set->find(_graph.source(pred));
|
|
1410
|
+
int d = _blossom_set->find(_graph.source(next));
|
|
1411
|
+
|
|
1412
|
+
int ib = -1, id = -1;
|
|
1413
|
+
for (int i = 0; i < int(subblossoms.size()); ++i) {
|
|
1414
|
+
if (subblossoms[i] == b) ib = i;
|
|
1415
|
+
if (subblossoms[i] == d) id = i;
|
|
1416
|
+
|
|
1417
|
+
(*_blossom_data)[subblossoms[i]].offset = offset;
|
|
1418
|
+
if (!_blossom_set->trivial(subblossoms[i])) {
|
|
1419
|
+
(*_blossom_data)[subblossoms[i]].pot -= 2 * offset;
|
|
1420
|
+
}
|
|
1421
|
+
if (_blossom_set->classPrio(subblossoms[i]) !=
|
|
1422
|
+
std::numeric_limits<Value>::max()) {
|
|
1423
|
+
_delta2->push(subblossoms[i],
|
|
1424
|
+
_blossom_set->classPrio(subblossoms[i]) -
|
|
1425
|
+
(*_blossom_data)[subblossoms[i]].offset);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) {
|
|
1430
|
+
for (int i = (id + 1) % subblossoms.size();
|
|
1431
|
+
i != ib; i = (i + 2) % subblossoms.size()) {
|
|
1432
|
+
int sb = subblossoms[i];
|
|
1433
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
1434
|
+
(*_blossom_data)[sb].next =
|
|
1435
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) {
|
|
1439
|
+
int sb = subblossoms[i];
|
|
1440
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
1441
|
+
int ub = subblossoms[(i + 2) % subblossoms.size()];
|
|
1442
|
+
|
|
1443
|
+
(*_blossom_data)[sb].status = ODD;
|
|
1444
|
+
matchedToOdd(sb);
|
|
1445
|
+
_tree_set->insert(sb, tree);
|
|
1446
|
+
(*_blossom_data)[sb].pred = pred;
|
|
1447
|
+
(*_blossom_data)[sb].next =
|
|
1448
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
1449
|
+
|
|
1450
|
+
pred = (*_blossom_data)[ub].next;
|
|
1451
|
+
|
|
1452
|
+
(*_blossom_data)[tb].status = EVEN;
|
|
1453
|
+
matchedToEven(tb, tree);
|
|
1454
|
+
_tree_set->insert(tb, tree);
|
|
1455
|
+
(*_blossom_data)[tb].pred = (*_blossom_data)[tb].next;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
(*_blossom_data)[subblossoms[id]].status = ODD;
|
|
1459
|
+
matchedToOdd(subblossoms[id]);
|
|
1460
|
+
_tree_set->insert(subblossoms[id], tree);
|
|
1461
|
+
(*_blossom_data)[subblossoms[id]].next = next;
|
|
1462
|
+
(*_blossom_data)[subblossoms[id]].pred = pred;
|
|
1463
|
+
|
|
1464
|
+
} else {
|
|
1465
|
+
|
|
1466
|
+
for (int i = (ib + 1) % subblossoms.size();
|
|
1467
|
+
i != id; i = (i + 2) % subblossoms.size()) {
|
|
1468
|
+
int sb = subblossoms[i];
|
|
1469
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
1470
|
+
(*_blossom_data)[sb].next =
|
|
1471
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) {
|
|
1475
|
+
int sb = subblossoms[i];
|
|
1476
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
1477
|
+
int ub = subblossoms[(i + 2) % subblossoms.size()];
|
|
1478
|
+
|
|
1479
|
+
(*_blossom_data)[sb].status = ODD;
|
|
1480
|
+
matchedToOdd(sb);
|
|
1481
|
+
_tree_set->insert(sb, tree);
|
|
1482
|
+
(*_blossom_data)[sb].next = next;
|
|
1483
|
+
(*_blossom_data)[sb].pred =
|
|
1484
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
1485
|
+
|
|
1486
|
+
(*_blossom_data)[tb].status = EVEN;
|
|
1487
|
+
matchedToEven(tb, tree);
|
|
1488
|
+
_tree_set->insert(tb, tree);
|
|
1489
|
+
(*_blossom_data)[tb].pred =
|
|
1490
|
+
(*_blossom_data)[tb].next =
|
|
1491
|
+
_graph.oppositeArc((*_blossom_data)[ub].next);
|
|
1492
|
+
next = (*_blossom_data)[ub].next;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
(*_blossom_data)[subblossoms[ib]].status = ODD;
|
|
1496
|
+
matchedToOdd(subblossoms[ib]);
|
|
1497
|
+
_tree_set->insert(subblossoms[ib], tree);
|
|
1498
|
+
(*_blossom_data)[subblossoms[ib]].next = next;
|
|
1499
|
+
(*_blossom_data)[subblossoms[ib]].pred = pred;
|
|
1500
|
+
}
|
|
1501
|
+
_tree_set->erase(blossom);
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
void extractBlossom(int blossom, const Node& base, const Arc& matching) {
|
|
1505
|
+
if (_blossom_set->trivial(blossom)) {
|
|
1506
|
+
int bi = (*_node_index)[base];
|
|
1507
|
+
Value pot = (*_node_data)[bi].pot;
|
|
1508
|
+
|
|
1509
|
+
(*_matching)[base] = matching;
|
|
1510
|
+
_blossom_node_list.push_back(base);
|
|
1511
|
+
(*_node_potential)[base] = pot;
|
|
1512
|
+
} else {
|
|
1513
|
+
|
|
1514
|
+
Value pot = (*_blossom_data)[blossom].pot;
|
|
1515
|
+
int bn = _blossom_node_list.size();
|
|
1516
|
+
|
|
1517
|
+
std::vector<int> subblossoms;
|
|
1518
|
+
_blossom_set->split(blossom, std::back_inserter(subblossoms));
|
|
1519
|
+
int b = _blossom_set->find(base);
|
|
1520
|
+
int ib = -1;
|
|
1521
|
+
for (int i = 0; i < int(subblossoms.size()); ++i) {
|
|
1522
|
+
if (subblossoms[i] == b) { ib = i; break; }
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
for (int i = 1; i < int(subblossoms.size()); i += 2) {
|
|
1526
|
+
int sb = subblossoms[(ib + i) % subblossoms.size()];
|
|
1527
|
+
int tb = subblossoms[(ib + i + 1) % subblossoms.size()];
|
|
1528
|
+
|
|
1529
|
+
Arc m = (*_blossom_data)[tb].next;
|
|
1530
|
+
extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m));
|
|
1531
|
+
extractBlossom(tb, _graph.source(m), m);
|
|
1532
|
+
}
|
|
1533
|
+
extractBlossom(subblossoms[ib], base, matching);
|
|
1534
|
+
|
|
1535
|
+
int en = _blossom_node_list.size();
|
|
1536
|
+
|
|
1537
|
+
_blossom_potential.push_back(BlossomVariable(bn, en, pot));
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
void extractMatching() {
|
|
1542
|
+
std::vector<int> blossoms;
|
|
1543
|
+
for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) {
|
|
1544
|
+
blossoms.push_back(c);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
for (int i = 0; i < int(blossoms.size()); ++i) {
|
|
1548
|
+
if ((*_blossom_data)[blossoms[i]].next != INVALID) {
|
|
1549
|
+
|
|
1550
|
+
Value offset = (*_blossom_data)[blossoms[i]].offset;
|
|
1551
|
+
(*_blossom_data)[blossoms[i]].pot += 2 * offset;
|
|
1552
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]);
|
|
1553
|
+
n != INVALID; ++n) {
|
|
1554
|
+
(*_node_data)[(*_node_index)[n]].pot -= offset;
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
Arc matching = (*_blossom_data)[blossoms[i]].next;
|
|
1558
|
+
Node base = _graph.source(matching);
|
|
1559
|
+
extractBlossom(blossoms[i], base, matching);
|
|
1560
|
+
} else {
|
|
1561
|
+
Node base = (*_blossom_data)[blossoms[i]].base;
|
|
1562
|
+
extractBlossom(blossoms[i], base, INVALID);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
public:
|
|
1568
|
+
|
|
1569
|
+
/// \brief Constructor
|
|
1570
|
+
///
|
|
1571
|
+
/// Constructor.
|
|
1572
|
+
MaxWeightedMatching(const Graph& graph, const WeightMap& weight)
|
|
1573
|
+
: _graph(graph), _weight(weight), _matching(0),
|
|
1574
|
+
_node_potential(0), _blossom_potential(), _blossom_node_list(),
|
|
1575
|
+
_node_num(0), _blossom_num(0),
|
|
1576
|
+
|
|
1577
|
+
_blossom_index(0), _blossom_set(0), _blossom_data(0),
|
|
1578
|
+
_node_index(0), _node_heap_index(0), _node_data(0),
|
|
1579
|
+
_tree_set_index(0), _tree_set(0),
|
|
1580
|
+
|
|
1581
|
+
_delta1_index(0), _delta1(0),
|
|
1582
|
+
_delta2_index(0), _delta2(0),
|
|
1583
|
+
_delta3_index(0), _delta3(0),
|
|
1584
|
+
_delta4_index(0), _delta4(0),
|
|
1585
|
+
|
|
1586
|
+
_delta_sum(), _unmatched(0),
|
|
1587
|
+
|
|
1588
|
+
_fractional(0)
|
|
1589
|
+
{}
|
|
1590
|
+
|
|
1591
|
+
~MaxWeightedMatching() {
|
|
1592
|
+
destroyStructures();
|
|
1593
|
+
if (_fractional) {
|
|
1594
|
+
delete _fractional;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
/// \name Execution Control
|
|
1599
|
+
/// The simplest way to execute the algorithm is to use the
|
|
1600
|
+
/// \ref run() member function.
|
|
1601
|
+
|
|
1602
|
+
///@{
|
|
1603
|
+
|
|
1604
|
+
/// \brief Initialize the algorithm
|
|
1605
|
+
///
|
|
1606
|
+
/// This function initializes the algorithm.
|
|
1607
|
+
void init() {
|
|
1608
|
+
createStructures();
|
|
1609
|
+
|
|
1610
|
+
_blossom_node_list.clear();
|
|
1611
|
+
_blossom_potential.clear();
|
|
1612
|
+
|
|
1613
|
+
for (ArcIt e(_graph); e != INVALID; ++e) {
|
|
1614
|
+
(*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
|
|
1615
|
+
}
|
|
1616
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1617
|
+
(*_delta1_index)[n] = _delta1->PRE_HEAP;
|
|
1618
|
+
}
|
|
1619
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1620
|
+
(*_delta3_index)[e] = _delta3->PRE_HEAP;
|
|
1621
|
+
}
|
|
1622
|
+
for (int i = 0; i < _blossom_num; ++i) {
|
|
1623
|
+
(*_delta2_index)[i] = _delta2->PRE_HEAP;
|
|
1624
|
+
(*_delta4_index)[i] = _delta4->PRE_HEAP;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
_unmatched = _node_num;
|
|
1628
|
+
|
|
1629
|
+
_delta1->clear();
|
|
1630
|
+
_delta2->clear();
|
|
1631
|
+
_delta3->clear();
|
|
1632
|
+
_delta4->clear();
|
|
1633
|
+
_blossom_set->clear();
|
|
1634
|
+
_tree_set->clear();
|
|
1635
|
+
|
|
1636
|
+
int index = 0;
|
|
1637
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1638
|
+
Value max = 0;
|
|
1639
|
+
for (OutArcIt e(_graph, n); e != INVALID; ++e) {
|
|
1640
|
+
if (_graph.target(e) == n) continue;
|
|
1641
|
+
if ((dualScale * _weight[e]) / 2 > max) {
|
|
1642
|
+
max = (dualScale * _weight[e]) / 2;
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
(*_node_index)[n] = index;
|
|
1646
|
+
(*_node_data)[index].heap_index.clear();
|
|
1647
|
+
(*_node_data)[index].heap.clear();
|
|
1648
|
+
(*_node_data)[index].pot = max;
|
|
1649
|
+
_delta1->push(n, max);
|
|
1650
|
+
int blossom =
|
|
1651
|
+
_blossom_set->insert(n, std::numeric_limits<Value>::max());
|
|
1652
|
+
|
|
1653
|
+
_tree_set->insert(blossom);
|
|
1654
|
+
|
|
1655
|
+
(*_blossom_data)[blossom].status = EVEN;
|
|
1656
|
+
(*_blossom_data)[blossom].pred = INVALID;
|
|
1657
|
+
(*_blossom_data)[blossom].next = INVALID;
|
|
1658
|
+
(*_blossom_data)[blossom].pot = 0;
|
|
1659
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
1660
|
+
++index;
|
|
1661
|
+
}
|
|
1662
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1663
|
+
int si = (*_node_index)[_graph.u(e)];
|
|
1664
|
+
int ti = (*_node_index)[_graph.v(e)];
|
|
1665
|
+
if (_graph.u(e) != _graph.v(e)) {
|
|
1666
|
+
_delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
|
|
1667
|
+
dualScale * _weight[e]) / 2);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
/// \brief Initialize the algorithm with fractional matching
|
|
1673
|
+
///
|
|
1674
|
+
/// This function initializes the algorithm with a fractional
|
|
1675
|
+
/// matching. This initialization is also called jumpstart heuristic.
|
|
1676
|
+
void fractionalInit() {
|
|
1677
|
+
createStructures();
|
|
1678
|
+
|
|
1679
|
+
_blossom_node_list.clear();
|
|
1680
|
+
_blossom_potential.clear();
|
|
1681
|
+
|
|
1682
|
+
if (_fractional == 0) {
|
|
1683
|
+
_fractional = new FractionalMatching(_graph, _weight, false);
|
|
1684
|
+
}
|
|
1685
|
+
_fractional->run();
|
|
1686
|
+
|
|
1687
|
+
for (ArcIt e(_graph); e != INVALID; ++e) {
|
|
1688
|
+
(*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
|
|
1689
|
+
}
|
|
1690
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1691
|
+
(*_delta1_index)[n] = _delta1->PRE_HEAP;
|
|
1692
|
+
}
|
|
1693
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1694
|
+
(*_delta3_index)[e] = _delta3->PRE_HEAP;
|
|
1695
|
+
}
|
|
1696
|
+
for (int i = 0; i < _blossom_num; ++i) {
|
|
1697
|
+
(*_delta2_index)[i] = _delta2->PRE_HEAP;
|
|
1698
|
+
(*_delta4_index)[i] = _delta4->PRE_HEAP;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
_unmatched = 0;
|
|
1702
|
+
|
|
1703
|
+
_delta1->clear();
|
|
1704
|
+
_delta2->clear();
|
|
1705
|
+
_delta3->clear();
|
|
1706
|
+
_delta4->clear();
|
|
1707
|
+
_blossom_set->clear();
|
|
1708
|
+
_tree_set->clear();
|
|
1709
|
+
|
|
1710
|
+
int index = 0;
|
|
1711
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1712
|
+
Value pot = _fractional->nodeValue(n);
|
|
1713
|
+
(*_node_index)[n] = index;
|
|
1714
|
+
(*_node_data)[index].pot = pot;
|
|
1715
|
+
(*_node_data)[index].heap_index.clear();
|
|
1716
|
+
(*_node_data)[index].heap.clear();
|
|
1717
|
+
int blossom =
|
|
1718
|
+
_blossom_set->insert(n, std::numeric_limits<Value>::max());
|
|
1719
|
+
|
|
1720
|
+
(*_blossom_data)[blossom].status = MATCHED;
|
|
1721
|
+
(*_blossom_data)[blossom].pred = INVALID;
|
|
1722
|
+
(*_blossom_data)[blossom].next = _fractional->matching(n);
|
|
1723
|
+
if (_fractional->matching(n) == INVALID) {
|
|
1724
|
+
(*_blossom_data)[blossom].base = n;
|
|
1725
|
+
}
|
|
1726
|
+
(*_blossom_data)[blossom].pot = 0;
|
|
1727
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
1728
|
+
++index;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
typename Graph::template NodeMap<bool> processed(_graph, false);
|
|
1732
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1733
|
+
if (processed[n]) continue;
|
|
1734
|
+
processed[n] = true;
|
|
1735
|
+
if (_fractional->matching(n) == INVALID) continue;
|
|
1736
|
+
int num = 1;
|
|
1737
|
+
Node v = _graph.target(_fractional->matching(n));
|
|
1738
|
+
while (n != v) {
|
|
1739
|
+
processed[v] = true;
|
|
1740
|
+
v = _graph.target(_fractional->matching(v));
|
|
1741
|
+
++num;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
if (num % 2 == 1) {
|
|
1745
|
+
std::vector<int> subblossoms(num);
|
|
1746
|
+
|
|
1747
|
+
subblossoms[--num] = _blossom_set->find(n);
|
|
1748
|
+
_delta1->push(n, _fractional->nodeValue(n));
|
|
1749
|
+
v = _graph.target(_fractional->matching(n));
|
|
1750
|
+
while (n != v) {
|
|
1751
|
+
subblossoms[--num] = _blossom_set->find(v);
|
|
1752
|
+
_delta1->push(v, _fractional->nodeValue(v));
|
|
1753
|
+
v = _graph.target(_fractional->matching(v));
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
int surface =
|
|
1757
|
+
_blossom_set->join(subblossoms.begin(), subblossoms.end());
|
|
1758
|
+
(*_blossom_data)[surface].status = EVEN;
|
|
1759
|
+
(*_blossom_data)[surface].pred = INVALID;
|
|
1760
|
+
(*_blossom_data)[surface].next = INVALID;
|
|
1761
|
+
(*_blossom_data)[surface].pot = 0;
|
|
1762
|
+
(*_blossom_data)[surface].offset = 0;
|
|
1763
|
+
|
|
1764
|
+
_tree_set->insert(surface);
|
|
1765
|
+
++_unmatched;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1770
|
+
int si = (*_node_index)[_graph.u(e)];
|
|
1771
|
+
int sb = _blossom_set->find(_graph.u(e));
|
|
1772
|
+
int ti = (*_node_index)[_graph.v(e)];
|
|
1773
|
+
int tb = _blossom_set->find(_graph.v(e));
|
|
1774
|
+
if ((*_blossom_data)[sb].status == EVEN &&
|
|
1775
|
+
(*_blossom_data)[tb].status == EVEN && sb != tb) {
|
|
1776
|
+
_delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
|
|
1777
|
+
dualScale * _weight[e]) / 2);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1782
|
+
int nb = _blossom_set->find(n);
|
|
1783
|
+
if ((*_blossom_data)[nb].status != MATCHED) continue;
|
|
1784
|
+
int ni = (*_node_index)[n];
|
|
1785
|
+
|
|
1786
|
+
for (OutArcIt e(_graph, n); e != INVALID; ++e) {
|
|
1787
|
+
Node v = _graph.target(e);
|
|
1788
|
+
int vb = _blossom_set->find(v);
|
|
1789
|
+
int vi = (*_node_index)[v];
|
|
1790
|
+
|
|
1791
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
1792
|
+
dualScale * _weight[e];
|
|
1793
|
+
|
|
1794
|
+
if ((*_blossom_data)[vb].status == EVEN) {
|
|
1795
|
+
|
|
1796
|
+
int vt = _tree_set->find(vb);
|
|
1797
|
+
|
|
1798
|
+
typename std::map<int, Arc>::iterator it =
|
|
1799
|
+
(*_node_data)[ni].heap_index.find(vt);
|
|
1800
|
+
|
|
1801
|
+
if (it != (*_node_data)[ni].heap_index.end()) {
|
|
1802
|
+
if ((*_node_data)[ni].heap[it->second] > rw) {
|
|
1803
|
+
(*_node_data)[ni].heap.replace(it->second, e);
|
|
1804
|
+
(*_node_data)[ni].heap.decrease(e, rw);
|
|
1805
|
+
it->second = e;
|
|
1806
|
+
}
|
|
1807
|
+
} else {
|
|
1808
|
+
(*_node_data)[ni].heap.push(e, rw);
|
|
1809
|
+
(*_node_data)[ni].heap_index.insert(std::make_pair(vt, e));
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
if (!(*_node_data)[ni].heap.empty()) {
|
|
1815
|
+
_blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
|
|
1816
|
+
_delta2->push(nb, _blossom_set->classPrio(nb));
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
/// \brief Start the algorithm
|
|
1822
|
+
///
|
|
1823
|
+
/// This function starts the algorithm.
|
|
1824
|
+
///
|
|
1825
|
+
/// \pre \ref init() or \ref fractionalInit() must be called
|
|
1826
|
+
/// before using this function.
|
|
1827
|
+
void start() {
|
|
1828
|
+
enum OpType {
|
|
1829
|
+
D1, D2, D3, D4
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
while (_unmatched > 0) {
|
|
1833
|
+
Value d1 = !_delta1->empty() ?
|
|
1834
|
+
_delta1->prio() : std::numeric_limits<Value>::max();
|
|
1835
|
+
|
|
1836
|
+
Value d2 = !_delta2->empty() ?
|
|
1837
|
+
_delta2->prio() : std::numeric_limits<Value>::max();
|
|
1838
|
+
|
|
1839
|
+
Value d3 = !_delta3->empty() ?
|
|
1840
|
+
_delta3->prio() : std::numeric_limits<Value>::max();
|
|
1841
|
+
|
|
1842
|
+
Value d4 = !_delta4->empty() ?
|
|
1843
|
+
_delta4->prio() : std::numeric_limits<Value>::max();
|
|
1844
|
+
|
|
1845
|
+
_delta_sum = d3; OpType ot = D3;
|
|
1846
|
+
if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; }
|
|
1847
|
+
if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
|
|
1848
|
+
if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; }
|
|
1849
|
+
|
|
1850
|
+
switch (ot) {
|
|
1851
|
+
case D1:
|
|
1852
|
+
{
|
|
1853
|
+
Node n = _delta1->top();
|
|
1854
|
+
unmatchNode(n);
|
|
1855
|
+
--_unmatched;
|
|
1856
|
+
}
|
|
1857
|
+
break;
|
|
1858
|
+
case D2:
|
|
1859
|
+
{
|
|
1860
|
+
int blossom = _delta2->top();
|
|
1861
|
+
Node n = _blossom_set->classTop(blossom);
|
|
1862
|
+
Arc a = (*_node_data)[(*_node_index)[n]].heap.top();
|
|
1863
|
+
if ((*_blossom_data)[blossom].next == INVALID) {
|
|
1864
|
+
augmentOnArc(a);
|
|
1865
|
+
--_unmatched;
|
|
1866
|
+
} else {
|
|
1867
|
+
extendOnArc(a);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
break;
|
|
1871
|
+
case D3:
|
|
1872
|
+
{
|
|
1873
|
+
Edge e = _delta3->top();
|
|
1874
|
+
|
|
1875
|
+
int left_blossom = _blossom_set->find(_graph.u(e));
|
|
1876
|
+
int right_blossom = _blossom_set->find(_graph.v(e));
|
|
1877
|
+
|
|
1878
|
+
if (left_blossom == right_blossom) {
|
|
1879
|
+
_delta3->pop();
|
|
1880
|
+
} else {
|
|
1881
|
+
int left_tree = _tree_set->find(left_blossom);
|
|
1882
|
+
int right_tree = _tree_set->find(right_blossom);
|
|
1883
|
+
|
|
1884
|
+
if (left_tree == right_tree) {
|
|
1885
|
+
shrinkOnEdge(e, left_tree);
|
|
1886
|
+
} else {
|
|
1887
|
+
augmentOnEdge(e);
|
|
1888
|
+
_unmatched -= 2;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
} break;
|
|
1892
|
+
case D4:
|
|
1893
|
+
splitBlossom(_delta4->top());
|
|
1894
|
+
break;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
extractMatching();
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
/// \brief Run the algorithm.
|
|
1901
|
+
///
|
|
1902
|
+
/// This method runs the \c %MaxWeightedMatching algorithm.
|
|
1903
|
+
///
|
|
1904
|
+
/// \note mwm.run() is just a shortcut of the following code.
|
|
1905
|
+
/// \code
|
|
1906
|
+
/// mwm.fractionalInit();
|
|
1907
|
+
/// mwm.start();
|
|
1908
|
+
/// \endcode
|
|
1909
|
+
void run() {
|
|
1910
|
+
fractionalInit();
|
|
1911
|
+
start();
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
/// @}
|
|
1915
|
+
|
|
1916
|
+
/// \name Primal Solution
|
|
1917
|
+
/// Functions to get the primal solution, i.e. the maximum weighted
|
|
1918
|
+
/// matching.\n
|
|
1919
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
1920
|
+
/// using them.
|
|
1921
|
+
|
|
1922
|
+
/// @{
|
|
1923
|
+
|
|
1924
|
+
/// \brief Return the weight of the matching.
|
|
1925
|
+
///
|
|
1926
|
+
/// This function returns the weight of the found matching.
|
|
1927
|
+
///
|
|
1928
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1929
|
+
Value matchingWeight() const {
|
|
1930
|
+
Value sum = 0;
|
|
1931
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1932
|
+
if ((*_matching)[n] != INVALID) {
|
|
1933
|
+
sum += _weight[(*_matching)[n]];
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
return sum / 2;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
/// \brief Return the size (cardinality) of the matching.
|
|
1940
|
+
///
|
|
1941
|
+
/// This function returns the size (cardinality) of the found matching.
|
|
1942
|
+
///
|
|
1943
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1944
|
+
int matchingSize() const {
|
|
1945
|
+
int num = 0;
|
|
1946
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1947
|
+
if ((*_matching)[n] != INVALID) {
|
|
1948
|
+
++num;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
return num /= 2;
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
/// \brief Return \c true if the given edge is in the matching.
|
|
1955
|
+
///
|
|
1956
|
+
/// This function returns \c true if the given edge is in the found
|
|
1957
|
+
/// matching.
|
|
1958
|
+
///
|
|
1959
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1960
|
+
bool matching(const Edge& edge) const {
|
|
1961
|
+
return edge == (*_matching)[_graph.u(edge)];
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
/// \brief Return the matching arc (or edge) incident to the given node.
|
|
1965
|
+
///
|
|
1966
|
+
/// This function returns the matching arc (or edge) incident to the
|
|
1967
|
+
/// given node in the found matching or \c INVALID if the node is
|
|
1968
|
+
/// not covered by the matching.
|
|
1969
|
+
///
|
|
1970
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1971
|
+
Arc matching(const Node& node) const {
|
|
1972
|
+
return (*_matching)[node];
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
/// \brief Return a const reference to the matching map.
|
|
1976
|
+
///
|
|
1977
|
+
/// This function returns a const reference to a node map that stores
|
|
1978
|
+
/// the matching arc (or edge) incident to each node.
|
|
1979
|
+
const MatchingMap& matchingMap() const {
|
|
1980
|
+
return *_matching;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
/// \brief Return the mate of the given node.
|
|
1984
|
+
///
|
|
1985
|
+
/// This function returns the mate of the given node in the found
|
|
1986
|
+
/// matching or \c INVALID if the node is not covered by the matching.
|
|
1987
|
+
///
|
|
1988
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1989
|
+
Node mate(const Node& node) const {
|
|
1990
|
+
return (*_matching)[node] != INVALID ?
|
|
1991
|
+
_graph.target((*_matching)[node]) : INVALID;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
/// @}
|
|
1995
|
+
|
|
1996
|
+
/// \name Dual Solution
|
|
1997
|
+
/// Functions to get the dual solution.\n
|
|
1998
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
1999
|
+
/// using them.
|
|
2000
|
+
|
|
2001
|
+
/// @{
|
|
2002
|
+
|
|
2003
|
+
/// \brief Return the value of the dual solution.
|
|
2004
|
+
///
|
|
2005
|
+
/// This function returns the value of the dual solution.
|
|
2006
|
+
/// It should be equal to the primal value scaled by \ref dualScale
|
|
2007
|
+
/// "dual scale".
|
|
2008
|
+
///
|
|
2009
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2010
|
+
Value dualValue() const {
|
|
2011
|
+
Value sum = 0;
|
|
2012
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
2013
|
+
sum += nodeValue(n);
|
|
2014
|
+
}
|
|
2015
|
+
for (int i = 0; i < blossomNum(); ++i) {
|
|
2016
|
+
sum += blossomValue(i) * (blossomSize(i) / 2);
|
|
2017
|
+
}
|
|
2018
|
+
return sum;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
/// \brief Return the dual value (potential) of the given node.
|
|
2022
|
+
///
|
|
2023
|
+
/// This function returns the dual value (potential) of the given node.
|
|
2024
|
+
///
|
|
2025
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2026
|
+
Value nodeValue(const Node& n) const {
|
|
2027
|
+
return (*_node_potential)[n];
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
/// \brief Return the number of the blossoms in the basis.
|
|
2031
|
+
///
|
|
2032
|
+
/// This function returns the number of the blossoms in the basis.
|
|
2033
|
+
///
|
|
2034
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2035
|
+
/// \see BlossomIt
|
|
2036
|
+
int blossomNum() const {
|
|
2037
|
+
return _blossom_potential.size();
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
/// \brief Return the number of the nodes in the given blossom.
|
|
2041
|
+
///
|
|
2042
|
+
/// This function returns the number of the nodes in the given blossom.
|
|
2043
|
+
///
|
|
2044
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2045
|
+
/// \see BlossomIt
|
|
2046
|
+
int blossomSize(int k) const {
|
|
2047
|
+
return _blossom_potential[k].end - _blossom_potential[k].begin;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
/// \brief Return the dual value (ptential) of the given blossom.
|
|
2051
|
+
///
|
|
2052
|
+
/// This function returns the dual value (ptential) of the given blossom.
|
|
2053
|
+
///
|
|
2054
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2055
|
+
Value blossomValue(int k) const {
|
|
2056
|
+
return _blossom_potential[k].value;
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
/// \brief Iterator for obtaining the nodes of a blossom.
|
|
2060
|
+
///
|
|
2061
|
+
/// This class provides an iterator for obtaining the nodes of the
|
|
2062
|
+
/// given blossom. It lists a subset of the nodes.
|
|
2063
|
+
/// Before using this iterator, you must allocate a
|
|
2064
|
+
/// MaxWeightedMatching class and execute it.
|
|
2065
|
+
class BlossomIt {
|
|
2066
|
+
public:
|
|
2067
|
+
|
|
2068
|
+
/// \brief Constructor.
|
|
2069
|
+
///
|
|
2070
|
+
/// Constructor to get the nodes of the given variable.
|
|
2071
|
+
///
|
|
2072
|
+
/// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or
|
|
2073
|
+
/// \ref MaxWeightedMatching::start() "algorithm.start()" must be
|
|
2074
|
+
/// called before initializing this iterator.
|
|
2075
|
+
BlossomIt(const MaxWeightedMatching& algorithm, int variable)
|
|
2076
|
+
: _algorithm(&algorithm)
|
|
2077
|
+
{
|
|
2078
|
+
_index = _algorithm->_blossom_potential[variable].begin;
|
|
2079
|
+
_last = _algorithm->_blossom_potential[variable].end;
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
/// \brief Conversion to \c Node.
|
|
2083
|
+
///
|
|
2084
|
+
/// Conversion to \c Node.
|
|
2085
|
+
operator Node() const {
|
|
2086
|
+
return _algorithm->_blossom_node_list[_index];
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
/// \brief Increment operator.
|
|
2090
|
+
///
|
|
2091
|
+
/// Increment operator.
|
|
2092
|
+
BlossomIt& operator++() {
|
|
2093
|
+
++_index;
|
|
2094
|
+
return *this;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
/// \brief Validity checking
|
|
2098
|
+
///
|
|
2099
|
+
/// Checks whether the iterator is invalid.
|
|
2100
|
+
bool operator==(Invalid) const { return _index == _last; }
|
|
2101
|
+
|
|
2102
|
+
/// \brief Validity checking
|
|
2103
|
+
///
|
|
2104
|
+
/// Checks whether the iterator is valid.
|
|
2105
|
+
bool operator!=(Invalid) const { return _index != _last; }
|
|
2106
|
+
|
|
2107
|
+
private:
|
|
2108
|
+
const MaxWeightedMatching* _algorithm;
|
|
2109
|
+
int _last;
|
|
2110
|
+
int _index;
|
|
2111
|
+
};
|
|
2112
|
+
|
|
2113
|
+
/// @}
|
|
2114
|
+
|
|
2115
|
+
};
|
|
2116
|
+
|
|
2117
|
+
/// \ingroup matching
|
|
2118
|
+
///
|
|
2119
|
+
/// \brief Weighted perfect matching in general graphs
|
|
2120
|
+
///
|
|
2121
|
+
/// This class provides an efficient implementation of Edmond's
|
|
2122
|
+
/// maximum weighted perfect matching algorithm. The implementation
|
|
2123
|
+
/// is based on extensive use of priority queues and provides
|
|
2124
|
+
/// \f$O(nm\log n)\f$ time complexity.
|
|
2125
|
+
///
|
|
2126
|
+
/// The maximum weighted perfect matching problem is to find a subset of
|
|
2127
|
+
/// the edges in an undirected graph with maximum overall weight for which
|
|
2128
|
+
/// each node has exactly one incident edge.
|
|
2129
|
+
/// It can be formulated with the following linear program.
|
|
2130
|
+
/// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f]
|
|
2131
|
+
/** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2}
|
|
2132
|
+
\quad \forall B\in\mathcal{O}\f] */
|
|
2133
|
+
/// \f[x_e \ge 0\quad \forall e\in E\f]
|
|
2134
|
+
/// \f[\max \sum_{e\in E}x_ew_e\f]
|
|
2135
|
+
/// where \f$\delta(X)\f$ is the set of edges incident to a node in
|
|
2136
|
+
/// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in
|
|
2137
|
+
/// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality
|
|
2138
|
+
/// subsets of the nodes.
|
|
2139
|
+
///
|
|
2140
|
+
/// The algorithm calculates an optimal matching and a proof of the
|
|
2141
|
+
/// optimality. The solution of the dual problem can be used to check
|
|
2142
|
+
/// the result of the algorithm. The dual linear problem is the
|
|
2143
|
+
/// following.
|
|
2144
|
+
/** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)}z_B \ge
|
|
2145
|
+
w_{uv} \quad \forall uv\in E\f] */
|
|
2146
|
+
/// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f]
|
|
2147
|
+
/** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}}
|
|
2148
|
+
\frac{\vert B \vert - 1}{2}z_B\f] */
|
|
2149
|
+
///
|
|
2150
|
+
/// The algorithm can be executed with the run() function.
|
|
2151
|
+
/// After it the matching (the primal solution) and the dual solution
|
|
2152
|
+
/// can be obtained using the query functions and the
|
|
2153
|
+
/// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class,
|
|
2154
|
+
/// which is able to iterate on the nodes of a blossom.
|
|
2155
|
+
/// If the value type is integer, then the dual solution is multiplied
|
|
2156
|
+
/// by \ref MaxWeightedMatching::dualScale "4".
|
|
2157
|
+
///
|
|
2158
|
+
/// \tparam GR The undirected graph type the algorithm runs on.
|
|
2159
|
+
/// \tparam WM The type edge weight map. The default type is
|
|
2160
|
+
/// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
|
|
2161
|
+
#ifdef DOXYGEN
|
|
2162
|
+
template <typename GR, typename WM>
|
|
2163
|
+
#else
|
|
2164
|
+
template <typename GR,
|
|
2165
|
+
typename WM = typename GR::template EdgeMap<int> >
|
|
2166
|
+
#endif
|
|
2167
|
+
class MaxWeightedPerfectMatching {
|
|
2168
|
+
public:
|
|
2169
|
+
|
|
2170
|
+
/// The graph type of the algorithm
|
|
2171
|
+
typedef GR Graph;
|
|
2172
|
+
/// The type of the edge weight map
|
|
2173
|
+
typedef WM WeightMap;
|
|
2174
|
+
/// The value type of the edge weights
|
|
2175
|
+
typedef typename WeightMap::Value Value;
|
|
2176
|
+
|
|
2177
|
+
/// \brief Scaling factor for dual solution
|
|
2178
|
+
///
|
|
2179
|
+
/// Scaling factor for dual solution, it is equal to 4 or 1
|
|
2180
|
+
/// according to the value type.
|
|
2181
|
+
static const int dualScale =
|
|
2182
|
+
std::numeric_limits<Value>::is_integer ? 4 : 1;
|
|
2183
|
+
|
|
2184
|
+
/// The type of the matching map
|
|
2185
|
+
typedef typename Graph::template NodeMap<typename Graph::Arc>
|
|
2186
|
+
MatchingMap;
|
|
2187
|
+
|
|
2188
|
+
private:
|
|
2189
|
+
|
|
2190
|
+
TEMPLATE_GRAPH_TYPEDEFS(Graph);
|
|
2191
|
+
|
|
2192
|
+
typedef typename Graph::template NodeMap<Value> NodePotential;
|
|
2193
|
+
typedef std::vector<Node> BlossomNodeList;
|
|
2194
|
+
|
|
2195
|
+
struct BlossomVariable {
|
|
2196
|
+
int begin, end;
|
|
2197
|
+
Value value;
|
|
2198
|
+
|
|
2199
|
+
BlossomVariable(int _begin, int _end, Value _value)
|
|
2200
|
+
: begin(_begin), end(_end), value(_value) {}
|
|
2201
|
+
|
|
2202
|
+
};
|
|
2203
|
+
|
|
2204
|
+
typedef std::vector<BlossomVariable> BlossomPotential;
|
|
2205
|
+
|
|
2206
|
+
const Graph& _graph;
|
|
2207
|
+
const WeightMap& _weight;
|
|
2208
|
+
|
|
2209
|
+
MatchingMap* _matching;
|
|
2210
|
+
|
|
2211
|
+
NodePotential* _node_potential;
|
|
2212
|
+
|
|
2213
|
+
BlossomPotential _blossom_potential;
|
|
2214
|
+
BlossomNodeList _blossom_node_list;
|
|
2215
|
+
|
|
2216
|
+
int _node_num;
|
|
2217
|
+
int _blossom_num;
|
|
2218
|
+
|
|
2219
|
+
typedef RangeMap<int> IntIntMap;
|
|
2220
|
+
|
|
2221
|
+
enum Status {
|
|
2222
|
+
EVEN = -1, MATCHED = 0, ODD = 1
|
|
2223
|
+
};
|
|
2224
|
+
|
|
2225
|
+
typedef HeapUnionFind<Value, IntNodeMap> BlossomSet;
|
|
2226
|
+
struct BlossomData {
|
|
2227
|
+
int tree;
|
|
2228
|
+
Status status;
|
|
2229
|
+
Arc pred, next;
|
|
2230
|
+
Value pot, offset;
|
|
2231
|
+
};
|
|
2232
|
+
|
|
2233
|
+
IntNodeMap *_blossom_index;
|
|
2234
|
+
BlossomSet *_blossom_set;
|
|
2235
|
+
RangeMap<BlossomData>* _blossom_data;
|
|
2236
|
+
|
|
2237
|
+
IntNodeMap *_node_index;
|
|
2238
|
+
IntArcMap *_node_heap_index;
|
|
2239
|
+
|
|
2240
|
+
struct NodeData {
|
|
2241
|
+
|
|
2242
|
+
NodeData(IntArcMap& node_heap_index)
|
|
2243
|
+
: heap(node_heap_index) {}
|
|
2244
|
+
|
|
2245
|
+
int blossom;
|
|
2246
|
+
Value pot;
|
|
2247
|
+
BinHeap<Value, IntArcMap> heap;
|
|
2248
|
+
std::map<int, Arc> heap_index;
|
|
2249
|
+
|
|
2250
|
+
int tree;
|
|
2251
|
+
};
|
|
2252
|
+
|
|
2253
|
+
RangeMap<NodeData>* _node_data;
|
|
2254
|
+
|
|
2255
|
+
typedef ExtendFindEnum<IntIntMap> TreeSet;
|
|
2256
|
+
|
|
2257
|
+
IntIntMap *_tree_set_index;
|
|
2258
|
+
TreeSet *_tree_set;
|
|
2259
|
+
|
|
2260
|
+
IntIntMap *_delta2_index;
|
|
2261
|
+
BinHeap<Value, IntIntMap> *_delta2;
|
|
2262
|
+
|
|
2263
|
+
IntEdgeMap *_delta3_index;
|
|
2264
|
+
BinHeap<Value, IntEdgeMap> *_delta3;
|
|
2265
|
+
|
|
2266
|
+
IntIntMap *_delta4_index;
|
|
2267
|
+
BinHeap<Value, IntIntMap> *_delta4;
|
|
2268
|
+
|
|
2269
|
+
Value _delta_sum;
|
|
2270
|
+
int _unmatched;
|
|
2271
|
+
|
|
2272
|
+
typedef MaxWeightedPerfectFractionalMatching<Graph, WeightMap>
|
|
2273
|
+
FractionalMatching;
|
|
2274
|
+
FractionalMatching *_fractional;
|
|
2275
|
+
|
|
2276
|
+
void createStructures() {
|
|
2277
|
+
_node_num = countNodes(_graph);
|
|
2278
|
+
_blossom_num = _node_num * 3 / 2;
|
|
2279
|
+
|
|
2280
|
+
if (!_matching) {
|
|
2281
|
+
_matching = new MatchingMap(_graph);
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
if (!_node_potential) {
|
|
2285
|
+
_node_potential = new NodePotential(_graph);
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
if (!_blossom_set) {
|
|
2289
|
+
_blossom_index = new IntNodeMap(_graph);
|
|
2290
|
+
_blossom_set = new BlossomSet(*_blossom_index);
|
|
2291
|
+
_blossom_data = new RangeMap<BlossomData>(_blossom_num);
|
|
2292
|
+
} else if (_blossom_data->size() != _blossom_num) {
|
|
2293
|
+
delete _blossom_data;
|
|
2294
|
+
_blossom_data = new RangeMap<BlossomData>(_blossom_num);
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
if (!_node_index) {
|
|
2298
|
+
_node_index = new IntNodeMap(_graph);
|
|
2299
|
+
_node_heap_index = new IntArcMap(_graph);
|
|
2300
|
+
_node_data = new RangeMap<NodeData>(_node_num,
|
|
2301
|
+
NodeData(*_node_heap_index));
|
|
2302
|
+
} else if (_node_data->size() != _node_num) {
|
|
2303
|
+
delete _node_data;
|
|
2304
|
+
_node_data = new RangeMap<NodeData>(_node_num,
|
|
2305
|
+
NodeData(*_node_heap_index));
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
if (!_tree_set) {
|
|
2309
|
+
_tree_set_index = new IntIntMap(_blossom_num);
|
|
2310
|
+
_tree_set = new TreeSet(*_tree_set_index);
|
|
2311
|
+
} else {
|
|
2312
|
+
_tree_set_index->resize(_blossom_num);
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
if (!_delta2) {
|
|
2316
|
+
_delta2_index = new IntIntMap(_blossom_num);
|
|
2317
|
+
_delta2 = new BinHeap<Value, IntIntMap>(*_delta2_index);
|
|
2318
|
+
} else {
|
|
2319
|
+
_delta2_index->resize(_blossom_num);
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
if (!_delta3) {
|
|
2323
|
+
_delta3_index = new IntEdgeMap(_graph);
|
|
2324
|
+
_delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
if (!_delta4) {
|
|
2328
|
+
_delta4_index = new IntIntMap(_blossom_num);
|
|
2329
|
+
_delta4 = new BinHeap<Value, IntIntMap>(*_delta4_index);
|
|
2330
|
+
} else {
|
|
2331
|
+
_delta4_index->resize(_blossom_num);
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
void destroyStructures() {
|
|
2336
|
+
if (_matching) {
|
|
2337
|
+
delete _matching;
|
|
2338
|
+
}
|
|
2339
|
+
if (_node_potential) {
|
|
2340
|
+
delete _node_potential;
|
|
2341
|
+
}
|
|
2342
|
+
if (_blossom_set) {
|
|
2343
|
+
delete _blossom_index;
|
|
2344
|
+
delete _blossom_set;
|
|
2345
|
+
delete _blossom_data;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
if (_node_index) {
|
|
2349
|
+
delete _node_index;
|
|
2350
|
+
delete _node_heap_index;
|
|
2351
|
+
delete _node_data;
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
if (_tree_set) {
|
|
2355
|
+
delete _tree_set_index;
|
|
2356
|
+
delete _tree_set;
|
|
2357
|
+
}
|
|
2358
|
+
if (_delta2) {
|
|
2359
|
+
delete _delta2_index;
|
|
2360
|
+
delete _delta2;
|
|
2361
|
+
}
|
|
2362
|
+
if (_delta3) {
|
|
2363
|
+
delete _delta3_index;
|
|
2364
|
+
delete _delta3;
|
|
2365
|
+
}
|
|
2366
|
+
if (_delta4) {
|
|
2367
|
+
delete _delta4_index;
|
|
2368
|
+
delete _delta4;
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
void matchedToEven(int blossom, int tree) {
|
|
2373
|
+
if (_delta2->state(blossom) == _delta2->IN_HEAP) {
|
|
2374
|
+
_delta2->erase(blossom);
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
2378
|
+
(*_blossom_data)[blossom].pot -=
|
|
2379
|
+
2 * (_delta_sum - (*_blossom_data)[blossom].offset);
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
|
|
2383
|
+
n != INVALID; ++n) {
|
|
2384
|
+
|
|
2385
|
+
_blossom_set->increase(n, std::numeric_limits<Value>::max());
|
|
2386
|
+
int ni = (*_node_index)[n];
|
|
2387
|
+
|
|
2388
|
+
(*_node_data)[ni].heap.clear();
|
|
2389
|
+
(*_node_data)[ni].heap_index.clear();
|
|
2390
|
+
|
|
2391
|
+
(*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset;
|
|
2392
|
+
|
|
2393
|
+
for (InArcIt e(_graph, n); e != INVALID; ++e) {
|
|
2394
|
+
Node v = _graph.source(e);
|
|
2395
|
+
int vb = _blossom_set->find(v);
|
|
2396
|
+
int vi = (*_node_index)[v];
|
|
2397
|
+
|
|
2398
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
2399
|
+
dualScale * _weight[e];
|
|
2400
|
+
|
|
2401
|
+
if ((*_blossom_data)[vb].status == EVEN) {
|
|
2402
|
+
if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
|
|
2403
|
+
_delta3->push(e, rw / 2);
|
|
2404
|
+
}
|
|
2405
|
+
} else {
|
|
2406
|
+
typename std::map<int, Arc>::iterator it =
|
|
2407
|
+
(*_node_data)[vi].heap_index.find(tree);
|
|
2408
|
+
|
|
2409
|
+
if (it != (*_node_data)[vi].heap_index.end()) {
|
|
2410
|
+
if ((*_node_data)[vi].heap[it->second] > rw) {
|
|
2411
|
+
(*_node_data)[vi].heap.replace(it->second, e);
|
|
2412
|
+
(*_node_data)[vi].heap.decrease(e, rw);
|
|
2413
|
+
it->second = e;
|
|
2414
|
+
}
|
|
2415
|
+
} else {
|
|
2416
|
+
(*_node_data)[vi].heap.push(e, rw);
|
|
2417
|
+
(*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
|
|
2421
|
+
_blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
|
|
2422
|
+
|
|
2423
|
+
if ((*_blossom_data)[vb].status == MATCHED) {
|
|
2424
|
+
if (_delta2->state(vb) != _delta2->IN_HEAP) {
|
|
2425
|
+
_delta2->push(vb, _blossom_set->classPrio(vb) -
|
|
2426
|
+
(*_blossom_data)[vb].offset);
|
|
2427
|
+
} else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
|
|
2428
|
+
(*_blossom_data)[vb].offset){
|
|
2429
|
+
_delta2->decrease(vb, _blossom_set->classPrio(vb) -
|
|
2430
|
+
(*_blossom_data)[vb].offset);
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
void matchedToOdd(int blossom) {
|
|
2441
|
+
if (_delta2->state(blossom) == _delta2->IN_HEAP) {
|
|
2442
|
+
_delta2->erase(blossom);
|
|
2443
|
+
}
|
|
2444
|
+
(*_blossom_data)[blossom].offset += _delta_sum;
|
|
2445
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
2446
|
+
_delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 +
|
|
2447
|
+
(*_blossom_data)[blossom].offset);
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
void evenToMatched(int blossom, int tree) {
|
|
2452
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
2453
|
+
(*_blossom_data)[blossom].pot += 2 * _delta_sum;
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
|
|
2457
|
+
n != INVALID; ++n) {
|
|
2458
|
+
int ni = (*_node_index)[n];
|
|
2459
|
+
(*_node_data)[ni].pot -= _delta_sum;
|
|
2460
|
+
|
|
2461
|
+
for (InArcIt e(_graph, n); e != INVALID; ++e) {
|
|
2462
|
+
Node v = _graph.source(e);
|
|
2463
|
+
int vb = _blossom_set->find(v);
|
|
2464
|
+
int vi = (*_node_index)[v];
|
|
2465
|
+
|
|
2466
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
2467
|
+
dualScale * _weight[e];
|
|
2468
|
+
|
|
2469
|
+
if (vb == blossom) {
|
|
2470
|
+
if (_delta3->state(e) == _delta3->IN_HEAP) {
|
|
2471
|
+
_delta3->erase(e);
|
|
2472
|
+
}
|
|
2473
|
+
} else if ((*_blossom_data)[vb].status == EVEN) {
|
|
2474
|
+
|
|
2475
|
+
if (_delta3->state(e) == _delta3->IN_HEAP) {
|
|
2476
|
+
_delta3->erase(e);
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
int vt = _tree_set->find(vb);
|
|
2480
|
+
|
|
2481
|
+
if (vt != tree) {
|
|
2482
|
+
|
|
2483
|
+
Arc r = _graph.oppositeArc(e);
|
|
2484
|
+
|
|
2485
|
+
typename std::map<int, Arc>::iterator it =
|
|
2486
|
+
(*_node_data)[ni].heap_index.find(vt);
|
|
2487
|
+
|
|
2488
|
+
if (it != (*_node_data)[ni].heap_index.end()) {
|
|
2489
|
+
if ((*_node_data)[ni].heap[it->second] > rw) {
|
|
2490
|
+
(*_node_data)[ni].heap.replace(it->second, r);
|
|
2491
|
+
(*_node_data)[ni].heap.decrease(r, rw);
|
|
2492
|
+
it->second = r;
|
|
2493
|
+
}
|
|
2494
|
+
} else {
|
|
2495
|
+
(*_node_data)[ni].heap.push(r, rw);
|
|
2496
|
+
(*_node_data)[ni].heap_index.insert(std::make_pair(vt, r));
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) {
|
|
2500
|
+
_blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
|
|
2501
|
+
|
|
2502
|
+
if (_delta2->state(blossom) != _delta2->IN_HEAP) {
|
|
2503
|
+
_delta2->push(blossom, _blossom_set->classPrio(blossom) -
|
|
2504
|
+
(*_blossom_data)[blossom].offset);
|
|
2505
|
+
} else if ((*_delta2)[blossom] >
|
|
2506
|
+
_blossom_set->classPrio(blossom) -
|
|
2507
|
+
(*_blossom_data)[blossom].offset){
|
|
2508
|
+
_delta2->decrease(blossom, _blossom_set->classPrio(blossom) -
|
|
2509
|
+
(*_blossom_data)[blossom].offset);
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
} else {
|
|
2514
|
+
|
|
2515
|
+
typename std::map<int, Arc>::iterator it =
|
|
2516
|
+
(*_node_data)[vi].heap_index.find(tree);
|
|
2517
|
+
|
|
2518
|
+
if (it != (*_node_data)[vi].heap_index.end()) {
|
|
2519
|
+
(*_node_data)[vi].heap.erase(it->second);
|
|
2520
|
+
(*_node_data)[vi].heap_index.erase(it);
|
|
2521
|
+
if ((*_node_data)[vi].heap.empty()) {
|
|
2522
|
+
_blossom_set->increase(v, std::numeric_limits<Value>::max());
|
|
2523
|
+
} else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) {
|
|
2524
|
+
_blossom_set->increase(v, (*_node_data)[vi].heap.prio());
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
if ((*_blossom_data)[vb].status == MATCHED) {
|
|
2528
|
+
if (_blossom_set->classPrio(vb) ==
|
|
2529
|
+
std::numeric_limits<Value>::max()) {
|
|
2530
|
+
_delta2->erase(vb);
|
|
2531
|
+
} else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) -
|
|
2532
|
+
(*_blossom_data)[vb].offset) {
|
|
2533
|
+
_delta2->increase(vb, _blossom_set->classPrio(vb) -
|
|
2534
|
+
(*_blossom_data)[vb].offset);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
void oddToMatched(int blossom) {
|
|
2544
|
+
(*_blossom_data)[blossom].offset -= _delta_sum;
|
|
2545
|
+
|
|
2546
|
+
if (_blossom_set->classPrio(blossom) !=
|
|
2547
|
+
std::numeric_limits<Value>::max()) {
|
|
2548
|
+
_delta2->push(blossom, _blossom_set->classPrio(blossom) -
|
|
2549
|
+
(*_blossom_data)[blossom].offset);
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
2553
|
+
_delta4->erase(blossom);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
void oddToEven(int blossom, int tree) {
|
|
2558
|
+
if (!_blossom_set->trivial(blossom)) {
|
|
2559
|
+
_delta4->erase(blossom);
|
|
2560
|
+
(*_blossom_data)[blossom].pot -=
|
|
2561
|
+
2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset);
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);
|
|
2565
|
+
n != INVALID; ++n) {
|
|
2566
|
+
int ni = (*_node_index)[n];
|
|
2567
|
+
|
|
2568
|
+
_blossom_set->increase(n, std::numeric_limits<Value>::max());
|
|
2569
|
+
|
|
2570
|
+
(*_node_data)[ni].heap.clear();
|
|
2571
|
+
(*_node_data)[ni].heap_index.clear();
|
|
2572
|
+
(*_node_data)[ni].pot +=
|
|
2573
|
+
2 * _delta_sum - (*_blossom_data)[blossom].offset;
|
|
2574
|
+
|
|
2575
|
+
for (InArcIt e(_graph, n); e != INVALID; ++e) {
|
|
2576
|
+
Node v = _graph.source(e);
|
|
2577
|
+
int vb = _blossom_set->find(v);
|
|
2578
|
+
int vi = (*_node_index)[v];
|
|
2579
|
+
|
|
2580
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
2581
|
+
dualScale * _weight[e];
|
|
2582
|
+
|
|
2583
|
+
if ((*_blossom_data)[vb].status == EVEN) {
|
|
2584
|
+
if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) {
|
|
2585
|
+
_delta3->push(e, rw / 2);
|
|
2586
|
+
}
|
|
2587
|
+
} else {
|
|
2588
|
+
|
|
2589
|
+
typename std::map<int, Arc>::iterator it =
|
|
2590
|
+
(*_node_data)[vi].heap_index.find(tree);
|
|
2591
|
+
|
|
2592
|
+
if (it != (*_node_data)[vi].heap_index.end()) {
|
|
2593
|
+
if ((*_node_data)[vi].heap[it->second] > rw) {
|
|
2594
|
+
(*_node_data)[vi].heap.replace(it->second, e);
|
|
2595
|
+
(*_node_data)[vi].heap.decrease(e, rw);
|
|
2596
|
+
it->second = e;
|
|
2597
|
+
}
|
|
2598
|
+
} else {
|
|
2599
|
+
(*_node_data)[vi].heap.push(e, rw);
|
|
2600
|
+
(*_node_data)[vi].heap_index.insert(std::make_pair(tree, e));
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) {
|
|
2604
|
+
_blossom_set->decrease(v, (*_node_data)[vi].heap.prio());
|
|
2605
|
+
|
|
2606
|
+
if ((*_blossom_data)[vb].status == MATCHED) {
|
|
2607
|
+
if (_delta2->state(vb) != _delta2->IN_HEAP) {
|
|
2608
|
+
_delta2->push(vb, _blossom_set->classPrio(vb) -
|
|
2609
|
+
(*_blossom_data)[vb].offset);
|
|
2610
|
+
} else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) -
|
|
2611
|
+
(*_blossom_data)[vb].offset) {
|
|
2612
|
+
_delta2->decrease(vb, _blossom_set->classPrio(vb) -
|
|
2613
|
+
(*_blossom_data)[vb].offset);
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
void alternatePath(int even, int tree) {
|
|
2624
|
+
int odd;
|
|
2625
|
+
|
|
2626
|
+
evenToMatched(even, tree);
|
|
2627
|
+
(*_blossom_data)[even].status = MATCHED;
|
|
2628
|
+
|
|
2629
|
+
while ((*_blossom_data)[even].pred != INVALID) {
|
|
2630
|
+
odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred));
|
|
2631
|
+
(*_blossom_data)[odd].status = MATCHED;
|
|
2632
|
+
oddToMatched(odd);
|
|
2633
|
+
(*_blossom_data)[odd].next = (*_blossom_data)[odd].pred;
|
|
2634
|
+
|
|
2635
|
+
even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred));
|
|
2636
|
+
(*_blossom_data)[even].status = MATCHED;
|
|
2637
|
+
evenToMatched(even, tree);
|
|
2638
|
+
(*_blossom_data)[even].next =
|
|
2639
|
+
_graph.oppositeArc((*_blossom_data)[odd].pred);
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2644
|
+
void destroyTree(int tree) {
|
|
2645
|
+
for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) {
|
|
2646
|
+
if ((*_blossom_data)[b].status == EVEN) {
|
|
2647
|
+
(*_blossom_data)[b].status = MATCHED;
|
|
2648
|
+
evenToMatched(b, tree);
|
|
2649
|
+
} else if ((*_blossom_data)[b].status == ODD) {
|
|
2650
|
+
(*_blossom_data)[b].status = MATCHED;
|
|
2651
|
+
oddToMatched(b);
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
_tree_set->eraseClass(tree);
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
void augmentOnEdge(const Edge& edge) {
|
|
2658
|
+
|
|
2659
|
+
int left = _blossom_set->find(_graph.u(edge));
|
|
2660
|
+
int right = _blossom_set->find(_graph.v(edge));
|
|
2661
|
+
|
|
2662
|
+
int left_tree = _tree_set->find(left);
|
|
2663
|
+
alternatePath(left, left_tree);
|
|
2664
|
+
destroyTree(left_tree);
|
|
2665
|
+
|
|
2666
|
+
int right_tree = _tree_set->find(right);
|
|
2667
|
+
alternatePath(right, right_tree);
|
|
2668
|
+
destroyTree(right_tree);
|
|
2669
|
+
|
|
2670
|
+
(*_blossom_data)[left].next = _graph.direct(edge, true);
|
|
2671
|
+
(*_blossom_data)[right].next = _graph.direct(edge, false);
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
void extendOnArc(const Arc& arc) {
|
|
2675
|
+
int base = _blossom_set->find(_graph.target(arc));
|
|
2676
|
+
int tree = _tree_set->find(base);
|
|
2677
|
+
|
|
2678
|
+
int odd = _blossom_set->find(_graph.source(arc));
|
|
2679
|
+
_tree_set->insert(odd, tree);
|
|
2680
|
+
(*_blossom_data)[odd].status = ODD;
|
|
2681
|
+
matchedToOdd(odd);
|
|
2682
|
+
(*_blossom_data)[odd].pred = arc;
|
|
2683
|
+
|
|
2684
|
+
int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next));
|
|
2685
|
+
(*_blossom_data)[even].pred = (*_blossom_data)[even].next;
|
|
2686
|
+
_tree_set->insert(even, tree);
|
|
2687
|
+
(*_blossom_data)[even].status = EVEN;
|
|
2688
|
+
matchedToEven(even, tree);
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
void shrinkOnEdge(const Edge& edge, int tree) {
|
|
2692
|
+
int nca = -1;
|
|
2693
|
+
std::vector<int> left_path, right_path;
|
|
2694
|
+
|
|
2695
|
+
{
|
|
2696
|
+
std::set<int> left_set, right_set;
|
|
2697
|
+
int left = _blossom_set->find(_graph.u(edge));
|
|
2698
|
+
left_path.push_back(left);
|
|
2699
|
+
left_set.insert(left);
|
|
2700
|
+
|
|
2701
|
+
int right = _blossom_set->find(_graph.v(edge));
|
|
2702
|
+
right_path.push_back(right);
|
|
2703
|
+
right_set.insert(right);
|
|
2704
|
+
|
|
2705
|
+
while (true) {
|
|
2706
|
+
|
|
2707
|
+
if ((*_blossom_data)[left].pred == INVALID) break;
|
|
2708
|
+
|
|
2709
|
+
left =
|
|
2710
|
+
_blossom_set->find(_graph.target((*_blossom_data)[left].pred));
|
|
2711
|
+
left_path.push_back(left);
|
|
2712
|
+
left =
|
|
2713
|
+
_blossom_set->find(_graph.target((*_blossom_data)[left].pred));
|
|
2714
|
+
left_path.push_back(left);
|
|
2715
|
+
|
|
2716
|
+
left_set.insert(left);
|
|
2717
|
+
|
|
2718
|
+
if (right_set.find(left) != right_set.end()) {
|
|
2719
|
+
nca = left;
|
|
2720
|
+
break;
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
if ((*_blossom_data)[right].pred == INVALID) break;
|
|
2724
|
+
|
|
2725
|
+
right =
|
|
2726
|
+
_blossom_set->find(_graph.target((*_blossom_data)[right].pred));
|
|
2727
|
+
right_path.push_back(right);
|
|
2728
|
+
right =
|
|
2729
|
+
_blossom_set->find(_graph.target((*_blossom_data)[right].pred));
|
|
2730
|
+
right_path.push_back(right);
|
|
2731
|
+
|
|
2732
|
+
right_set.insert(right);
|
|
2733
|
+
|
|
2734
|
+
if (left_set.find(right) != left_set.end()) {
|
|
2735
|
+
nca = right;
|
|
2736
|
+
break;
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
if (nca == -1) {
|
|
2742
|
+
if ((*_blossom_data)[left].pred == INVALID) {
|
|
2743
|
+
nca = right;
|
|
2744
|
+
while (left_set.find(nca) == left_set.end()) {
|
|
2745
|
+
nca =
|
|
2746
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
2747
|
+
right_path.push_back(nca);
|
|
2748
|
+
nca =
|
|
2749
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
2750
|
+
right_path.push_back(nca);
|
|
2751
|
+
}
|
|
2752
|
+
} else {
|
|
2753
|
+
nca = left;
|
|
2754
|
+
while (right_set.find(nca) == right_set.end()) {
|
|
2755
|
+
nca =
|
|
2756
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
2757
|
+
left_path.push_back(nca);
|
|
2758
|
+
nca =
|
|
2759
|
+
_blossom_set->find(_graph.target((*_blossom_data)[nca].pred));
|
|
2760
|
+
left_path.push_back(nca);
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
std::vector<int> subblossoms;
|
|
2767
|
+
Arc prev;
|
|
2768
|
+
|
|
2769
|
+
prev = _graph.direct(edge, true);
|
|
2770
|
+
for (int i = 0; left_path[i] != nca; i += 2) {
|
|
2771
|
+
subblossoms.push_back(left_path[i]);
|
|
2772
|
+
(*_blossom_data)[left_path[i]].next = prev;
|
|
2773
|
+
_tree_set->erase(left_path[i]);
|
|
2774
|
+
|
|
2775
|
+
subblossoms.push_back(left_path[i + 1]);
|
|
2776
|
+
(*_blossom_data)[left_path[i + 1]].status = EVEN;
|
|
2777
|
+
oddToEven(left_path[i + 1], tree);
|
|
2778
|
+
_tree_set->erase(left_path[i + 1]);
|
|
2779
|
+
prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred);
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
int k = 0;
|
|
2783
|
+
while (right_path[k] != nca) ++k;
|
|
2784
|
+
|
|
2785
|
+
subblossoms.push_back(nca);
|
|
2786
|
+
(*_blossom_data)[nca].next = prev;
|
|
2787
|
+
|
|
2788
|
+
for (int i = k - 2; i >= 0; i -= 2) {
|
|
2789
|
+
subblossoms.push_back(right_path[i + 1]);
|
|
2790
|
+
(*_blossom_data)[right_path[i + 1]].status = EVEN;
|
|
2791
|
+
oddToEven(right_path[i + 1], tree);
|
|
2792
|
+
_tree_set->erase(right_path[i + 1]);
|
|
2793
|
+
|
|
2794
|
+
(*_blossom_data)[right_path[i + 1]].next =
|
|
2795
|
+
(*_blossom_data)[right_path[i + 1]].pred;
|
|
2796
|
+
|
|
2797
|
+
subblossoms.push_back(right_path[i]);
|
|
2798
|
+
_tree_set->erase(right_path[i]);
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2801
|
+
int surface =
|
|
2802
|
+
_blossom_set->join(subblossoms.begin(), subblossoms.end());
|
|
2803
|
+
|
|
2804
|
+
for (int i = 0; i < int(subblossoms.size()); ++i) {
|
|
2805
|
+
if (!_blossom_set->trivial(subblossoms[i])) {
|
|
2806
|
+
(*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum;
|
|
2807
|
+
}
|
|
2808
|
+
(*_blossom_data)[subblossoms[i]].status = MATCHED;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
(*_blossom_data)[surface].pot = -2 * _delta_sum;
|
|
2812
|
+
(*_blossom_data)[surface].offset = 0;
|
|
2813
|
+
(*_blossom_data)[surface].status = EVEN;
|
|
2814
|
+
(*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred;
|
|
2815
|
+
(*_blossom_data)[surface].next = (*_blossom_data)[nca].pred;
|
|
2816
|
+
|
|
2817
|
+
_tree_set->insert(surface, tree);
|
|
2818
|
+
_tree_set->erase(nca);
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
void splitBlossom(int blossom) {
|
|
2822
|
+
Arc next = (*_blossom_data)[blossom].next;
|
|
2823
|
+
Arc pred = (*_blossom_data)[blossom].pred;
|
|
2824
|
+
|
|
2825
|
+
int tree = _tree_set->find(blossom);
|
|
2826
|
+
|
|
2827
|
+
(*_blossom_data)[blossom].status = MATCHED;
|
|
2828
|
+
oddToMatched(blossom);
|
|
2829
|
+
if (_delta2->state(blossom) == _delta2->IN_HEAP) {
|
|
2830
|
+
_delta2->erase(blossom);
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
std::vector<int> subblossoms;
|
|
2834
|
+
_blossom_set->split(blossom, std::back_inserter(subblossoms));
|
|
2835
|
+
|
|
2836
|
+
Value offset = (*_blossom_data)[blossom].offset;
|
|
2837
|
+
int b = _blossom_set->find(_graph.source(pred));
|
|
2838
|
+
int d = _blossom_set->find(_graph.source(next));
|
|
2839
|
+
|
|
2840
|
+
int ib = -1, id = -1;
|
|
2841
|
+
for (int i = 0; i < int(subblossoms.size()); ++i) {
|
|
2842
|
+
if (subblossoms[i] == b) ib = i;
|
|
2843
|
+
if (subblossoms[i] == d) id = i;
|
|
2844
|
+
|
|
2845
|
+
(*_blossom_data)[subblossoms[i]].offset = offset;
|
|
2846
|
+
if (!_blossom_set->trivial(subblossoms[i])) {
|
|
2847
|
+
(*_blossom_data)[subblossoms[i]].pot -= 2 * offset;
|
|
2848
|
+
}
|
|
2849
|
+
if (_blossom_set->classPrio(subblossoms[i]) !=
|
|
2850
|
+
std::numeric_limits<Value>::max()) {
|
|
2851
|
+
_delta2->push(subblossoms[i],
|
|
2852
|
+
_blossom_set->classPrio(subblossoms[i]) -
|
|
2853
|
+
(*_blossom_data)[subblossoms[i]].offset);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) {
|
|
2858
|
+
for (int i = (id + 1) % subblossoms.size();
|
|
2859
|
+
i != ib; i = (i + 2) % subblossoms.size()) {
|
|
2860
|
+
int sb = subblossoms[i];
|
|
2861
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
2862
|
+
(*_blossom_data)[sb].next =
|
|
2863
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) {
|
|
2867
|
+
int sb = subblossoms[i];
|
|
2868
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
2869
|
+
int ub = subblossoms[(i + 2) % subblossoms.size()];
|
|
2870
|
+
|
|
2871
|
+
(*_blossom_data)[sb].status = ODD;
|
|
2872
|
+
matchedToOdd(sb);
|
|
2873
|
+
_tree_set->insert(sb, tree);
|
|
2874
|
+
(*_blossom_data)[sb].pred = pred;
|
|
2875
|
+
(*_blossom_data)[sb].next =
|
|
2876
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
2877
|
+
|
|
2878
|
+
pred = (*_blossom_data)[ub].next;
|
|
2879
|
+
|
|
2880
|
+
(*_blossom_data)[tb].status = EVEN;
|
|
2881
|
+
matchedToEven(tb, tree);
|
|
2882
|
+
_tree_set->insert(tb, tree);
|
|
2883
|
+
(*_blossom_data)[tb].pred = (*_blossom_data)[tb].next;
|
|
2884
|
+
}
|
|
2885
|
+
|
|
2886
|
+
(*_blossom_data)[subblossoms[id]].status = ODD;
|
|
2887
|
+
matchedToOdd(subblossoms[id]);
|
|
2888
|
+
_tree_set->insert(subblossoms[id], tree);
|
|
2889
|
+
(*_blossom_data)[subblossoms[id]].next = next;
|
|
2890
|
+
(*_blossom_data)[subblossoms[id]].pred = pred;
|
|
2891
|
+
|
|
2892
|
+
} else {
|
|
2893
|
+
|
|
2894
|
+
for (int i = (ib + 1) % subblossoms.size();
|
|
2895
|
+
i != id; i = (i + 2) % subblossoms.size()) {
|
|
2896
|
+
int sb = subblossoms[i];
|
|
2897
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
2898
|
+
(*_blossom_data)[sb].next =
|
|
2899
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
2900
|
+
}
|
|
2901
|
+
|
|
2902
|
+
for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) {
|
|
2903
|
+
int sb = subblossoms[i];
|
|
2904
|
+
int tb = subblossoms[(i + 1) % subblossoms.size()];
|
|
2905
|
+
int ub = subblossoms[(i + 2) % subblossoms.size()];
|
|
2906
|
+
|
|
2907
|
+
(*_blossom_data)[sb].status = ODD;
|
|
2908
|
+
matchedToOdd(sb);
|
|
2909
|
+
_tree_set->insert(sb, tree);
|
|
2910
|
+
(*_blossom_data)[sb].next = next;
|
|
2911
|
+
(*_blossom_data)[sb].pred =
|
|
2912
|
+
_graph.oppositeArc((*_blossom_data)[tb].next);
|
|
2913
|
+
|
|
2914
|
+
(*_blossom_data)[tb].status = EVEN;
|
|
2915
|
+
matchedToEven(tb, tree);
|
|
2916
|
+
_tree_set->insert(tb, tree);
|
|
2917
|
+
(*_blossom_data)[tb].pred =
|
|
2918
|
+
(*_blossom_data)[tb].next =
|
|
2919
|
+
_graph.oppositeArc((*_blossom_data)[ub].next);
|
|
2920
|
+
next = (*_blossom_data)[ub].next;
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2923
|
+
(*_blossom_data)[subblossoms[ib]].status = ODD;
|
|
2924
|
+
matchedToOdd(subblossoms[ib]);
|
|
2925
|
+
_tree_set->insert(subblossoms[ib], tree);
|
|
2926
|
+
(*_blossom_data)[subblossoms[ib]].next = next;
|
|
2927
|
+
(*_blossom_data)[subblossoms[ib]].pred = pred;
|
|
2928
|
+
}
|
|
2929
|
+
_tree_set->erase(blossom);
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
void extractBlossom(int blossom, const Node& base, const Arc& matching) {
|
|
2933
|
+
if (_blossom_set->trivial(blossom)) {
|
|
2934
|
+
int bi = (*_node_index)[base];
|
|
2935
|
+
Value pot = (*_node_data)[bi].pot;
|
|
2936
|
+
|
|
2937
|
+
(*_matching)[base] = matching;
|
|
2938
|
+
_blossom_node_list.push_back(base);
|
|
2939
|
+
(*_node_potential)[base] = pot;
|
|
2940
|
+
} else {
|
|
2941
|
+
|
|
2942
|
+
Value pot = (*_blossom_data)[blossom].pot;
|
|
2943
|
+
int bn = _blossom_node_list.size();
|
|
2944
|
+
|
|
2945
|
+
std::vector<int> subblossoms;
|
|
2946
|
+
_blossom_set->split(blossom, std::back_inserter(subblossoms));
|
|
2947
|
+
int b = _blossom_set->find(base);
|
|
2948
|
+
int ib = -1;
|
|
2949
|
+
for (int i = 0; i < int(subblossoms.size()); ++i) {
|
|
2950
|
+
if (subblossoms[i] == b) { ib = i; break; }
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
for (int i = 1; i < int(subblossoms.size()); i += 2) {
|
|
2954
|
+
int sb = subblossoms[(ib + i) % subblossoms.size()];
|
|
2955
|
+
int tb = subblossoms[(ib + i + 1) % subblossoms.size()];
|
|
2956
|
+
|
|
2957
|
+
Arc m = (*_blossom_data)[tb].next;
|
|
2958
|
+
extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m));
|
|
2959
|
+
extractBlossom(tb, _graph.source(m), m);
|
|
2960
|
+
}
|
|
2961
|
+
extractBlossom(subblossoms[ib], base, matching);
|
|
2962
|
+
|
|
2963
|
+
int en = _blossom_node_list.size();
|
|
2964
|
+
|
|
2965
|
+
_blossom_potential.push_back(BlossomVariable(bn, en, pot));
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
void extractMatching() {
|
|
2970
|
+
std::vector<int> blossoms;
|
|
2971
|
+
for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) {
|
|
2972
|
+
blossoms.push_back(c);
|
|
2973
|
+
}
|
|
2974
|
+
|
|
2975
|
+
for (int i = 0; i < int(blossoms.size()); ++i) {
|
|
2976
|
+
|
|
2977
|
+
Value offset = (*_blossom_data)[blossoms[i]].offset;
|
|
2978
|
+
(*_blossom_data)[blossoms[i]].pot += 2 * offset;
|
|
2979
|
+
for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]);
|
|
2980
|
+
n != INVALID; ++n) {
|
|
2981
|
+
(*_node_data)[(*_node_index)[n]].pot -= offset;
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
Arc matching = (*_blossom_data)[blossoms[i]].next;
|
|
2985
|
+
Node base = _graph.source(matching);
|
|
2986
|
+
extractBlossom(blossoms[i], base, matching);
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2990
|
+
public:
|
|
2991
|
+
|
|
2992
|
+
/// \brief Constructor
|
|
2993
|
+
///
|
|
2994
|
+
/// Constructor.
|
|
2995
|
+
MaxWeightedPerfectMatching(const Graph& graph, const WeightMap& weight)
|
|
2996
|
+
: _graph(graph), _weight(weight), _matching(0),
|
|
2997
|
+
_node_potential(0), _blossom_potential(), _blossom_node_list(),
|
|
2998
|
+
_node_num(0), _blossom_num(0),
|
|
2999
|
+
|
|
3000
|
+
_blossom_index(0), _blossom_set(0), _blossom_data(0),
|
|
3001
|
+
_node_index(0), _node_heap_index(0), _node_data(0),
|
|
3002
|
+
_tree_set_index(0), _tree_set(0),
|
|
3003
|
+
|
|
3004
|
+
_delta2_index(0), _delta2(0),
|
|
3005
|
+
_delta3_index(0), _delta3(0),
|
|
3006
|
+
_delta4_index(0), _delta4(0),
|
|
3007
|
+
|
|
3008
|
+
_delta_sum(), _unmatched(0),
|
|
3009
|
+
|
|
3010
|
+
_fractional(0)
|
|
3011
|
+
{}
|
|
3012
|
+
|
|
3013
|
+
~MaxWeightedPerfectMatching() {
|
|
3014
|
+
destroyStructures();
|
|
3015
|
+
if (_fractional) {
|
|
3016
|
+
delete _fractional;
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
/// \name Execution Control
|
|
3021
|
+
/// The simplest way to execute the algorithm is to use the
|
|
3022
|
+
/// \ref run() member function.
|
|
3023
|
+
|
|
3024
|
+
///@{
|
|
3025
|
+
|
|
3026
|
+
/// \brief Initialize the algorithm
|
|
3027
|
+
///
|
|
3028
|
+
/// This function initializes the algorithm.
|
|
3029
|
+
void init() {
|
|
3030
|
+
createStructures();
|
|
3031
|
+
|
|
3032
|
+
_blossom_node_list.clear();
|
|
3033
|
+
_blossom_potential.clear();
|
|
3034
|
+
|
|
3035
|
+
for (ArcIt e(_graph); e != INVALID; ++e) {
|
|
3036
|
+
(*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
|
|
3037
|
+
}
|
|
3038
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
3039
|
+
(*_delta3_index)[e] = _delta3->PRE_HEAP;
|
|
3040
|
+
}
|
|
3041
|
+
for (int i = 0; i < _blossom_num; ++i) {
|
|
3042
|
+
(*_delta2_index)[i] = _delta2->PRE_HEAP;
|
|
3043
|
+
(*_delta4_index)[i] = _delta4->PRE_HEAP;
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
_unmatched = _node_num;
|
|
3047
|
+
|
|
3048
|
+
_delta2->clear();
|
|
3049
|
+
_delta3->clear();
|
|
3050
|
+
_delta4->clear();
|
|
3051
|
+
_blossom_set->clear();
|
|
3052
|
+
_tree_set->clear();
|
|
3053
|
+
|
|
3054
|
+
int index = 0;
|
|
3055
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
3056
|
+
Value max = - std::numeric_limits<Value>::max();
|
|
3057
|
+
for (OutArcIt e(_graph, n); e != INVALID; ++e) {
|
|
3058
|
+
if (_graph.target(e) == n) continue;
|
|
3059
|
+
if ((dualScale * _weight[e]) / 2 > max) {
|
|
3060
|
+
max = (dualScale * _weight[e]) / 2;
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
(*_node_index)[n] = index;
|
|
3064
|
+
(*_node_data)[index].heap_index.clear();
|
|
3065
|
+
(*_node_data)[index].heap.clear();
|
|
3066
|
+
(*_node_data)[index].pot = max;
|
|
3067
|
+
int blossom =
|
|
3068
|
+
_blossom_set->insert(n, std::numeric_limits<Value>::max());
|
|
3069
|
+
|
|
3070
|
+
_tree_set->insert(blossom);
|
|
3071
|
+
|
|
3072
|
+
(*_blossom_data)[blossom].status = EVEN;
|
|
3073
|
+
(*_blossom_data)[blossom].pred = INVALID;
|
|
3074
|
+
(*_blossom_data)[blossom].next = INVALID;
|
|
3075
|
+
(*_blossom_data)[blossom].pot = 0;
|
|
3076
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
3077
|
+
++index;
|
|
3078
|
+
}
|
|
3079
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
3080
|
+
int si = (*_node_index)[_graph.u(e)];
|
|
3081
|
+
int ti = (*_node_index)[_graph.v(e)];
|
|
3082
|
+
if (_graph.u(e) != _graph.v(e)) {
|
|
3083
|
+
_delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
|
|
3084
|
+
dualScale * _weight[e]) / 2);
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
/// \brief Initialize the algorithm with fractional matching
|
|
3090
|
+
///
|
|
3091
|
+
/// This function initializes the algorithm with a fractional
|
|
3092
|
+
/// matching. This initialization is also called jumpstart heuristic.
|
|
3093
|
+
void fractionalInit() {
|
|
3094
|
+
createStructures();
|
|
3095
|
+
|
|
3096
|
+
_blossom_node_list.clear();
|
|
3097
|
+
_blossom_potential.clear();
|
|
3098
|
+
|
|
3099
|
+
if (_fractional == 0) {
|
|
3100
|
+
_fractional = new FractionalMatching(_graph, _weight, false);
|
|
3101
|
+
}
|
|
3102
|
+
if (!_fractional->run()) {
|
|
3103
|
+
_unmatched = -1;
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
for (ArcIt e(_graph); e != INVALID; ++e) {
|
|
3108
|
+
(*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP;
|
|
3109
|
+
}
|
|
3110
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
3111
|
+
(*_delta3_index)[e] = _delta3->PRE_HEAP;
|
|
3112
|
+
}
|
|
3113
|
+
for (int i = 0; i < _blossom_num; ++i) {
|
|
3114
|
+
(*_delta2_index)[i] = _delta2->PRE_HEAP;
|
|
3115
|
+
(*_delta4_index)[i] = _delta4->PRE_HEAP;
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3118
|
+
_unmatched = 0;
|
|
3119
|
+
|
|
3120
|
+
_delta2->clear();
|
|
3121
|
+
_delta3->clear();
|
|
3122
|
+
_delta4->clear();
|
|
3123
|
+
_blossom_set->clear();
|
|
3124
|
+
_tree_set->clear();
|
|
3125
|
+
|
|
3126
|
+
int index = 0;
|
|
3127
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
3128
|
+
Value pot = _fractional->nodeValue(n);
|
|
3129
|
+
(*_node_index)[n] = index;
|
|
3130
|
+
(*_node_data)[index].pot = pot;
|
|
3131
|
+
(*_node_data)[index].heap_index.clear();
|
|
3132
|
+
(*_node_data)[index].heap.clear();
|
|
3133
|
+
int blossom =
|
|
3134
|
+
_blossom_set->insert(n, std::numeric_limits<Value>::max());
|
|
3135
|
+
|
|
3136
|
+
(*_blossom_data)[blossom].status = MATCHED;
|
|
3137
|
+
(*_blossom_data)[blossom].pred = INVALID;
|
|
3138
|
+
(*_blossom_data)[blossom].next = _fractional->matching(n);
|
|
3139
|
+
(*_blossom_data)[blossom].pot = 0;
|
|
3140
|
+
(*_blossom_data)[blossom].offset = 0;
|
|
3141
|
+
++index;
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
typename Graph::template NodeMap<bool> processed(_graph, false);
|
|
3145
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
3146
|
+
if (processed[n]) continue;
|
|
3147
|
+
processed[n] = true;
|
|
3148
|
+
if (_fractional->matching(n) == INVALID) continue;
|
|
3149
|
+
int num = 1;
|
|
3150
|
+
Node v = _graph.target(_fractional->matching(n));
|
|
3151
|
+
while (n != v) {
|
|
3152
|
+
processed[v] = true;
|
|
3153
|
+
v = _graph.target(_fractional->matching(v));
|
|
3154
|
+
++num;
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
if (num % 2 == 1) {
|
|
3158
|
+
std::vector<int> subblossoms(num);
|
|
3159
|
+
|
|
3160
|
+
subblossoms[--num] = _blossom_set->find(n);
|
|
3161
|
+
v = _graph.target(_fractional->matching(n));
|
|
3162
|
+
while (n != v) {
|
|
3163
|
+
subblossoms[--num] = _blossom_set->find(v);
|
|
3164
|
+
v = _graph.target(_fractional->matching(v));
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
int surface =
|
|
3168
|
+
_blossom_set->join(subblossoms.begin(), subblossoms.end());
|
|
3169
|
+
(*_blossom_data)[surface].status = EVEN;
|
|
3170
|
+
(*_blossom_data)[surface].pred = INVALID;
|
|
3171
|
+
(*_blossom_data)[surface].next = INVALID;
|
|
3172
|
+
(*_blossom_data)[surface].pot = 0;
|
|
3173
|
+
(*_blossom_data)[surface].offset = 0;
|
|
3174
|
+
|
|
3175
|
+
_tree_set->insert(surface);
|
|
3176
|
+
++_unmatched;
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
3181
|
+
int si = (*_node_index)[_graph.u(e)];
|
|
3182
|
+
int sb = _blossom_set->find(_graph.u(e));
|
|
3183
|
+
int ti = (*_node_index)[_graph.v(e)];
|
|
3184
|
+
int tb = _blossom_set->find(_graph.v(e));
|
|
3185
|
+
if ((*_blossom_data)[sb].status == EVEN &&
|
|
3186
|
+
(*_blossom_data)[tb].status == EVEN && sb != tb) {
|
|
3187
|
+
_delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot -
|
|
3188
|
+
dualScale * _weight[e]) / 2);
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
3193
|
+
int nb = _blossom_set->find(n);
|
|
3194
|
+
if ((*_blossom_data)[nb].status != MATCHED) continue;
|
|
3195
|
+
int ni = (*_node_index)[n];
|
|
3196
|
+
|
|
3197
|
+
for (OutArcIt e(_graph, n); e != INVALID; ++e) {
|
|
3198
|
+
Node v = _graph.target(e);
|
|
3199
|
+
int vb = _blossom_set->find(v);
|
|
3200
|
+
int vi = (*_node_index)[v];
|
|
3201
|
+
|
|
3202
|
+
Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -
|
|
3203
|
+
dualScale * _weight[e];
|
|
3204
|
+
|
|
3205
|
+
if ((*_blossom_data)[vb].status == EVEN) {
|
|
3206
|
+
|
|
3207
|
+
int vt = _tree_set->find(vb);
|
|
3208
|
+
|
|
3209
|
+
typename std::map<int, Arc>::iterator it =
|
|
3210
|
+
(*_node_data)[ni].heap_index.find(vt);
|
|
3211
|
+
|
|
3212
|
+
if (it != (*_node_data)[ni].heap_index.end()) {
|
|
3213
|
+
if ((*_node_data)[ni].heap[it->second] > rw) {
|
|
3214
|
+
(*_node_data)[ni].heap.replace(it->second, e);
|
|
3215
|
+
(*_node_data)[ni].heap.decrease(e, rw);
|
|
3216
|
+
it->second = e;
|
|
3217
|
+
}
|
|
3218
|
+
} else {
|
|
3219
|
+
(*_node_data)[ni].heap.push(e, rw);
|
|
3220
|
+
(*_node_data)[ni].heap_index.insert(std::make_pair(vt, e));
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
if (!(*_node_data)[ni].heap.empty()) {
|
|
3226
|
+
_blossom_set->decrease(n, (*_node_data)[ni].heap.prio());
|
|
3227
|
+
_delta2->push(nb, _blossom_set->classPrio(nb));
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
/// \brief Start the algorithm
|
|
3233
|
+
///
|
|
3234
|
+
/// This function starts the algorithm.
|
|
3235
|
+
///
|
|
3236
|
+
/// \pre \ref init() or \ref fractionalInit() must be called before
|
|
3237
|
+
/// using this function.
|
|
3238
|
+
bool start() {
|
|
3239
|
+
enum OpType {
|
|
3240
|
+
D2, D3, D4
|
|
3241
|
+
};
|
|
3242
|
+
|
|
3243
|
+
if (_unmatched == -1) return false;
|
|
3244
|
+
|
|
3245
|
+
while (_unmatched > 0) {
|
|
3246
|
+
Value d2 = !_delta2->empty() ?
|
|
3247
|
+
_delta2->prio() : std::numeric_limits<Value>::max();
|
|
3248
|
+
|
|
3249
|
+
Value d3 = !_delta3->empty() ?
|
|
3250
|
+
_delta3->prio() : std::numeric_limits<Value>::max();
|
|
3251
|
+
|
|
3252
|
+
Value d4 = !_delta4->empty() ?
|
|
3253
|
+
_delta4->prio() : std::numeric_limits<Value>::max();
|
|
3254
|
+
|
|
3255
|
+
_delta_sum = d3; OpType ot = D3;
|
|
3256
|
+
if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
|
|
3257
|
+
if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; }
|
|
3258
|
+
|
|
3259
|
+
if (_delta_sum == std::numeric_limits<Value>::max()) {
|
|
3260
|
+
return false;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
switch (ot) {
|
|
3264
|
+
case D2:
|
|
3265
|
+
{
|
|
3266
|
+
int blossom = _delta2->top();
|
|
3267
|
+
Node n = _blossom_set->classTop(blossom);
|
|
3268
|
+
Arc e = (*_node_data)[(*_node_index)[n]].heap.top();
|
|
3269
|
+
extendOnArc(e);
|
|
3270
|
+
}
|
|
3271
|
+
break;
|
|
3272
|
+
case D3:
|
|
3273
|
+
{
|
|
3274
|
+
Edge e = _delta3->top();
|
|
3275
|
+
|
|
3276
|
+
int left_blossom = _blossom_set->find(_graph.u(e));
|
|
3277
|
+
int right_blossom = _blossom_set->find(_graph.v(e));
|
|
3278
|
+
|
|
3279
|
+
if (left_blossom == right_blossom) {
|
|
3280
|
+
_delta3->pop();
|
|
3281
|
+
} else {
|
|
3282
|
+
int left_tree = _tree_set->find(left_blossom);
|
|
3283
|
+
int right_tree = _tree_set->find(right_blossom);
|
|
3284
|
+
|
|
3285
|
+
if (left_tree == right_tree) {
|
|
3286
|
+
shrinkOnEdge(e, left_tree);
|
|
3287
|
+
} else {
|
|
3288
|
+
augmentOnEdge(e);
|
|
3289
|
+
_unmatched -= 2;
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
} break;
|
|
3293
|
+
case D4:
|
|
3294
|
+
splitBlossom(_delta4->top());
|
|
3295
|
+
break;
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
extractMatching();
|
|
3299
|
+
return true;
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3302
|
+
/// \brief Run the algorithm.
|
|
3303
|
+
///
|
|
3304
|
+
/// This method runs the \c %MaxWeightedPerfectMatching algorithm.
|
|
3305
|
+
///
|
|
3306
|
+
/// \note mwpm.run() is just a shortcut of the following code.
|
|
3307
|
+
/// \code
|
|
3308
|
+
/// mwpm.fractionalInit();
|
|
3309
|
+
/// mwpm.start();
|
|
3310
|
+
/// \endcode
|
|
3311
|
+
bool run() {
|
|
3312
|
+
fractionalInit();
|
|
3313
|
+
return start();
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
/// @}
|
|
3317
|
+
|
|
3318
|
+
/// \name Primal Solution
|
|
3319
|
+
/// Functions to get the primal solution, i.e. the maximum weighted
|
|
3320
|
+
/// perfect matching.\n
|
|
3321
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
3322
|
+
/// using them.
|
|
3323
|
+
|
|
3324
|
+
/// @{
|
|
3325
|
+
|
|
3326
|
+
/// \brief Return the weight of the matching.
|
|
3327
|
+
///
|
|
3328
|
+
/// This function returns the weight of the found matching.
|
|
3329
|
+
///
|
|
3330
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3331
|
+
Value matchingWeight() const {
|
|
3332
|
+
Value sum = 0;
|
|
3333
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
3334
|
+
if ((*_matching)[n] != INVALID) {
|
|
3335
|
+
sum += _weight[(*_matching)[n]];
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
return sum / 2;
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
/// \brief Return \c true if the given edge is in the matching.
|
|
3342
|
+
///
|
|
3343
|
+
/// This function returns \c true if the given edge is in the found
|
|
3344
|
+
/// matching.
|
|
3345
|
+
///
|
|
3346
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3347
|
+
bool matching(const Edge& edge) const {
|
|
3348
|
+
return static_cast<const Edge&>((*_matching)[_graph.u(edge)]) == edge;
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3351
|
+
/// \brief Return the matching arc (or edge) incident to the given node.
|
|
3352
|
+
///
|
|
3353
|
+
/// This function returns the matching arc (or edge) incident to the
|
|
3354
|
+
/// given node in the found matching or \c INVALID if the node is
|
|
3355
|
+
/// not covered by the matching.
|
|
3356
|
+
///
|
|
3357
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3358
|
+
Arc matching(const Node& node) const {
|
|
3359
|
+
return (*_matching)[node];
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3362
|
+
/// \brief Return a const reference to the matching map.
|
|
3363
|
+
///
|
|
3364
|
+
/// This function returns a const reference to a node map that stores
|
|
3365
|
+
/// the matching arc (or edge) incident to each node.
|
|
3366
|
+
const MatchingMap& matchingMap() const {
|
|
3367
|
+
return *_matching;
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
/// \brief Return the mate of the given node.
|
|
3371
|
+
///
|
|
3372
|
+
/// This function returns the mate of the given node in the found
|
|
3373
|
+
/// matching or \c INVALID if the node is not covered by the matching.
|
|
3374
|
+
///
|
|
3375
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3376
|
+
Node mate(const Node& node) const {
|
|
3377
|
+
return _graph.target((*_matching)[node]);
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
/// @}
|
|
3381
|
+
|
|
3382
|
+
/// \name Dual Solution
|
|
3383
|
+
/// Functions to get the dual solution.\n
|
|
3384
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
3385
|
+
/// using them.
|
|
3386
|
+
|
|
3387
|
+
/// @{
|
|
3388
|
+
|
|
3389
|
+
/// \brief Return the value of the dual solution.
|
|
3390
|
+
///
|
|
3391
|
+
/// This function returns the value of the dual solution.
|
|
3392
|
+
/// It should be equal to the primal value scaled by \ref dualScale
|
|
3393
|
+
/// "dual scale".
|
|
3394
|
+
///
|
|
3395
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3396
|
+
Value dualValue() const {
|
|
3397
|
+
Value sum = 0;
|
|
3398
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
3399
|
+
sum += nodeValue(n);
|
|
3400
|
+
}
|
|
3401
|
+
for (int i = 0; i < blossomNum(); ++i) {
|
|
3402
|
+
sum += blossomValue(i) * (blossomSize(i) / 2);
|
|
3403
|
+
}
|
|
3404
|
+
return sum;
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
/// \brief Return the dual value (potential) of the given node.
|
|
3408
|
+
///
|
|
3409
|
+
/// This function returns the dual value (potential) of the given node.
|
|
3410
|
+
///
|
|
3411
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3412
|
+
Value nodeValue(const Node& n) const {
|
|
3413
|
+
return (*_node_potential)[n];
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
/// \brief Return the number of the blossoms in the basis.
|
|
3417
|
+
///
|
|
3418
|
+
/// This function returns the number of the blossoms in the basis.
|
|
3419
|
+
///
|
|
3420
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3421
|
+
/// \see BlossomIt
|
|
3422
|
+
int blossomNum() const {
|
|
3423
|
+
return _blossom_potential.size();
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
/// \brief Return the number of the nodes in the given blossom.
|
|
3427
|
+
///
|
|
3428
|
+
/// This function returns the number of the nodes in the given blossom.
|
|
3429
|
+
///
|
|
3430
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3431
|
+
/// \see BlossomIt
|
|
3432
|
+
int blossomSize(int k) const {
|
|
3433
|
+
return _blossom_potential[k].end - _blossom_potential[k].begin;
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
/// \brief Return the dual value (ptential) of the given blossom.
|
|
3437
|
+
///
|
|
3438
|
+
/// This function returns the dual value (ptential) of the given blossom.
|
|
3439
|
+
///
|
|
3440
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
3441
|
+
Value blossomValue(int k) const {
|
|
3442
|
+
return _blossom_potential[k].value;
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
/// \brief Iterator for obtaining the nodes of a blossom.
|
|
3446
|
+
///
|
|
3447
|
+
/// This class provides an iterator for obtaining the nodes of the
|
|
3448
|
+
/// given blossom. It lists a subset of the nodes.
|
|
3449
|
+
/// Before using this iterator, you must allocate a
|
|
3450
|
+
/// MaxWeightedPerfectMatching class and execute it.
|
|
3451
|
+
class BlossomIt {
|
|
3452
|
+
public:
|
|
3453
|
+
|
|
3454
|
+
/// \brief Constructor.
|
|
3455
|
+
///
|
|
3456
|
+
/// Constructor to get the nodes of the given variable.
|
|
3457
|
+
///
|
|
3458
|
+
/// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()"
|
|
3459
|
+
/// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()"
|
|
3460
|
+
/// must be called before initializing this iterator.
|
|
3461
|
+
BlossomIt(const MaxWeightedPerfectMatching& algorithm, int variable)
|
|
3462
|
+
: _algorithm(&algorithm)
|
|
3463
|
+
{
|
|
3464
|
+
_index = _algorithm->_blossom_potential[variable].begin;
|
|
3465
|
+
_last = _algorithm->_blossom_potential[variable].end;
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
/// \brief Conversion to \c Node.
|
|
3469
|
+
///
|
|
3470
|
+
/// Conversion to \c Node.
|
|
3471
|
+
operator Node() const {
|
|
3472
|
+
return _algorithm->_blossom_node_list[_index];
|
|
3473
|
+
}
|
|
3474
|
+
|
|
3475
|
+
/// \brief Increment operator.
|
|
3476
|
+
///
|
|
3477
|
+
/// Increment operator.
|
|
3478
|
+
BlossomIt& operator++() {
|
|
3479
|
+
++_index;
|
|
3480
|
+
return *this;
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
/// \brief Validity checking
|
|
3484
|
+
///
|
|
3485
|
+
/// This function checks whether the iterator is invalid.
|
|
3486
|
+
bool operator==(Invalid) const { return _index == _last; }
|
|
3487
|
+
|
|
3488
|
+
/// \brief Validity checking
|
|
3489
|
+
///
|
|
3490
|
+
/// This function checks whether the iterator is valid.
|
|
3491
|
+
bool operator!=(Invalid) const { return _index != _last; }
|
|
3492
|
+
|
|
3493
|
+
private:
|
|
3494
|
+
const MaxWeightedPerfectMatching* _algorithm;
|
|
3495
|
+
int _last;
|
|
3496
|
+
int _index;
|
|
3497
|
+
};
|
|
3498
|
+
|
|
3499
|
+
/// @}
|
|
3500
|
+
|
|
3501
|
+
};
|
|
3502
|
+
|
|
3503
|
+
} //END OF NAMESPACE LEMON
|
|
3504
|
+
|
|
3505
|
+
#endif //LEMON_MATCHING_H
|