0
2
0
| ... | ... |
@@ -649,28 +649,29 @@ |
| 649 | 649 |
/// The algorithm calculates an optimal fractional matching and a |
| 650 | 650 |
/// proof of the optimality. The solution of the dual problem can be |
| 651 | 651 |
/// used to check the result of the algorithm. The dual linear |
| 652 | 652 |
/// problem is the following. |
| 653 | 653 |
/// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
|
| 654 | 654 |
/// \f[y_u \ge 0 \quad \forall u \in V\f] |
| 655 | 655 |
/// \f[\min \sum_{u \in V}y_u \f]
|
| 656 | 656 |
/// |
| 657 | 657 |
/// The algorithm can be executed with the run() function. |
| 658 | 658 |
/// After it the matching (the primal solution) and the dual solution |
| 659 | 659 |
/// can be obtained using the query functions. |
| 660 | 660 |
/// |
| 661 |
/// If the value type is integer, then the primal and the dual |
|
| 662 |
/// solutions are multiplied by |
|
| 663 |
/// \ref MaxWeightedFractionalMatching::primalScale "2" and |
|
| 664 |
/// \ref MaxWeightedFractionalMatching::dualScale "4" respectively. |
|
| 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". |
|
| 665 | 666 |
/// |
| 666 | 667 |
/// \tparam GR The undirected graph type the algorithm runs on. |
| 667 | 668 |
/// \tparam WM The type edge weight map. The default type is |
| 668 | 669 |
/// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>". |
| 669 | 670 |
#ifdef DOXYGEN |
| 670 | 671 |
template <typename GR, typename WM> |
| 671 | 672 |
#else |
| 672 | 673 |
template <typename GR, |
| 673 | 674 |
typename WM = typename GR::template EdgeMap<int> > |
| 674 | 675 |
#endif |
| 675 | 676 |
class MaxWeightedFractionalMatching {
|
| 676 | 677 |
public: |
| ... | ... |
@@ -679,28 +680,26 @@ |
| 679 | 680 |
typedef GR Graph; |
| 680 | 681 |
/// The type of the edge weight map |
| 681 | 682 |
typedef WM WeightMap; |
| 682 | 683 |
/// The value type of the edge weights |
| 683 | 684 |
typedef typename WeightMap::Value Value; |
| 684 | 685 |
|
| 685 | 686 |
/// The type of the matching map |
| 686 | 687 |
typedef typename Graph::template NodeMap<typename Graph::Arc> |
| 687 | 688 |
MatchingMap; |
| 688 | 689 |
|
| 689 | 690 |
/// \brief Scaling factor for primal solution |
| 690 | 691 |
/// |
| 691 |
/// Scaling factor for primal solution. It is equal to 2 or 1 |
|
| 692 |
/// according to the value type. |
|
| 693 |
static const int primalScale = |
|
| 694 |
std::numeric_limits<Value>::is_integer ? 2 : 1; |
|
| 692 |
/// Scaling factor for primal solution. |
|
| 693 |
static const int primalScale = 2; |
|
| 695 | 694 |
|
| 696 | 695 |
/// \brief Scaling factor for dual solution |
| 697 | 696 |
/// |
| 698 | 697 |
/// Scaling factor for dual solution. It is equal to 4 or 1 |
| 699 | 698 |
/// according to the value type. |
| 700 | 699 |
static const int dualScale = |
| 701 | 700 |
std::numeric_limits<Value>::is_integer ? 4 : 1; |
| 702 | 701 |
|
| 703 | 702 |
private: |
| 704 | 703 |
|
| 705 | 704 |
TEMPLATE_GRAPH_TYPEDEFS(Graph); |
| 706 | 705 |
|
| ... | ... |
@@ -1320,28 +1319,27 @@ |
| 1320 | 1319 |
} |
| 1321 | 1320 |
} |
| 1322 | 1321 |
return num; |
| 1323 | 1322 |
} |
| 1324 | 1323 |
|
| 1325 | 1324 |
/// \brief Return \c true if the given edge is in the matching. |
| 1326 | 1325 |
/// |
| 1327 | 1326 |
/// This function returns \c true if the given edge is in the |
| 1328 | 1327 |
/// found matching. The result is scaled by \ref primalScale |
| 1329 | 1328 |
/// "primal scale". |
| 1330 | 1329 |
/// |
| 1331 | 1330 |
/// \pre Either run() or start() must be called before using this function. |
| 1332 |
Value matching(const Edge& edge) const {
|
|
| 1333 |
return Value(edge == (*_matching)[_graph.u(edge)] ? 1 : 0) |
|
| 1334 |
* primalScale / 2 + Value(edge == (*_matching)[_graph.v(edge)] ? 1 : 0) |
|
| 1335 |
* primalScale / 2; |
|
| 1331 |
int matching(const Edge& edge) const {
|
|
| 1332 |
return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) |
|
| 1333 |
+ (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); |
|
| 1336 | 1334 |
} |
| 1337 | 1335 |
|
| 1338 | 1336 |
/// \brief Return the fractional matching arc (or edge) incident |
| 1339 | 1337 |
/// to the given node. |
| 1340 | 1338 |
/// |
| 1341 | 1339 |
/// This function returns one of the fractional matching arc (or |
| 1342 | 1340 |
/// edge) incident to the given node in the found matching or \c |
| 1343 | 1341 |
/// INVALID if the node is not covered by the matching or if the |
| 1344 | 1342 |
/// node is on an odd length cycle then it is the successor edge |
| 1345 | 1343 |
/// on the cycle. |
| 1346 | 1344 |
/// |
| 1347 | 1345 |
/// \pre Either run() or start() must be called before using this function. |
| ... | ... |
@@ -1414,29 +1412,30 @@ |
| 1414 | 1412 |
/// value edges and a set of odd length cycles with half value edges. |
| 1415 | 1413 |
/// |
| 1416 | 1414 |
/// The algorithm calculates an optimal fractional matching and a |
| 1417 | 1415 |
/// proof of the optimality. The solution of the dual problem can be |
| 1418 | 1416 |
/// used to check the result of the algorithm. The dual linear |
| 1419 | 1417 |
/// problem is the following. |
| 1420 | 1418 |
/// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f]
|
| 1421 | 1419 |
/// \f[\min \sum_{u \in V}y_u \f]
|
| 1422 | 1420 |
/// |
| 1423 | 1421 |
/// The algorithm can be executed with the run() function. |
| 1424 | 1422 |
/// After it the matching (the primal solution) and the dual solution |
| 1425 | 1423 |
/// can be obtained using the query functions. |
| 1426 |
|
|
| 1427 |
/// If the value type is integer, then the primal and the dual |
|
| 1428 |
/// solutions are multiplied by |
|
| 1429 |
/// \ref MaxWeightedPerfectFractionalMatching::primalScale "2" and |
|
| 1430 |
/// |
|
| 1424 |
/// |
|
| 1425 |
/// The primal solution is multiplied by |
|
| 1426 |
/// \ref MaxWeightedPerfectFractionalMatching::primalScale "2". |
|
| 1427 |
/// If the value type is integer, then the dual |
|
| 1428 |
/// solution is scaled by |
|
| 1429 |
/// \ref MaxWeightedPerfectFractionalMatching::dualScale "4". |
|
| 1431 | 1430 |
/// |
| 1432 | 1431 |
/// \tparam GR The undirected graph type the algorithm runs on. |
| 1433 | 1432 |
/// \tparam WM The type edge weight map. The default type is |
| 1434 | 1433 |
/// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>". |
| 1435 | 1434 |
#ifdef DOXYGEN |
| 1436 | 1435 |
template <typename GR, typename WM> |
| 1437 | 1436 |
#else |
| 1438 | 1437 |
template <typename GR, |
| 1439 | 1438 |
typename WM = typename GR::template EdgeMap<int> > |
| 1440 | 1439 |
#endif |
| 1441 | 1440 |
class MaxWeightedPerfectFractionalMatching {
|
| 1442 | 1441 |
public: |
| ... | ... |
@@ -1445,28 +1444,26 @@ |
| 1445 | 1444 |
typedef GR Graph; |
| 1446 | 1445 |
/// The type of the edge weight map |
| 1447 | 1446 |
typedef WM WeightMap; |
| 1448 | 1447 |
/// The value type of the edge weights |
| 1449 | 1448 |
typedef typename WeightMap::Value Value; |
| 1450 | 1449 |
|
| 1451 | 1450 |
/// The type of the matching map |
| 1452 | 1451 |
typedef typename Graph::template NodeMap<typename Graph::Arc> |
| 1453 | 1452 |
MatchingMap; |
| 1454 | 1453 |
|
| 1455 | 1454 |
/// \brief Scaling factor for primal solution |
| 1456 | 1455 |
/// |
| 1457 |
/// Scaling factor for primal solution. It is equal to 2 or 1 |
|
| 1458 |
/// according to the value type. |
|
| 1459 |
static const int primalScale = |
|
| 1460 |
std::numeric_limits<Value>::is_integer ? 2 : 1; |
|
| 1456 |
/// Scaling factor for primal solution. |
|
| 1457 |
static const int primalScale = 2; |
|
| 1461 | 1458 |
|
| 1462 | 1459 |
/// \brief Scaling factor for dual solution |
| 1463 | 1460 |
/// |
| 1464 | 1461 |
/// Scaling factor for dual solution. It is equal to 4 or 1 |
| 1465 | 1462 |
/// according to the value type. |
| 1466 | 1463 |
static const int dualScale = |
| 1467 | 1464 |
std::numeric_limits<Value>::is_integer ? 4 : 1; |
| 1468 | 1465 |
|
| 1469 | 1466 |
private: |
| 1470 | 1467 |
|
| 1471 | 1468 |
TEMPLATE_GRAPH_TYPEDEFS(Graph); |
| 1472 | 1469 |
|
| ... | ... |
@@ -2055,28 +2052,27 @@ |
| 2055 | 2052 |
} |
| 2056 | 2053 |
} |
| 2057 | 2054 |
return num; |
| 2058 | 2055 |
} |
| 2059 | 2056 |
|
| 2060 | 2057 |
/// \brief Return \c true if the given edge is in the matching. |
| 2061 | 2058 |
/// |
| 2062 | 2059 |
/// This function returns \c true if the given edge is in the |
| 2063 | 2060 |
/// found matching. The result is scaled by \ref primalScale |
| 2064 | 2061 |
/// "primal scale". |
| 2065 | 2062 |
/// |
| 2066 | 2063 |
/// \pre Either run() or start() must be called before using this function. |
| 2067 |
Value matching(const Edge& edge) const {
|
|
| 2068 |
return Value(edge == (*_matching)[_graph.u(edge)] ? 1 : 0) |
|
| 2069 |
* primalScale / 2 + Value(edge == (*_matching)[_graph.v(edge)] ? 1 : 0) |
|
| 2070 |
* primalScale / 2; |
|
| 2064 |
int matching(const Edge& edge) const {
|
|
| 2065 |
return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) |
|
| 2066 |
+ (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); |
|
| 2071 | 2067 |
} |
| 2072 | 2068 |
|
| 2073 | 2069 |
/// \brief Return the fractional matching arc (or edge) incident |
| 2074 | 2070 |
/// to the given node. |
| 2075 | 2071 |
/// |
| 2076 | 2072 |
/// This function returns one of the fractional matching arc (or |
| 2077 | 2073 |
/// edge) incident to the given node in the found matching or \c |
| 2078 | 2074 |
/// INVALID if the node is not covered by the matching or if the |
| 2079 | 2075 |
/// node is on an odd length cycle then it is the successor edge |
| 2080 | 2076 |
/// on the cycle. |
| 2081 | 2077 |
/// |
| 2082 | 2078 |
/// \pre Either run() or start() must be called before using this function. |
| ... | ... |
@@ -227,24 +227,30 @@ |
| 227 | 227 |
++indeg; |
| 228 | 228 |
} |
| 229 | 229 |
} |
| 230 | 230 |
if (mfm.matching(n) != INVALID) {
|
| 231 | 231 |
check(indeg == 1, "Invalid matching"); |
| 232 | 232 |
++pv; |
| 233 | 233 |
} else {
|
| 234 | 234 |
check(indeg == 0, "Invalid matching"); |
| 235 | 235 |
} |
| 236 | 236 |
} |
| 237 | 237 |
check(pv == mfm.matchingSize(), "Wrong matching size"); |
| 238 | 238 |
|
| 239 |
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
|
|
| 240 |
check((e == mfm.matching(graph.u(e)) ? 1 : 0) + |
|
| 241 |
(e == mfm.matching(graph.v(e)) ? 1 : 0) == |
|
| 242 |
mfm.matching(e), "Invalid matching"); |
|
| 243 |
} |
|
| 244 |
|
|
| 239 | 245 |
SmartGraph::NodeMap<bool> processed(graph, false); |
| 240 | 246 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
|
| 241 | 247 |
if (processed[n]) continue; |
| 242 | 248 |
processed[n] = true; |
| 243 | 249 |
if (mfm.matching(n) == INVALID) continue; |
| 244 | 250 |
int num = 1; |
| 245 | 251 |
Node v = graph.target(mfm.matching(n)); |
| 246 | 252 |
while (v != n) {
|
| 247 | 253 |
processed[v] = true; |
| 248 | 254 |
++num; |
| 249 | 255 |
v = graph.target(mfm.matching(v)); |
| 250 | 256 |
} |
| ... | ... |
@@ -275,24 +281,29 @@ |
| 275 | 281 |
bool perfect, bool allow_loops = true) {
|
| 276 | 282 |
if (perfect) {
|
| 277 | 283 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
|
| 278 | 284 |
int indeg = 0; |
| 279 | 285 |
for (InArcIt a(graph, n); a != INVALID; ++a) {
|
| 280 | 286 |
if (mfm.matching(graph.source(a)) == a) {
|
| 281 | 287 |
++indeg; |
| 282 | 288 |
} |
| 283 | 289 |
} |
| 284 | 290 |
check(mfm.matching(n) != INVALID, "Invalid matching"); |
| 285 | 291 |
check(indeg == 1, "Invalid matching"); |
| 286 | 292 |
} |
| 293 |
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
|
|
| 294 |
check((e == mfm.matching(graph.u(e)) ? 1 : 0) + |
|
| 295 |
(e == mfm.matching(graph.v(e)) ? 1 : 0) == |
|
| 296 |
mfm.matching(e), "Invalid matching"); |
|
| 297 |
} |
|
| 287 | 298 |
} else {
|
| 288 | 299 |
int anum = 0, bnum = 0; |
| 289 | 300 |
SmartGraph::NodeMap<bool> neighbours(graph, false); |
| 290 | 301 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
|
| 291 | 302 |
if (!mfm.barrier(n)) continue; |
| 292 | 303 |
++anum; |
| 293 | 304 |
for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) {
|
| 294 | 305 |
Node u = graph.source(a); |
| 295 | 306 |
if (!allow_loops && u == n) continue; |
| 296 | 307 |
if (!neighbours[u]) {
|
| 297 | 308 |
neighbours[u] = true; |
| 298 | 309 |
++bnum; |
| ... | ... |
@@ -328,24 +339,30 @@ |
| 328 | 339 |
check(indeg <= 1, "Invalid matching"); |
| 329 | 340 |
if (mwfm.matching(n) != INVALID) {
|
| 330 | 341 |
check(mwfm.nodeValue(n) >= 0, "Invalid node value"); |
| 331 | 342 |
check(indeg == 1, "Invalid matching"); |
| 332 | 343 |
pv += weight[mwfm.matching(n)]; |
| 333 | 344 |
SmartGraph::Node o = graph.target(mwfm.matching(n)); |
| 334 | 345 |
} else {
|
| 335 | 346 |
check(mwfm.nodeValue(n) == 0, "Invalid matching"); |
| 336 | 347 |
check(indeg == 0, "Invalid matching"); |
| 337 | 348 |
} |
| 338 | 349 |
} |
| 339 | 350 |
|
| 351 |
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
|
|
| 352 |
check((e == mwfm.matching(graph.u(e)) ? 1 : 0) + |
|
| 353 |
(e == mwfm.matching(graph.v(e)) ? 1 : 0) == |
|
| 354 |
mwfm.matching(e), "Invalid matching"); |
|
| 355 |
} |
|
| 356 |
|
|
| 340 | 357 |
int dv = 0; |
| 341 | 358 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
|
| 342 | 359 |
dv += mwfm.nodeValue(n); |
| 343 | 360 |
} |
| 344 | 361 |
|
| 345 | 362 |
check(pv * mwfm.dualScale == dv * 2, "Wrong duality"); |
| 346 | 363 |
|
| 347 | 364 |
SmartGraph::NodeMap<bool> processed(graph, false); |
| 348 | 365 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
|
| 349 | 366 |
if (processed[n]) continue; |
| 350 | 367 |
processed[n] = true; |
| 351 | 368 |
if (mwfm.matching(n) == INVALID) continue; |
| ... | ... |
@@ -382,24 +399,30 @@ |
| 382 | 399 |
int indeg = 0; |
| 383 | 400 |
for (InArcIt a(graph, n); a != INVALID; ++a) {
|
| 384 | 401 |
if (mwpfm.matching(graph.source(a)) == a) {
|
| 385 | 402 |
++indeg; |
| 386 | 403 |
} |
| 387 | 404 |
} |
| 388 | 405 |
check(mwpfm.matching(n) != INVALID, "Invalid perfect matching"); |
| 389 | 406 |
check(indeg == 1, "Invalid perfect matching"); |
| 390 | 407 |
pv += weight[mwpfm.matching(n)]; |
| 391 | 408 |
SmartGraph::Node o = graph.target(mwpfm.matching(n)); |
| 392 | 409 |
} |
| 393 | 410 |
|
| 411 |
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
|
|
| 412 |
check((e == mwpfm.matching(graph.u(e)) ? 1 : 0) + |
|
| 413 |
(e == mwpfm.matching(graph.v(e)) ? 1 : 0) == |
|
| 414 |
mwpfm.matching(e), "Invalid matching"); |
|
| 415 |
} |
|
| 416 |
|
|
| 394 | 417 |
int dv = 0; |
| 395 | 418 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
|
| 396 | 419 |
dv += mwpfm.nodeValue(n); |
| 397 | 420 |
} |
| 398 | 421 |
|
| 399 | 422 |
check(pv * mwpfm.dualScale == dv * 2, "Wrong duality"); |
| 400 | 423 |
|
| 401 | 424 |
SmartGraph::NodeMap<bool> processed(graph, false); |
| 402 | 425 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
|
| 403 | 426 |
if (processed[n]) continue; |
| 404 | 427 |
processed[n] = true; |
| 405 | 428 |
if (mwpfm.matching(n) == INVALID) continue; |
0 comments (0 inline)