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,2139 @@
|
|
|
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_FRACTIONAL_MATCHING_H
|
|
20
|
+
#define LEMON_FRACTIONAL_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/assert.h>
|
|
32
|
+
#include <lemon/elevator.h>
|
|
33
|
+
|
|
34
|
+
///\ingroup matching
|
|
35
|
+
///\file
|
|
36
|
+
///\brief Fractional matching algorithms in general graphs.
|
|
37
|
+
|
|
38
|
+
namespace lemon {
|
|
39
|
+
|
|
40
|
+
/// \brief Default traits class of MaxFractionalMatching class.
|
|
41
|
+
///
|
|
42
|
+
/// Default traits class of MaxFractionalMatching class.
|
|
43
|
+
/// \tparam GR Graph type.
|
|
44
|
+
template <typename GR>
|
|
45
|
+
struct MaxFractionalMatchingDefaultTraits {
|
|
46
|
+
|
|
47
|
+
/// \brief The type of the graph the algorithm runs on.
|
|
48
|
+
typedef GR Graph;
|
|
49
|
+
|
|
50
|
+
/// \brief The type of the map that stores the matching.
|
|
51
|
+
///
|
|
52
|
+
/// The type of the map that stores the matching arcs.
|
|
53
|
+
/// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
|
|
54
|
+
typedef typename Graph::template NodeMap<typename GR::Arc> MatchingMap;
|
|
55
|
+
|
|
56
|
+
/// \brief Instantiates a MatchingMap.
|
|
57
|
+
///
|
|
58
|
+
/// This function instantiates a \ref MatchingMap.
|
|
59
|
+
/// \param graph The graph for which we would like to define
|
|
60
|
+
/// the matching map.
|
|
61
|
+
static MatchingMap* createMatchingMap(const Graph& graph) {
|
|
62
|
+
return new MatchingMap(graph);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// \brief The elevator type used by MaxFractionalMatching algorithm.
|
|
66
|
+
///
|
|
67
|
+
/// The elevator type used by MaxFractionalMatching algorithm.
|
|
68
|
+
///
|
|
69
|
+
/// \sa Elevator
|
|
70
|
+
/// \sa LinkedElevator
|
|
71
|
+
typedef LinkedElevator<Graph, typename Graph::Node> Elevator;
|
|
72
|
+
|
|
73
|
+
/// \brief Instantiates an Elevator.
|
|
74
|
+
///
|
|
75
|
+
/// This function instantiates an \ref Elevator.
|
|
76
|
+
/// \param graph The graph for which we would like to define
|
|
77
|
+
/// the elevator.
|
|
78
|
+
/// \param max_level The maximum level of the elevator.
|
|
79
|
+
static Elevator* createElevator(const Graph& graph, int max_level) {
|
|
80
|
+
return new Elevator(graph, max_level);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/// \ingroup matching
|
|
85
|
+
///
|
|
86
|
+
/// \brief Max cardinality fractional matching
|
|
87
|
+
///
|
|
88
|
+
/// This class provides an implementation of fractional matching
|
|
89
|
+
/// algorithm based on push-relabel principle.
|
|
90
|
+
///
|
|
91
|
+
/// The maximum cardinality fractional matching is a relaxation of the
|
|
92
|
+
/// maximum cardinality matching problem where the odd set constraints
|
|
93
|
+
/// are omitted.
|
|
94
|
+
/// It can be formulated with the following linear program.
|
|
95
|
+
/// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f]
|
|
96
|
+
/// \f[x_e \ge 0\quad \forall e\in E\f]
|
|
97
|
+
/// \f[\max \sum_{e\in E}x_e\f]
|
|
98
|
+
/// where \f$\delta(X)\f$ is the set of edges incident to a node in
|
|
99
|
+
/// \f$X\f$. The result can be represented as the union of a
|
|
100
|
+
/// matching with one value edges and a set of odd length cycles
|
|
101
|
+
/// with half value edges.
|
|
102
|
+
///
|
|
103
|
+
/// The algorithm calculates an optimal fractional matching and a
|
|
104
|
+
/// barrier. The number of adjacents of any node set minus the size
|
|
105
|
+
/// of node set is a lower bound on the uncovered nodes in the
|
|
106
|
+
/// graph. For maximum matching a barrier is computed which
|
|
107
|
+
/// maximizes this difference.
|
|
108
|
+
///
|
|
109
|
+
/// The algorithm can be executed with the run() function. After it
|
|
110
|
+
/// the matching (the primal solution) and the barrier (the dual
|
|
111
|
+
/// solution) can be obtained using the query functions.
|
|
112
|
+
///
|
|
113
|
+
/// The primal solution is multiplied by
|
|
114
|
+
/// \ref MaxFractionalMatching::primalScale "2".
|
|
115
|
+
///
|
|
116
|
+
/// \tparam GR The undirected graph type the algorithm runs on.
|
|
117
|
+
#ifdef DOXYGEN
|
|
118
|
+
template <typename GR, typename TR>
|
|
119
|
+
#else
|
|
120
|
+
template <typename GR,
|
|
121
|
+
typename TR = MaxFractionalMatchingDefaultTraits<GR> >
|
|
122
|
+
#endif
|
|
123
|
+
class MaxFractionalMatching {
|
|
124
|
+
public:
|
|
125
|
+
|
|
126
|
+
/// \brief The \ref lemon::MaxFractionalMatchingDefaultTraits
|
|
127
|
+
/// "traits class" of the algorithm.
|
|
128
|
+
typedef TR Traits;
|
|
129
|
+
/// The type of the graph the algorithm runs on.
|
|
130
|
+
typedef typename TR::Graph Graph;
|
|
131
|
+
/// The type of the matching map.
|
|
132
|
+
typedef typename TR::MatchingMap MatchingMap;
|
|
133
|
+
/// The type of the elevator.
|
|
134
|
+
typedef typename TR::Elevator Elevator;
|
|
135
|
+
|
|
136
|
+
/// \brief Scaling factor for primal solution
|
|
137
|
+
///
|
|
138
|
+
/// Scaling factor for primal solution.
|
|
139
|
+
static const int primalScale = 2;
|
|
140
|
+
|
|
141
|
+
private:
|
|
142
|
+
|
|
143
|
+
const Graph &_graph;
|
|
144
|
+
int _node_num;
|
|
145
|
+
bool _allow_loops;
|
|
146
|
+
int _empty_level;
|
|
147
|
+
|
|
148
|
+
TEMPLATE_GRAPH_TYPEDEFS(Graph);
|
|
149
|
+
|
|
150
|
+
bool _local_matching;
|
|
151
|
+
MatchingMap *_matching;
|
|
152
|
+
|
|
153
|
+
bool _local_level;
|
|
154
|
+
Elevator *_level;
|
|
155
|
+
|
|
156
|
+
typedef typename Graph::template NodeMap<int> InDegMap;
|
|
157
|
+
InDegMap *_indeg;
|
|
158
|
+
|
|
159
|
+
void createStructures() {
|
|
160
|
+
_node_num = countNodes(_graph);
|
|
161
|
+
|
|
162
|
+
if (!_matching) {
|
|
163
|
+
_local_matching = true;
|
|
164
|
+
_matching = Traits::createMatchingMap(_graph);
|
|
165
|
+
}
|
|
166
|
+
if (!_level) {
|
|
167
|
+
_local_level = true;
|
|
168
|
+
_level = Traits::createElevator(_graph, _node_num);
|
|
169
|
+
}
|
|
170
|
+
if (!_indeg) {
|
|
171
|
+
_indeg = new InDegMap(_graph);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
void destroyStructures() {
|
|
176
|
+
if (_local_matching) {
|
|
177
|
+
delete _matching;
|
|
178
|
+
}
|
|
179
|
+
if (_local_level) {
|
|
180
|
+
delete _level;
|
|
181
|
+
}
|
|
182
|
+
if (_indeg) {
|
|
183
|
+
delete _indeg;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
void postprocessing() {
|
|
188
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
189
|
+
if ((*_indeg)[n] != 0) continue;
|
|
190
|
+
_indeg->set(n, -1);
|
|
191
|
+
Node u = n;
|
|
192
|
+
while ((*_matching)[u] != INVALID) {
|
|
193
|
+
Node v = _graph.target((*_matching)[u]);
|
|
194
|
+
_indeg->set(v, -1);
|
|
195
|
+
Arc a = _graph.oppositeArc((*_matching)[u]);
|
|
196
|
+
u = _graph.target((*_matching)[v]);
|
|
197
|
+
_indeg->set(u, -1);
|
|
198
|
+
_matching->set(v, a);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
203
|
+
if ((*_indeg)[n] != 1) continue;
|
|
204
|
+
_indeg->set(n, -1);
|
|
205
|
+
|
|
206
|
+
int num = 1;
|
|
207
|
+
Node u = _graph.target((*_matching)[n]);
|
|
208
|
+
while (u != n) {
|
|
209
|
+
_indeg->set(u, -1);
|
|
210
|
+
u = _graph.target((*_matching)[u]);
|
|
211
|
+
++num;
|
|
212
|
+
}
|
|
213
|
+
if (num % 2 == 0 && num > 2) {
|
|
214
|
+
Arc prev = _graph.oppositeArc((*_matching)[n]);
|
|
215
|
+
Node v = _graph.target((*_matching)[n]);
|
|
216
|
+
u = _graph.target((*_matching)[v]);
|
|
217
|
+
_matching->set(v, prev);
|
|
218
|
+
while (u != n) {
|
|
219
|
+
prev = _graph.oppositeArc((*_matching)[u]);
|
|
220
|
+
v = _graph.target((*_matching)[u]);
|
|
221
|
+
u = _graph.target((*_matching)[v]);
|
|
222
|
+
_matching->set(v, prev);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public:
|
|
229
|
+
|
|
230
|
+
typedef MaxFractionalMatching Create;
|
|
231
|
+
|
|
232
|
+
///\name Named Template Parameters
|
|
233
|
+
|
|
234
|
+
///@{
|
|
235
|
+
|
|
236
|
+
template <typename T>
|
|
237
|
+
struct SetMatchingMapTraits : public Traits {
|
|
238
|
+
typedef T MatchingMap;
|
|
239
|
+
static MatchingMap *createMatchingMap(const Graph&) {
|
|
240
|
+
LEMON_ASSERT(false, "MatchingMap is not initialized");
|
|
241
|
+
return 0; // ignore warnings
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/// \brief \ref named-templ-param "Named parameter" for setting
|
|
246
|
+
/// MatchingMap type
|
|
247
|
+
///
|
|
248
|
+
/// \ref named-templ-param "Named parameter" for setting MatchingMap
|
|
249
|
+
/// type.
|
|
250
|
+
template <typename T>
|
|
251
|
+
struct SetMatchingMap
|
|
252
|
+
: public MaxFractionalMatching<Graph, SetMatchingMapTraits<T> > {
|
|
253
|
+
typedef MaxFractionalMatching<Graph, SetMatchingMapTraits<T> > Create;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
template <typename T>
|
|
257
|
+
struct SetElevatorTraits : public Traits {
|
|
258
|
+
typedef T Elevator;
|
|
259
|
+
static Elevator *createElevator(const Graph&, int) {
|
|
260
|
+
LEMON_ASSERT(false, "Elevator is not initialized");
|
|
261
|
+
return 0; // ignore warnings
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/// \brief \ref named-templ-param "Named parameter" for setting
|
|
266
|
+
/// Elevator type
|
|
267
|
+
///
|
|
268
|
+
/// \ref named-templ-param "Named parameter" for setting Elevator
|
|
269
|
+
/// type. If this named parameter is used, then an external
|
|
270
|
+
/// elevator object must be passed to the algorithm using the
|
|
271
|
+
/// \ref elevator(Elevator&) "elevator()" function before calling
|
|
272
|
+
/// \ref run() or \ref init().
|
|
273
|
+
/// \sa SetStandardElevator
|
|
274
|
+
template <typename T>
|
|
275
|
+
struct SetElevator
|
|
276
|
+
: public MaxFractionalMatching<Graph, SetElevatorTraits<T> > {
|
|
277
|
+
typedef MaxFractionalMatching<Graph, SetElevatorTraits<T> > Create;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
template <typename T>
|
|
281
|
+
struct SetStandardElevatorTraits : public Traits {
|
|
282
|
+
typedef T Elevator;
|
|
283
|
+
static Elevator *createElevator(const Graph& graph, int max_level) {
|
|
284
|
+
return new Elevator(graph, max_level);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
/// \brief \ref named-templ-param "Named parameter" for setting
|
|
289
|
+
/// Elevator type with automatic allocation
|
|
290
|
+
///
|
|
291
|
+
/// \ref named-templ-param "Named parameter" for setting Elevator
|
|
292
|
+
/// type with automatic allocation.
|
|
293
|
+
/// The Elevator should have standard constructor interface to be
|
|
294
|
+
/// able to automatically created by the algorithm (i.e. the
|
|
295
|
+
/// graph and the maximum level should be passed to it).
|
|
296
|
+
/// However an external elevator object could also be passed to the
|
|
297
|
+
/// algorithm with the \ref elevator(Elevator&) "elevator()" function
|
|
298
|
+
/// before calling \ref run() or \ref init().
|
|
299
|
+
/// \sa SetElevator
|
|
300
|
+
template <typename T>
|
|
301
|
+
struct SetStandardElevator
|
|
302
|
+
: public MaxFractionalMatching<Graph, SetStandardElevatorTraits<T> > {
|
|
303
|
+
typedef MaxFractionalMatching<Graph,
|
|
304
|
+
SetStandardElevatorTraits<T> > Create;
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/// @}
|
|
308
|
+
|
|
309
|
+
protected:
|
|
310
|
+
|
|
311
|
+
MaxFractionalMatching() {}
|
|
312
|
+
|
|
313
|
+
public:
|
|
314
|
+
|
|
315
|
+
/// \brief Constructor
|
|
316
|
+
///
|
|
317
|
+
/// Constructor.
|
|
318
|
+
///
|
|
319
|
+
MaxFractionalMatching(const Graph &graph, bool allow_loops = true)
|
|
320
|
+
: _graph(graph), _allow_loops(allow_loops),
|
|
321
|
+
_local_matching(false), _matching(0),
|
|
322
|
+
_local_level(false), _level(0), _indeg(0)
|
|
323
|
+
{}
|
|
324
|
+
|
|
325
|
+
~MaxFractionalMatching() {
|
|
326
|
+
destroyStructures();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/// \brief Sets the matching map.
|
|
330
|
+
///
|
|
331
|
+
/// Sets the matching map.
|
|
332
|
+
/// If you don't use this function before calling \ref run() or
|
|
333
|
+
/// \ref init(), an instance will be allocated automatically.
|
|
334
|
+
/// The destructor deallocates this automatically allocated map,
|
|
335
|
+
/// of course.
|
|
336
|
+
/// \return <tt>(*this)</tt>
|
|
337
|
+
MaxFractionalMatching& matchingMap(MatchingMap& map) {
|
|
338
|
+
if (_local_matching) {
|
|
339
|
+
delete _matching;
|
|
340
|
+
_local_matching = false;
|
|
341
|
+
}
|
|
342
|
+
_matching = ↦
|
|
343
|
+
return *this;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/// \brief Sets the elevator used by algorithm.
|
|
347
|
+
///
|
|
348
|
+
/// Sets the elevator used by algorithm.
|
|
349
|
+
/// If you don't use this function before calling \ref run() or
|
|
350
|
+
/// \ref init(), an instance will be allocated automatically.
|
|
351
|
+
/// The destructor deallocates this automatically allocated elevator,
|
|
352
|
+
/// of course.
|
|
353
|
+
/// \return <tt>(*this)</tt>
|
|
354
|
+
MaxFractionalMatching& elevator(Elevator& elevator) {
|
|
355
|
+
if (_local_level) {
|
|
356
|
+
delete _level;
|
|
357
|
+
_local_level = false;
|
|
358
|
+
}
|
|
359
|
+
_level = &elevator;
|
|
360
|
+
return *this;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/// \brief Returns a const reference to the elevator.
|
|
364
|
+
///
|
|
365
|
+
/// Returns a const reference to the elevator.
|
|
366
|
+
///
|
|
367
|
+
/// \pre Either \ref run() or \ref init() must be called before
|
|
368
|
+
/// using this function.
|
|
369
|
+
const Elevator& elevator() const {
|
|
370
|
+
return *_level;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/// \name Execution control
|
|
374
|
+
/// The simplest way to execute the algorithm is to use one of the
|
|
375
|
+
/// member functions called \c run(). \n
|
|
376
|
+
/// If you need more control on the execution, first
|
|
377
|
+
/// you must call \ref init() and then one variant of the start()
|
|
378
|
+
/// member.
|
|
379
|
+
|
|
380
|
+
/// @{
|
|
381
|
+
|
|
382
|
+
/// \brief Initializes the internal data structures.
|
|
383
|
+
///
|
|
384
|
+
/// Initializes the internal data structures and sets the initial
|
|
385
|
+
/// matching.
|
|
386
|
+
void init() {
|
|
387
|
+
createStructures();
|
|
388
|
+
|
|
389
|
+
_level->initStart();
|
|
390
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
391
|
+
_indeg->set(n, 0);
|
|
392
|
+
_matching->set(n, INVALID);
|
|
393
|
+
_level->initAddItem(n);
|
|
394
|
+
}
|
|
395
|
+
_level->initFinish();
|
|
396
|
+
|
|
397
|
+
_empty_level = _node_num;
|
|
398
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
399
|
+
for (OutArcIt a(_graph, n); a != INVALID; ++a) {
|
|
400
|
+
if (_graph.target(a) == n && !_allow_loops) continue;
|
|
401
|
+
_matching->set(n, a);
|
|
402
|
+
Node v = _graph.target((*_matching)[n]);
|
|
403
|
+
_indeg->set(v, (*_indeg)[v] + 1);
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
409
|
+
if ((*_indeg)[n] == 0) {
|
|
410
|
+
_level->activate(n);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/// \brief Starts the algorithm and computes a fractional matching
|
|
416
|
+
///
|
|
417
|
+
/// The algorithm computes a maximum fractional matching.
|
|
418
|
+
///
|
|
419
|
+
/// \param postprocess The algorithm computes first a matching
|
|
420
|
+
/// which is a union of a matching with one value edges, cycles
|
|
421
|
+
/// with half value edges and even length paths with half value
|
|
422
|
+
/// edges. If the parameter is true, then after the push-relabel
|
|
423
|
+
/// algorithm it postprocesses the matching to contain only
|
|
424
|
+
/// matching edges and half value odd cycles.
|
|
425
|
+
void start(bool postprocess = true) {
|
|
426
|
+
Node n;
|
|
427
|
+
while ((n = _level->highestActive()) != INVALID) {
|
|
428
|
+
int level = _level->highestActiveLevel();
|
|
429
|
+
int new_level = _level->maxLevel();
|
|
430
|
+
for (InArcIt a(_graph, n); a != INVALID; ++a) {
|
|
431
|
+
Node u = _graph.source(a);
|
|
432
|
+
if (n == u && !_allow_loops) continue;
|
|
433
|
+
Node v = _graph.target((*_matching)[u]);
|
|
434
|
+
if ((*_level)[v] < level) {
|
|
435
|
+
_indeg->set(v, (*_indeg)[v] - 1);
|
|
436
|
+
if ((*_indeg)[v] == 0) {
|
|
437
|
+
_level->activate(v);
|
|
438
|
+
}
|
|
439
|
+
_matching->set(u, a);
|
|
440
|
+
_indeg->set(n, (*_indeg)[n] + 1);
|
|
441
|
+
_level->deactivate(n);
|
|
442
|
+
goto no_more_push;
|
|
443
|
+
} else if (new_level > (*_level)[v]) {
|
|
444
|
+
new_level = (*_level)[v];
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (new_level + 1 < _level->maxLevel()) {
|
|
449
|
+
_level->liftHighestActive(new_level + 1);
|
|
450
|
+
} else {
|
|
451
|
+
_level->liftHighestActiveToTop();
|
|
452
|
+
}
|
|
453
|
+
if (_level->emptyLevel(level)) {
|
|
454
|
+
_level->liftToTop(level);
|
|
455
|
+
}
|
|
456
|
+
no_more_push:
|
|
457
|
+
;
|
|
458
|
+
}
|
|
459
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
460
|
+
if ((*_matching)[n] == INVALID) continue;
|
|
461
|
+
Node u = _graph.target((*_matching)[n]);
|
|
462
|
+
if ((*_indeg)[u] > 1) {
|
|
463
|
+
_indeg->set(u, (*_indeg)[u] - 1);
|
|
464
|
+
_matching->set(n, INVALID);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (postprocess) {
|
|
468
|
+
postprocessing();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/// \brief Starts the algorithm and computes a perfect fractional
|
|
473
|
+
/// matching
|
|
474
|
+
///
|
|
475
|
+
/// The algorithm computes a perfect fractional matching. If it
|
|
476
|
+
/// does not exists, then the algorithm returns false and the
|
|
477
|
+
/// matching is undefined and the barrier.
|
|
478
|
+
///
|
|
479
|
+
/// \param postprocess The algorithm computes first a matching
|
|
480
|
+
/// which is a union of a matching with one value edges, cycles
|
|
481
|
+
/// with half value edges and even length paths with half value
|
|
482
|
+
/// edges. If the parameter is true, then after the push-relabel
|
|
483
|
+
/// algorithm it postprocesses the matching to contain only
|
|
484
|
+
/// matching edges and half value odd cycles.
|
|
485
|
+
bool startPerfect(bool postprocess = true) {
|
|
486
|
+
Node n;
|
|
487
|
+
while ((n = _level->highestActive()) != INVALID) {
|
|
488
|
+
int level = _level->highestActiveLevel();
|
|
489
|
+
int new_level = _level->maxLevel();
|
|
490
|
+
for (InArcIt a(_graph, n); a != INVALID; ++a) {
|
|
491
|
+
Node u = _graph.source(a);
|
|
492
|
+
if (n == u && !_allow_loops) continue;
|
|
493
|
+
Node v = _graph.target((*_matching)[u]);
|
|
494
|
+
if ((*_level)[v] < level) {
|
|
495
|
+
_indeg->set(v, (*_indeg)[v] - 1);
|
|
496
|
+
if ((*_indeg)[v] == 0) {
|
|
497
|
+
_level->activate(v);
|
|
498
|
+
}
|
|
499
|
+
_matching->set(u, a);
|
|
500
|
+
_indeg->set(n, (*_indeg)[n] + 1);
|
|
501
|
+
_level->deactivate(n);
|
|
502
|
+
goto no_more_push;
|
|
503
|
+
} else if (new_level > (*_level)[v]) {
|
|
504
|
+
new_level = (*_level)[v];
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (new_level + 1 < _level->maxLevel()) {
|
|
509
|
+
_level->liftHighestActive(new_level + 1);
|
|
510
|
+
} else {
|
|
511
|
+
_level->liftHighestActiveToTop();
|
|
512
|
+
_empty_level = _level->maxLevel() - 1;
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
if (_level->emptyLevel(level)) {
|
|
516
|
+
_level->liftToTop(level);
|
|
517
|
+
_empty_level = level;
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
no_more_push:
|
|
521
|
+
;
|
|
522
|
+
}
|
|
523
|
+
if (postprocess) {
|
|
524
|
+
postprocessing();
|
|
525
|
+
}
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/// \brief Runs the algorithm
|
|
530
|
+
///
|
|
531
|
+
/// Just a shortcut for the next code:
|
|
532
|
+
///\code
|
|
533
|
+
/// init();
|
|
534
|
+
/// start();
|
|
535
|
+
///\endcode
|
|
536
|
+
void run(bool postprocess = true) {
|
|
537
|
+
init();
|
|
538
|
+
start(postprocess);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/// \brief Runs the algorithm to find a perfect fractional matching
|
|
542
|
+
///
|
|
543
|
+
/// Just a shortcut for the next code:
|
|
544
|
+
///\code
|
|
545
|
+
/// init();
|
|
546
|
+
/// startPerfect();
|
|
547
|
+
///\endcode
|
|
548
|
+
bool runPerfect(bool postprocess = true) {
|
|
549
|
+
init();
|
|
550
|
+
return startPerfect(postprocess);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
///@}
|
|
554
|
+
|
|
555
|
+
/// \name Query Functions
|
|
556
|
+
/// The result of the %Matching algorithm can be obtained using these
|
|
557
|
+
/// functions.\n
|
|
558
|
+
/// Before the use of these functions,
|
|
559
|
+
/// either run() or start() must be called.
|
|
560
|
+
///@{
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
/// \brief Return the number of covered nodes in the matching.
|
|
564
|
+
///
|
|
565
|
+
/// This function returns the number of covered nodes in the matching.
|
|
566
|
+
///
|
|
567
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
568
|
+
int matchingSize() const {
|
|
569
|
+
int num = 0;
|
|
570
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
571
|
+
if ((*_matching)[n] != INVALID) {
|
|
572
|
+
++num;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return num;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/// \brief Returns a const reference to the matching map.
|
|
579
|
+
///
|
|
580
|
+
/// Returns a const reference to the node map storing the found
|
|
581
|
+
/// fractional matching. This method can be called after
|
|
582
|
+
/// running the algorithm.
|
|
583
|
+
///
|
|
584
|
+
/// \pre Either \ref run() or \ref init() must be called before
|
|
585
|
+
/// using this function.
|
|
586
|
+
const MatchingMap& matchingMap() const {
|
|
587
|
+
return *_matching;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/// \brief Return \c true if the given edge is in the matching.
|
|
591
|
+
///
|
|
592
|
+
/// This function returns \c true if the given edge is in the
|
|
593
|
+
/// found matching. The result is scaled by \ref primalScale
|
|
594
|
+
/// "primal scale".
|
|
595
|
+
///
|
|
596
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
597
|
+
int matching(const Edge& edge) const {
|
|
598
|
+
return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) +
|
|
599
|
+
(edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/// \brief Return the fractional matching arc (or edge) incident
|
|
603
|
+
/// to the given node.
|
|
604
|
+
///
|
|
605
|
+
/// This function returns one of the fractional matching arc (or
|
|
606
|
+
/// edge) incident to the given node in the found matching or \c
|
|
607
|
+
/// INVALID if the node is not covered by the matching or if the
|
|
608
|
+
/// node is on an odd length cycle then it is the successor edge
|
|
609
|
+
/// on the cycle.
|
|
610
|
+
///
|
|
611
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
612
|
+
Arc matching(const Node& node) const {
|
|
613
|
+
return (*_matching)[node];
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/// \brief Returns true if the node is in the barrier
|
|
617
|
+
///
|
|
618
|
+
/// The barrier is a subset of the nodes. If the nodes in the
|
|
619
|
+
/// barrier have less adjacent nodes than the size of the barrier,
|
|
620
|
+
/// then at least as much nodes cannot be covered as the
|
|
621
|
+
/// difference of the two subsets.
|
|
622
|
+
bool barrier(const Node& node) const {
|
|
623
|
+
return (*_level)[node] >= _empty_level;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/// @}
|
|
627
|
+
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
/// \ingroup matching
|
|
631
|
+
///
|
|
632
|
+
/// \brief Weighted fractional matching in general graphs
|
|
633
|
+
///
|
|
634
|
+
/// This class provides an efficient implementation of fractional
|
|
635
|
+
/// matching algorithm. The implementation uses priority queues and
|
|
636
|
+
/// provides \f$O(nm\log n)\f$ time complexity.
|
|
637
|
+
///
|
|
638
|
+
/// The maximum weighted fractional matching is a relaxation of the
|
|
639
|
+
/// maximum weighted matching problem where the odd set constraints
|
|
640
|
+
/// are omitted.
|
|
641
|
+
/// It can be formulated with the following linear program.
|
|
642
|
+
/// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f]
|
|
643
|
+
/// \f[x_e \ge 0\quad \forall e\in E\f]
|
|
644
|
+
/// \f[\max \sum_{e\in E}x_ew_e\f]
|
|
645
|
+
/// where \f$\delta(X)\f$ is the set of edges incident to a node in
|
|
646
|
+
/// \f$X\f$. The result must be the union of a matching with one
|
|
647
|
+
/// value edges and a set of odd length cycles with half value edges.
|
|
648
|
+
///
|
|
649
|
+
/// The algorithm calculates an optimal fractional matching and a
|
|
650
|
+
/// proof of the optimality. The solution of the dual problem can be
|
|
651
|
+
/// used to check the result of the algorithm. The dual linear
|
|
652
|
+
/// problem is the following.
|
|
653
|
+
/// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
|
|
654
|
+
/// \f[y_u \ge 0 \quad \forall u \in V\f]
|
|
655
|
+
/// \f[\min \sum_{u \in V}y_u \f]
|
|
656
|
+
///
|
|
657
|
+
/// The algorithm can be executed with the run() function.
|
|
658
|
+
/// After it the matching (the primal solution) and the dual solution
|
|
659
|
+
/// can be obtained using the query functions.
|
|
660
|
+
///
|
|
661
|
+
/// The primal solution is multiplied by
|
|
662
|
+
/// \ref MaxWeightedFractionalMatching::primalScale "2".
|
|
663
|
+
/// If the value type is integer, then the dual
|
|
664
|
+
/// solution is scaled by
|
|
665
|
+
/// \ref MaxWeightedFractionalMatching::dualScale "4".
|
|
666
|
+
///
|
|
667
|
+
/// \tparam GR The undirected graph type the algorithm runs on.
|
|
668
|
+
/// \tparam WM The type edge weight map. The default type is
|
|
669
|
+
/// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
|
|
670
|
+
#ifdef DOXYGEN
|
|
671
|
+
template <typename GR, typename WM>
|
|
672
|
+
#else
|
|
673
|
+
template <typename GR,
|
|
674
|
+
typename WM = typename GR::template EdgeMap<int> >
|
|
675
|
+
#endif
|
|
676
|
+
class MaxWeightedFractionalMatching {
|
|
677
|
+
public:
|
|
678
|
+
|
|
679
|
+
/// The graph type of the algorithm
|
|
680
|
+
typedef GR Graph;
|
|
681
|
+
/// The type of the edge weight map
|
|
682
|
+
typedef WM WeightMap;
|
|
683
|
+
/// The value type of the edge weights
|
|
684
|
+
typedef typename WeightMap::Value Value;
|
|
685
|
+
|
|
686
|
+
/// The type of the matching map
|
|
687
|
+
typedef typename Graph::template NodeMap<typename Graph::Arc>
|
|
688
|
+
MatchingMap;
|
|
689
|
+
|
|
690
|
+
/// \brief Scaling factor for primal solution
|
|
691
|
+
///
|
|
692
|
+
/// Scaling factor for primal solution.
|
|
693
|
+
static const int primalScale = 2;
|
|
694
|
+
|
|
695
|
+
/// \brief Scaling factor for dual solution
|
|
696
|
+
///
|
|
697
|
+
/// Scaling factor for dual solution. It is equal to 4 or 1
|
|
698
|
+
/// according to the value type.
|
|
699
|
+
static const int dualScale =
|
|
700
|
+
std::numeric_limits<Value>::is_integer ? 4 : 1;
|
|
701
|
+
|
|
702
|
+
private:
|
|
703
|
+
|
|
704
|
+
TEMPLATE_GRAPH_TYPEDEFS(Graph);
|
|
705
|
+
|
|
706
|
+
typedef typename Graph::template NodeMap<Value> NodePotential;
|
|
707
|
+
|
|
708
|
+
const Graph& _graph;
|
|
709
|
+
const WeightMap& _weight;
|
|
710
|
+
|
|
711
|
+
MatchingMap* _matching;
|
|
712
|
+
NodePotential* _node_potential;
|
|
713
|
+
|
|
714
|
+
int _node_num;
|
|
715
|
+
bool _allow_loops;
|
|
716
|
+
|
|
717
|
+
enum Status {
|
|
718
|
+
EVEN = -1, MATCHED = 0, ODD = 1
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
typedef typename Graph::template NodeMap<Status> StatusMap;
|
|
722
|
+
StatusMap* _status;
|
|
723
|
+
|
|
724
|
+
typedef typename Graph::template NodeMap<Arc> PredMap;
|
|
725
|
+
PredMap* _pred;
|
|
726
|
+
|
|
727
|
+
typedef ExtendFindEnum<IntNodeMap> TreeSet;
|
|
728
|
+
|
|
729
|
+
IntNodeMap *_tree_set_index;
|
|
730
|
+
TreeSet *_tree_set;
|
|
731
|
+
|
|
732
|
+
IntNodeMap *_delta1_index;
|
|
733
|
+
BinHeap<Value, IntNodeMap> *_delta1;
|
|
734
|
+
|
|
735
|
+
IntNodeMap *_delta2_index;
|
|
736
|
+
BinHeap<Value, IntNodeMap> *_delta2;
|
|
737
|
+
|
|
738
|
+
IntEdgeMap *_delta3_index;
|
|
739
|
+
BinHeap<Value, IntEdgeMap> *_delta3;
|
|
740
|
+
|
|
741
|
+
Value _delta_sum;
|
|
742
|
+
|
|
743
|
+
void createStructures() {
|
|
744
|
+
_node_num = countNodes(_graph);
|
|
745
|
+
|
|
746
|
+
if (!_matching) {
|
|
747
|
+
_matching = new MatchingMap(_graph);
|
|
748
|
+
}
|
|
749
|
+
if (!_node_potential) {
|
|
750
|
+
_node_potential = new NodePotential(_graph);
|
|
751
|
+
}
|
|
752
|
+
if (!_status) {
|
|
753
|
+
_status = new StatusMap(_graph);
|
|
754
|
+
}
|
|
755
|
+
if (!_pred) {
|
|
756
|
+
_pred = new PredMap(_graph);
|
|
757
|
+
}
|
|
758
|
+
if (!_tree_set) {
|
|
759
|
+
_tree_set_index = new IntNodeMap(_graph);
|
|
760
|
+
_tree_set = new TreeSet(*_tree_set_index);
|
|
761
|
+
}
|
|
762
|
+
if (!_delta1) {
|
|
763
|
+
_delta1_index = new IntNodeMap(_graph);
|
|
764
|
+
_delta1 = new BinHeap<Value, IntNodeMap>(*_delta1_index);
|
|
765
|
+
}
|
|
766
|
+
if (!_delta2) {
|
|
767
|
+
_delta2_index = new IntNodeMap(_graph);
|
|
768
|
+
_delta2 = new BinHeap<Value, IntNodeMap>(*_delta2_index);
|
|
769
|
+
}
|
|
770
|
+
if (!_delta3) {
|
|
771
|
+
_delta3_index = new IntEdgeMap(_graph);
|
|
772
|
+
_delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
void destroyStructures() {
|
|
777
|
+
if (_matching) {
|
|
778
|
+
delete _matching;
|
|
779
|
+
}
|
|
780
|
+
if (_node_potential) {
|
|
781
|
+
delete _node_potential;
|
|
782
|
+
}
|
|
783
|
+
if (_status) {
|
|
784
|
+
delete _status;
|
|
785
|
+
}
|
|
786
|
+
if (_pred) {
|
|
787
|
+
delete _pred;
|
|
788
|
+
}
|
|
789
|
+
if (_tree_set) {
|
|
790
|
+
delete _tree_set_index;
|
|
791
|
+
delete _tree_set;
|
|
792
|
+
}
|
|
793
|
+
if (_delta1) {
|
|
794
|
+
delete _delta1_index;
|
|
795
|
+
delete _delta1;
|
|
796
|
+
}
|
|
797
|
+
if (_delta2) {
|
|
798
|
+
delete _delta2_index;
|
|
799
|
+
delete _delta2;
|
|
800
|
+
}
|
|
801
|
+
if (_delta3) {
|
|
802
|
+
delete _delta3_index;
|
|
803
|
+
delete _delta3;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
void matchedToEven(Node node, int tree) {
|
|
808
|
+
_tree_set->insert(node, tree);
|
|
809
|
+
_node_potential->set(node, (*_node_potential)[node] + _delta_sum);
|
|
810
|
+
_delta1->push(node, (*_node_potential)[node]);
|
|
811
|
+
|
|
812
|
+
if (_delta2->state(node) == _delta2->IN_HEAP) {
|
|
813
|
+
_delta2->erase(node);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
for (InArcIt a(_graph, node); a != INVALID; ++a) {
|
|
817
|
+
Node v = _graph.source(a);
|
|
818
|
+
Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
|
|
819
|
+
dualScale * _weight[a];
|
|
820
|
+
if (node == v) {
|
|
821
|
+
if (_allow_loops && _graph.direction(a)) {
|
|
822
|
+
_delta3->push(a, rw / 2);
|
|
823
|
+
}
|
|
824
|
+
} else if ((*_status)[v] == EVEN) {
|
|
825
|
+
_delta3->push(a, rw / 2);
|
|
826
|
+
} else if ((*_status)[v] == MATCHED) {
|
|
827
|
+
if (_delta2->state(v) != _delta2->IN_HEAP) {
|
|
828
|
+
_pred->set(v, a);
|
|
829
|
+
_delta2->push(v, rw);
|
|
830
|
+
} else if ((*_delta2)[v] > rw) {
|
|
831
|
+
_pred->set(v, a);
|
|
832
|
+
_delta2->decrease(v, rw);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
void matchedToOdd(Node node, int tree) {
|
|
839
|
+
_tree_set->insert(node, tree);
|
|
840
|
+
_node_potential->set(node, (*_node_potential)[node] - _delta_sum);
|
|
841
|
+
|
|
842
|
+
if (_delta2->state(node) == _delta2->IN_HEAP) {
|
|
843
|
+
_delta2->erase(node);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
void evenToMatched(Node node, int tree) {
|
|
848
|
+
_delta1->erase(node);
|
|
849
|
+
_node_potential->set(node, (*_node_potential)[node] - _delta_sum);
|
|
850
|
+
Arc min = INVALID;
|
|
851
|
+
Value minrw = std::numeric_limits<Value>::max();
|
|
852
|
+
for (InArcIt a(_graph, node); a != INVALID; ++a) {
|
|
853
|
+
Node v = _graph.source(a);
|
|
854
|
+
Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
|
|
855
|
+
dualScale * _weight[a];
|
|
856
|
+
|
|
857
|
+
if (node == v) {
|
|
858
|
+
if (_allow_loops && _graph.direction(a)) {
|
|
859
|
+
_delta3->erase(a);
|
|
860
|
+
}
|
|
861
|
+
} else if ((*_status)[v] == EVEN) {
|
|
862
|
+
_delta3->erase(a);
|
|
863
|
+
if (minrw > rw) {
|
|
864
|
+
min = _graph.oppositeArc(a);
|
|
865
|
+
minrw = rw;
|
|
866
|
+
}
|
|
867
|
+
} else if ((*_status)[v] == MATCHED) {
|
|
868
|
+
if ((*_pred)[v] == a) {
|
|
869
|
+
Arc mina = INVALID;
|
|
870
|
+
Value minrwa = std::numeric_limits<Value>::max();
|
|
871
|
+
for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) {
|
|
872
|
+
Node va = _graph.target(aa);
|
|
873
|
+
if ((*_status)[va] != EVEN ||
|
|
874
|
+
_tree_set->find(va) == tree) continue;
|
|
875
|
+
Value rwa = (*_node_potential)[v] + (*_node_potential)[va] -
|
|
876
|
+
dualScale * _weight[aa];
|
|
877
|
+
if (minrwa > rwa) {
|
|
878
|
+
minrwa = rwa;
|
|
879
|
+
mina = aa;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
if (mina != INVALID) {
|
|
883
|
+
_pred->set(v, mina);
|
|
884
|
+
_delta2->increase(v, minrwa);
|
|
885
|
+
} else {
|
|
886
|
+
_pred->set(v, INVALID);
|
|
887
|
+
_delta2->erase(v);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
if (min != INVALID) {
|
|
893
|
+
_pred->set(node, min);
|
|
894
|
+
_delta2->push(node, minrw);
|
|
895
|
+
} else {
|
|
896
|
+
_pred->set(node, INVALID);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
void oddToMatched(Node node) {
|
|
901
|
+
_node_potential->set(node, (*_node_potential)[node] + _delta_sum);
|
|
902
|
+
Arc min = INVALID;
|
|
903
|
+
Value minrw = std::numeric_limits<Value>::max();
|
|
904
|
+
for (InArcIt a(_graph, node); a != INVALID; ++a) {
|
|
905
|
+
Node v = _graph.source(a);
|
|
906
|
+
if ((*_status)[v] != EVEN) continue;
|
|
907
|
+
Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
|
|
908
|
+
dualScale * _weight[a];
|
|
909
|
+
|
|
910
|
+
if (minrw > rw) {
|
|
911
|
+
min = _graph.oppositeArc(a);
|
|
912
|
+
minrw = rw;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
if (min != INVALID) {
|
|
916
|
+
_pred->set(node, min);
|
|
917
|
+
_delta2->push(node, minrw);
|
|
918
|
+
} else {
|
|
919
|
+
_pred->set(node, INVALID);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
void alternatePath(Node even, int tree) {
|
|
924
|
+
Node odd;
|
|
925
|
+
|
|
926
|
+
_status->set(even, MATCHED);
|
|
927
|
+
evenToMatched(even, tree);
|
|
928
|
+
|
|
929
|
+
Arc prev = (*_matching)[even];
|
|
930
|
+
while (prev != INVALID) {
|
|
931
|
+
odd = _graph.target(prev);
|
|
932
|
+
even = _graph.target((*_pred)[odd]);
|
|
933
|
+
_matching->set(odd, (*_pred)[odd]);
|
|
934
|
+
_status->set(odd, MATCHED);
|
|
935
|
+
oddToMatched(odd);
|
|
936
|
+
|
|
937
|
+
prev = (*_matching)[even];
|
|
938
|
+
_status->set(even, MATCHED);
|
|
939
|
+
_matching->set(even, _graph.oppositeArc((*_matching)[odd]));
|
|
940
|
+
evenToMatched(even, tree);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
void destroyTree(int tree) {
|
|
945
|
+
for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) {
|
|
946
|
+
if ((*_status)[n] == EVEN) {
|
|
947
|
+
_status->set(n, MATCHED);
|
|
948
|
+
evenToMatched(n, tree);
|
|
949
|
+
} else if ((*_status)[n] == ODD) {
|
|
950
|
+
_status->set(n, MATCHED);
|
|
951
|
+
oddToMatched(n);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
_tree_set->eraseClass(tree);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
void unmatchNode(const Node& node) {
|
|
959
|
+
int tree = _tree_set->find(node);
|
|
960
|
+
|
|
961
|
+
alternatePath(node, tree);
|
|
962
|
+
destroyTree(tree);
|
|
963
|
+
|
|
964
|
+
_matching->set(node, INVALID);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
void augmentOnEdge(const Edge& edge) {
|
|
969
|
+
Node left = _graph.u(edge);
|
|
970
|
+
int left_tree = _tree_set->find(left);
|
|
971
|
+
|
|
972
|
+
alternatePath(left, left_tree);
|
|
973
|
+
destroyTree(left_tree);
|
|
974
|
+
_matching->set(left, _graph.direct(edge, true));
|
|
975
|
+
|
|
976
|
+
Node right = _graph.v(edge);
|
|
977
|
+
int right_tree = _tree_set->find(right);
|
|
978
|
+
|
|
979
|
+
alternatePath(right, right_tree);
|
|
980
|
+
destroyTree(right_tree);
|
|
981
|
+
_matching->set(right, _graph.direct(edge, false));
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
void augmentOnArc(const Arc& arc) {
|
|
985
|
+
Node left = _graph.source(arc);
|
|
986
|
+
_status->set(left, MATCHED);
|
|
987
|
+
_matching->set(left, arc);
|
|
988
|
+
_pred->set(left, arc);
|
|
989
|
+
|
|
990
|
+
Node right = _graph.target(arc);
|
|
991
|
+
int right_tree = _tree_set->find(right);
|
|
992
|
+
|
|
993
|
+
alternatePath(right, right_tree);
|
|
994
|
+
destroyTree(right_tree);
|
|
995
|
+
_matching->set(right, _graph.oppositeArc(arc));
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
void extendOnArc(const Arc& arc) {
|
|
999
|
+
Node base = _graph.target(arc);
|
|
1000
|
+
int tree = _tree_set->find(base);
|
|
1001
|
+
|
|
1002
|
+
Node odd = _graph.source(arc);
|
|
1003
|
+
_tree_set->insert(odd, tree);
|
|
1004
|
+
_status->set(odd, ODD);
|
|
1005
|
+
matchedToOdd(odd, tree);
|
|
1006
|
+
_pred->set(odd, arc);
|
|
1007
|
+
|
|
1008
|
+
Node even = _graph.target((*_matching)[odd]);
|
|
1009
|
+
_tree_set->insert(even, tree);
|
|
1010
|
+
_status->set(even, EVEN);
|
|
1011
|
+
matchedToEven(even, tree);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
void cycleOnEdge(const Edge& edge, int tree) {
|
|
1015
|
+
Node nca = INVALID;
|
|
1016
|
+
std::vector<Node> left_path, right_path;
|
|
1017
|
+
|
|
1018
|
+
{
|
|
1019
|
+
std::set<Node> left_set, right_set;
|
|
1020
|
+
Node left = _graph.u(edge);
|
|
1021
|
+
left_path.push_back(left);
|
|
1022
|
+
left_set.insert(left);
|
|
1023
|
+
|
|
1024
|
+
Node right = _graph.v(edge);
|
|
1025
|
+
right_path.push_back(right);
|
|
1026
|
+
right_set.insert(right);
|
|
1027
|
+
|
|
1028
|
+
while (true) {
|
|
1029
|
+
|
|
1030
|
+
if (left_set.find(right) != left_set.end()) {
|
|
1031
|
+
nca = right;
|
|
1032
|
+
break;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
if ((*_matching)[left] == INVALID) break;
|
|
1036
|
+
|
|
1037
|
+
left = _graph.target((*_matching)[left]);
|
|
1038
|
+
left_path.push_back(left);
|
|
1039
|
+
left = _graph.target((*_pred)[left]);
|
|
1040
|
+
left_path.push_back(left);
|
|
1041
|
+
|
|
1042
|
+
left_set.insert(left);
|
|
1043
|
+
|
|
1044
|
+
if (right_set.find(left) != right_set.end()) {
|
|
1045
|
+
nca = left;
|
|
1046
|
+
break;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
if ((*_matching)[right] == INVALID) break;
|
|
1050
|
+
|
|
1051
|
+
right = _graph.target((*_matching)[right]);
|
|
1052
|
+
right_path.push_back(right);
|
|
1053
|
+
right = _graph.target((*_pred)[right]);
|
|
1054
|
+
right_path.push_back(right);
|
|
1055
|
+
|
|
1056
|
+
right_set.insert(right);
|
|
1057
|
+
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (nca == INVALID) {
|
|
1061
|
+
if ((*_matching)[left] == INVALID) {
|
|
1062
|
+
nca = right;
|
|
1063
|
+
while (left_set.find(nca) == left_set.end()) {
|
|
1064
|
+
nca = _graph.target((*_matching)[nca]);
|
|
1065
|
+
right_path.push_back(nca);
|
|
1066
|
+
nca = _graph.target((*_pred)[nca]);
|
|
1067
|
+
right_path.push_back(nca);
|
|
1068
|
+
}
|
|
1069
|
+
} else {
|
|
1070
|
+
nca = left;
|
|
1071
|
+
while (right_set.find(nca) == right_set.end()) {
|
|
1072
|
+
nca = _graph.target((*_matching)[nca]);
|
|
1073
|
+
left_path.push_back(nca);
|
|
1074
|
+
nca = _graph.target((*_pred)[nca]);
|
|
1075
|
+
left_path.push_back(nca);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
alternatePath(nca, tree);
|
|
1082
|
+
Arc prev;
|
|
1083
|
+
|
|
1084
|
+
prev = _graph.direct(edge, true);
|
|
1085
|
+
for (int i = 0; left_path[i] != nca; i += 2) {
|
|
1086
|
+
_matching->set(left_path[i], prev);
|
|
1087
|
+
_status->set(left_path[i], MATCHED);
|
|
1088
|
+
evenToMatched(left_path[i], tree);
|
|
1089
|
+
|
|
1090
|
+
prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]);
|
|
1091
|
+
_status->set(left_path[i + 1], MATCHED);
|
|
1092
|
+
oddToMatched(left_path[i + 1]);
|
|
1093
|
+
}
|
|
1094
|
+
_matching->set(nca, prev);
|
|
1095
|
+
|
|
1096
|
+
for (int i = 0; right_path[i] != nca; i += 2) {
|
|
1097
|
+
_status->set(right_path[i], MATCHED);
|
|
1098
|
+
evenToMatched(right_path[i], tree);
|
|
1099
|
+
|
|
1100
|
+
_matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]);
|
|
1101
|
+
_status->set(right_path[i + 1], MATCHED);
|
|
1102
|
+
oddToMatched(right_path[i + 1]);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
destroyTree(tree);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
void extractCycle(const Arc &arc) {
|
|
1109
|
+
Node left = _graph.source(arc);
|
|
1110
|
+
Node odd = _graph.target((*_matching)[left]);
|
|
1111
|
+
Arc prev;
|
|
1112
|
+
while (odd != left) {
|
|
1113
|
+
Node even = _graph.target((*_matching)[odd]);
|
|
1114
|
+
prev = (*_matching)[odd];
|
|
1115
|
+
odd = _graph.target((*_matching)[even]);
|
|
1116
|
+
_matching->set(even, _graph.oppositeArc(prev));
|
|
1117
|
+
}
|
|
1118
|
+
_matching->set(left, arc);
|
|
1119
|
+
|
|
1120
|
+
Node right = _graph.target(arc);
|
|
1121
|
+
int right_tree = _tree_set->find(right);
|
|
1122
|
+
alternatePath(right, right_tree);
|
|
1123
|
+
destroyTree(right_tree);
|
|
1124
|
+
_matching->set(right, _graph.oppositeArc(arc));
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
public:
|
|
1128
|
+
|
|
1129
|
+
/// \brief Constructor
|
|
1130
|
+
///
|
|
1131
|
+
/// Constructor.
|
|
1132
|
+
MaxWeightedFractionalMatching(const Graph& graph, const WeightMap& weight,
|
|
1133
|
+
bool allow_loops = true)
|
|
1134
|
+
: _graph(graph), _weight(weight), _matching(0),
|
|
1135
|
+
_node_potential(0), _node_num(0), _allow_loops(allow_loops),
|
|
1136
|
+
_status(0), _pred(0),
|
|
1137
|
+
_tree_set_index(0), _tree_set(0),
|
|
1138
|
+
|
|
1139
|
+
_delta1_index(0), _delta1(0),
|
|
1140
|
+
_delta2_index(0), _delta2(0),
|
|
1141
|
+
_delta3_index(0), _delta3(0),
|
|
1142
|
+
|
|
1143
|
+
_delta_sum() {}
|
|
1144
|
+
|
|
1145
|
+
~MaxWeightedFractionalMatching() {
|
|
1146
|
+
destroyStructures();
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/// \name Execution Control
|
|
1150
|
+
/// The simplest way to execute the algorithm is to use the
|
|
1151
|
+
/// \ref run() member function.
|
|
1152
|
+
|
|
1153
|
+
///@{
|
|
1154
|
+
|
|
1155
|
+
/// \brief Initialize the algorithm
|
|
1156
|
+
///
|
|
1157
|
+
/// This function initializes the algorithm.
|
|
1158
|
+
void init() {
|
|
1159
|
+
createStructures();
|
|
1160
|
+
|
|
1161
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1162
|
+
(*_delta1_index)[n] = _delta1->PRE_HEAP;
|
|
1163
|
+
(*_delta2_index)[n] = _delta2->PRE_HEAP;
|
|
1164
|
+
}
|
|
1165
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1166
|
+
(*_delta3_index)[e] = _delta3->PRE_HEAP;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
_delta1->clear();
|
|
1170
|
+
_delta2->clear();
|
|
1171
|
+
_delta3->clear();
|
|
1172
|
+
_tree_set->clear();
|
|
1173
|
+
|
|
1174
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1175
|
+
Value max = 0;
|
|
1176
|
+
for (OutArcIt e(_graph, n); e != INVALID; ++e) {
|
|
1177
|
+
if (_graph.target(e) == n && !_allow_loops) continue;
|
|
1178
|
+
if ((dualScale * _weight[e]) / 2 > max) {
|
|
1179
|
+
max = (dualScale * _weight[e]) / 2;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
_node_potential->set(n, max);
|
|
1183
|
+
_delta1->push(n, max);
|
|
1184
|
+
|
|
1185
|
+
_tree_set->insert(n);
|
|
1186
|
+
|
|
1187
|
+
_matching->set(n, INVALID);
|
|
1188
|
+
_status->set(n, EVEN);
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1192
|
+
Node left = _graph.u(e);
|
|
1193
|
+
Node right = _graph.v(e);
|
|
1194
|
+
if (left == right && !_allow_loops) continue;
|
|
1195
|
+
_delta3->push(e, ((*_node_potential)[left] +
|
|
1196
|
+
(*_node_potential)[right] -
|
|
1197
|
+
dualScale * _weight[e]) / 2);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
/// \brief Start the algorithm
|
|
1202
|
+
///
|
|
1203
|
+
/// This function starts the algorithm.
|
|
1204
|
+
///
|
|
1205
|
+
/// \pre \ref init() must be called before using this function.
|
|
1206
|
+
void start() {
|
|
1207
|
+
enum OpType {
|
|
1208
|
+
D1, D2, D3
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1211
|
+
int unmatched = _node_num;
|
|
1212
|
+
while (unmatched > 0) {
|
|
1213
|
+
Value d1 = !_delta1->empty() ?
|
|
1214
|
+
_delta1->prio() : std::numeric_limits<Value>::max();
|
|
1215
|
+
|
|
1216
|
+
Value d2 = !_delta2->empty() ?
|
|
1217
|
+
_delta2->prio() : std::numeric_limits<Value>::max();
|
|
1218
|
+
|
|
1219
|
+
Value d3 = !_delta3->empty() ?
|
|
1220
|
+
_delta3->prio() : std::numeric_limits<Value>::max();
|
|
1221
|
+
|
|
1222
|
+
_delta_sum = d3; OpType ot = D3;
|
|
1223
|
+
if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; }
|
|
1224
|
+
if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
|
|
1225
|
+
|
|
1226
|
+
switch (ot) {
|
|
1227
|
+
case D1:
|
|
1228
|
+
{
|
|
1229
|
+
Node n = _delta1->top();
|
|
1230
|
+
unmatchNode(n);
|
|
1231
|
+
--unmatched;
|
|
1232
|
+
}
|
|
1233
|
+
break;
|
|
1234
|
+
case D2:
|
|
1235
|
+
{
|
|
1236
|
+
Node n = _delta2->top();
|
|
1237
|
+
Arc a = (*_pred)[n];
|
|
1238
|
+
if ((*_matching)[n] == INVALID) {
|
|
1239
|
+
augmentOnArc(a);
|
|
1240
|
+
--unmatched;
|
|
1241
|
+
} else {
|
|
1242
|
+
Node v = _graph.target((*_matching)[n]);
|
|
1243
|
+
if ((*_matching)[n] !=
|
|
1244
|
+
_graph.oppositeArc((*_matching)[v])) {
|
|
1245
|
+
extractCycle(a);
|
|
1246
|
+
--unmatched;
|
|
1247
|
+
} else {
|
|
1248
|
+
extendOnArc(a);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
} break;
|
|
1252
|
+
case D3:
|
|
1253
|
+
{
|
|
1254
|
+
Edge e = _delta3->top();
|
|
1255
|
+
|
|
1256
|
+
Node left = _graph.u(e);
|
|
1257
|
+
Node right = _graph.v(e);
|
|
1258
|
+
|
|
1259
|
+
int left_tree = _tree_set->find(left);
|
|
1260
|
+
int right_tree = _tree_set->find(right);
|
|
1261
|
+
|
|
1262
|
+
if (left_tree == right_tree) {
|
|
1263
|
+
cycleOnEdge(e, left_tree);
|
|
1264
|
+
--unmatched;
|
|
1265
|
+
} else {
|
|
1266
|
+
augmentOnEdge(e);
|
|
1267
|
+
unmatched -= 2;
|
|
1268
|
+
}
|
|
1269
|
+
} break;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
/// \brief Run the algorithm.
|
|
1275
|
+
///
|
|
1276
|
+
/// This method runs the \c %MaxWeightedFractionalMatching algorithm.
|
|
1277
|
+
///
|
|
1278
|
+
/// \note mwfm.run() is just a shortcut of the following code.
|
|
1279
|
+
/// \code
|
|
1280
|
+
/// mwfm.init();
|
|
1281
|
+
/// mwfm.start();
|
|
1282
|
+
/// \endcode
|
|
1283
|
+
void run() {
|
|
1284
|
+
init();
|
|
1285
|
+
start();
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/// @}
|
|
1289
|
+
|
|
1290
|
+
/// \name Primal Solution
|
|
1291
|
+
/// Functions to get the primal solution, i.e. the maximum weighted
|
|
1292
|
+
/// matching.\n
|
|
1293
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
1294
|
+
/// using them.
|
|
1295
|
+
|
|
1296
|
+
/// @{
|
|
1297
|
+
|
|
1298
|
+
/// \brief Return the weight of the matching.
|
|
1299
|
+
///
|
|
1300
|
+
/// This function returns the weight of the found matching. This
|
|
1301
|
+
/// value is scaled by \ref primalScale "primal scale".
|
|
1302
|
+
///
|
|
1303
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1304
|
+
Value matchingWeight() const {
|
|
1305
|
+
Value sum = 0;
|
|
1306
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1307
|
+
if ((*_matching)[n] != INVALID) {
|
|
1308
|
+
sum += _weight[(*_matching)[n]];
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
return sum * primalScale / 2;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
/// \brief Return the number of covered nodes in the matching.
|
|
1315
|
+
///
|
|
1316
|
+
/// This function returns the number of covered nodes in the matching.
|
|
1317
|
+
///
|
|
1318
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1319
|
+
int matchingSize() const {
|
|
1320
|
+
int num = 0;
|
|
1321
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1322
|
+
if ((*_matching)[n] != INVALID) {
|
|
1323
|
+
++num;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
return num;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
/// \brief Return \c true if the given edge is in the matching.
|
|
1330
|
+
///
|
|
1331
|
+
/// This function returns \c true if the given edge is in the
|
|
1332
|
+
/// found matching. The result is scaled by \ref primalScale
|
|
1333
|
+
/// "primal scale".
|
|
1334
|
+
///
|
|
1335
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1336
|
+
int matching(const Edge& edge) const {
|
|
1337
|
+
return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
|
|
1338
|
+
+ (edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
/// \brief Return the fractional matching arc (or edge) incident
|
|
1342
|
+
/// to the given node.
|
|
1343
|
+
///
|
|
1344
|
+
/// This function returns one of the fractional matching arc (or
|
|
1345
|
+
/// edge) incident to the given node in the found matching or \c
|
|
1346
|
+
/// INVALID if the node is not covered by the matching or if the
|
|
1347
|
+
/// node is on an odd length cycle then it is the successor edge
|
|
1348
|
+
/// on the cycle.
|
|
1349
|
+
///
|
|
1350
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1351
|
+
Arc matching(const Node& node) const {
|
|
1352
|
+
return (*_matching)[node];
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
/// \brief Return a const reference to the matching map.
|
|
1356
|
+
///
|
|
1357
|
+
/// This function returns a const reference to a node map that stores
|
|
1358
|
+
/// the matching arc (or edge) incident to each node.
|
|
1359
|
+
const MatchingMap& matchingMap() const {
|
|
1360
|
+
return *_matching;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
/// @}
|
|
1364
|
+
|
|
1365
|
+
/// \name Dual Solution
|
|
1366
|
+
/// Functions to get the dual solution.\n
|
|
1367
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
1368
|
+
/// using them.
|
|
1369
|
+
|
|
1370
|
+
/// @{
|
|
1371
|
+
|
|
1372
|
+
/// \brief Return the value of the dual solution.
|
|
1373
|
+
///
|
|
1374
|
+
/// This function returns the value of the dual solution.
|
|
1375
|
+
/// It should be equal to the primal value scaled by \ref dualScale
|
|
1376
|
+
/// "dual scale".
|
|
1377
|
+
///
|
|
1378
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1379
|
+
Value dualValue() const {
|
|
1380
|
+
Value sum = 0;
|
|
1381
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1382
|
+
sum += nodeValue(n);
|
|
1383
|
+
}
|
|
1384
|
+
return sum;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
/// \brief Return the dual value (potential) of the given node.
|
|
1388
|
+
///
|
|
1389
|
+
/// This function returns the dual value (potential) of the given node.
|
|
1390
|
+
///
|
|
1391
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
1392
|
+
Value nodeValue(const Node& n) const {
|
|
1393
|
+
return (*_node_potential)[n];
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
/// @}
|
|
1397
|
+
|
|
1398
|
+
};
|
|
1399
|
+
|
|
1400
|
+
/// \ingroup matching
|
|
1401
|
+
///
|
|
1402
|
+
/// \brief Weighted fractional perfect matching in general graphs
|
|
1403
|
+
///
|
|
1404
|
+
/// This class provides an efficient implementation of fractional
|
|
1405
|
+
/// matching algorithm. The implementation uses priority queues and
|
|
1406
|
+
/// provides \f$O(nm\log n)\f$ time complexity.
|
|
1407
|
+
///
|
|
1408
|
+
/// The maximum weighted fractional perfect matching is a relaxation
|
|
1409
|
+
/// of the maximum weighted perfect matching problem where the odd
|
|
1410
|
+
/// set constraints are omitted.
|
|
1411
|
+
/// It can be formulated with the following linear program.
|
|
1412
|
+
/// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f]
|
|
1413
|
+
/// \f[x_e \ge 0\quad \forall e\in E\f]
|
|
1414
|
+
/// \f[\max \sum_{e\in E}x_ew_e\f]
|
|
1415
|
+
/// where \f$\delta(X)\f$ is the set of edges incident to a node in
|
|
1416
|
+
/// \f$X\f$. The result must be the union of a matching with one
|
|
1417
|
+
/// value edges and a set of odd length cycles with half value edges.
|
|
1418
|
+
///
|
|
1419
|
+
/// The algorithm calculates an optimal fractional matching and a
|
|
1420
|
+
/// proof of the optimality. The solution of the dual problem can be
|
|
1421
|
+
/// used to check the result of the algorithm. The dual linear
|
|
1422
|
+
/// problem is the following.
|
|
1423
|
+
/// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
|
|
1424
|
+
/// \f[\min \sum_{u \in V}y_u \f]
|
|
1425
|
+
///
|
|
1426
|
+
/// The algorithm can be executed with the run() function.
|
|
1427
|
+
/// After it the matching (the primal solution) and the dual solution
|
|
1428
|
+
/// can be obtained using the query functions.
|
|
1429
|
+
///
|
|
1430
|
+
/// The primal solution is multiplied by
|
|
1431
|
+
/// \ref MaxWeightedPerfectFractionalMatching::primalScale "2".
|
|
1432
|
+
/// If the value type is integer, then the dual
|
|
1433
|
+
/// solution is scaled by
|
|
1434
|
+
/// \ref MaxWeightedPerfectFractionalMatching::dualScale "4".
|
|
1435
|
+
///
|
|
1436
|
+
/// \tparam GR The undirected graph type the algorithm runs on.
|
|
1437
|
+
/// \tparam WM The type edge weight map. The default type is
|
|
1438
|
+
/// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>".
|
|
1439
|
+
#ifdef DOXYGEN
|
|
1440
|
+
template <typename GR, typename WM>
|
|
1441
|
+
#else
|
|
1442
|
+
template <typename GR,
|
|
1443
|
+
typename WM = typename GR::template EdgeMap<int> >
|
|
1444
|
+
#endif
|
|
1445
|
+
class MaxWeightedPerfectFractionalMatching {
|
|
1446
|
+
public:
|
|
1447
|
+
|
|
1448
|
+
/// The graph type of the algorithm
|
|
1449
|
+
typedef GR Graph;
|
|
1450
|
+
/// The type of the edge weight map
|
|
1451
|
+
typedef WM WeightMap;
|
|
1452
|
+
/// The value type of the edge weights
|
|
1453
|
+
typedef typename WeightMap::Value Value;
|
|
1454
|
+
|
|
1455
|
+
/// The type of the matching map
|
|
1456
|
+
typedef typename Graph::template NodeMap<typename Graph::Arc>
|
|
1457
|
+
MatchingMap;
|
|
1458
|
+
|
|
1459
|
+
/// \brief Scaling factor for primal solution
|
|
1460
|
+
///
|
|
1461
|
+
/// Scaling factor for primal solution.
|
|
1462
|
+
static const int primalScale = 2;
|
|
1463
|
+
|
|
1464
|
+
/// \brief Scaling factor for dual solution
|
|
1465
|
+
///
|
|
1466
|
+
/// Scaling factor for dual solution. It is equal to 4 or 1
|
|
1467
|
+
/// according to the value type.
|
|
1468
|
+
static const int dualScale =
|
|
1469
|
+
std::numeric_limits<Value>::is_integer ? 4 : 1;
|
|
1470
|
+
|
|
1471
|
+
private:
|
|
1472
|
+
|
|
1473
|
+
TEMPLATE_GRAPH_TYPEDEFS(Graph);
|
|
1474
|
+
|
|
1475
|
+
typedef typename Graph::template NodeMap<Value> NodePotential;
|
|
1476
|
+
|
|
1477
|
+
const Graph& _graph;
|
|
1478
|
+
const WeightMap& _weight;
|
|
1479
|
+
|
|
1480
|
+
MatchingMap* _matching;
|
|
1481
|
+
NodePotential* _node_potential;
|
|
1482
|
+
|
|
1483
|
+
int _node_num;
|
|
1484
|
+
bool _allow_loops;
|
|
1485
|
+
|
|
1486
|
+
enum Status {
|
|
1487
|
+
EVEN = -1, MATCHED = 0, ODD = 1
|
|
1488
|
+
};
|
|
1489
|
+
|
|
1490
|
+
typedef typename Graph::template NodeMap<Status> StatusMap;
|
|
1491
|
+
StatusMap* _status;
|
|
1492
|
+
|
|
1493
|
+
typedef typename Graph::template NodeMap<Arc> PredMap;
|
|
1494
|
+
PredMap* _pred;
|
|
1495
|
+
|
|
1496
|
+
typedef ExtendFindEnum<IntNodeMap> TreeSet;
|
|
1497
|
+
|
|
1498
|
+
IntNodeMap *_tree_set_index;
|
|
1499
|
+
TreeSet *_tree_set;
|
|
1500
|
+
|
|
1501
|
+
IntNodeMap *_delta2_index;
|
|
1502
|
+
BinHeap<Value, IntNodeMap> *_delta2;
|
|
1503
|
+
|
|
1504
|
+
IntEdgeMap *_delta3_index;
|
|
1505
|
+
BinHeap<Value, IntEdgeMap> *_delta3;
|
|
1506
|
+
|
|
1507
|
+
Value _delta_sum;
|
|
1508
|
+
|
|
1509
|
+
void createStructures() {
|
|
1510
|
+
_node_num = countNodes(_graph);
|
|
1511
|
+
|
|
1512
|
+
if (!_matching) {
|
|
1513
|
+
_matching = new MatchingMap(_graph);
|
|
1514
|
+
}
|
|
1515
|
+
if (!_node_potential) {
|
|
1516
|
+
_node_potential = new NodePotential(_graph);
|
|
1517
|
+
}
|
|
1518
|
+
if (!_status) {
|
|
1519
|
+
_status = new StatusMap(_graph);
|
|
1520
|
+
}
|
|
1521
|
+
if (!_pred) {
|
|
1522
|
+
_pred = new PredMap(_graph);
|
|
1523
|
+
}
|
|
1524
|
+
if (!_tree_set) {
|
|
1525
|
+
_tree_set_index = new IntNodeMap(_graph);
|
|
1526
|
+
_tree_set = new TreeSet(*_tree_set_index);
|
|
1527
|
+
}
|
|
1528
|
+
if (!_delta2) {
|
|
1529
|
+
_delta2_index = new IntNodeMap(_graph);
|
|
1530
|
+
_delta2 = new BinHeap<Value, IntNodeMap>(*_delta2_index);
|
|
1531
|
+
}
|
|
1532
|
+
if (!_delta3) {
|
|
1533
|
+
_delta3_index = new IntEdgeMap(_graph);
|
|
1534
|
+
_delta3 = new BinHeap<Value, IntEdgeMap>(*_delta3_index);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
void destroyStructures() {
|
|
1539
|
+
if (_matching) {
|
|
1540
|
+
delete _matching;
|
|
1541
|
+
}
|
|
1542
|
+
if (_node_potential) {
|
|
1543
|
+
delete _node_potential;
|
|
1544
|
+
}
|
|
1545
|
+
if (_status) {
|
|
1546
|
+
delete _status;
|
|
1547
|
+
}
|
|
1548
|
+
if (_pred) {
|
|
1549
|
+
delete _pred;
|
|
1550
|
+
}
|
|
1551
|
+
if (_tree_set) {
|
|
1552
|
+
delete _tree_set_index;
|
|
1553
|
+
delete _tree_set;
|
|
1554
|
+
}
|
|
1555
|
+
if (_delta2) {
|
|
1556
|
+
delete _delta2_index;
|
|
1557
|
+
delete _delta2;
|
|
1558
|
+
}
|
|
1559
|
+
if (_delta3) {
|
|
1560
|
+
delete _delta3_index;
|
|
1561
|
+
delete _delta3;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
void matchedToEven(Node node, int tree) {
|
|
1566
|
+
_tree_set->insert(node, tree);
|
|
1567
|
+
_node_potential->set(node, (*_node_potential)[node] + _delta_sum);
|
|
1568
|
+
|
|
1569
|
+
if (_delta2->state(node) == _delta2->IN_HEAP) {
|
|
1570
|
+
_delta2->erase(node);
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
for (InArcIt a(_graph, node); a != INVALID; ++a) {
|
|
1574
|
+
Node v = _graph.source(a);
|
|
1575
|
+
Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
|
|
1576
|
+
dualScale * _weight[a];
|
|
1577
|
+
if (node == v) {
|
|
1578
|
+
if (_allow_loops && _graph.direction(a)) {
|
|
1579
|
+
_delta3->push(a, rw / 2);
|
|
1580
|
+
}
|
|
1581
|
+
} else if ((*_status)[v] == EVEN) {
|
|
1582
|
+
_delta3->push(a, rw / 2);
|
|
1583
|
+
} else if ((*_status)[v] == MATCHED) {
|
|
1584
|
+
if (_delta2->state(v) != _delta2->IN_HEAP) {
|
|
1585
|
+
_pred->set(v, a);
|
|
1586
|
+
_delta2->push(v, rw);
|
|
1587
|
+
} else if ((*_delta2)[v] > rw) {
|
|
1588
|
+
_pred->set(v, a);
|
|
1589
|
+
_delta2->decrease(v, rw);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
void matchedToOdd(Node node, int tree) {
|
|
1596
|
+
_tree_set->insert(node, tree);
|
|
1597
|
+
_node_potential->set(node, (*_node_potential)[node] - _delta_sum);
|
|
1598
|
+
|
|
1599
|
+
if (_delta2->state(node) == _delta2->IN_HEAP) {
|
|
1600
|
+
_delta2->erase(node);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
void evenToMatched(Node node, int tree) {
|
|
1605
|
+
_node_potential->set(node, (*_node_potential)[node] - _delta_sum);
|
|
1606
|
+
Arc min = INVALID;
|
|
1607
|
+
Value minrw = std::numeric_limits<Value>::max();
|
|
1608
|
+
for (InArcIt a(_graph, node); a != INVALID; ++a) {
|
|
1609
|
+
Node v = _graph.source(a);
|
|
1610
|
+
Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
|
|
1611
|
+
dualScale * _weight[a];
|
|
1612
|
+
|
|
1613
|
+
if (node == v) {
|
|
1614
|
+
if (_allow_loops && _graph.direction(a)) {
|
|
1615
|
+
_delta3->erase(a);
|
|
1616
|
+
}
|
|
1617
|
+
} else if ((*_status)[v] == EVEN) {
|
|
1618
|
+
_delta3->erase(a);
|
|
1619
|
+
if (minrw > rw) {
|
|
1620
|
+
min = _graph.oppositeArc(a);
|
|
1621
|
+
minrw = rw;
|
|
1622
|
+
}
|
|
1623
|
+
} else if ((*_status)[v] == MATCHED) {
|
|
1624
|
+
if ((*_pred)[v] == a) {
|
|
1625
|
+
Arc mina = INVALID;
|
|
1626
|
+
Value minrwa = std::numeric_limits<Value>::max();
|
|
1627
|
+
for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) {
|
|
1628
|
+
Node va = _graph.target(aa);
|
|
1629
|
+
if ((*_status)[va] != EVEN ||
|
|
1630
|
+
_tree_set->find(va) == tree) continue;
|
|
1631
|
+
Value rwa = (*_node_potential)[v] + (*_node_potential)[va] -
|
|
1632
|
+
dualScale * _weight[aa];
|
|
1633
|
+
if (minrwa > rwa) {
|
|
1634
|
+
minrwa = rwa;
|
|
1635
|
+
mina = aa;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
if (mina != INVALID) {
|
|
1639
|
+
_pred->set(v, mina);
|
|
1640
|
+
_delta2->increase(v, minrwa);
|
|
1641
|
+
} else {
|
|
1642
|
+
_pred->set(v, INVALID);
|
|
1643
|
+
_delta2->erase(v);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
if (min != INVALID) {
|
|
1649
|
+
_pred->set(node, min);
|
|
1650
|
+
_delta2->push(node, minrw);
|
|
1651
|
+
} else {
|
|
1652
|
+
_pred->set(node, INVALID);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
void oddToMatched(Node node) {
|
|
1657
|
+
_node_potential->set(node, (*_node_potential)[node] + _delta_sum);
|
|
1658
|
+
Arc min = INVALID;
|
|
1659
|
+
Value minrw = std::numeric_limits<Value>::max();
|
|
1660
|
+
for (InArcIt a(_graph, node); a != INVALID; ++a) {
|
|
1661
|
+
Node v = _graph.source(a);
|
|
1662
|
+
if ((*_status)[v] != EVEN) continue;
|
|
1663
|
+
Value rw = (*_node_potential)[node] + (*_node_potential)[v] -
|
|
1664
|
+
dualScale * _weight[a];
|
|
1665
|
+
|
|
1666
|
+
if (minrw > rw) {
|
|
1667
|
+
min = _graph.oppositeArc(a);
|
|
1668
|
+
minrw = rw;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
if (min != INVALID) {
|
|
1672
|
+
_pred->set(node, min);
|
|
1673
|
+
_delta2->push(node, minrw);
|
|
1674
|
+
} else {
|
|
1675
|
+
_pred->set(node, INVALID);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
void alternatePath(Node even, int tree) {
|
|
1680
|
+
Node odd;
|
|
1681
|
+
|
|
1682
|
+
_status->set(even, MATCHED);
|
|
1683
|
+
evenToMatched(even, tree);
|
|
1684
|
+
|
|
1685
|
+
Arc prev = (*_matching)[even];
|
|
1686
|
+
while (prev != INVALID) {
|
|
1687
|
+
odd = _graph.target(prev);
|
|
1688
|
+
even = _graph.target((*_pred)[odd]);
|
|
1689
|
+
_matching->set(odd, (*_pred)[odd]);
|
|
1690
|
+
_status->set(odd, MATCHED);
|
|
1691
|
+
oddToMatched(odd);
|
|
1692
|
+
|
|
1693
|
+
prev = (*_matching)[even];
|
|
1694
|
+
_status->set(even, MATCHED);
|
|
1695
|
+
_matching->set(even, _graph.oppositeArc((*_matching)[odd]));
|
|
1696
|
+
evenToMatched(even, tree);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
void destroyTree(int tree) {
|
|
1701
|
+
for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) {
|
|
1702
|
+
if ((*_status)[n] == EVEN) {
|
|
1703
|
+
_status->set(n, MATCHED);
|
|
1704
|
+
evenToMatched(n, tree);
|
|
1705
|
+
} else if ((*_status)[n] == ODD) {
|
|
1706
|
+
_status->set(n, MATCHED);
|
|
1707
|
+
oddToMatched(n);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
_tree_set->eraseClass(tree);
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
void augmentOnEdge(const Edge& edge) {
|
|
1714
|
+
Node left = _graph.u(edge);
|
|
1715
|
+
int left_tree = _tree_set->find(left);
|
|
1716
|
+
|
|
1717
|
+
alternatePath(left, left_tree);
|
|
1718
|
+
destroyTree(left_tree);
|
|
1719
|
+
_matching->set(left, _graph.direct(edge, true));
|
|
1720
|
+
|
|
1721
|
+
Node right = _graph.v(edge);
|
|
1722
|
+
int right_tree = _tree_set->find(right);
|
|
1723
|
+
|
|
1724
|
+
alternatePath(right, right_tree);
|
|
1725
|
+
destroyTree(right_tree);
|
|
1726
|
+
_matching->set(right, _graph.direct(edge, false));
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
void augmentOnArc(const Arc& arc) {
|
|
1730
|
+
Node left = _graph.source(arc);
|
|
1731
|
+
_status->set(left, MATCHED);
|
|
1732
|
+
_matching->set(left, arc);
|
|
1733
|
+
_pred->set(left, arc);
|
|
1734
|
+
|
|
1735
|
+
Node right = _graph.target(arc);
|
|
1736
|
+
int right_tree = _tree_set->find(right);
|
|
1737
|
+
|
|
1738
|
+
alternatePath(right, right_tree);
|
|
1739
|
+
destroyTree(right_tree);
|
|
1740
|
+
_matching->set(right, _graph.oppositeArc(arc));
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
void extendOnArc(const Arc& arc) {
|
|
1744
|
+
Node base = _graph.target(arc);
|
|
1745
|
+
int tree = _tree_set->find(base);
|
|
1746
|
+
|
|
1747
|
+
Node odd = _graph.source(arc);
|
|
1748
|
+
_tree_set->insert(odd, tree);
|
|
1749
|
+
_status->set(odd, ODD);
|
|
1750
|
+
matchedToOdd(odd, tree);
|
|
1751
|
+
_pred->set(odd, arc);
|
|
1752
|
+
|
|
1753
|
+
Node even = _graph.target((*_matching)[odd]);
|
|
1754
|
+
_tree_set->insert(even, tree);
|
|
1755
|
+
_status->set(even, EVEN);
|
|
1756
|
+
matchedToEven(even, tree);
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
void cycleOnEdge(const Edge& edge, int tree) {
|
|
1760
|
+
Node nca = INVALID;
|
|
1761
|
+
std::vector<Node> left_path, right_path;
|
|
1762
|
+
|
|
1763
|
+
{
|
|
1764
|
+
std::set<Node> left_set, right_set;
|
|
1765
|
+
Node left = _graph.u(edge);
|
|
1766
|
+
left_path.push_back(left);
|
|
1767
|
+
left_set.insert(left);
|
|
1768
|
+
|
|
1769
|
+
Node right = _graph.v(edge);
|
|
1770
|
+
right_path.push_back(right);
|
|
1771
|
+
right_set.insert(right);
|
|
1772
|
+
|
|
1773
|
+
while (true) {
|
|
1774
|
+
|
|
1775
|
+
if (left_set.find(right) != left_set.end()) {
|
|
1776
|
+
nca = right;
|
|
1777
|
+
break;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
if ((*_matching)[left] == INVALID) break;
|
|
1781
|
+
|
|
1782
|
+
left = _graph.target((*_matching)[left]);
|
|
1783
|
+
left_path.push_back(left);
|
|
1784
|
+
left = _graph.target((*_pred)[left]);
|
|
1785
|
+
left_path.push_back(left);
|
|
1786
|
+
|
|
1787
|
+
left_set.insert(left);
|
|
1788
|
+
|
|
1789
|
+
if (right_set.find(left) != right_set.end()) {
|
|
1790
|
+
nca = left;
|
|
1791
|
+
break;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
if ((*_matching)[right] == INVALID) break;
|
|
1795
|
+
|
|
1796
|
+
right = _graph.target((*_matching)[right]);
|
|
1797
|
+
right_path.push_back(right);
|
|
1798
|
+
right = _graph.target((*_pred)[right]);
|
|
1799
|
+
right_path.push_back(right);
|
|
1800
|
+
|
|
1801
|
+
right_set.insert(right);
|
|
1802
|
+
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
if (nca == INVALID) {
|
|
1806
|
+
if ((*_matching)[left] == INVALID) {
|
|
1807
|
+
nca = right;
|
|
1808
|
+
while (left_set.find(nca) == left_set.end()) {
|
|
1809
|
+
nca = _graph.target((*_matching)[nca]);
|
|
1810
|
+
right_path.push_back(nca);
|
|
1811
|
+
nca = _graph.target((*_pred)[nca]);
|
|
1812
|
+
right_path.push_back(nca);
|
|
1813
|
+
}
|
|
1814
|
+
} else {
|
|
1815
|
+
nca = left;
|
|
1816
|
+
while (right_set.find(nca) == right_set.end()) {
|
|
1817
|
+
nca = _graph.target((*_matching)[nca]);
|
|
1818
|
+
left_path.push_back(nca);
|
|
1819
|
+
nca = _graph.target((*_pred)[nca]);
|
|
1820
|
+
left_path.push_back(nca);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
alternatePath(nca, tree);
|
|
1827
|
+
Arc prev;
|
|
1828
|
+
|
|
1829
|
+
prev = _graph.direct(edge, true);
|
|
1830
|
+
for (int i = 0; left_path[i] != nca; i += 2) {
|
|
1831
|
+
_matching->set(left_path[i], prev);
|
|
1832
|
+
_status->set(left_path[i], MATCHED);
|
|
1833
|
+
evenToMatched(left_path[i], tree);
|
|
1834
|
+
|
|
1835
|
+
prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]);
|
|
1836
|
+
_status->set(left_path[i + 1], MATCHED);
|
|
1837
|
+
oddToMatched(left_path[i + 1]);
|
|
1838
|
+
}
|
|
1839
|
+
_matching->set(nca, prev);
|
|
1840
|
+
|
|
1841
|
+
for (int i = 0; right_path[i] != nca; i += 2) {
|
|
1842
|
+
_status->set(right_path[i], MATCHED);
|
|
1843
|
+
evenToMatched(right_path[i], tree);
|
|
1844
|
+
|
|
1845
|
+
_matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]);
|
|
1846
|
+
_status->set(right_path[i + 1], MATCHED);
|
|
1847
|
+
oddToMatched(right_path[i + 1]);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
destroyTree(tree);
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
void extractCycle(const Arc &arc) {
|
|
1854
|
+
Node left = _graph.source(arc);
|
|
1855
|
+
Node odd = _graph.target((*_matching)[left]);
|
|
1856
|
+
Arc prev;
|
|
1857
|
+
while (odd != left) {
|
|
1858
|
+
Node even = _graph.target((*_matching)[odd]);
|
|
1859
|
+
prev = (*_matching)[odd];
|
|
1860
|
+
odd = _graph.target((*_matching)[even]);
|
|
1861
|
+
_matching->set(even, _graph.oppositeArc(prev));
|
|
1862
|
+
}
|
|
1863
|
+
_matching->set(left, arc);
|
|
1864
|
+
|
|
1865
|
+
Node right = _graph.target(arc);
|
|
1866
|
+
int right_tree = _tree_set->find(right);
|
|
1867
|
+
alternatePath(right, right_tree);
|
|
1868
|
+
destroyTree(right_tree);
|
|
1869
|
+
_matching->set(right, _graph.oppositeArc(arc));
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
public:
|
|
1873
|
+
|
|
1874
|
+
/// \brief Constructor
|
|
1875
|
+
///
|
|
1876
|
+
/// Constructor.
|
|
1877
|
+
MaxWeightedPerfectFractionalMatching(const Graph& graph,
|
|
1878
|
+
const WeightMap& weight,
|
|
1879
|
+
bool allow_loops = true)
|
|
1880
|
+
: _graph(graph), _weight(weight), _matching(0),
|
|
1881
|
+
_node_potential(0), _node_num(0), _allow_loops(allow_loops),
|
|
1882
|
+
_status(0), _pred(0),
|
|
1883
|
+
_tree_set_index(0), _tree_set(0),
|
|
1884
|
+
|
|
1885
|
+
_delta2_index(0), _delta2(0),
|
|
1886
|
+
_delta3_index(0), _delta3(0),
|
|
1887
|
+
|
|
1888
|
+
_delta_sum() {}
|
|
1889
|
+
|
|
1890
|
+
~MaxWeightedPerfectFractionalMatching() {
|
|
1891
|
+
destroyStructures();
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
/// \name Execution Control
|
|
1895
|
+
/// The simplest way to execute the algorithm is to use the
|
|
1896
|
+
/// \ref run() member function.
|
|
1897
|
+
|
|
1898
|
+
///@{
|
|
1899
|
+
|
|
1900
|
+
/// \brief Initialize the algorithm
|
|
1901
|
+
///
|
|
1902
|
+
/// This function initializes the algorithm.
|
|
1903
|
+
void init() {
|
|
1904
|
+
createStructures();
|
|
1905
|
+
|
|
1906
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1907
|
+
(*_delta2_index)[n] = _delta2->PRE_HEAP;
|
|
1908
|
+
}
|
|
1909
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1910
|
+
(*_delta3_index)[e] = _delta3->PRE_HEAP;
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
_delta2->clear();
|
|
1914
|
+
_delta3->clear();
|
|
1915
|
+
_tree_set->clear();
|
|
1916
|
+
|
|
1917
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
1918
|
+
Value max = - std::numeric_limits<Value>::max();
|
|
1919
|
+
for (OutArcIt e(_graph, n); e != INVALID; ++e) {
|
|
1920
|
+
if (_graph.target(e) == n && !_allow_loops) continue;
|
|
1921
|
+
if ((dualScale * _weight[e]) / 2 > max) {
|
|
1922
|
+
max = (dualScale * _weight[e]) / 2;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
_node_potential->set(n, max);
|
|
1926
|
+
|
|
1927
|
+
_tree_set->insert(n);
|
|
1928
|
+
|
|
1929
|
+
_matching->set(n, INVALID);
|
|
1930
|
+
_status->set(n, EVEN);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
for (EdgeIt e(_graph); e != INVALID; ++e) {
|
|
1934
|
+
Node left = _graph.u(e);
|
|
1935
|
+
Node right = _graph.v(e);
|
|
1936
|
+
if (left == right && !_allow_loops) continue;
|
|
1937
|
+
_delta3->push(e, ((*_node_potential)[left] +
|
|
1938
|
+
(*_node_potential)[right] -
|
|
1939
|
+
dualScale * _weight[e]) / 2);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
/// \brief Start the algorithm
|
|
1944
|
+
///
|
|
1945
|
+
/// This function starts the algorithm.
|
|
1946
|
+
///
|
|
1947
|
+
/// \pre \ref init() must be called before using this function.
|
|
1948
|
+
bool start() {
|
|
1949
|
+
enum OpType {
|
|
1950
|
+
D2, D3
|
|
1951
|
+
};
|
|
1952
|
+
|
|
1953
|
+
int unmatched = _node_num;
|
|
1954
|
+
while (unmatched > 0) {
|
|
1955
|
+
Value d2 = !_delta2->empty() ?
|
|
1956
|
+
_delta2->prio() : std::numeric_limits<Value>::max();
|
|
1957
|
+
|
|
1958
|
+
Value d3 = !_delta3->empty() ?
|
|
1959
|
+
_delta3->prio() : std::numeric_limits<Value>::max();
|
|
1960
|
+
|
|
1961
|
+
_delta_sum = d3; OpType ot = D3;
|
|
1962
|
+
if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; }
|
|
1963
|
+
|
|
1964
|
+
if (_delta_sum == std::numeric_limits<Value>::max()) {
|
|
1965
|
+
return false;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
switch (ot) {
|
|
1969
|
+
case D2:
|
|
1970
|
+
{
|
|
1971
|
+
Node n = _delta2->top();
|
|
1972
|
+
Arc a = (*_pred)[n];
|
|
1973
|
+
if ((*_matching)[n] == INVALID) {
|
|
1974
|
+
augmentOnArc(a);
|
|
1975
|
+
--unmatched;
|
|
1976
|
+
} else {
|
|
1977
|
+
Node v = _graph.target((*_matching)[n]);
|
|
1978
|
+
if ((*_matching)[n] !=
|
|
1979
|
+
_graph.oppositeArc((*_matching)[v])) {
|
|
1980
|
+
extractCycle(a);
|
|
1981
|
+
--unmatched;
|
|
1982
|
+
} else {
|
|
1983
|
+
extendOnArc(a);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
} break;
|
|
1987
|
+
case D3:
|
|
1988
|
+
{
|
|
1989
|
+
Edge e = _delta3->top();
|
|
1990
|
+
|
|
1991
|
+
Node left = _graph.u(e);
|
|
1992
|
+
Node right = _graph.v(e);
|
|
1993
|
+
|
|
1994
|
+
int left_tree = _tree_set->find(left);
|
|
1995
|
+
int right_tree = _tree_set->find(right);
|
|
1996
|
+
|
|
1997
|
+
if (left_tree == right_tree) {
|
|
1998
|
+
cycleOnEdge(e, left_tree);
|
|
1999
|
+
--unmatched;
|
|
2000
|
+
} else {
|
|
2001
|
+
augmentOnEdge(e);
|
|
2002
|
+
unmatched -= 2;
|
|
2003
|
+
}
|
|
2004
|
+
} break;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
return true;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
/// \brief Run the algorithm.
|
|
2011
|
+
///
|
|
2012
|
+
/// This method runs the \c %MaxWeightedPerfectFractionalMatching
|
|
2013
|
+
/// algorithm.
|
|
2014
|
+
///
|
|
2015
|
+
/// \note mwfm.run() is just a shortcut of the following code.
|
|
2016
|
+
/// \code
|
|
2017
|
+
/// mwpfm.init();
|
|
2018
|
+
/// mwpfm.start();
|
|
2019
|
+
/// \endcode
|
|
2020
|
+
bool run() {
|
|
2021
|
+
init();
|
|
2022
|
+
return start();
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
/// @}
|
|
2026
|
+
|
|
2027
|
+
/// \name Primal Solution
|
|
2028
|
+
/// Functions to get the primal solution, i.e. the maximum weighted
|
|
2029
|
+
/// matching.\n
|
|
2030
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
2031
|
+
/// using them.
|
|
2032
|
+
|
|
2033
|
+
/// @{
|
|
2034
|
+
|
|
2035
|
+
/// \brief Return the weight of the matching.
|
|
2036
|
+
///
|
|
2037
|
+
/// This function returns the weight of the found matching. This
|
|
2038
|
+
/// value is scaled by \ref primalScale "primal scale".
|
|
2039
|
+
///
|
|
2040
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2041
|
+
Value matchingWeight() const {
|
|
2042
|
+
Value sum = 0;
|
|
2043
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
2044
|
+
if ((*_matching)[n] != INVALID) {
|
|
2045
|
+
sum += _weight[(*_matching)[n]];
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
return sum * primalScale / 2;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
/// \brief Return the number of covered nodes in the matching.
|
|
2052
|
+
///
|
|
2053
|
+
/// This function returns the number of covered nodes in the matching.
|
|
2054
|
+
///
|
|
2055
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2056
|
+
int matchingSize() const {
|
|
2057
|
+
int num = 0;
|
|
2058
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
2059
|
+
if ((*_matching)[n] != INVALID) {
|
|
2060
|
+
++num;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
return num;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
/// \brief Return \c true if the given edge is in the matching.
|
|
2067
|
+
///
|
|
2068
|
+
/// This function returns \c true if the given edge is in the
|
|
2069
|
+
/// found matching. The result is scaled by \ref primalScale
|
|
2070
|
+
/// "primal scale".
|
|
2071
|
+
///
|
|
2072
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2073
|
+
int matching(const Edge& edge) const {
|
|
2074
|
+
return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0)
|
|
2075
|
+
+ (edge == (*_matching)[_graph.v(edge)] ? 1 : 0);
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
/// \brief Return the fractional matching arc (or edge) incident
|
|
2079
|
+
/// to the given node.
|
|
2080
|
+
///
|
|
2081
|
+
/// This function returns one of the fractional matching arc (or
|
|
2082
|
+
/// edge) incident to the given node in the found matching or \c
|
|
2083
|
+
/// INVALID if the node is not covered by the matching or if the
|
|
2084
|
+
/// node is on an odd length cycle then it is the successor edge
|
|
2085
|
+
/// on the cycle.
|
|
2086
|
+
///
|
|
2087
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2088
|
+
Arc matching(const Node& node) const {
|
|
2089
|
+
return (*_matching)[node];
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
/// \brief Return a const reference to the matching map.
|
|
2093
|
+
///
|
|
2094
|
+
/// This function returns a const reference to a node map that stores
|
|
2095
|
+
/// the matching arc (or edge) incident to each node.
|
|
2096
|
+
const MatchingMap& matchingMap() const {
|
|
2097
|
+
return *_matching;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/// @}
|
|
2101
|
+
|
|
2102
|
+
/// \name Dual Solution
|
|
2103
|
+
/// Functions to get the dual solution.\n
|
|
2104
|
+
/// Either \ref run() or \ref start() function should be called before
|
|
2105
|
+
/// using them.
|
|
2106
|
+
|
|
2107
|
+
/// @{
|
|
2108
|
+
|
|
2109
|
+
/// \brief Return the value of the dual solution.
|
|
2110
|
+
///
|
|
2111
|
+
/// This function returns the value of the dual solution.
|
|
2112
|
+
/// It should be equal to the primal value scaled by \ref dualScale
|
|
2113
|
+
/// "dual scale".
|
|
2114
|
+
///
|
|
2115
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2116
|
+
Value dualValue() const {
|
|
2117
|
+
Value sum = 0;
|
|
2118
|
+
for (NodeIt n(_graph); n != INVALID; ++n) {
|
|
2119
|
+
sum += nodeValue(n);
|
|
2120
|
+
}
|
|
2121
|
+
return sum;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
/// \brief Return the dual value (potential) of the given node.
|
|
2125
|
+
///
|
|
2126
|
+
/// This function returns the dual value (potential) of the given node.
|
|
2127
|
+
///
|
|
2128
|
+
/// \pre Either run() or start() must be called before using this function.
|
|
2129
|
+
Value nodeValue(const Node& n) const {
|
|
2130
|
+
return (*_node_potential)[n];
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
/// @}
|
|
2134
|
+
|
|
2135
|
+
};
|
|
2136
|
+
|
|
2137
|
+
} //END OF NAMESPACE LEMON
|
|
2138
|
+
|
|
2139
|
+
#endif //LEMON_FRACTIONAL_MATCHING_H
|