Ticket #168: bp_benchmark_ea93dc149092.patch
File bp_benchmark_ea93dc149092.patch, 20.5 KB (added by , 13 years ago) |
---|
-
lemon/dimacs.h
# HG changeset patch # User Daniel Poroszkai <poroszd@inf.elte.hu> # Date 1328397809 -3600 # Node ID ea93dc1490922914aac7dbfaeb71e9cffa7eaf6d # Parent 55711f25c446935bd8fda1fa3c6b556d3679c041 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 is.unget(); 154 155 // remaining nodes are blue: 156 for (int k = 1; k <= desc.nodeNum; ++k) { 157 if (nodes[k] == INVALID) nodes[k] = g.addBlueNode(); 158 } 159 160 // reading edges 161 while (is >> c && c == 'a') { 162 is >> i >> j; 163 getline(is, str); 164 e = g.addEdge(g.asRedNode(nodes[i]), g.asBlueNode(nodes[j])); 165 } 166 } 167 168 169 /// \brief DIMACS weighted bipartite matching problem reader function. 170 /// 171 /// This function reads a weighted bipartite matching problem instance from 172 /// DIMACS format, i.e. from a DIMACS file having a line starting with 173 /// \code 174 /// p wbm 175 /// \endcode 176 /// and creates the corresponding bipartite graph and weight map. 177 /// 178 /// At the beginning, \c g is cleared by \c g.clear(). 179 /// 180 /// If the file type was previously evaluated by dimacsType(), then 181 /// the descriptor struct should be given by the \c dest parameter. 182 template <typename BpGraph, typename WeightMap> 183 void readDimacsWbm(std::istream& is, 184 BpGraph &g, 185 WeightMap &m, 186 DimacsDescriptor desc=DimacsDescriptor()) 187 { 188 g.clear(); 189 190 if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); 191 if(desc.type!=DimacsDescriptor::WBM) 192 throw FormatError("Problem type mismatch"); 193 194 std::vector<typename BpGraph::Node> nodes(desc.nodeNum + 1, INVALID); 195 typename BpGraph::Edge e; 196 std::string problem, str; 197 char c; 198 int i, j; 199 typename WeightMap::Value w; 200 201 // eat up comment lines and problem line 202 while (is >> c && (c=='c' || c=='p')) { 203 getline(is, str); 204 } 205 is.unget(); 206 207 // reading red nodes 208 while (is >> c && c == 'n') { 209 is >> i; 210 getline(is, str); 211 nodes[i] = g.addRedNode(); 212 } 213 is.unget(); 214 215 // remaining nodes are blue: 216 for (int k = 1; k <= desc.nodeNum; ++k) { 217 if (nodes[k] == INVALID) nodes[k] = g.addBlueNode(); 218 } 219 220 // reading edges and weights 221 while (is >> c && c == 'a') { 222 is >> i >> j >> w; 223 getline(is, str); 224 e = g.addEdge(g.asRedNode(nodes[i]), g.asBlueNode(nodes[j])); 225 m.set(e, w); 226 } 227 } 228 229 230 /// \brief DIMACS assignment problem reader function. 231 /// 232 /// This function reads an assignment problem instance from DIMACS format, 233 /// i.e. from a DIMACS file having a line starting with 234 /// \code 235 /// p asn 236 /// \endcode 237 /// and creates the corresponding digraph, arc cost- and supply map. 238 /// 239 /// At the beginning, \c g is cleared by \c g.clear(). 240 /// Cost of the arcs are written to the cost map, 241 /// and the supply map contains the supply of the nodes, which is 242 /// 1 for sources and -1 for sink nodes. 243 /// 244 /// If the file type was previously evaluated by dimacsType(), then 245 /// the descriptor struct should be given by the \c dest parameter. 246 template <typename Digraph, typename CostMap> 247 void readDimacsAsn(std::istream& is, 248 Digraph &g, 249 CostMap &cost, 250 typename Digraph::template NodeMap<int> &supply, 251 DimacsDescriptor desc=DimacsDescriptor()) 252 { 253 g.clear(); 254 255 if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); 256 if(desc.type!=DimacsDescriptor::ASN) 257 throw FormatError("Problem type mismatch"); 258 259 std::vector<typename Digraph::Node> nodes(desc.nodeNum + 1, INVALID); 260 typename Digraph::Arc e; 261 std::string problem, str; 262 char c; 263 int i, j; 264 typename CostMap::Value co; 265 266 for (int k = 1; k <= desc.nodeNum; ++k) { 267 nodes[k] = g.addNode(); 268 supply.set(nodes[k], -1); 269 } 270 271 // eat up comment lines and problem line 272 while (is >> c && (c=='c' || c=='p')) { 273 getline(is, str); 274 } 275 is.unget(); 276 277 // reading source nodes 278 while (is >> c && c == 'n') { 279 is >> i; 280 getline(is, str); 281 supply.set(nodes[i], 1); 282 } 283 is.unget(); 284 285 // reading arcs 286 while (is >> c && c == 'a') { 287 is >> i >> j >> co; 288 getline(is, str); 289 e = g.addArc(nodes[i], nodes[j]); 290 cost.set(e, co); 291 } 292 } 293 104 294 /// \brief DIMACS minimum cost flow reader function. 105 295 /// 106 296 /// 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(weighted-bp-gen weighted-bp-gen.cc) 20 TARGET_LINK_LIBRARIES(weighted-bp-gen lemon) 21 22 ADD_EXECUTABLE(unweighted-bp-gen unweighted-bp-gen.cc) 23 TARGET_LINK_LIBRARIES(unweighted-bp-gen lemon) 24 25 ADD_EXECUTABLE(bp-matching-benchmark bp-matching-benchmark.cc) 26 TARGET_LINK_LIBRARIES(bp-matching-benchmark lemon) 27 19 28 INSTALL( 20 29 TARGETS lgf-gen dimacs-to-lgf dimacs-solver 21 30 RUNTIME DESTINATION bin -
tools/Makefile.am
diff --git a/tools/Makefile.am b/tools/Makefile.am
a b 4 4 if WANT_TOOLS 5 5 6 6 bin_PROGRAMS += \ 7 tools/bp-matching-benchmark \ 7 8 tools/dimacs-solver \ 8 9 tools/dimacs-to-lgf \ 9 tools/lgf-gen 10 tools/lgf-gen \ 11 tools/unweighted-bp-gen \ 12 tools/weighted-bp-gen 10 13 11 14 dist_bin_SCRIPTS += tools/lemon-0.x-to-1.x.sh 12 15 13 16 endif WANT_TOOLS 14 17 18 tools_bp_matching_benchmark_SOURCES = tools/bp-matching-benchmark.cc 15 19 tools_dimacs_solver_SOURCES = tools/dimacs-solver.cc 16 20 tools_dimacs_to_lgf_SOURCES = tools/dimacs-to-lgf.cc 17 21 tools_lgf_gen_SOURCES = tools/lgf-gen.cc 22 tools_unweighted_bp_gen_SOURCES = tools/unweighted-bp-gen.cc 23 tools_weighted_bp_gen_SOURCES = tools/weighted-bp-gen.cc 24 No newline at end of file -
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::RedNodeIt r(bpg); r!=INVALID; ++r) { 45 xref.set(r, network.addNode()); 46 network.addArc(source, xref[r]); 47 } 48 for (typename BpGraph::BlueNodeIt 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::MaxWeightedBpMatching "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 MaxWeightedBpMatching<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 83 cout << "c Random bipartite graph for weighted bipartite matching\n" 84 << "c----------------------------------------------\n" 85 << "c Input parameters:\n" 86 << "c Random seed: " << seed << "\n" 87 << "c Number of nodes: " << red + blue << "\n" 88 << "c Number of red nodes: " << red << "\n" 89 << "c Number of blue nodes: " << blue << "\n" 90 << "c Number of edges: " << density << "\n" 91 << "c Minimal weight of edges: " << minweight << "\n" 92 << "c Maximal weight of edges: " << maxweight << "\n" 93 << "c----------------------------------------------\n"; 94 cout << "p wbm " << red + blue << " " << density << "\n"; 95 96 // red nodes: 97 for (int r=1; r <= red; ++r) { 98 cout << "n " << r << "\n"; 99 } 100 101 // edges: 102 for (int r = 1; r <= red; ++r) { 103 for (int b = red+1; b <= red + blue; ++b) { 104 if (rnd.boolean(static_cast<long double>(edge_left) / max_edge)) { 105 --edge_left; 106 cout << "a " << r << " " << b << " " 107 << rnd.integer(minweight, maxweight+1) << "\n"; 108 } 109 --max_edge; 110 } 111 } 112 113 return 0; 114 } 115