COIN-OR::LEMON - Graph Library

Ticket #168: bp_benchmark_7a790fbf8e7d.patch

File bp_benchmark_7a790fbf8e7d.patch, 19.9 KB (added by Poroszkai Daniel, 9 years ago)

Bipartite matching benchmark tools

  • 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  
    22 *
    33 * This file is a part of LEMON, a generic C++ optimization library.
    44 *
    5  * Copyright (C) 2003-2010
     5 * Copyright (C) 2003-2012
    66 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    77 * (Egervary Research Group on Combinatorial Optimization, EGRES).
    88 *
     
    4545      MIN,   ///< DIMACS file type for minimum cost flow problems.
    4646      MAX,   ///< DIMACS file type for maximum flow problems.
    4747      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.
    4952    };
    5053    ///The file type
    5154    Type type;
     
    8285              else if(problem=="max") r.type=DimacsDescriptor::MAX;
    8386              else if(problem=="sp") r.type=DimacsDescriptor::SP;
    8487              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;
    8591              else throw FormatError("Unknown problem type");
    8692              return r;
    8793            }
     
    101107  }
    102108
    103109
     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
    104298  /// \brief DIMACS minimum cost flow reader function.
    105299  ///
    106300  /// 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  
    1616ADD_EXECUTABLE(dimacs-solver dimacs-solver.cc)
    1717TARGET_LINK_LIBRARIES(dimacs-solver lemon)
    1818
     19ADD_EXECUTABLE(bp-matching-benchmark bp-matching-benchmark.cc)
     20TARGET_LINK_LIBRARIES(bp-matching-benchmark lemon)
     21
     22ADD_EXECUTABLE(weighted-bp-gen weighted-bp-gen.cc)
     23TARGET_LINK_LIBRARIES(weighted-bp-gen lemon)
     24
     25ADD_EXECUTABLE(unweighted-bp-gen unweighted-bp-gen.cc)
     26TARGET_LINK_LIBRARIES(unweighted-bp-gen lemon)
     27
    1928INSTALL(
    2029  TARGETS lgf-gen dimacs-to-lgf dimacs-solver
    2130  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
     29using namespace std;
     30using namespace lemon;
     31
     32
     33template <typename BpGraph, typename Digraph>
     34void 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
     58typedef SmartDigraph Digraph;
     59typedef 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.
     82int 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
     22using namespace lemon;
     23using 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.
     33int 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
     22using namespace lemon;
     23using 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.
     33int 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