tools/dimacs-solver.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 732 bb70ad62c95f
parent 636 6c408d864fa1
parent 622 20dac2104519
child 761 f1398882a928
child 794 c5990f454032
permissions -rw-r--r--
Fix critical bug in preflow (#372)

The wrong transition between the bound decrease and highest active
heuristics caused the bug. The last node chosen in bound decrease mode
is used in the first iteration in highest active mode.
alpar@385
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
alpar@385
     2
 *
alpar@385
     3
 * This file is a part of LEMON, a generic C++ optimization library.
alpar@385
     4
 *
alpar@440
     5
 * Copyright (C) 2003-2009
alpar@385
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@385
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@385
     8
 *
alpar@385
     9
 * Permission to use, modify and distribute this software is granted
alpar@385
    10
 * provided that this copyright notice appears in all copies. For
alpar@385
    11
 * precise terms see the accompanying LICENSE file.
alpar@385
    12
 *
alpar@385
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@385
    14
 * express or implied, and with no claim as to its suitability for any
alpar@385
    15
 * purpose.
alpar@385
    16
 *
alpar@385
    17
 */
alpar@385
    18
alpar@385
    19
///\ingroup tools
alpar@385
    20
///\file
kpeter@518
    21
///\brief DIMACS problem solver.
alpar@385
    22
///
kpeter@518
    23
/// This program solves various problems given in DIMACS format.
alpar@385
    24
///
alpar@385
    25
/// See
kpeter@576
    26
/// \code
kpeter@576
    27
///   dimacs-solver --help
kpeter@576
    28
/// \endcode
alpar@385
    29
/// for more info on usage.
alpar@385
    30
alpar@385
    31
#include <iostream>
alpar@385
    32
#include <fstream>
alpar@385
    33
#include <cstring>
alpar@385
    34
alpar@385
    35
#include <lemon/smart_graph.h>
alpar@385
    36
#include <lemon/dimacs.h>
alpar@385
    37
#include <lemon/lgf_writer.h>
alpar@510
    38
#include <lemon/time_measure.h>
alpar@385
    39
alpar@385
    40
#include <lemon/arg_parser.h>
alpar@387
    41
#include <lemon/error.h>
alpar@385
    42
alpar@510
    43
#include <lemon/dijkstra.h>
alpar@510
    44
#include <lemon/preflow.h>
kpeter@586
    45
#include <lemon/matching.h>
kpeter@594
    46
#include <lemon/network_simplex.h>
alpar@510
    47
alpar@385
    48
using namespace lemon;
alpar@510
    49
typedef SmartDigraph Digraph;
alpar@510
    50
DIGRAPH_TYPEDEFS(Digraph);
alpar@510
    51
typedef SmartGraph Graph;
alpar@385
    52
alpar@510
    53
template<class Value>
alpar@510
    54
void solve_sp(ArgParser &ap, std::istream &is, std::ostream &,
alpar@510
    55
              DimacsDescriptor &desc)
alpar@510
    56
{
alpar@510
    57
  bool report = !ap.given("q");
alpar@510
    58
  Digraph g;
alpar@510
    59
  Node s;
alpar@510
    60
  Digraph::ArcMap<Value> len(g);
alpar@510
    61
  Timer t;
alpar@510
    62
  t.restart();
alpar@510
    63
  readDimacsSp(is, g, len, s, desc);
alpar@510
    64
  if(report) std::cerr << "Read the file: " << t << '\n';
alpar@510
    65
  t.restart();
alpar@510
    66
  Dijkstra<Digraph, Digraph::ArcMap<Value> > dij(g,len);
alpar@510
    67
  if(report) std::cerr << "Setup Dijkstra class: " << t << '\n';
alpar@510
    68
  t.restart();
alpar@510
    69
  dij.run(s);
alpar@510
    70
  if(report) std::cerr << "Run Dijkstra: " << t << '\n';
alpar@510
    71
}
alpar@510
    72
alpar@510
    73
template<class Value>
alpar@510
    74
void solve_max(ArgParser &ap, std::istream &is, std::ostream &,
alpar@552
    75
               Value infty, DimacsDescriptor &desc)
alpar@510
    76
{
alpar@510
    77
  bool report = !ap.given("q");
alpar@510
    78
  Digraph g;
alpar@510
    79
  Node s,t;
alpar@510
    80
  Digraph::ArcMap<Value> cap(g);
alpar@510
    81
  Timer ti;
alpar@510
    82
  ti.restart();
alpar@552
    83
  readDimacsMax(is, g, cap, s, t, infty, desc);
alpar@510
    84
  if(report) std::cerr << "Read the file: " << ti << '\n';
alpar@510
    85
  ti.restart();
alpar@510
    86
  Preflow<Digraph, Digraph::ArcMap<Value> > pre(g,cap,s,t);
alpar@510
    87
  if(report) std::cerr << "Setup Preflow class: " << ti << '\n';
alpar@510
    88
  ti.restart();
alpar@510
    89
  pre.run();
alpar@510
    90
  if(report) std::cerr << "Run Preflow: " << ti << '\n';
alpar@510
    91
  if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n';  
alpar@510
    92
}
alpar@510
    93
kpeter@594
    94
template<class Value>
kpeter@594
    95
void solve_min(ArgParser &ap, std::istream &is, std::ostream &,
kpeter@606
    96
               Value infty, DimacsDescriptor &desc)
kpeter@594
    97
{
kpeter@594
    98
  bool report = !ap.given("q");
kpeter@594
    99
  Digraph g;
kpeter@594
   100
  Digraph::ArcMap<Value> lower(g), cap(g), cost(g);
kpeter@594
   101
  Digraph::NodeMap<Value> sup(g);
kpeter@594
   102
  Timer ti;
kpeter@606
   103
kpeter@594
   104
  ti.restart();
kpeter@606
   105
  readDimacsMin(is, g, lower, cap, cost, sup, infty, desc);
kpeter@606
   106
  ti.stop();
kpeter@606
   107
  Value sum_sup = 0;
kpeter@606
   108
  for (Digraph::NodeIt n(g); n != INVALID; ++n) {
kpeter@606
   109
    sum_sup += sup[n];
kpeter@606
   110
  }
kpeter@606
   111
  if (report) {
kpeter@606
   112
    std::cerr << "Sum of supply values: " << sum_sup << "\n";
kpeter@606
   113
    if (sum_sup <= 0)
kpeter@606
   114
      std::cerr << "GEQ supply contraints are used for NetworkSimplex\n\n";
kpeter@606
   115
    else
kpeter@606
   116
      std::cerr << "LEQ supply contraints are used for NetworkSimplex\n\n";
kpeter@606
   117
  }
kpeter@594
   118
  if (report) std::cerr << "Read the file: " << ti << '\n';
kpeter@606
   119
kpeter@594
   120
  ti.restart();
kpeter@597
   121
  NetworkSimplex<Digraph, Value> ns(g);
kpeter@636
   122
  ns.lowerMap(lower).upperMap(cap).costMap(cost).supplyMap(sup);
kpeter@636
   123
  if (sum_sup > 0) ns.supplyType(ns.LEQ);
kpeter@594
   124
  if (report) std::cerr << "Setup NetworkSimplex class: " << ti << '\n';
kpeter@594
   125
  ti.restart();
kpeter@606
   126
  bool res = ns.run();
kpeter@606
   127
  if (report) {
kpeter@606
   128
    std::cerr << "Run NetworkSimplex: " << ti << "\n\n";
kpeter@606
   129
    std::cerr << "Feasible flow: " << (res ? "found" : "not found") << '\n';
kpeter@606
   130
    if (res) std::cerr << "Min flow cost: " << ns.totalCost() << '\n';
kpeter@606
   131
  }
kpeter@594
   132
}
kpeter@594
   133
alpar@510
   134
void solve_mat(ArgParser &ap, std::istream &is, std::ostream &,
alpar@510
   135
              DimacsDescriptor &desc)
alpar@510
   136
{
alpar@510
   137
  bool report = !ap.given("q");
alpar@510
   138
  Graph g;
alpar@510
   139
  Timer ti;
alpar@510
   140
  ti.restart();
alpar@510
   141
  readDimacsMat(is, g, desc);
alpar@510
   142
  if(report) std::cerr << "Read the file: " << ti << '\n';
alpar@510
   143
  ti.restart();
alpar@510
   144
  MaxMatching<Graph> mat(g);
alpar@510
   145
  if(report) std::cerr << "Setup MaxMatching class: " << ti << '\n';
alpar@510
   146
  ti.restart();
alpar@510
   147
  mat.run();
alpar@510
   148
  if(report) std::cerr << "Run MaxMatching: " << ti << '\n';
alpar@510
   149
  if(report) std::cerr << "\nCardinality of max matching: "
alpar@510
   150
                       << mat.matchingSize() << '\n';  
alpar@510
   151
}
alpar@510
   152
alpar@510
   153
alpar@510
   154
template<class Value>
alpar@510
   155
void solve(ArgParser &ap, std::istream &is, std::ostream &os,
alpar@510
   156
           DimacsDescriptor &desc)
alpar@510
   157
{
ladanyi@561
   158
  std::stringstream iss(static_cast<std::string>(ap["infcap"]));
alpar@552
   159
  Value infty;
alpar@552
   160
  iss >> infty;
alpar@552
   161
  if(iss.fail())
alpar@552
   162
    {
alpar@552
   163
      std::cerr << "Cannot interpret '"
alpar@552
   164
                << static_cast<std::string>(ap["infcap"]) << "' as infinite"
alpar@552
   165
                << std::endl;
alpar@552
   166
      exit(1);
alpar@552
   167
    }
alpar@552
   168
  
alpar@510
   169
  switch(desc.type)
alpar@510
   170
    {
alpar@510
   171
    case DimacsDescriptor::MIN:
kpeter@606
   172
      solve_min<Value>(ap,is,os,infty,desc);
alpar@510
   173
      break;
alpar@510
   174
    case DimacsDescriptor::MAX:
alpar@552
   175
      solve_max<Value>(ap,is,os,infty,desc);
alpar@510
   176
      break;
alpar@510
   177
    case DimacsDescriptor::SP:
alpar@510
   178
      solve_sp<Value>(ap,is,os,desc);
alpar@510
   179
      break;
alpar@510
   180
    case DimacsDescriptor::MAT:
alpar@510
   181
      solve_mat(ap,is,os,desc);
alpar@510
   182
      break;
alpar@510
   183
    default:
alpar@510
   184
      break;
alpar@510
   185
    }
alpar@510
   186
}
alpar@385
   187
alpar@385
   188
int main(int argc, const char *argv[]) {
alpar@385
   189
  typedef SmartDigraph Digraph;
alpar@385
   190
alpar@385
   191
  typedef Digraph::Arc Arc;
alpar@385
   192
alpar@385
   193
  std::string inputName;
alpar@385
   194
  std::string outputName;
alpar@385
   195
alpar@385
   196
  ArgParser ap(argc, argv);
alpar@387
   197
  ap.other("[INFILE [OUTFILE]]",
alpar@387
   198
           "If either the INFILE or OUTFILE file is missing the standard\n"
alpar@387
   199
           "     input/output will be used instead.")
alpar@510
   200
    .boolOption("q", "Do not print any report")
alpar@510
   201
    .boolOption("int","Use 'int' for capacities, costs etc. (default)")
alpar@510
   202
    .optionGroup("datatype","int")
ladanyi@622
   203
#ifdef LEMON_HAVE_LONG_LONG
alpar@510
   204
    .boolOption("long","Use 'long long' for capacities, costs etc.")
alpar@510
   205
    .optionGroup("datatype","long")
alpar@510
   206
#endif
alpar@510
   207
    .boolOption("double","Use 'double' for capacities, costs etc.")
alpar@510
   208
    .optionGroup("datatype","double")
alpar@510
   209
    .boolOption("ldouble","Use 'long double' for capacities, costs etc.")
alpar@510
   210
    .optionGroup("datatype","ldouble")
alpar@510
   211
    .onlyOneGroup("datatype")
alpar@552
   212
    .stringOption("infcap","Value used for 'very high' capacities","0")
alpar@385
   213
    .run();
alpar@385
   214
alpar@510
   215
  std::ifstream input;
alpar@510
   216
  std::ofstream output;
alpar@387
   217
alpar@387
   218
  switch(ap.files().size())
alpar@387
   219
    {
alpar@387
   220
    case 2:
alpar@387
   221
      output.open(ap.files()[1].c_str());
alpar@387
   222
      if (!output) {
alpar@387
   223
        throw IoError("Cannot open the file for writing", ap.files()[1]);
alpar@387
   224
      }
alpar@387
   225
    case 1:
alpar@387
   226
      input.open(ap.files()[0].c_str());
alpar@387
   227
      if (!input) {
alpar@387
   228
        throw IoError("File cannot be found", ap.files()[0]);
alpar@387
   229
      }
alpar@387
   230
    case 0:
alpar@387
   231
      break;
alpar@387
   232
    default:
alpar@510
   233
      std::cerr << ap.commandName() << ": too many arguments\n";
alpar@387
   234
      return 1;
kpeter@518
   235
    }
alpar@510
   236
  std::istream& is = (ap.files().size()<1 ? std::cin : input);
alpar@510
   237
  std::ostream& os = (ap.files().size()<2 ? std::cout : output);
alpar@387
   238
alpar@387
   239
  DimacsDescriptor desc = dimacsType(is);
alpar@510
   240
  
alpar@510
   241
  if(!ap.given("q"))
alpar@387
   242
    {
alpar@510
   243
      std::cout << "Problem type: ";
alpar@510
   244
      switch(desc.type)
alpar@510
   245
        {
alpar@510
   246
        case DimacsDescriptor::MIN:
alpar@510
   247
          std::cout << "min";
alpar@510
   248
          break;
alpar@510
   249
        case DimacsDescriptor::MAX:
alpar@510
   250
          std::cout << "max";
alpar@510
   251
          break;
alpar@510
   252
        case DimacsDescriptor::SP:
alpar@510
   253
          std::cout << "sp";
alpar@510
   254
        case DimacsDescriptor::MAT:
alpar@510
   255
          std::cout << "mat";
alpar@510
   256
          break;
alpar@510
   257
        default:
alpar@510
   258
          exit(1);
alpar@510
   259
          break;
alpar@510
   260
        }
alpar@510
   261
      std::cout << "\nNum of nodes: " << desc.nodeNum;
alpar@510
   262
      std::cout << "\nNum of arcs:  " << desc.edgeNum;
kpeter@518
   263
      std::cout << "\n\n";
alpar@385
   264
    }
alpar@510
   265
    
alpar@510
   266
  if(ap.given("double"))
alpar@510
   267
    solve<double>(ap,is,os,desc);
alpar@510
   268
  else if(ap.given("ldouble"))
alpar@510
   269
    solve<long double>(ap,is,os,desc);
ladanyi@622
   270
#ifdef LEMON_HAVE_LONG_LONG
alpar@510
   271
  else if(ap.given("long"))
alpar@510
   272
    solve<long long>(ap,is,os,desc);
alpar@510
   273
#endif
alpar@510
   274
  else solve<int>(ap,is,os,desc);
alpar@510
   275
alpar@385
   276
  return 0;
alpar@385
   277
}