Ticket #168: bp_benchmark_7a790fbf8e7d.patch
File bp_benchmark_7a790fbf8e7d.patch, 19.9 KB (added by , 13 years ago) |
---|
-
lemon/dimacs.h
# HG changeset patch # User Daniel Poroszkai <poroszd@inf.elte.hu> # Date 1328316823 -3600 # Node ID 7a790fbf8e7d87e25b4be47f0034b13eecca836b # Parent 1c65e16c4264a0373f232d59ab494d33a7fa3260 Tools for bipartite matching benchmarks diff --git a/lemon/dimacs.h b/lemon/dimacs.h
a b 2 2 * 3 3 * This file is a part of LEMON, a generic C++ optimization library. 4 4 * 5 * Copyright (C) 2003-201 05 * Copyright (C) 2003-2012 6 6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport 7 7 * (Egervary Research Group on Combinatorial Optimization, EGRES). 8 8 * … … 45 45 MIN, ///< DIMACS file type for minimum cost flow problems. 46 46 MAX, ///< DIMACS file type for maximum flow problems. 47 47 SP, ///< DIMACS file type for shostest path problems. 48 MAT ///< DIMACS file type for plain graphs and matching problems. 48 MAT, ///< DIMACS file type for plain graphs and matching problems. 49 ASN, ///< DIMACS file type for assignment problems. 50 UBM, ///< DIMACS file type for unweighted bipartite matching problems. 51 WBM ///< DIMACS file type for weighted bipartite matching problems. 49 52 }; 50 53 ///The file type 51 54 Type type; … … 82 85 else if(problem=="max") r.type=DimacsDescriptor::MAX; 83 86 else if(problem=="sp") r.type=DimacsDescriptor::SP; 84 87 else if(problem=="mat") r.type=DimacsDescriptor::MAT; 88 else if(problem=="asn") r.type=DimacsDescriptor::ASN; 89 else if(problem=="ubm") r.type=DimacsDescriptor::UBM; 90 else if(problem=="wbm") r.type=DimacsDescriptor::WBM; 85 91 else throw FormatError("Unknown problem type"); 86 92 return r; 87 93 } … … 101 107 } 102 108 103 109 110 111 /// \brief DIMACS unweighted bipartite matching problem reader function. 112 /// 113 /// This function reads an unweighted bipartite matching problem instance 114 /// from DIMACS format, i.e. from a DIMACS file having a line starting with 115 /// \code 116 /// p ubm 117 /// \endcode 118 /// and creates the corresponding bipartite graph. 119 /// 120 /// At the beginning, \c g is cleared by \c g.clear(). 121 /// 122 /// If the file type was previously evaluated by dimacsType(), then 123 /// the descriptor struct should be given by the \c dest parameter. 124 template <typename BpGraph> 125 void readDimacsUbm(std::istream& is, 126 BpGraph &g, 127 DimacsDescriptor desc=DimacsDescriptor()) 128 { 129 g.clear(); 130 131 if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); 132 if(desc.type!=DimacsDescriptor::UBM) 133 throw FormatError("Problem type mismatch"); 134 135 std::vector<typename BpGraph::Node> nodes(desc.nodeNum + 1, INVALID); 136 typename BpGraph::Edge e; 137 std::string problem, str; 138 char c; 139 int i, j; 140 141 // eat up comment lines and problem line 142 while (is >> c && (c=='c' || c=='p')) { 143 getline(is, str); 144 } 145 is.unget(); 146 147 // reading red nodes 148 while (is >> c && c == 'n') { 149 is >> i; 150 getline(is, str); 151 nodes[i] = g.addRedNode(); 152 } 153 154 // remaining nodes are blue: 155 for (int k = 1; k <= desc.nodeNum; ++k) { 156 if (nodes[k] == INVALID) nodes[k] = g.addBlueNode(); 157 } 158 159 // reading edges 160 if (c == 'a') { 161 is >> i >> j; 162 getline(is, str); 163 e = g.addEdge(nodes[i], nodes[j]); 164 } 165 while (is >> c && c == 'a') { 166 is >> i >> j; 167 getline(is, str); 168 e = g.addEdge(nodes[i], nodes[j]); 169 } 170 } 171 172 173 /// \brief DIMACS weighted bipartite matching problem reader function. 174 /// 175 /// This function reads a weighted bipartite matching problem instance from 176 /// DIMACS format, i.e. from a DIMACS file having a line starting with 177 /// \code 178 /// p wbm 179 /// \endcode 180 /// and creates the corresponding bipartite graph and weight map. 181 /// 182 /// At the beginning, \c g is cleared by \c g.clear(). 183 /// 184 /// If the file type was previously evaluated by dimacsType(), then 185 /// the descriptor struct should be given by the \c dest parameter. 186 template <typename BpGraph, typename WeightMap> 187 void readDimacsWbm(std::istream& is, 188 BpGraph &g, 189 WeightMap &m, 190 DimacsDescriptor desc=DimacsDescriptor()) 191 { 192 g.clear(); 193 194 if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); 195 if(desc.type!=DimacsDescriptor::WBM) 196 throw FormatError("Problem type mismatch"); 197 198 std::vector<typename BpGraph::Node> nodes(desc.nodeNum + 1, INVALID); 199 typename BpGraph::Edge e; 200 std::string problem, str; 201 char c; 202 int i, j; 203 typename WeightMap::Value w; 204 205 // eat up comment lines and problem line 206 while (is >> c && (c=='c' || c=='p')) { 207 getline(is, str); 208 } 209 is.unget(); 210 211 // reading red nodes 212 while (is >> c && c == 'n') { 213 is >> i; 214 getline(is, str); 215 nodes[i] = g.addRedNode(); 216 } 217 is.unget(); 218 219 // remaining nodes are blue: 220 for (int k = 1; k <= desc.nodeNum; ++k) { 221 if (nodes[k] == INVALID) nodes[k] = g.addBlueNode(); 222 } 223 224 // reading edges and weights 225 while (is >> c && c == 'a') { 226 is >> i >> j >> w; 227 getline(is, str); 228 e = g.addEdge(nodes[i], nodes[j]); 229 m.set(e, w); 230 } 231 } 232 233 234 /// \brief DIMACS assignment problem reader function. 235 /// 236 /// This function reads an assignment problem instance from DIMACS format, 237 /// i.e. from a DIMACS file having a line starting with 238 /// \code 239 /// p asn 240 /// \endcode 241 /// and creates the corresponding digraph, arc cost- and supply map. 242 /// 243 /// At the beginning, \c g is cleared by \c g.clear(). 244 /// Cost of the arcs are written to the cost map, 245 /// and the supply map contains the supply of the nodes, which is 246 /// 1 for sources and -1 for sink nodes. 247 /// 248 /// If the file type was previously evaluated by dimacsType(), then 249 /// the descriptor struct should be given by the \c dest parameter. 250 template <typename Digraph, typename CostMap> 251 void readDimacsAsn(std::istream& is, 252 Digraph &g, 253 CostMap &cost, 254 typename Digraph::template NodeMap<int> &supply, 255 DimacsDescriptor desc=DimacsDescriptor()) 256 { 257 g.clear(); 258 259 if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); 260 if(desc.type!=DimacsDescriptor::ASN) 261 throw FormatError("Problem type mismatch"); 262 263 std::vector<typename Digraph::Node> nodes(desc.nodeNum + 1, INVALID); 264 typename Digraph::Arc e; 265 std::string problem, str; 266 char c; 267 int i, j; 268 typename CostMap::Value co; 269 270 for (int k = 1; k <= desc.nodeNum; ++k) { 271 nodes[k] = g.addNode(); 272 supply.set(nodes[k], -1); 273 } 274 275 // eat up comment lines and problem line 276 while (is >> c && (c=='c' || c=='p')) { 277 getline(is, str); 278 } 279 is.unget(); 280 281 // reading source nodes 282 while (is >> c && c == 'n') { 283 is >> i; 284 getline(is, str); 285 supply.set(nodes[i], 1); 286 } 287 is.unget(); 288 289 // reading arcs 290 while (is >> c && c == 'a') { 291 is >> i >> j >> co; 292 getline(is, str); 293 e = g.addArc(nodes[i], nodes[j]); 294 cost.set(e, co); 295 } 296 } 297 104 298 /// \brief DIMACS minimum cost flow reader function. 105 299 /// 106 300 /// This function reads a minimum cost flow instance from DIMACS format, -
tools/CMakeLists.txt
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
a b 16 16 ADD_EXECUTABLE(dimacs-solver dimacs-solver.cc) 17 17 TARGET_LINK_LIBRARIES(dimacs-solver lemon) 18 18 19 ADD_EXECUTABLE(bp-matching-benchmark bp-matching-benchmark.cc) 20 TARGET_LINK_LIBRARIES(bp-matching-benchmark lemon) 21 22 ADD_EXECUTABLE(weighted-bp-gen weighted-bp-gen.cc) 23 TARGET_LINK_LIBRARIES(weighted-bp-gen lemon) 24 25 ADD_EXECUTABLE(unweighted-bp-gen unweighted-bp-gen.cc) 26 TARGET_LINK_LIBRARIES(unweighted-bp-gen lemon) 27 19 28 INSTALL( 20 29 TARGETS lgf-gen dimacs-to-lgf dimacs-solver 21 30 RUNTIME DESTINATION bin -
new file tools/bp-matching-benchmark.cc
diff --git a/tools/bp-matching-benchmark.cc b/tools/bp-matching-benchmark.cc new file mode 100644
- + 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-2012 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 #include <lemon/dimacs.h> 20 #include <lemon/maps.h> 21 #include <lemon/smart_graph.h> 22 #include <lemon/time_measure.h> 23 #include <lemon/hopcroft_karp.h> 24 #include <lemon/matching.h> 25 #include <lemon/preflow.h> 26 #include <lemon/bp_matching.h> 27 #include <iostream> 28 29 using namespace std; 30 using namespace lemon; 31 32 33 template <typename BpGraph, typename Digraph> 34 void create_network(const BpGraph &bpg, 35 Digraph &network, 36 typename Digraph::Node &source, 37 typename Digraph::Node &sink) 38 { 39 network.clear(); 40 source = network.addNode(); 41 sink = network.addNode(); 42 43 typename BpGraph::template NodeMap<typename Digraph::Node> xref(bpg); 44 for (typename BpGraph::RedIt r(bpg); r!=INVALID; ++r) { 45 xref.set(r, network.addNode()); 46 network.addArc(source, xref[r]); 47 } 48 for (typename BpGraph::BlueIt b(bpg); b!=INVALID; ++b) { 49 xref.set(b, network.addNode()); 50 network.addArc(xref[b], sink); 51 } 52 53 for (typename BpGraph::EdgeIt e(bpg); e!=INVALID; ++e) { 54 network.addArc(xref[bpg.redNode(e)], xref[bpg.blueNode(e)]); 55 } 56 } 57 58 typedef SmartDigraph Digraph; 59 typedef SmartBpGraph BpGraph; 60 61 ///\ingroup tools 62 ///\file 63 ///\brief Benchmark program for weighted and unweighted bipartite matching. 64 /// 65 /// The program input is a Dimacs file with a problem line starting 66 /// \code 67 /// p ubm 68 /// \endcode 69 /// or 70 /// \code 71 /// p wbm 72 /// \endcode 73 /// 74 /// Depending on the input, it runs the \ref lemon::HopcroftKarp 75 /// "Hopcroft-Karp", the \ref lemon::MaxMatching "general matching" 76 /// and the \ref lemon::Preflow "Preflow" algorithms for finding 77 /// a maximum cardinality bipartite matching, or the 78 /// \ref lemon::MaxWeightedBipartiteMatching "max. weighted matching 79 /// for sparse bipartite graphs" and the \ref lemon::MaxWeightedMatching 80 /// "max. weighted matching for general graph" to find the maximum 81 /// weighted matching. 82 int main() { 83 DimacsDescriptor desc = dimacsType(cin); 84 if (desc.type == DimacsDescriptor::UBM) { 85 // unweighted bipartite matching 86 Timer hk_t(false), mm_t(false), pf_t(false); 87 88 BpGraph bpg; 89 readDimacsUbm(cin, bpg, desc); 90 91 Digraph network; 92 Digraph::Node source, target; 93 create_network(bpg, network, source, target); 94 95 hk_t.start(); 96 HopcroftKarp<BpGraph> hk(bpg); 97 hk.run(); 98 hk_t.stop(); 99 100 mm_t.start(); 101 MaxMatching<BpGraph> mm(bpg); 102 mm.run(); 103 mm_t.stop(); 104 105 pf_t.start(); 106 Preflow<Digraph, ConstMap<Digraph::Arc, int> > 107 pf(network, constMap<Digraph::Arc, int>(1), source, target); 108 pf.run(); 109 pf_t.stop(); 110 111 cout << "Benchmarking in unweighted case, using a bipartite graph\n" 112 << "with " << countRedNodes(bpg) << " red, " 113 << countBlueNodes(bpg) << " blue nodes, and " 114 << desc.edgeNum << " edges.\n" 115 << "--------------------------------------------------------\n" 116 << "Algorithm used Matching size Time\n" 117 << "Hopcroft-Karp " << hk.matchingSize() 118 << " " << hk_t.realTime() << "\n" 119 << "General matching " << mm.matchingSize() 120 << " " << mm_t.realTime() << "\n" 121 << "Preflow " << pf.flowValue() 122 << " " << pf_t.realTime() << endl; 123 124 } else if (desc.type == DimacsDescriptor::WBM) { 125 // weighted bipartite matching 126 Timer bm_t(false), gm_t(false); 127 128 BpGraph bpg; 129 BpGraph::EdgeMap<int> weight(bpg); 130 readDimacsWbm(cin, bpg, weight, desc); 131 132 bm_t.start(); 133 MaxWeightedBipartiteMatching<BpGraph> bm(bpg, weight); 134 bm.run(); 135 bm_t.stop(); 136 137 gm_t.start(); 138 MaxWeightedMatching<BpGraph> gm(bpg, weight); 139 gm.run(); 140 gm_t.stop(); 141 142 cout << "Benchmarking on weighted bipartite matching problem on a " 143 << "graph\nwith " << countRedNodes(bpg) << " red, " 144 << countBlueNodes(bpg) << " blue nodes and " 145 << desc.edgeNum << " edges\n" 146 << "--------------------------------------------------------\n" 147 << "Algorithm used Maximum weight Time\n" 148 << "Bipartite matching " << bm.matchingWeight() 149 << " " << bm_t.realTime() << "\n" 150 << "General matching " << gm.matchingWeight() 151 << " " << gm_t.realTime() << endl; 152 153 } else { 154 cerr << "Wrong problem type." << endl; 155 return 1; 156 } 157 158 return 0; 159 } -
new file tools/unweighted-bp-gen.cc
diff --git a/tools/unweighted-bp-gen.cc b/tools/unweighted-bp-gen.cc new file mode 100644
- + 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-2012 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 #include <lemon/arg_parser.h> 20 #include <lemon/random.h> 21 22 using namespace lemon; 23 using namespace std; 24 25 ///\ingroup tools 26 ///\file 27 ///\brief Random bipartite graph generator. 28 /// 29 /// This program generates an unweighted bipartite matching problem. 30 /// The output is in Dimacs format, with problem type of 'ubm'. The 31 /// enumerated nodes form one set of the bipartite graph, and 32 /// the edges do not have any label. 33 int main(int argc, char** argv) { 34 int seed = 1, 35 red = 5, 36 blue = 5, 37 density = 10; 38 39 ArgParser arg_p(argc, argv); 40 41 arg_p.refOption("seed", 42 "Seed of the random number generator (default: 1)", 43 seed) 44 .refOption("red", 45 "Number of red nodes (default: 5)", 46 red) 47 .refOption("blue", 48 "Number of blue nodes (default: 5)", 49 blue) 50 .refOption("density", 51 "Number of edges (default: 10)", 52 density); 53 54 arg_p.synonym("s", "seed") 55 .synonym("r", "red") 56 .synonym("b", "blue") 57 .synonym("d", "density"); 58 59 arg_p.parse(); 60 61 rnd.seed(seed); 62 63 64 long max_edge = red*blue; 65 long edge_left = density; 66 67 if (max_edge < density) { 68 cerr << "Too many edges!\n" 69 << "At most " << max_edge << " edges can be placed in the graph.\n"; 70 return 1; 71 } 72 73 cout << "c Random bipartite graph for bipartite matching\n" 74 << "c----------------------------------------------\n" 75 << "c Input parameters:\n" 76 << "c Random seed: " << seed << "\n" 77 << "c Number of nodes: " << red + blue << "\n" 78 << "c Number of red nodes: " << red << "\n" 79 << "c Number of blue nodes: " << blue << "\n" 80 << "c Number of edges: " << density << "\n" 81 << "c----------------------------------------------\n"; 82 cout << "p ubm " << red + blue << " " << density << "\n"; 83 84 // red nodes: 85 for (int r=1; r <= red; ++r) { 86 cout << "n " << r << "\n"; 87 } 88 89 // edges: 90 for (int r = 1; r <= red; ++r) { 91 for (int b = red+1; b <= red + blue; ++b) { 92 if (rnd.boolean(static_cast<long double>(edge_left) / max_edge)) { 93 --edge_left; 94 cout << "a " << r << " " << b << "\n"; 95 } 96 --max_edge; 97 } 98 } 99 100 return 0; 101 } 102 -
new file tools/weighted-bp-gen.cc
diff --git a/tools/weighted-bp-gen.cc b/tools/weighted-bp-gen.cc new file mode 100644
- + 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-2012 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 #include <lemon/arg_parser.h> 20 #include <lemon/random.h> 21 22 using namespace lemon; 23 using namespace std; 24 25 ///\ingroup tools 26 ///\file 27 ///\brief Random weighted bipartite graph generator. 28 /// 29 /// This program generates a weighted bipartite matching problem. 30 /// The output is in Dimacs format, with problem type of 'wbm'. The 31 /// enumerated nodes form one set of the bipartite graph, and 32 /// the edge labels denote weights. 33 int main(int argc, char** argv) { 34 int seed = 1, 35 red = 5, 36 blue = 5, 37 density = 10, 38 minweight = 10, 39 maxweight = 100; 40 41 ArgParser arg_p(argc, argv); 42 43 arg_p.refOption("seed", 44 "Seed of the random number generator (default: 1)", 45 seed) 46 .refOption("red", 47 "Number of red nodes (default: 5)", 48 red) 49 .refOption("blue", 50 "Number of blue nodes (default: 5)", 51 blue) 52 .refOption("density", 53 "Number of edges (default: 10)", 54 density) 55 .refOption("minweight", 56 "Minimal weight of edges (default: 10)", 57 minweight) 58 .refOption("maxweight", 59 "Maximal weight of edges (default: 100", 60 maxweight); 61 62 arg_p.synonym("s", "seed") 63 .synonym("r", "red") 64 .synonym("b", "blue") 65 .synonym("d", "density") 66 .synonym("min", "minweight") 67 .synonym("max", "maxweight"); 68 69 arg_p.parse(); 70 71 rnd.seed(seed); 72 73 74 long max_edge = red*blue; 75 long edge_left = density; 76 77 if (max_edge < density) { 78 cerr << "Too many edges!\n" 79 << "At most " << max_edge << " edges can be placed in the graph.\n"; 80 return 1; 81 } 82 if (minweight > maxweight) { 83 cerr << "Inconsistent weights!\n" 84 << "The minimal weight should not be higher than the maximal.\n"; 85 return 1; 86 } 87 88 cout << "c Random bipartite graph for weighted bipartite matching\n" 89 << "c----------------------------------------------\n" 90 << "c Input parameters:\n" 91 << "c Random seed: " << seed << "\n" 92 << "c Number of nodes: " << red + blue << "\n" 93 << "c Number of red nodes: " << red << "\n" 94 << "c Number of blue nodes: " << blue << "\n" 95 << "c Number of edges: " << density << "\n" 96 << "c Minimal weight of edges: " << minweight << "\n" 97 << "c Maximal weight of edges: " << maxweight << "\n" 98 << "c----------------------------------------------\n"; 99 cout << "p wbm " << red + blue << " " << density << "\n"; 100 101 // red nodes: 102 for (int r=1; r <= red; ++r) { 103 cout << "n " << r << "\n"; 104 } 105 106 // edges: 107 for (int r = 1; r <= red; ++r) { 108 for (int b = red+1; b <= red + blue; ++b) { 109 if (rnd.boolean(static_cast<long double>(edge_left) / max_edge)) { 110 --edge_left; 111 cout << "a " << r << " " << b << " " 112 << rnd.integer(minweight, maxweight+1) << "\n"; 113 } 114 --max_edge; 115 } 116 } 117 118 return 0; 119 } 120