tools/dimacs-solver.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 891 bb70ad62c95f
parent 640 6c408d864fa1
parent 627 20dac2104519
child 846 9d380bf27194
child 1005 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@532
    21
///\brief DIMACS problem solver.
alpar@385
    22
///
kpeter@532
    23
/// This program solves various problems given in DIMACS format.
alpar@385
    24
///
alpar@385
    25
/// See
kpeter@584
    26
/// \code
kpeter@584
    27
///   dimacs-solver --help
kpeter@584
    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@526
    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@526
    43
#include <lemon/dijkstra.h>
alpar@526
    44
#include <lemon/preflow.h>
kpeter@594
    45
#include <lemon/matching.h>
kpeter@602
    46
#include <lemon/network_simplex.h>
alpar@526
    47
alpar@385
    48
using namespace lemon;
alpar@526
    49
typedef SmartDigraph Digraph;
alpar@526
    50
DIGRAPH_TYPEDEFS(Digraph);
alpar@526
    51
typedef SmartGraph Graph;
alpar@385
    52
alpar@526
    53
template<class Value>
alpar@526
    54
void solve_sp(ArgParser &ap, std::istream &is, std::ostream &,
alpar@526
    55
              DimacsDescriptor &desc)
alpar@526
    56
{
alpar@526
    57
  bool report = !ap.given("q");
alpar@526
    58
  Digraph g;
alpar@526
    59
  Node s;
alpar@526
    60
  Digraph::ArcMap<Value> len(g);
alpar@526
    61
  Timer t;
alpar@526
    62
  t.restart();
alpar@526
    63
  readDimacsSp(is, g, len, s, desc);
alpar@526
    64
  if(report) std::cerr << "Read the file: " << t << '\n';
alpar@526
    65
  t.restart();
alpar@526
    66
  Dijkstra<Digraph, Digraph::ArcMap<Value> > dij(g,len);
alpar@526
    67
  if(report) std::cerr << "Setup Dijkstra class: " << t << '\n';
alpar@526
    68
  t.restart();
alpar@526
    69
  dij.run(s);
alpar@526
    70
  if(report) std::cerr << "Run Dijkstra: " << t << '\n';
alpar@526
    71
}
alpar@526
    72
alpar@526
    73
template<class Value>
alpar@526
    74
void solve_max(ArgParser &ap, std::istream &is, std::ostream &,
alpar@561
    75
               Value infty, DimacsDescriptor &desc)
alpar@526
    76
{
alpar@526
    77
  bool report = !ap.given("q");
alpar@526
    78
  Digraph g;
alpar@526
    79
  Node s,t;
alpar@526
    80
  Digraph::ArcMap<Value> cap(g);
alpar@526
    81
  Timer ti;
alpar@526
    82
  ti.restart();
alpar@561
    83
  readDimacsMax(is, g, cap, s, t, infty, desc);
alpar@526
    84
  if(report) std::cerr << "Read the file: " << ti << '\n';
alpar@526
    85
  ti.restart();
alpar@526
    86
  Preflow<Digraph, Digraph::ArcMap<Value> > pre(g,cap,s,t);
alpar@526
    87
  if(report) std::cerr << "Setup Preflow class: " << ti << '\n';
alpar@526
    88
  ti.restart();
alpar@526
    89
  pre.run();
alpar@526
    90
  if(report) std::cerr << "Run Preflow: " << ti << '\n';
alpar@526
    91
  if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n';  
alpar@526
    92
}
alpar@526
    93
kpeter@602
    94
template<class Value>
kpeter@602
    95
void solve_min(ArgParser &ap, std::istream &is, std::ostream &,
kpeter@614
    96
               Value infty, DimacsDescriptor &desc)
kpeter@602
    97
{
kpeter@602
    98
  bool report = !ap.given("q");
kpeter@602
    99
  Digraph g;
kpeter@602
   100
  Digraph::ArcMap<Value> lower(g), cap(g), cost(g);
kpeter@602
   101
  Digraph::NodeMap<Value> sup(g);
kpeter@602
   102
  Timer ti;
kpeter@614
   103
kpeter@602
   104
  ti.restart();
kpeter@614
   105
  readDimacsMin(is, g, lower, cap, cost, sup, infty, desc);
kpeter@614
   106
  ti.stop();
kpeter@614
   107
  Value sum_sup = 0;
kpeter@614
   108
  for (Digraph::NodeIt n(g); n != INVALID; ++n) {
kpeter@614
   109
    sum_sup += sup[n];
kpeter@614
   110
  }
kpeter@614
   111
  if (report) {
kpeter@614
   112
    std::cerr << "Sum of supply values: " << sum_sup << "\n";
kpeter@614
   113
    if (sum_sup <= 0)
kpeter@614
   114
      std::cerr << "GEQ supply contraints are used for NetworkSimplex\n\n";
kpeter@614
   115
    else
kpeter@614
   116
      std::cerr << "LEQ supply contraints are used for NetworkSimplex\n\n";
kpeter@614
   117
  }
kpeter@602
   118
  if (report) std::cerr << "Read the file: " << ti << '\n';
kpeter@614
   119
kpeter@602
   120
  ti.restart();
kpeter@605
   121
  NetworkSimplex<Digraph, Value> ns(g);
kpeter@640
   122
  ns.lowerMap(lower).upperMap(cap).costMap(cost).supplyMap(sup);
kpeter@640
   123
  if (sum_sup > 0) ns.supplyType(ns.LEQ);
kpeter@602
   124
  if (report) std::cerr << "Setup NetworkSimplex class: " << ti << '\n';
kpeter@602
   125
  ti.restart();
kpeter@614
   126
  bool res = ns.run();
kpeter@614
   127
  if (report) {
kpeter@614
   128
    std::cerr << "Run NetworkSimplex: " << ti << "\n\n";
kpeter@614
   129
    std::cerr << "Feasible flow: " << (res ? "found" : "not found") << '\n';
kpeter@614
   130
    if (res) std::cerr << "Min flow cost: " << ns.totalCost() << '\n';
kpeter@614
   131
  }
kpeter@602
   132
}
kpeter@602
   133
alpar@526
   134
void solve_mat(ArgParser &ap, std::istream &is, std::ostream &,
alpar@526
   135
              DimacsDescriptor &desc)
alpar@526
   136
{
alpar@526
   137
  bool report = !ap.given("q");
alpar@526
   138
  Graph g;
alpar@526
   139
  Timer ti;
alpar@526
   140
  ti.restart();
alpar@526
   141
  readDimacsMat(is, g, desc);
alpar@526
   142
  if(report) std::cerr << "Read the file: " << ti << '\n';
alpar@526
   143
  ti.restart();
alpar@526
   144
  MaxMatching<Graph> mat(g);
alpar@526
   145
  if(report) std::cerr << "Setup MaxMatching class: " << ti << '\n';
alpar@526
   146
  ti.restart();
alpar@526
   147
  mat.run();
alpar@526
   148
  if(report) std::cerr << "Run MaxMatching: " << ti << '\n';
alpar@526
   149
  if(report) std::cerr << "\nCardinality of max matching: "
alpar@526
   150
                       << mat.matchingSize() << '\n';  
alpar@526
   151
}
alpar@526
   152
alpar@526
   153
alpar@526
   154
template<class Value>
alpar@526
   155
void solve(ArgParser &ap, std::istream &is, std::ostream &os,
alpar@526
   156
           DimacsDescriptor &desc)
alpar@526
   157
{
ladanyi@569
   158
  std::stringstream iss(static_cast<std::string>(ap["infcap"]));
alpar@561
   159
  Value infty;
alpar@561
   160
  iss >> infty;
alpar@561
   161
  if(iss.fail())
alpar@561
   162
    {
alpar@561
   163
      std::cerr << "Cannot interpret '"
alpar@561
   164
                << static_cast<std::string>(ap["infcap"]) << "' as infinite"
alpar@561
   165
                << std::endl;
alpar@561
   166
      exit(1);
alpar@561
   167
    }
alpar@561
   168
  
alpar@526
   169
  switch(desc.type)
alpar@526
   170
    {
alpar@526
   171
    case DimacsDescriptor::MIN:
kpeter@614
   172
      solve_min<Value>(ap,is,os,infty,desc);
alpar@526
   173
      break;
alpar@526
   174
    case DimacsDescriptor::MAX:
alpar@561
   175
      solve_max<Value>(ap,is,os,infty,desc);
alpar@526
   176
      break;
alpar@526
   177
    case DimacsDescriptor::SP:
alpar@526
   178
      solve_sp<Value>(ap,is,os,desc);
alpar@526
   179
      break;
alpar@526
   180
    case DimacsDescriptor::MAT:
alpar@526
   181
      solve_mat(ap,is,os,desc);
alpar@526
   182
      break;
alpar@526
   183
    default:
alpar@526
   184
      break;
alpar@526
   185
    }
alpar@526
   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@526
   200
    .boolOption("q", "Do not print any report")
alpar@526
   201
    .boolOption("int","Use 'int' for capacities, costs etc. (default)")
alpar@526
   202
    .optionGroup("datatype","int")
ladanyi@627
   203
#ifdef LEMON_HAVE_LONG_LONG
alpar@526
   204
    .boolOption("long","Use 'long long' for capacities, costs etc.")
alpar@526
   205
    .optionGroup("datatype","long")
alpar@526
   206
#endif
alpar@526
   207
    .boolOption("double","Use 'double' for capacities, costs etc.")
alpar@526
   208
    .optionGroup("datatype","double")
alpar@526
   209
    .boolOption("ldouble","Use 'long double' for capacities, costs etc.")
alpar@526
   210
    .optionGroup("datatype","ldouble")
alpar@526
   211
    .onlyOneGroup("datatype")
alpar@561
   212
    .stringOption("infcap","Value used for 'very high' capacities","0")
alpar@385
   213
    .run();
alpar@385
   214
alpar@526
   215
  std::ifstream input;
alpar@526
   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@526
   233
      std::cerr << ap.commandName() << ": too many arguments\n";
alpar@387
   234
      return 1;
kpeter@532
   235
    }
alpar@526
   236
  std::istream& is = (ap.files().size()<1 ? std::cin : input);
alpar@526
   237
  std::ostream& os = (ap.files().size()<2 ? std::cout : output);
alpar@387
   238
alpar@387
   239
  DimacsDescriptor desc = dimacsType(is);
alpar@526
   240
  
alpar@526
   241
  if(!ap.given("q"))
alpar@387
   242
    {
alpar@526
   243
      std::cout << "Problem type: ";
alpar@526
   244
      switch(desc.type)
alpar@526
   245
        {
alpar@526
   246
        case DimacsDescriptor::MIN:
alpar@526
   247
          std::cout << "min";
alpar@526
   248
          break;
alpar@526
   249
        case DimacsDescriptor::MAX:
alpar@526
   250
          std::cout << "max";
alpar@526
   251
          break;
alpar@526
   252
        case DimacsDescriptor::SP:
alpar@526
   253
          std::cout << "sp";
alpar@526
   254
        case DimacsDescriptor::MAT:
alpar@526
   255
          std::cout << "mat";
alpar@526
   256
          break;
alpar@526
   257
        default:
alpar@526
   258
          exit(1);
alpar@526
   259
          break;
alpar@526
   260
        }
alpar@526
   261
      std::cout << "\nNum of nodes: " << desc.nodeNum;
alpar@526
   262
      std::cout << "\nNum of arcs:  " << desc.edgeNum;
kpeter@532
   263
      std::cout << "\n\n";
alpar@385
   264
    }
alpar@526
   265
    
alpar@526
   266
  if(ap.given("double"))
alpar@526
   267
    solve<double>(ap,is,os,desc);
alpar@526
   268
  else if(ap.given("ldouble"))
alpar@526
   269
    solve<long double>(ap,is,os,desc);
ladanyi@627
   270
#ifdef LEMON_HAVE_LONG_LONG
alpar@526
   271
  else if(ap.given("long"))
alpar@526
   272
    solve<long long>(ap,is,os,desc);
alpar@526
   273
#endif
alpar@526
   274
  else solve<int>(ap,is,os,desc);
alpar@526
   275
alpar@385
   276
  return 0;
alpar@385
   277
}