Changes in / [873:23da1b807280:874:d8ea85825e02] in lemon-main
- Files:
-
- 2 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/groups.dox
r873 r874 387 387 problem of maximum flow. 388 388 389 \ref Circulation is a preflow push-relabel algorithm implemented directly 389 \ref Circulation is a preflow push-relabel algorithm implemented directly 390 390 for finding feasible circulations, which is a somewhat different problem, 391 391 but it is strongly related to maximum flow. … … 523 523 Edmond's blossom shrinking algorithm for calculating maximum weighted 524 524 perfect matching in general graphs. 525 - \ref MaxFractionalMatching Push-relabel algorithm for calculating 526 maximum cardinality fractional matching in general graphs. 527 - \ref MaxWeightedFractionalMatching Augmenting path algorithm for calculating 528 maximum weighted fractional matching in general graphs. 529 - \ref MaxWeightedPerfectFractionalMatching 530 Augmenting path algorithm for calculating maximum weighted 531 perfect fractional matching in general graphs. 525 532 526 533 \image html matching.png -
lemon/Makefile.am
r864 r874 85 85 lemon/euler.h \ 86 86 lemon/fib_heap.h \ 87 lemon/fractional_matching.h \ 87 88 lemon/full_graph.h \ 88 89 lemon/glpk.h \ -
lemon/matching.h
r651 r870 17 17 */ 18 18 19 #ifndef LEMON_MA X_MATCHING_H20 #define LEMON_MA X_MATCHING_H19 #ifndef LEMON_MATCHING_H 20 #define LEMON_MATCHING_H 21 21 22 22 #include <vector> … … 29 29 #include <lemon/bin_heap.h> 30 30 #include <lemon/maps.h> 31 #include <lemon/fractional_matching.h> 31 32 32 33 ///\ingroup matching … … 42 43 /// This class implements Edmonds' alternating forest matching algorithm 43 44 /// for finding a maximum cardinality matching in a general undirected graph. 44 /// It can be started from an arbitrary initial matching 45 /// It can be started from an arbitrary initial matching 45 46 /// (the default is the empty one). 46 47 /// … … 70 71 ///\brief Status constants for Gallai-Edmonds decomposition. 71 72 /// 72 ///These constants are used for indicating the Gallai-Edmonds 73 ///These constants are used for indicating the Gallai-Edmonds 73 74 ///decomposition of a graph. The nodes with status \c EVEN (or \c D) 74 75 ///induce a subgraph with factor-critical components, the nodes with 75 76 ///status \c ODD (or \c A) form the canonical barrier, and the nodes 76 ///with status \c MATCHED (or \c C) induce a subgraph having a 77 ///with status \c MATCHED (or \c C) induce a subgraph having a 77 78 ///perfect matching. 78 79 enum Status { … … 513 514 } 514 515 515 /// \brief Start Edmonds' algorithm with a heuristic improvement 516 /// \brief Start Edmonds' algorithm with a heuristic improvement 516 517 /// for dense graphs 517 518 /// … … 535 536 /// \brief Run Edmonds' algorithm 536 537 /// 537 /// This function runs Edmonds' algorithm. An additional heuristic of 538 /// postponing shrinks is used for relatively dense graphs 538 /// This function runs Edmonds' algorithm. An additional heuristic of 539 /// postponing shrinks is used for relatively dense graphs 539 540 /// (for which <tt>m>=2*n</tt> holds). 540 541 void run() { … … 557 558 /// \brief Return the size (cardinality) of the matching. 558 559 /// 559 /// This function returns the size (cardinality) of the current matching. 560 /// This function returns the size (cardinality) of the current matching. 560 561 /// After run() it returns the size of the maximum matching in the graph. 561 562 int matchingSize() const { … … 571 572 /// \brief Return \c true if the given edge is in the matching. 572 573 /// 573 /// This function returns \c true if the given edge is in the current 574 /// This function returns \c true if the given edge is in the current 574 575 /// matching. 575 576 bool matching(const Edge& edge) const { … … 580 581 /// 581 582 /// This function returns the matching arc (or edge) incident to the 582 /// given node in the current matching or \c INVALID if the node is 583 /// given node in the current matching or \c INVALID if the node is 583 584 /// not covered by the matching. 584 585 Arc matching(const Node& n) const { … … 596 597 /// \brief Return the mate of the given node. 597 598 /// 598 /// This function returns the mate of the given node in the current 599 /// This function returns the mate of the given node in the current 599 600 /// matching or \c INVALID if the node is not covered by the matching. 600 601 Node mate(const Node& n) const { … … 606 607 607 608 /// \name Dual Solution 608 /// Functions to get the dual solution, i.e. the Gallai-Edmonds 609 /// Functions to get the dual solution, i.e. the Gallai-Edmonds 609 610 /// decomposition. 610 611 … … 649 650 /// \f$O(nm\log n)\f$ time complexity. 650 651 /// 651 /// The maximum weighted matching problem is to find a subset of the 652 /// edges in an undirected graph with maximum overall weight for which 652 /// The maximum weighted matching problem is to find a subset of the 653 /// edges in an undirected graph with maximum overall weight for which 653 654 /// each node has at most one incident edge. 654 655 /// It can be formulated with the following linear program. … … 674 675 \frac{\vert B \vert - 1}{2}z_B\f] */ 675 676 /// 676 /// The algorithm can be executed with the run() function. 677 /// The algorithm can be executed with the run() function. 677 678 /// After it the matching (the primal solution) and the dual solution 678 /// can be obtained using the query functions and the 679 /// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class, 680 /// which is able to iterate on the nodes of a blossom. 679 /// can be obtained using the query functions and the 680 /// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class, 681 /// which is able to iterate on the nodes of a blossom. 681 682 /// If the value type is integer, then the dual solution is multiplied 682 683 /// by \ref MaxWeightedMatching::dualScale "4". 683 684 /// 684 685 /// \tparam GR The undirected graph type the algorithm runs on. 685 /// \tparam WM The type edge weight map. The default type is 686 /// \tparam WM The type edge weight map. The default type is 686 687 /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>". 687 688 #ifdef DOXYGEN … … 746 747 747 748 enum Status { 748 EVEN = -1, MATCHED = 0, ODD = 1 , UNMATCHED = -2749 EVEN = -1, MATCHED = 0, ODD = 1 749 750 }; 750 751 … … 798 799 799 800 Value _delta_sum; 801 int _unmatched; 802 803 typedef MaxWeightedFractionalMatching<Graph, WeightMap> FractionalMatching; 804 FractionalMatching *_fractional; 800 805 801 806 void createStructures() { … … 845 850 846 851 void destroyStructures() { 847 _node_num = countNodes(_graph);848 _blossom_num = _node_num * 3 / 2;849 850 852 if (_matching) { 851 853 delete _matching; … … 922 924 if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { 923 925 _delta3->push(e, rw / 2); 924 }925 } else if ((*_blossom_data)[vb].status == UNMATCHED) {926 if (_delta3->state(e) != _delta3->IN_HEAP) {927 _delta3->push(e, rw);928 926 } 929 927 } else { … … 950 948 (*_blossom_data)[vb].offset); 951 949 } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - 952 (*_blossom_data)[vb].offset) {950 (*_blossom_data)[vb].offset) { 953 951 _delta2->decrease(vb, _blossom_set->classPrio(vb) - 954 952 (*_blossom_data)[vb].offset); … … 969 967 if (!_blossom_set->trivial(blossom)) { 970 968 _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 + 971 (*_blossom_data)[blossom].offset);969 (*_blossom_data)[blossom].offset); 972 970 } 973 971 } … … 1036 1034 } 1037 1035 } 1038 }1039 1040 } else if ((*_blossom_data)[vb].status == UNMATCHED) {1041 if (_delta3->state(e) == _delta3->IN_HEAP) {1042 _delta3->erase(e);1043 1036 } 1044 1037 } else { … … 1078 1071 std::numeric_limits<Value>::max()) { 1079 1072 _delta2->push(blossom, _blossom_set->classPrio(blossom) - 1080 1073 (*_blossom_data)[blossom].offset); 1081 1074 } 1082 1075 … … 1117 1110 if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { 1118 1111 _delta3->push(e, rw / 2); 1119 }1120 } else if ((*_blossom_data)[vb].status == UNMATCHED) {1121 if (_delta3->state(e) != _delta3->IN_HEAP) {1122 _delta3->push(e, rw);1123 1112 } 1124 1113 } else { … … 1158 1147 } 1159 1148 1160 1161 void matchedToUnmatched(int blossom) {1162 if (_delta2->state(blossom) == _delta2->IN_HEAP) {1163 _delta2->erase(blossom);1164 }1165 1166 for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);1167 n != INVALID; ++n) {1168 int ni = (*_node_index)[n];1169 1170 _blossom_set->increase(n, std::numeric_limits<Value>::max());1171 1172 (*_node_data)[ni].heap.clear();1173 (*_node_data)[ni].heap_index.clear();1174 1175 for (OutArcIt e(_graph, n); e != INVALID; ++e) {1176 Node v = _graph.target(e);1177 int vb = _blossom_set->find(v);1178 int vi = (*_node_index)[v];1179 1180 Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -1181 dualScale * _weight[e];1182 1183 if ((*_blossom_data)[vb].status == EVEN) {1184 if (_delta3->state(e) != _delta3->IN_HEAP) {1185 _delta3->push(e, rw);1186 }1187 }1188 }1189 }1190 }1191 1192 void unmatchedToMatched(int blossom) {1193 for (typename BlossomSet::ItemIt n(*_blossom_set, blossom);1194 n != INVALID; ++n) {1195 int ni = (*_node_index)[n];1196 1197 for (InArcIt e(_graph, n); e != INVALID; ++e) {1198 Node v = _graph.source(e);1199 int vb = _blossom_set->find(v);1200 int vi = (*_node_index)[v];1201 1202 Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot -1203 dualScale * _weight[e];1204 1205 if (vb == blossom) {1206 if (_delta3->state(e) == _delta3->IN_HEAP) {1207 _delta3->erase(e);1208 }1209 } else if ((*_blossom_data)[vb].status == EVEN) {1210 1211 if (_delta3->state(e) == _delta3->IN_HEAP) {1212 _delta3->erase(e);1213 }1214 1215 int vt = _tree_set->find(vb);1216 1217 Arc r = _graph.oppositeArc(e);1218 1219 typename std::map<int, Arc>::iterator it =1220 (*_node_data)[ni].heap_index.find(vt);1221 1222 if (it != (*_node_data)[ni].heap_index.end()) {1223 if ((*_node_data)[ni].heap[it->second] > rw) {1224 (*_node_data)[ni].heap.replace(it->second, r);1225 (*_node_data)[ni].heap.decrease(r, rw);1226 it->second = r;1227 }1228 } else {1229 (*_node_data)[ni].heap.push(r, rw);1230 (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r));1231 }1232 1233 if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) {1234 _blossom_set->decrease(n, (*_node_data)[ni].heap.prio());1235 1236 if (_delta2->state(blossom) != _delta2->IN_HEAP) {1237 _delta2->push(blossom, _blossom_set->classPrio(blossom) -1238 (*_blossom_data)[blossom].offset);1239 } else if ((*_delta2)[blossom] > _blossom_set->classPrio(blossom)-1240 (*_blossom_data)[blossom].offset){1241 _delta2->decrease(blossom, _blossom_set->classPrio(blossom) -1242 (*_blossom_data)[blossom].offset);1243 }1244 }1245 1246 } else if ((*_blossom_data)[vb].status == UNMATCHED) {1247 if (_delta3->state(e) == _delta3->IN_HEAP) {1248 _delta3->erase(e);1249 }1250 }1251 }1252 }1253 }1254 1255 1149 void alternatePath(int even, int tree) { 1256 1150 int odd; … … 1295 1189 destroyTree(tree); 1296 1190 1297 (*_blossom_data)[blossom].status = UNMATCHED;1298 1191 (*_blossom_data)[blossom].base = node; 1299 matchedToUnmatched(blossom); 1300 } 1301 1192 (*_blossom_data)[blossom].next = INVALID; 1193 } 1302 1194 1303 1195 void augmentOnEdge(const Edge& edge) { … … 1306 1198 int right = _blossom_set->find(_graph.v(edge)); 1307 1199 1308 if ((*_blossom_data)[left].status == EVEN) { 1309 int left_tree = _tree_set->find(left); 1310 alternatePath(left, left_tree); 1311 destroyTree(left_tree); 1312 } else { 1313 (*_blossom_data)[left].status = MATCHED; 1314 unmatchedToMatched(left); 1315 } 1316 1317 if ((*_blossom_data)[right].status == EVEN) { 1318 int right_tree = _tree_set->find(right); 1319 alternatePath(right, right_tree); 1320 destroyTree(right_tree); 1321 } else { 1322 (*_blossom_data)[right].status = MATCHED; 1323 unmatchedToMatched(right); 1324 } 1200 int left_tree = _tree_set->find(left); 1201 alternatePath(left, left_tree); 1202 destroyTree(left_tree); 1203 1204 int right_tree = _tree_set->find(right); 1205 alternatePath(right, right_tree); 1206 destroyTree(right_tree); 1325 1207 1326 1208 (*_blossom_data)[left].next = _graph.direct(edge, true); 1327 1209 (*_blossom_data)[right].next = _graph.direct(edge, false); 1210 } 1211 1212 void augmentOnArc(const Arc& arc) { 1213 1214 int left = _blossom_set->find(_graph.source(arc)); 1215 int right = _blossom_set->find(_graph.target(arc)); 1216 1217 (*_blossom_data)[left].status = MATCHED; 1218 1219 int right_tree = _tree_set->find(right); 1220 alternatePath(right, right_tree); 1221 destroyTree(right_tree); 1222 1223 (*_blossom_data)[left].next = arc; 1224 (*_blossom_data)[right].next = _graph.oppositeArc(arc); 1328 1225 } 1329 1226 … … 1530 1427 (*_blossom_data)[sb].pred = pred; 1531 1428 (*_blossom_data)[sb].next = 1532 1429 _graph.oppositeArc((*_blossom_data)[tb].next); 1533 1430 1534 1431 pred = (*_blossom_data)[ub].next; … … 1630 1527 1631 1528 for (int i = 0; i < int(blossoms.size()); ++i) { 1632 if ((*_blossom_data)[blossoms[i]]. status == MATCHED) {1529 if ((*_blossom_data)[blossoms[i]].next != INVALID) { 1633 1530 1634 1531 Value offset = (*_blossom_data)[blossoms[i]].offset; … … 1668 1565 _delta4_index(0), _delta4(0), 1669 1566 1670 _delta_sum() {} 1567 _delta_sum(), _unmatched(0), 1568 1569 _fractional(0) 1570 {} 1671 1571 1672 1572 ~MaxWeightedMatching() { 1673 1573 destroyStructures(); 1574 if (_fractional) { 1575 delete _fractional; 1576 } 1674 1577 } 1675 1578 … … 1699 1602 (*_delta4_index)[i] = _delta4->PRE_HEAP; 1700 1603 } 1604 1605 _unmatched = _node_num; 1701 1606 1702 1607 int index = 0; … … 1734 1639 } 1735 1640 1641 /// \brief Initialize the algorithm with fractional matching 1642 /// 1643 /// This function initializes the algorithm with a fractional 1644 /// matching. This initialization is also called jumpstart heuristic. 1645 void fractionalInit() { 1646 createStructures(); 1647 1648 if (_fractional == 0) { 1649 _fractional = new FractionalMatching(_graph, _weight, false); 1650 } 1651 _fractional->run(); 1652 1653 for (ArcIt e(_graph); e != INVALID; ++e) { 1654 (*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP; 1655 } 1656 for (NodeIt n(_graph); n != INVALID; ++n) { 1657 (*_delta1_index)[n] = _delta1->PRE_HEAP; 1658 } 1659 for (EdgeIt e(_graph); e != INVALID; ++e) { 1660 (*_delta3_index)[e] = _delta3->PRE_HEAP; 1661 } 1662 for (int i = 0; i < _blossom_num; ++i) { 1663 (*_delta2_index)[i] = _delta2->PRE_HEAP; 1664 (*_delta4_index)[i] = _delta4->PRE_HEAP; 1665 } 1666 1667 _unmatched = 0; 1668 1669 int index = 0; 1670 for (NodeIt n(_graph); n != INVALID; ++n) { 1671 Value pot = _fractional->nodeValue(n); 1672 (*_node_index)[n] = index; 1673 (*_node_data)[index].pot = pot; 1674 int blossom = 1675 _blossom_set->insert(n, std::numeric_limits<Value>::max()); 1676 1677 (*_blossom_data)[blossom].status = MATCHED; 1678 (*_blossom_data)[blossom].pred = INVALID; 1679 (*_blossom_data)[blossom].next = _fractional->matching(n); 1680 if (_fractional->matching(n) == INVALID) { 1681 (*_blossom_data)[blossom].base = n; 1682 } 1683 (*_blossom_data)[blossom].pot = 0; 1684 (*_blossom_data)[blossom].offset = 0; 1685 ++index; 1686 } 1687 1688 typename Graph::template NodeMap<bool> processed(_graph, false); 1689 for (NodeIt n(_graph); n != INVALID; ++n) { 1690 if (processed[n]) continue; 1691 processed[n] = true; 1692 if (_fractional->matching(n) == INVALID) continue; 1693 int num = 1; 1694 Node v = _graph.target(_fractional->matching(n)); 1695 while (n != v) { 1696 processed[v] = true; 1697 v = _graph.target(_fractional->matching(v)); 1698 ++num; 1699 } 1700 1701 if (num % 2 == 1) { 1702 std::vector<int> subblossoms(num); 1703 1704 subblossoms[--num] = _blossom_set->find(n); 1705 _delta1->push(n, _fractional->nodeValue(n)); 1706 v = _graph.target(_fractional->matching(n)); 1707 while (n != v) { 1708 subblossoms[--num] = _blossom_set->find(v); 1709 _delta1->push(v, _fractional->nodeValue(v)); 1710 v = _graph.target(_fractional->matching(v)); 1711 } 1712 1713 int surface = 1714 _blossom_set->join(subblossoms.begin(), subblossoms.end()); 1715 (*_blossom_data)[surface].status = EVEN; 1716 (*_blossom_data)[surface].pred = INVALID; 1717 (*_blossom_data)[surface].next = INVALID; 1718 (*_blossom_data)[surface].pot = 0; 1719 (*_blossom_data)[surface].offset = 0; 1720 1721 _tree_set->insert(surface); 1722 ++_unmatched; 1723 } 1724 } 1725 1726 for (EdgeIt e(_graph); e != INVALID; ++e) { 1727 int si = (*_node_index)[_graph.u(e)]; 1728 int sb = _blossom_set->find(_graph.u(e)); 1729 int ti = (*_node_index)[_graph.v(e)]; 1730 int tb = _blossom_set->find(_graph.v(e)); 1731 if ((*_blossom_data)[sb].status == EVEN && 1732 (*_blossom_data)[tb].status == EVEN && sb != tb) { 1733 _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - 1734 dualScale * _weight[e]) / 2); 1735 } 1736 } 1737 1738 for (NodeIt n(_graph); n != INVALID; ++n) { 1739 int nb = _blossom_set->find(n); 1740 if ((*_blossom_data)[nb].status != MATCHED) continue; 1741 int ni = (*_node_index)[n]; 1742 1743 for (OutArcIt e(_graph, n); e != INVALID; ++e) { 1744 Node v = _graph.target(e); 1745 int vb = _blossom_set->find(v); 1746 int vi = (*_node_index)[v]; 1747 1748 Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - 1749 dualScale * _weight[e]; 1750 1751 if ((*_blossom_data)[vb].status == EVEN) { 1752 1753 int vt = _tree_set->find(vb); 1754 1755 typename std::map<int, Arc>::iterator it = 1756 (*_node_data)[ni].heap_index.find(vt); 1757 1758 if (it != (*_node_data)[ni].heap_index.end()) { 1759 if ((*_node_data)[ni].heap[it->second] > rw) { 1760 (*_node_data)[ni].heap.replace(it->second, e); 1761 (*_node_data)[ni].heap.decrease(e, rw); 1762 it->second = e; 1763 } 1764 } else { 1765 (*_node_data)[ni].heap.push(e, rw); 1766 (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); 1767 } 1768 } 1769 } 1770 1771 if (!(*_node_data)[ni].heap.empty()) { 1772 _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); 1773 _delta2->push(nb, _blossom_set->classPrio(nb)); 1774 } 1775 } 1776 } 1777 1736 1778 /// \brief Start the algorithm 1737 1779 /// 1738 1780 /// This function starts the algorithm. 1739 1781 /// 1740 /// \pre \ref init() must be called before using this function. 1782 /// \pre \ref init() or \ref fractionalInit() must be called 1783 /// before using this function. 1741 1784 void start() { 1742 1785 enum OpType { … … 1744 1787 }; 1745 1788 1746 int unmatched = _node_num; 1747 while (unmatched > 0) { 1789 while (_unmatched > 0) { 1748 1790 Value d1 = !_delta1->empty() ? 1749 1791 _delta1->prio() : std::numeric_limits<Value>::max(); … … 1758 1800 _delta4->prio() : std::numeric_limits<Value>::max(); 1759 1801 1760 _delta_sum = d1; OpType ot = D1; 1802 _delta_sum = d3; OpType ot = D3; 1803 if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } 1761 1804 if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } 1762 if (d3 < _delta_sum) { _delta_sum = d3; ot = D3; }1763 1805 if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } 1764 1765 1806 1766 1807 switch (ot) { … … 1769 1810 Node n = _delta1->top(); 1770 1811 unmatchNode(n); 1771 -- unmatched;1812 --_unmatched; 1772 1813 } 1773 1814 break; … … 1776 1817 int blossom = _delta2->top(); 1777 1818 Node n = _blossom_set->classTop(blossom); 1778 Arc e = (*_node_data)[(*_node_index)[n]].heap.top(); 1779 extendOnArc(e); 1819 Arc a = (*_node_data)[(*_node_index)[n]].heap.top(); 1820 if ((*_blossom_data)[blossom].next == INVALID) { 1821 augmentOnArc(a); 1822 --_unmatched; 1823 } else { 1824 extendOnArc(a); 1825 } 1780 1826 } 1781 1827 break; … … 1790 1836 _delta3->pop(); 1791 1837 } else { 1792 int left_tree; 1793 if ((*_blossom_data)[left_blossom].status == EVEN) { 1794 left_tree = _tree_set->find(left_blossom); 1795 } else { 1796 left_tree = -1; 1797 ++unmatched; 1798 } 1799 int right_tree; 1800 if ((*_blossom_data)[right_blossom].status == EVEN) { 1801 right_tree = _tree_set->find(right_blossom); 1802 } else { 1803 right_tree = -1; 1804 ++unmatched; 1805 } 1838 int left_tree = _tree_set->find(left_blossom); 1839 int right_tree = _tree_set->find(right_blossom); 1806 1840 1807 1841 if (left_tree == right_tree) { … … 1809 1843 } else { 1810 1844 augmentOnEdge(e); 1811 unmatched -= 2;1845 _unmatched -= 2; 1812 1846 } 1813 1847 } … … 1827 1861 /// \note mwm.run() is just a shortcut of the following code. 1828 1862 /// \code 1829 /// mwm. init();1863 /// mwm.fractionalInit(); 1830 1864 /// mwm.start(); 1831 1865 /// \endcode 1832 1866 void run() { 1833 init();1867 fractionalInit(); 1834 1868 start(); 1835 1869 } … … 1838 1872 1839 1873 /// \name Primal Solution 1840 /// Functions to get the primal solution, i.e. the maximum weighted 1874 /// Functions to get the primal solution, i.e. the maximum weighted 1841 1875 /// matching.\n 1842 1876 /// Either \ref run() or \ref start() function should be called before … … 1857 1891 } 1858 1892 } 1859 return sum / =2;1893 return sum / 2; 1860 1894 } 1861 1895 … … 1877 1911 /// \brief Return \c true if the given edge is in the matching. 1878 1912 /// 1879 /// This function returns \c true if the given edge is in the found 1913 /// This function returns \c true if the given edge is in the found 1880 1914 /// matching. 1881 1915 /// … … 1888 1922 /// 1889 1923 /// This function returns the matching arc (or edge) incident to the 1890 /// given node in the found matching or \c INVALID if the node is 1924 /// given node in the found matching or \c INVALID if the node is 1891 1925 /// not covered by the matching. 1892 1926 /// … … 1906 1940 /// \brief Return the mate of the given node. 1907 1941 /// 1908 /// This function returns the mate of the given node in the found 1942 /// This function returns the mate of the given node in the found 1909 1943 /// matching or \c INVALID if the node is not covered by the matching. 1910 1944 /// … … 1926 1960 /// \brief Return the value of the dual solution. 1927 1961 /// 1928 /// This function returns the value of the dual solution. 1929 /// It should be equal to the primal value scaled by \ref dualScale 1962 /// This function returns the value of the dual solution. 1963 /// It should be equal to the primal value scaled by \ref dualScale 1930 1964 /// "dual scale". 1931 1965 /// … … 1982 2016 /// \brief Iterator for obtaining the nodes of a blossom. 1983 2017 /// 1984 /// This class provides an iterator for obtaining the nodes of the 2018 /// This class provides an iterator for obtaining the nodes of the 1985 2019 /// given blossom. It lists a subset of the nodes. 1986 /// Before using this iterator, you must allocate a 2020 /// Before using this iterator, you must allocate a 1987 2021 /// MaxWeightedMatching class and execute it. 1988 2022 class BlossomIt { … … 1993 2027 /// Constructor to get the nodes of the given variable. 1994 2028 /// 1995 /// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or 1996 /// \ref MaxWeightedMatching::start() "algorithm.start()" must be 2029 /// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or 2030 /// \ref MaxWeightedMatching::start() "algorithm.start()" must be 1997 2031 /// called before initializing this iterator. 1998 2032 BlossomIt(const MaxWeightedMatching& algorithm, int variable) … … 2047 2081 /// \f$O(nm\log n)\f$ time complexity. 2048 2082 /// 2049 /// The maximum weighted perfect matching problem is to find a subset of 2050 /// the edges in an undirected graph with maximum overall weight for which 2083 /// The maximum weighted perfect matching problem is to find a subset of 2084 /// the edges in an undirected graph with maximum overall weight for which 2051 2085 /// each node has exactly one incident edge. 2052 2086 /// It can be formulated with the following linear program. … … 2071 2105 \frac{\vert B \vert - 1}{2}z_B\f] */ 2072 2106 /// 2073 /// The algorithm can be executed with the run() function. 2107 /// The algorithm can be executed with the run() function. 2074 2108 /// After it the matching (the primal solution) and the dual solution 2075 /// can be obtained using the query functions and the 2076 /// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class, 2077 /// which is able to iterate on the nodes of a blossom. 2109 /// can be obtained using the query functions and the 2110 /// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class, 2111 /// which is able to iterate on the nodes of a blossom. 2078 2112 /// If the value type is integer, then the dual solution is multiplied 2079 2113 /// by \ref MaxWeightedMatching::dualScale "4". 2080 2114 /// 2081 2115 /// \tparam GR The undirected graph type the algorithm runs on. 2082 /// \tparam WM The type edge weight map. The default type is 2116 /// \tparam WM The type edge weight map. The default type is 2083 2117 /// \ref concepts::Graph::EdgeMap "GR::EdgeMap<int>". 2084 2118 #ifdef DOXYGEN … … 2191 2225 2192 2226 Value _delta_sum; 2227 int _unmatched; 2228 2229 typedef MaxWeightedPerfectFractionalMatching<Graph, WeightMap> 2230 FractionalMatching; 2231 FractionalMatching *_fractional; 2193 2232 2194 2233 void createStructures() { … … 2234 2273 2235 2274 void destroyStructures() { 2236 _node_num = countNodes(_graph);2237 _blossom_num = _node_num * 3 / 2;2238 2239 2275 if (_matching) { 2240 2276 delete _matching; … … 2909 2945 _delta4_index(0), _delta4(0), 2910 2946 2911 _delta_sum() {} 2947 _delta_sum(), _unmatched(0), 2948 2949 _fractional(0) 2950 {} 2912 2951 2913 2952 ~MaxWeightedPerfectMatching() { 2914 2953 destroyStructures(); 2954 if (_fractional) { 2955 delete _fractional; 2956 } 2915 2957 } 2916 2958 … … 2937 2979 (*_delta4_index)[i] = _delta4->PRE_HEAP; 2938 2980 } 2981 2982 _unmatched = _node_num; 2939 2983 2940 2984 int index = 0; … … 2971 3015 } 2972 3016 3017 /// \brief Initialize the algorithm with fractional matching 3018 /// 3019 /// This function initializes the algorithm with a fractional 3020 /// matching. This initialization is also called jumpstart heuristic. 3021 void fractionalInit() { 3022 createStructures(); 3023 3024 if (_fractional == 0) { 3025 _fractional = new FractionalMatching(_graph, _weight, false); 3026 } 3027 if (!_fractional->run()) { 3028 _unmatched = -1; 3029 return; 3030 } 3031 3032 for (ArcIt e(_graph); e != INVALID; ++e) { 3033 (*_node_heap_index)[e] = BinHeap<Value, IntArcMap>::PRE_HEAP; 3034 } 3035 for (EdgeIt e(_graph); e != INVALID; ++e) { 3036 (*_delta3_index)[e] = _delta3->PRE_HEAP; 3037 } 3038 for (int i = 0; i < _blossom_num; ++i) { 3039 (*_delta2_index)[i] = _delta2->PRE_HEAP; 3040 (*_delta4_index)[i] = _delta4->PRE_HEAP; 3041 } 3042 3043 _unmatched = 0; 3044 3045 int index = 0; 3046 for (NodeIt n(_graph); n != INVALID; ++n) { 3047 Value pot = _fractional->nodeValue(n); 3048 (*_node_index)[n] = index; 3049 (*_node_data)[index].pot = pot; 3050 int blossom = 3051 _blossom_set->insert(n, std::numeric_limits<Value>::max()); 3052 3053 (*_blossom_data)[blossom].status = MATCHED; 3054 (*_blossom_data)[blossom].pred = INVALID; 3055 (*_blossom_data)[blossom].next = _fractional->matching(n); 3056 (*_blossom_data)[blossom].pot = 0; 3057 (*_blossom_data)[blossom].offset = 0; 3058 ++index; 3059 } 3060 3061 typename Graph::template NodeMap<bool> processed(_graph, false); 3062 for (NodeIt n(_graph); n != INVALID; ++n) { 3063 if (processed[n]) continue; 3064 processed[n] = true; 3065 if (_fractional->matching(n) == INVALID) continue; 3066 int num = 1; 3067 Node v = _graph.target(_fractional->matching(n)); 3068 while (n != v) { 3069 processed[v] = true; 3070 v = _graph.target(_fractional->matching(v)); 3071 ++num; 3072 } 3073 3074 if (num % 2 == 1) { 3075 std::vector<int> subblossoms(num); 3076 3077 subblossoms[--num] = _blossom_set->find(n); 3078 v = _graph.target(_fractional->matching(n)); 3079 while (n != v) { 3080 subblossoms[--num] = _blossom_set->find(v); 3081 v = _graph.target(_fractional->matching(v)); 3082 } 3083 3084 int surface = 3085 _blossom_set->join(subblossoms.begin(), subblossoms.end()); 3086 (*_blossom_data)[surface].status = EVEN; 3087 (*_blossom_data)[surface].pred = INVALID; 3088 (*_blossom_data)[surface].next = INVALID; 3089 (*_blossom_data)[surface].pot = 0; 3090 (*_blossom_data)[surface].offset = 0; 3091 3092 _tree_set->insert(surface); 3093 ++_unmatched; 3094 } 3095 } 3096 3097 for (EdgeIt e(_graph); e != INVALID; ++e) { 3098 int si = (*_node_index)[_graph.u(e)]; 3099 int sb = _blossom_set->find(_graph.u(e)); 3100 int ti = (*_node_index)[_graph.v(e)]; 3101 int tb = _blossom_set->find(_graph.v(e)); 3102 if ((*_blossom_data)[sb].status == EVEN && 3103 (*_blossom_data)[tb].status == EVEN && sb != tb) { 3104 _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - 3105 dualScale * _weight[e]) / 2); 3106 } 3107 } 3108 3109 for (NodeIt n(_graph); n != INVALID; ++n) { 3110 int nb = _blossom_set->find(n); 3111 if ((*_blossom_data)[nb].status != MATCHED) continue; 3112 int ni = (*_node_index)[n]; 3113 3114 for (OutArcIt e(_graph, n); e != INVALID; ++e) { 3115 Node v = _graph.target(e); 3116 int vb = _blossom_set->find(v); 3117 int vi = (*_node_index)[v]; 3118 3119 Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - 3120 dualScale * _weight[e]; 3121 3122 if ((*_blossom_data)[vb].status == EVEN) { 3123 3124 int vt = _tree_set->find(vb); 3125 3126 typename std::map<int, Arc>::iterator it = 3127 (*_node_data)[ni].heap_index.find(vt); 3128 3129 if (it != (*_node_data)[ni].heap_index.end()) { 3130 if ((*_node_data)[ni].heap[it->second] > rw) { 3131 (*_node_data)[ni].heap.replace(it->second, e); 3132 (*_node_data)[ni].heap.decrease(e, rw); 3133 it->second = e; 3134 } 3135 } else { 3136 (*_node_data)[ni].heap.push(e, rw); 3137 (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); 3138 } 3139 } 3140 } 3141 3142 if (!(*_node_data)[ni].heap.empty()) { 3143 _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); 3144 _delta2->push(nb, _blossom_set->classPrio(nb)); 3145 } 3146 } 3147 } 3148 2973 3149 /// \brief Start the algorithm 2974 3150 /// 2975 3151 /// This function starts the algorithm. 2976 3152 /// 2977 /// \pre \ref init() must be called before using this function. 3153 /// \pre \ref init() or \ref fractionalInit() must be called before 3154 /// using this function. 2978 3155 bool start() { 2979 3156 enum OpType { … … 2981 3158 }; 2982 3159 2983 int unmatched = _node_num; 2984 while (unmatched > 0) { 3160 if (_unmatched == -1) return false; 3161 3162 while (_unmatched > 0) { 2985 3163 Value d2 = !_delta2->empty() ? 2986 3164 _delta2->prio() : std::numeric_limits<Value>::max(); … … 2992 3170 _delta4->prio() : std::numeric_limits<Value>::max(); 2993 3171 2994 _delta_sum = d 2; OpType ot = D2;2995 if (d 3 < _delta_sum) { _delta_sum = d3; ot = D3; }3172 _delta_sum = d3; OpType ot = D3; 3173 if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } 2996 3174 if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } 2997 3175 … … 3026 3204 } else { 3027 3205 augmentOnEdge(e); 3028 unmatched -= 2;3206 _unmatched -= 2; 3029 3207 } 3030 3208 } … … 3045 3223 /// \note mwpm.run() is just a shortcut of the following code. 3046 3224 /// \code 3047 /// mwpm. init();3225 /// mwpm.fractionalInit(); 3048 3226 /// mwpm.start(); 3049 3227 /// \endcode 3050 3228 bool run() { 3051 init();3229 fractionalInit(); 3052 3230 return start(); 3053 3231 } … … 3056 3234 3057 3235 /// \name Primal Solution 3058 /// Functions to get the primal solution, i.e. the maximum weighted 3236 /// Functions to get the primal solution, i.e. the maximum weighted 3059 3237 /// perfect matching.\n 3060 3238 /// Either \ref run() or \ref start() function should be called before … … 3075 3253 } 3076 3254 } 3077 return sum / =2;3255 return sum / 2; 3078 3256 } 3079 3257 3080 3258 /// \brief Return \c true if the given edge is in the matching. 3081 3259 /// 3082 /// This function returns \c true if the given edge is in the found 3260 /// This function returns \c true if the given edge is in the found 3083 3261 /// matching. 3084 3262 /// … … 3091 3269 /// 3092 3270 /// This function returns the matching arc (or edge) incident to the 3093 /// given node in the found matching or \c INVALID if the node is 3271 /// given node in the found matching or \c INVALID if the node is 3094 3272 /// not covered by the matching. 3095 3273 /// … … 3109 3287 /// \brief Return the mate of the given node. 3110 3288 /// 3111 /// This function returns the mate of the given node in the found 3289 /// This function returns the mate of the given node in the found 3112 3290 /// matching or \c INVALID if the node is not covered by the matching. 3113 3291 /// … … 3128 3306 /// \brief Return the value of the dual solution. 3129 3307 /// 3130 /// This function returns the value of the dual solution. 3131 /// It should be equal to the primal value scaled by \ref dualScale 3308 /// This function returns the value of the dual solution. 3309 /// It should be equal to the primal value scaled by \ref dualScale 3132 3310 /// "dual scale". 3133 3311 /// … … 3184 3362 /// \brief Iterator for obtaining the nodes of a blossom. 3185 3363 /// 3186 /// This class provides an iterator for obtaining the nodes of the 3364 /// This class provides an iterator for obtaining the nodes of the 3187 3365 /// given blossom. It lists a subset of the nodes. 3188 /// Before using this iterator, you must allocate a 3366 /// Before using this iterator, you must allocate a 3189 3367 /// MaxWeightedPerfectMatching class and execute it. 3190 3368 class BlossomIt { … … 3195 3373 /// Constructor to get the nodes of the given variable. 3196 3374 /// 3197 /// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()" 3198 /// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()" 3375 /// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()" 3376 /// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()" 3199 3377 /// must be called before initializing this iterator. 3200 3378 BlossomIt(const MaxWeightedPerfectMatching& algorithm, int variable) … … 3242 3420 } //END OF NAMESPACE LEMON 3243 3421 3244 #endif //LEMON_MA X_MATCHING_H3422 #endif //LEMON_MATCHING_H -
test/CMakeLists.txt
r799 r874 22 22 error_test 23 23 euler_test 24 fractional_matching_test 24 25 gomory_hu_test 25 26 graph_copy_test -
test/Makefile.am
r799 r874 24 24 test/error_test \ 25 25 test/euler_test \ 26 test/fractional_matching_test \ 26 27 test/gomory_hu_test \ 27 28 test/graph_copy_test \ … … 72 73 test_error_test_SOURCES = test/error_test.cc 73 74 test_euler_test_SOURCES = test/euler_test.cc 75 test_fractional_matching_test_SOURCES = test/fractional_matching_test.cc 74 76 test_gomory_hu_test_SOURCES = test/gomory_hu_test.cc 75 77 test_graph_copy_test_SOURCES = test/graph_copy_test.cc -
test/matching_test.cc
r594 r870 402 402 edgeMap("weight", weight).run(); 403 403 404 MaxMatching<SmartGraph> mm(graph); 405 mm.run(); 406 checkMatching(graph, mm); 407 408 MaxWeightedMatching<SmartGraph> mwm(graph, weight); 409 mwm.run(); 410 checkWeightedMatching(graph, weight, mwm); 411 412 MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight); 413 bool perfect = mwpm.run(); 414 415 check(perfect == (mm.matchingSize() * 2 == countNodes(graph)), 416 "Perfect matching found"); 417 418 if (perfect) { 419 checkWeightedPerfectMatching(graph, weight, mwpm); 404 bool perfect; 405 { 406 MaxMatching<SmartGraph> mm(graph); 407 mm.run(); 408 checkMatching(graph, mm); 409 perfect = 2 * mm.matchingSize() == countNodes(graph); 410 } 411 412 { 413 MaxWeightedMatching<SmartGraph> mwm(graph, weight); 414 mwm.run(); 415 checkWeightedMatching(graph, weight, mwm); 416 } 417 418 { 419 MaxWeightedMatching<SmartGraph> mwm(graph, weight); 420 mwm.init(); 421 mwm.start(); 422 checkWeightedMatching(graph, weight, mwm); 423 } 424 425 { 426 MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight); 427 bool result = mwpm.run(); 428 429 check(result == perfect, "Perfect matching found"); 430 if (perfect) { 431 checkWeightedPerfectMatching(graph, weight, mwpm); 432 } 433 } 434 435 { 436 MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight); 437 mwpm.init(); 438 bool result = mwpm.start(); 439 440 check(result == perfect, "Perfect matching found"); 441 if (perfect) { 442 checkWeightedPerfectMatching(graph, weight, mwpm); 443 } 420 444 } 421 445 }
Note: See TracChangeset
for help on using the changeset viewer.