0
2
0
... | ... |
@@ -613,130 +613,129 @@ |
613 | 613 |
return (*_matching)[node]; |
614 | 614 |
} |
615 | 615 |
|
616 | 616 |
/// \brief Returns true if the node is in the barrier |
617 | 617 |
/// |
618 | 618 |
/// The barrier is a subset of the nodes. If the nodes in the |
619 | 619 |
/// barrier have less adjacent nodes than the size of the barrier, |
620 | 620 |
/// then at least as much nodes cannot be covered as the |
621 | 621 |
/// difference of the two subsets. |
622 | 622 |
bool barrier(const Node& node) const { |
623 | 623 |
return (*_level)[node] >= _empty_level; |
624 | 624 |
} |
625 | 625 |
|
626 | 626 |
/// @} |
627 | 627 |
|
628 | 628 |
}; |
629 | 629 |
|
630 | 630 |
/// \ingroup matching |
631 | 631 |
/// |
632 | 632 |
/// \brief Weighted fractional matching in general graphs |
633 | 633 |
/// |
634 | 634 |
/// This class provides an efficient implementation of fractional |
635 | 635 |
/// matching algorithm. The implementation uses priority queues and |
636 | 636 |
/// provides \f$O(nm\log n)\f$ time complexity. |
637 | 637 |
/// |
638 | 638 |
/// The maximum weighted fractional matching is a relaxation of the |
639 | 639 |
/// maximum weighted matching problem where the odd set constraints |
640 | 640 |
/// are omitted. |
641 | 641 |
/// It can be formulated with the following linear program. |
642 | 642 |
/// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] |
643 | 643 |
/// \f[x_e \ge 0\quad \forall e\in E\f] |
644 | 644 |
/// \f[\max \sum_{e\in E}x_ew_e\f] |
645 | 645 |
/// where \f$\delta(X)\f$ is the set of edges incident to a node in |
646 | 646 |
/// \f$X\f$. The result must be the union of a matching with one |
647 | 647 |
/// value edges and a set of odd length cycles with half value edges. |
648 | 648 |
/// |
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: |
677 | 678 |
|
678 | 679 |
/// The graph type of the algorithm |
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 |
|
707 | 706 |
typedef typename Graph::template NodeMap<Value> NodePotential; |
708 | 707 |
|
709 | 708 |
const Graph& _graph; |
710 | 709 |
const WeightMap& _weight; |
711 | 710 |
|
712 | 711 |
MatchingMap* _matching; |
713 | 712 |
NodePotential* _node_potential; |
714 | 713 |
|
715 | 714 |
int _node_num; |
716 | 715 |
bool _allow_loops; |
717 | 716 |
|
718 | 717 |
enum Status { |
719 | 718 |
EVEN = -1, MATCHED = 0, ODD = 1 |
720 | 719 |
}; |
721 | 720 |
|
722 | 721 |
typedef typename Graph::template NodeMap<Status> StatusMap; |
723 | 722 |
StatusMap* _status; |
724 | 723 |
|
725 | 724 |
typedef typename Graph::template NodeMap<Arc> PredMap; |
726 | 725 |
PredMap* _pred; |
727 | 726 |
|
728 | 727 |
typedef ExtendFindEnum<IntNodeMap> TreeSet; |
729 | 728 |
|
730 | 729 |
IntNodeMap *_tree_set_index; |
731 | 730 |
TreeSet *_tree_set; |
732 | 731 |
|
733 | 732 |
IntNodeMap *_delta1_index; |
734 | 733 |
BinHeap<Value, IntNodeMap> *_delta1; |
735 | 734 |
|
736 | 735 |
IntNodeMap *_delta2_index; |
737 | 736 |
BinHeap<Value, IntNodeMap> *_delta2; |
738 | 737 |
|
739 | 738 |
IntEdgeMap *_delta3_index; |
740 | 739 |
BinHeap<Value, IntEdgeMap> *_delta3; |
741 | 740 |
|
742 | 741 |
Value _delta_sum; |
... | ... |
@@ -1284,225 +1283,223 @@ |
1284 | 1283 |
/// @} |
1285 | 1284 |
|
1286 | 1285 |
/// \name Primal Solution |
1287 | 1286 |
/// Functions to get the primal solution, i.e. the maximum weighted |
1288 | 1287 |
/// matching.\n |
1289 | 1288 |
/// Either \ref run() or \ref start() function should be called before |
1290 | 1289 |
/// using them. |
1291 | 1290 |
|
1292 | 1291 |
/// @{ |
1293 | 1292 |
|
1294 | 1293 |
/// \brief Return the weight of the matching. |
1295 | 1294 |
/// |
1296 | 1295 |
/// This function returns the weight of the found matching. This |
1297 | 1296 |
/// value is scaled by \ref primalScale "primal scale". |
1298 | 1297 |
/// |
1299 | 1298 |
/// \pre Either run() or start() must be called before using this function. |
1300 | 1299 |
Value matchingWeight() const { |
1301 | 1300 |
Value sum = 0; |
1302 | 1301 |
for (NodeIt n(_graph); n != INVALID; ++n) { |
1303 | 1302 |
if ((*_matching)[n] != INVALID) { |
1304 | 1303 |
sum += _weight[(*_matching)[n]]; |
1305 | 1304 |
} |
1306 | 1305 |
} |
1307 | 1306 |
return sum * primalScale / 2; |
1308 | 1307 |
} |
1309 | 1308 |
|
1310 | 1309 |
/// \brief Return the number of covered nodes in the matching. |
1311 | 1310 |
/// |
1312 | 1311 |
/// This function returns the number of covered nodes in the matching. |
1313 | 1312 |
/// |
1314 | 1313 |
/// \pre Either run() or start() must be called before using this function. |
1315 | 1314 |
int matchingSize() const { |
1316 | 1315 |
int num = 0; |
1317 | 1316 |
for (NodeIt n(_graph); n != INVALID; ++n) { |
1318 | 1317 |
if ((*_matching)[n] != INVALID) { |
1319 | 1318 |
++num; |
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. |
1348 | 1346 |
Arc matching(const Node& node) const { |
1349 | 1347 |
return (*_matching)[node]; |
1350 | 1348 |
} |
1351 | 1349 |
|
1352 | 1350 |
/// \brief Return a const reference to the matching map. |
1353 | 1351 |
/// |
1354 | 1352 |
/// This function returns a const reference to a node map that stores |
1355 | 1353 |
/// the matching arc (or edge) incident to each node. |
1356 | 1354 |
const MatchingMap& matchingMap() const { |
1357 | 1355 |
return *_matching; |
1358 | 1356 |
} |
1359 | 1357 |
|
1360 | 1358 |
/// @} |
1361 | 1359 |
|
1362 | 1360 |
/// \name Dual Solution |
1363 | 1361 |
/// Functions to get the dual solution.\n |
1364 | 1362 |
/// Either \ref run() or \ref start() function should be called before |
1365 | 1363 |
/// using them. |
1366 | 1364 |
|
1367 | 1365 |
/// @{ |
1368 | 1366 |
|
1369 | 1367 |
/// \brief Return the value of the dual solution. |
1370 | 1368 |
/// |
1371 | 1369 |
/// This function returns the value of the dual solution. |
1372 | 1370 |
/// It should be equal to the primal value scaled by \ref dualScale |
1373 | 1371 |
/// "dual scale". |
1374 | 1372 |
/// |
1375 | 1373 |
/// \pre Either run() or start() must be called before using this function. |
1376 | 1374 |
Value dualValue() const { |
1377 | 1375 |
Value sum = 0; |
1378 | 1376 |
for (NodeIt n(_graph); n != INVALID; ++n) { |
1379 | 1377 |
sum += nodeValue(n); |
1380 | 1378 |
} |
1381 | 1379 |
return sum; |
1382 | 1380 |
} |
1383 | 1381 |
|
1384 | 1382 |
/// \brief Return the dual value (potential) of the given node. |
1385 | 1383 |
/// |
1386 | 1384 |
/// This function returns the dual value (potential) of the given node. |
1387 | 1385 |
/// |
1388 | 1386 |
/// \pre Either run() or start() must be called before using this function. |
1389 | 1387 |
Value nodeValue(const Node& n) const { |
1390 | 1388 |
return (*_node_potential)[n]; |
1391 | 1389 |
} |
1392 | 1390 |
|
1393 | 1391 |
/// @} |
1394 | 1392 |
|
1395 | 1393 |
}; |
1396 | 1394 |
|
1397 | 1395 |
/// \ingroup matching |
1398 | 1396 |
/// |
1399 | 1397 |
/// \brief Weighted fractional perfect matching in general graphs |
1400 | 1398 |
/// |
1401 | 1399 |
/// This class provides an efficient implementation of fractional |
1402 | 1400 |
/// matching algorithm. The implementation uses priority queues and |
1403 | 1401 |
/// provides \f$O(nm\log n)\f$ time complexity. |
1404 | 1402 |
/// |
1405 | 1403 |
/// The maximum weighted fractional perfect matching is a relaxation |
1406 | 1404 |
/// of the maximum weighted perfect matching problem where the odd |
1407 | 1405 |
/// set constraints are omitted. |
1408 | 1406 |
/// It can be formulated with the following linear program. |
1409 | 1407 |
/// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] |
1410 | 1408 |
/// \f[x_e \ge 0\quad \forall e\in E\f] |
1411 | 1409 |
/// \f[\max \sum_{e\in E}x_ew_e\f] |
1412 | 1410 |
/// where \f$\delta(X)\f$ is the set of edges incident to a node in |
1413 | 1411 |
/// \f$X\f$. The result must be the union of a matching with one |
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: |
1443 | 1442 |
|
1444 | 1443 |
/// The graph type of the algorithm |
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 |
|
1473 | 1470 |
typedef typename Graph::template NodeMap<Value> NodePotential; |
1474 | 1471 |
|
1475 | 1472 |
const Graph& _graph; |
1476 | 1473 |
const WeightMap& _weight; |
1477 | 1474 |
|
1478 | 1475 |
MatchingMap* _matching; |
1479 | 1476 |
NodePotential* _node_potential; |
1480 | 1477 |
|
1481 | 1478 |
int _node_num; |
1482 | 1479 |
bool _allow_loops; |
1483 | 1480 |
|
1484 | 1481 |
enum Status { |
1485 | 1482 |
EVEN = -1, MATCHED = 0, ODD = 1 |
1486 | 1483 |
}; |
1487 | 1484 |
|
1488 | 1485 |
typedef typename Graph::template NodeMap<Status> StatusMap; |
1489 | 1486 |
StatusMap* _status; |
1490 | 1487 |
|
1491 | 1488 |
typedef typename Graph::template NodeMap<Arc> PredMap; |
1492 | 1489 |
PredMap* _pred; |
1493 | 1490 |
|
1494 | 1491 |
typedef ExtendFindEnum<IntNodeMap> TreeSet; |
1495 | 1492 |
|
1496 | 1493 |
IntNodeMap *_tree_set_index; |
1497 | 1494 |
TreeSet *_tree_set; |
1498 | 1495 |
|
1499 | 1496 |
IntNodeMap *_delta2_index; |
1500 | 1497 |
BinHeap<Value, IntNodeMap> *_delta2; |
1501 | 1498 |
|
1502 | 1499 |
IntEdgeMap *_delta3_index; |
1503 | 1500 |
BinHeap<Value, IntEdgeMap> *_delta3; |
1504 | 1501 |
|
1505 | 1502 |
Value _delta_sum; |
1506 | 1503 |
|
1507 | 1504 |
void createStructures() { |
1508 | 1505 |
_node_num = countNodes(_graph); |
... | ... |
@@ -2019,100 +2016,99 @@ |
2019 | 2016 |
/// @} |
2020 | 2017 |
|
2021 | 2018 |
/// \name Primal Solution |
2022 | 2019 |
/// Functions to get the primal solution, i.e. the maximum weighted |
2023 | 2020 |
/// matching.\n |
2024 | 2021 |
/// Either \ref run() or \ref start() function should be called before |
2025 | 2022 |
/// using them. |
2026 | 2023 |
|
2027 | 2024 |
/// @{ |
2028 | 2025 |
|
2029 | 2026 |
/// \brief Return the weight of the matching. |
2030 | 2027 |
/// |
2031 | 2028 |
/// This function returns the weight of the found matching. This |
2032 | 2029 |
/// value is scaled by \ref primalScale "primal scale". |
2033 | 2030 |
/// |
2034 | 2031 |
/// \pre Either run() or start() must be called before using this function. |
2035 | 2032 |
Value matchingWeight() const { |
2036 | 2033 |
Value sum = 0; |
2037 | 2034 |
for (NodeIt n(_graph); n != INVALID; ++n) { |
2038 | 2035 |
if ((*_matching)[n] != INVALID) { |
2039 | 2036 |
sum += _weight[(*_matching)[n]]; |
2040 | 2037 |
} |
2041 | 2038 |
} |
2042 | 2039 |
return sum * primalScale / 2; |
2043 | 2040 |
} |
2044 | 2041 |
|
2045 | 2042 |
/// \brief Return the number of covered nodes in the matching. |
2046 | 2043 |
/// |
2047 | 2044 |
/// This function returns the number of covered nodes in the matching. |
2048 | 2045 |
/// |
2049 | 2046 |
/// \pre Either run() or start() must be called before using this function. |
2050 | 2047 |
int matchingSize() const { |
2051 | 2048 |
int num = 0; |
2052 | 2049 |
for (NodeIt n(_graph); n != INVALID; ++n) { |
2053 | 2050 |
if ((*_matching)[n] != INVALID) { |
2054 | 2051 |
++num; |
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. |
2083 | 2079 |
Arc matching(const Node& node) const { |
2084 | 2080 |
return (*_matching)[node]; |
2085 | 2081 |
} |
2086 | 2082 |
|
2087 | 2083 |
/// \brief Return a const reference to the matching map. |
2088 | 2084 |
/// |
2089 | 2085 |
/// This function returns a const reference to a node map that stores |
2090 | 2086 |
/// the matching arc (or edge) incident to each node. |
2091 | 2087 |
const MatchingMap& matchingMap() const { |
2092 | 2088 |
return *_matching; |
2093 | 2089 |
} |
2094 | 2090 |
|
2095 | 2091 |
/// @} |
2096 | 2092 |
|
2097 | 2093 |
/// \name Dual Solution |
2098 | 2094 |
/// Functions to get the dual solution.\n |
2099 | 2095 |
/// Either \ref run() or \ref start() function should be called before |
2100 | 2096 |
/// using them. |
2101 | 2097 |
|
2102 | 2098 |
/// @{ |
2103 | 2099 |
|
2104 | 2100 |
/// \brief Return the value of the dual solution. |
2105 | 2101 |
/// |
2106 | 2102 |
/// This function returns the value of the dual solution. |
2107 | 2103 |
/// It should be equal to the primal value scaled by \ref dualScale |
2108 | 2104 |
/// "dual scale". |
2109 | 2105 |
/// |
2110 | 2106 |
/// \pre Either run() or start() must be called before using this function. |
2111 | 2107 |
Value dualValue() const { |
2112 | 2108 |
Value sum = 0; |
2113 | 2109 |
for (NodeIt n(_graph); n != INVALID; ++n) { |
2114 | 2110 |
sum += nodeValue(n); |
2115 | 2111 |
} |
2116 | 2112 |
return sum; |
2117 | 2113 |
} |
2118 | 2114 |
... | ... |
@@ -191,251 +191,274 @@ |
191 | 191 |
typedef Graph::Node Node; |
192 | 192 |
typedef Graph::Edge Edge; |
193 | 193 |
typedef Graph::EdgeMap<int> WeightMap; |
194 | 194 |
|
195 | 195 |
Graph g; |
196 | 196 |
Node n; |
197 | 197 |
Edge e; |
198 | 198 |
WeightMap w(g); |
199 | 199 |
|
200 | 200 |
MaxWeightedPerfectFractionalMatching<Graph> mat_test(g, w); |
201 | 201 |
const MaxWeightedPerfectFractionalMatching<Graph>& |
202 | 202 |
const_mat_test = mat_test; |
203 | 203 |
|
204 | 204 |
mat_test.init(); |
205 | 205 |
mat_test.start(); |
206 | 206 |
mat_test.run(); |
207 | 207 |
|
208 | 208 |
const_mat_test.matchingWeight(); |
209 | 209 |
const_mat_test.matching(e); |
210 | 210 |
const_mat_test.matching(n); |
211 | 211 |
const MaxWeightedPerfectFractionalMatching<Graph>::MatchingMap& mmap = |
212 | 212 |
const_mat_test.matchingMap(); |
213 | 213 |
e = mmap[n]; |
214 | 214 |
|
215 | 215 |
const_mat_test.dualValue(); |
216 | 216 |
const_mat_test.nodeValue(n); |
217 | 217 |
} |
218 | 218 |
|
219 | 219 |
void checkFractionalMatching(const SmartGraph& graph, |
220 | 220 |
const MaxFractionalMatching<SmartGraph>& mfm, |
221 | 221 |
bool allow_loops = true) { |
222 | 222 |
int pv = 0; |
223 | 223 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { |
224 | 224 |
int indeg = 0; |
225 | 225 |
for (InArcIt a(graph, n); a != INVALID; ++a) { |
226 | 226 |
if (mfm.matching(graph.source(a)) == a) { |
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 |
} |
251 | 257 |
check(num == 2 || num % 2 == 1, "Wrong cycle size"); |
252 | 258 |
check(allow_loops || num != 1, "Wrong cycle size"); |
253 | 259 |
} |
254 | 260 |
|
255 | 261 |
int anum = 0, bnum = 0; |
256 | 262 |
SmartGraph::NodeMap<bool> neighbours(graph, false); |
257 | 263 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { |
258 | 264 |
if (!mfm.barrier(n)) continue; |
259 | 265 |
++anum; |
260 | 266 |
for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) { |
261 | 267 |
Node u = graph.source(a); |
262 | 268 |
if (!allow_loops && u == n) continue; |
263 | 269 |
if (!neighbours[u]) { |
264 | 270 |
neighbours[u] = true; |
265 | 271 |
++bnum; |
266 | 272 |
} |
267 | 273 |
} |
268 | 274 |
} |
269 | 275 |
check(anum - bnum + mfm.matchingSize() == countNodes(graph), |
270 | 276 |
"Wrong barrier"); |
271 | 277 |
} |
272 | 278 |
|
273 | 279 |
void checkPerfectFractionalMatching(const SmartGraph& graph, |
274 | 280 |
const MaxFractionalMatching<SmartGraph>& mfm, |
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; |
299 | 310 |
} |
300 | 311 |
} |
301 | 312 |
} |
302 | 313 |
check(anum - bnum > 0, "Wrong barrier"); |
303 | 314 |
} |
304 | 315 |
} |
305 | 316 |
|
306 | 317 |
void checkWeightedFractionalMatching(const SmartGraph& graph, |
307 | 318 |
const SmartGraph::EdgeMap<int>& weight, |
308 | 319 |
const MaxWeightedFractionalMatching<SmartGraph>& mwfm, |
309 | 320 |
bool allow_loops = true) { |
310 | 321 |
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { |
311 | 322 |
if (graph.u(e) == graph.v(e) && !allow_loops) continue; |
312 | 323 |
int rw = mwfm.nodeValue(graph.u(e)) + mwfm.nodeValue(graph.v(e)) |
313 | 324 |
- weight[e] * mwfm.dualScale; |
314 | 325 |
|
315 | 326 |
check(rw >= 0, "Negative reduced weight"); |
316 | 327 |
check(rw == 0 || !mwfm.matching(e), |
317 | 328 |
"Non-zero reduced weight on matching edge"); |
318 | 329 |
} |
319 | 330 |
|
320 | 331 |
int pv = 0; |
321 | 332 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { |
322 | 333 |
int indeg = 0; |
323 | 334 |
for (InArcIt a(graph, n); a != INVALID; ++a) { |
324 | 335 |
if (mwfm.matching(graph.source(a)) == a) { |
325 | 336 |
++indeg; |
326 | 337 |
} |
327 | 338 |
} |
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; |
352 | 369 |
int num = 1; |
353 | 370 |
Node v = graph.target(mwfm.matching(n)); |
354 | 371 |
while (v != n) { |
355 | 372 |
processed[v] = true; |
356 | 373 |
++num; |
357 | 374 |
v = graph.target(mwfm.matching(v)); |
358 | 375 |
} |
359 | 376 |
check(num == 2 || num % 2 == 1, "Wrong cycle size"); |
360 | 377 |
check(allow_loops || num != 1, "Wrong cycle size"); |
361 | 378 |
} |
362 | 379 |
|
363 | 380 |
return; |
364 | 381 |
} |
365 | 382 |
|
366 | 383 |
void checkWeightedPerfectFractionalMatching(const SmartGraph& graph, |
367 | 384 |
const SmartGraph::EdgeMap<int>& weight, |
368 | 385 |
const MaxWeightedPerfectFractionalMatching<SmartGraph>& mwpfm, |
369 | 386 |
bool allow_loops = true) { |
370 | 387 |
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { |
371 | 388 |
if (graph.u(e) == graph.v(e) && !allow_loops) continue; |
372 | 389 |
int rw = mwpfm.nodeValue(graph.u(e)) + mwpfm.nodeValue(graph.v(e)) |
373 | 390 |
- weight[e] * mwpfm.dualScale; |
374 | 391 |
|
375 | 392 |
check(rw >= 0, "Negative reduced weight"); |
376 | 393 |
check(rw == 0 || !mwpfm.matching(e), |
377 | 394 |
"Non-zero reduced weight on matching edge"); |
378 | 395 |
} |
379 | 396 |
|
380 | 397 |
int pv = 0; |
381 | 398 |
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { |
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; |
406 | 429 |
int num = 1; |
407 | 430 |
Node v = graph.target(mwpfm.matching(n)); |
408 | 431 |
while (v != n) { |
409 | 432 |
processed[v] = true; |
410 | 433 |
++num; |
411 | 434 |
v = graph.target(mwpfm.matching(v)); |
412 | 435 |
} |
413 | 436 |
check(num == 2 || num % 2 == 1, "Wrong cycle size"); |
414 | 437 |
check(allow_loops || num != 1, "Wrong cycle size"); |
415 | 438 |
} |
416 | 439 |
|
417 | 440 |
return; |
418 | 441 |
} |
419 | 442 |
|
420 | 443 |
|
421 | 444 |
int main() { |
422 | 445 |
|
423 | 446 |
for (int i = 0; i < lgfn; ++i) { |
424 | 447 |
SmartGraph graph; |
425 | 448 |
SmartGraph::EdgeMap<int> weight(graph); |
426 | 449 |
|
427 | 450 |
istringstream lgfs(lgf[i]); |
428 | 451 |
graphReader(graph, lgfs). |
429 | 452 |
edgeMap("weight", weight).run(); |
430 | 453 |
|
431 | 454 |
bool perfect_with_loops; |
432 | 455 |
{ |
433 | 456 |
MaxFractionalMatching<SmartGraph> mfm(graph, true); |
434 | 457 |
mfm.run(); |
435 | 458 |
checkFractionalMatching(graph, mfm, true); |
436 | 459 |
perfect_with_loops = mfm.matchingSize() == countNodes(graph); |
437 | 460 |
} |
438 | 461 |
|
439 | 462 |
bool perfect_without_loops; |
440 | 463 |
{ |
441 | 464 |
MaxFractionalMatching<SmartGraph> mfm(graph, false); |
0 comments (0 inline)