tools/dimacs-solver.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 846 9d380bf27194
child 1006 764826c6e2b4
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
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@877
     5
 * Copyright (C) 2003-2010
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@877
    91
  if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n';
alpar@526
    92
}
alpar@526
    93
kpeter@846
    94
template<class Value, class LargeValue>
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@846
   130
    if (res) std::cerr << "Min flow cost: "
kpeter@846
   131
                       << ns.template totalCost<LargeValue>() << '\n';
kpeter@614
   132
  }
kpeter@602
   133
}
kpeter@602
   134
alpar@526
   135
void solve_mat(ArgParser &ap, std::istream &is, std::ostream &,
alpar@526
   136
              DimacsDescriptor &desc)
alpar@526
   137
{
alpar@526
   138
  bool report = !ap.given("q");
alpar@526
   139
  Graph g;
alpar@526
   140
  Timer ti;
alpar@526
   141
  ti.restart();
alpar@526
   142
  readDimacsMat(is, g, desc);
alpar@526
   143
  if(report) std::cerr << "Read the file: " << ti << '\n';
alpar@526
   144
  ti.restart();
alpar@526
   145
  MaxMatching<Graph> mat(g);
alpar@526
   146
  if(report) std::cerr << "Setup MaxMatching class: " << ti << '\n';
alpar@526
   147
  ti.restart();
alpar@526
   148
  mat.run();
alpar@526
   149
  if(report) std::cerr << "Run MaxMatching: " << ti << '\n';
alpar@526
   150
  if(report) std::cerr << "\nCardinality of max matching: "
alpar@877
   151
                       << mat.matchingSize() << '\n';
alpar@526
   152
}
alpar@526
   153
alpar@526
   154
kpeter@846
   155
template<class Value, class LargeValue>
alpar@526
   156
void solve(ArgParser &ap, std::istream &is, std::ostream &os,
alpar@526
   157
           DimacsDescriptor &desc)
alpar@526
   158
{
ladanyi@569
   159
  std::stringstream iss(static_cast<std::string>(ap["infcap"]));
alpar@561
   160
  Value infty;
alpar@561
   161
  iss >> infty;
alpar@561
   162
  if(iss.fail())
alpar@561
   163
    {
alpar@561
   164
      std::cerr << "Cannot interpret '"
alpar@561
   165
                << static_cast<std::string>(ap["infcap"]) << "' as infinite"
alpar@561
   166
                << std::endl;
alpar@561
   167
      exit(1);
alpar@561
   168
    }
alpar@877
   169
alpar@526
   170
  switch(desc.type)
alpar@526
   171
    {
alpar@526
   172
    case DimacsDescriptor::MIN:
kpeter@846
   173
      solve_min<Value, LargeValue>(ap,is,os,infty,desc);
alpar@526
   174
      break;
alpar@526
   175
    case DimacsDescriptor::MAX:
alpar@561
   176
      solve_max<Value>(ap,is,os,infty,desc);
alpar@526
   177
      break;
alpar@526
   178
    case DimacsDescriptor::SP:
alpar@526
   179
      solve_sp<Value>(ap,is,os,desc);
alpar@526
   180
      break;
alpar@526
   181
    case DimacsDescriptor::MAT:
alpar@526
   182
      solve_mat(ap,is,os,desc);
alpar@526
   183
      break;
alpar@526
   184
    default:
alpar@526
   185
      break;
alpar@526
   186
    }
alpar@526
   187
}
alpar@385
   188
alpar@385
   189
int main(int argc, const char *argv[]) {
alpar@385
   190
  typedef SmartDigraph Digraph;
alpar@385
   191
alpar@385
   192
  typedef Digraph::Arc Arc;
alpar@385
   193
alpar@385
   194
  std::string inputName;
alpar@385
   195
  std::string outputName;
alpar@385
   196
alpar@385
   197
  ArgParser ap(argc, argv);
alpar@387
   198
  ap.other("[INFILE [OUTFILE]]",
alpar@387
   199
           "If either the INFILE or OUTFILE file is missing the standard\n"
alpar@387
   200
           "     input/output will be used instead.")
alpar@526
   201
    .boolOption("q", "Do not print any report")
alpar@526
   202
    .boolOption("int","Use 'int' for capacities, costs etc. (default)")
alpar@526
   203
    .optionGroup("datatype","int")
ladanyi@627
   204
#ifdef LEMON_HAVE_LONG_LONG
alpar@526
   205
    .boolOption("long","Use 'long long' for capacities, costs etc.")
alpar@526
   206
    .optionGroup("datatype","long")
alpar@526
   207
#endif
alpar@526
   208
    .boolOption("double","Use 'double' for capacities, costs etc.")
alpar@526
   209
    .optionGroup("datatype","double")
alpar@526
   210
    .boolOption("ldouble","Use 'long double' for capacities, costs etc.")
alpar@526
   211
    .optionGroup("datatype","ldouble")
alpar@526
   212
    .onlyOneGroup("datatype")
alpar@561
   213
    .stringOption("infcap","Value used for 'very high' capacities","0")
alpar@385
   214
    .run();
alpar@385
   215
alpar@526
   216
  std::ifstream input;
alpar@526
   217
  std::ofstream output;
alpar@387
   218
alpar@387
   219
  switch(ap.files().size())
alpar@387
   220
    {
alpar@387
   221
    case 2:
alpar@387
   222
      output.open(ap.files()[1].c_str());
alpar@387
   223
      if (!output) {
alpar@387
   224
        throw IoError("Cannot open the file for writing", ap.files()[1]);
alpar@387
   225
      }
alpar@387
   226
    case 1:
alpar@387
   227
      input.open(ap.files()[0].c_str());
alpar@387
   228
      if (!input) {
alpar@387
   229
        throw IoError("File cannot be found", ap.files()[0]);
alpar@387
   230
      }
alpar@387
   231
    case 0:
alpar@387
   232
      break;
alpar@387
   233
    default:
alpar@526
   234
      std::cerr << ap.commandName() << ": too many arguments\n";
alpar@387
   235
      return 1;
kpeter@532
   236
    }
alpar@526
   237
  std::istream& is = (ap.files().size()<1 ? std::cin : input);
alpar@526
   238
  std::ostream& os = (ap.files().size()<2 ? std::cout : output);
alpar@387
   239
alpar@387
   240
  DimacsDescriptor desc = dimacsType(is);
alpar@877
   241
alpar@526
   242
  if(!ap.given("q"))
alpar@387
   243
    {
alpar@526
   244
      std::cout << "Problem type: ";
alpar@526
   245
      switch(desc.type)
alpar@526
   246
        {
alpar@526
   247
        case DimacsDescriptor::MIN:
alpar@526
   248
          std::cout << "min";
alpar@526
   249
          break;
alpar@526
   250
        case DimacsDescriptor::MAX:
alpar@526
   251
          std::cout << "max";
alpar@526
   252
          break;
alpar@526
   253
        case DimacsDescriptor::SP:
alpar@526
   254
          std::cout << "sp";
alpar@526
   255
        case DimacsDescriptor::MAT:
alpar@526
   256
          std::cout << "mat";
alpar@526
   257
          break;
alpar@526
   258
        default:
alpar@526
   259
          exit(1);
alpar@526
   260
          break;
alpar@526
   261
        }
alpar@526
   262
      std::cout << "\nNum of nodes: " << desc.nodeNum;
alpar@526
   263
      std::cout << "\nNum of arcs:  " << desc.edgeNum;
kpeter@532
   264
      std::cout << "\n\n";
alpar@385
   265
    }
alpar@877
   266
alpar@526
   267
  if(ap.given("double"))
kpeter@846
   268
    solve<double, double>(ap,is,os,desc);
alpar@526
   269
  else if(ap.given("ldouble"))
kpeter@846
   270
    solve<long double, long double>(ap,is,os,desc);
ladanyi@627
   271
#ifdef LEMON_HAVE_LONG_LONG
alpar@526
   272
  else if(ap.given("long"))
kpeter@846
   273
    solve<long long, long long>(ap,is,os,desc);
kpeter@846
   274
  else solve<int, long long>(ap,is,os,desc);
kpeter@846
   275
#else
kpeter@846
   276
  else solve<int, long>(ap,is,os,desc);
alpar@526
   277
#endif
alpar@526
   278
alpar@385
   279
  return 0;
alpar@385
   280
}