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