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