tools/dimacs-solver.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 17 Apr 2009 18:04:36 +0200
changeset 601 e6927fe719e6
parent 594 a79ef774fae1
child 603 85cb3aa71cce
permissions -rw-r--r--
Support >= and <= constraints in NetworkSimplex (#219, #234)

By default the same inequality constraints are supported as by
Circulation (the GEQ form), but the LEQ form can also be selected
using the problemType() function.

The documentation of the min. cost flow module is reworked and
extended with important notes and explanations about the different
variants of the problem and about the dual solution and optimality
conditions.
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
alpar@385
    26
/// \verbatim
alpar@510
    27
///  dimacs-solver --help
alpar@385
    28
/// \endverbatim
alpar@385
    29
/// for more info on usage.
alpar@385
    30
///
alpar@385
    31
alpar@385
    32
#include <iostream>
alpar@385
    33
#include <fstream>
alpar@385
    34
#include <cstring>
alpar@385
    35
alpar@385
    36
#include <lemon/smart_graph.h>
alpar@385
    37
#include <lemon/dimacs.h>
alpar@385
    38
#include <lemon/lgf_writer.h>
alpar@510
    39
#include <lemon/time_measure.h>
alpar@385
    40
alpar@385
    41
#include <lemon/arg_parser.h>
alpar@387
    42
#include <lemon/error.h>
alpar@385
    43
alpar@510
    44
#include <lemon/dijkstra.h>
alpar@510
    45
#include <lemon/preflow.h>
alpar@510
    46
#include <lemon/max_matching.h>
kpeter@594
    47
#include <lemon/network_simplex.h>
alpar@510
    48
alpar@385
    49
using namespace lemon;
alpar@510
    50
typedef SmartDigraph Digraph;
alpar@510
    51
DIGRAPH_TYPEDEFS(Digraph);
alpar@510
    52
typedef SmartGraph Graph;
alpar@385
    53
alpar@510
    54
template<class Value>
alpar@510
    55
void solve_sp(ArgParser &ap, std::istream &is, std::ostream &,
alpar@510
    56
              DimacsDescriptor &desc)
alpar@510
    57
{
alpar@510
    58
  bool report = !ap.given("q");
alpar@510
    59
  Digraph g;
alpar@510
    60
  Node s;
alpar@510
    61
  Digraph::ArcMap<Value> len(g);
alpar@510
    62
  Timer t;
alpar@510
    63
  t.restart();
alpar@510
    64
  readDimacsSp(is, g, len, s, desc);
alpar@510
    65
  if(report) std::cerr << "Read the file: " << t << '\n';
alpar@510
    66
  t.restart();
alpar@510
    67
  Dijkstra<Digraph, Digraph::ArcMap<Value> > dij(g,len);
alpar@510
    68
  if(report) std::cerr << "Setup Dijkstra class: " << t << '\n';
alpar@510
    69
  t.restart();
alpar@510
    70
  dij.run(s);
alpar@510
    71
  if(report) std::cerr << "Run Dijkstra: " << t << '\n';
alpar@510
    72
}
alpar@510
    73
alpar@510
    74
template<class Value>
alpar@510
    75
void solve_max(ArgParser &ap, std::istream &is, std::ostream &,
alpar@510
    76
              DimacsDescriptor &desc)
alpar@510
    77
{
alpar@510
    78
  bool report = !ap.given("q");
alpar@510
    79
  Digraph g;
alpar@510
    80
  Node s,t;
alpar@510
    81
  Digraph::ArcMap<Value> cap(g);
alpar@510
    82
  Timer ti;
alpar@510
    83
  ti.restart();
alpar@510
    84
  readDimacsMax(is, g, cap, s, t, desc);
alpar@510
    85
  if(report) std::cerr << "Read the file: " << ti << '\n';
alpar@510
    86
  ti.restart();
alpar@510
    87
  Preflow<Digraph, Digraph::ArcMap<Value> > pre(g,cap,s,t);
alpar@510
    88
  if(report) std::cerr << "Setup Preflow class: " << ti << '\n';
alpar@510
    89
  ti.restart();
alpar@510
    90
  pre.run();
alpar@510
    91
  if(report) std::cerr << "Run Preflow: " << ti << '\n';
alpar@510
    92
  if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n';  
alpar@510
    93
}
alpar@510
    94
kpeter@594
    95
template<class Value>
kpeter@594
    96
void solve_min(ArgParser &ap, std::istream &is, std::ostream &,
kpeter@594
    97
               DimacsDescriptor &desc)
kpeter@594
    98
{
kpeter@594
    99
  bool report = !ap.given("q");
kpeter@594
   100
  Digraph g;
kpeter@594
   101
  Digraph::ArcMap<Value> lower(g), cap(g), cost(g);
kpeter@594
   102
  Digraph::NodeMap<Value> sup(g);
kpeter@594
   103
  Timer ti;
kpeter@594
   104
  ti.restart();
kpeter@594
   105
  readDimacsMin(is, g, lower, cap, cost, sup, desc);
kpeter@594
   106
  if (report) std::cerr << "Read the file: " << ti << '\n';
kpeter@594
   107
  ti.restart();
kpeter@597
   108
  NetworkSimplex<Digraph, Value> ns(g);
kpeter@597
   109
  ns.lowerMap(lower).capacityMap(cap).costMap(cost).supplyMap(sup);
kpeter@594
   110
  if (report) std::cerr << "Setup NetworkSimplex class: " << ti << '\n';
kpeter@594
   111
  ti.restart();
kpeter@594
   112
  ns.run();
kpeter@594
   113
  if (report) std::cerr << "Run NetworkSimplex: " << ti << '\n';
kpeter@594
   114
  if (report) std::cerr << "\nMin flow cost: " << ns.totalCost() << '\n';
kpeter@594
   115
}
kpeter@594
   116
alpar@510
   117
void solve_mat(ArgParser &ap, std::istream &is, std::ostream &,
alpar@510
   118
              DimacsDescriptor &desc)
alpar@510
   119
{
alpar@510
   120
  bool report = !ap.given("q");
alpar@510
   121
  Graph g;
alpar@510
   122
  Timer ti;
alpar@510
   123
  ti.restart();
alpar@510
   124
  readDimacsMat(is, g, desc);
alpar@510
   125
  if(report) std::cerr << "Read the file: " << ti << '\n';
alpar@510
   126
  ti.restart();
alpar@510
   127
  MaxMatching<Graph> mat(g);
alpar@510
   128
  if(report) std::cerr << "Setup MaxMatching class: " << ti << '\n';
alpar@510
   129
  ti.restart();
alpar@510
   130
  mat.run();
alpar@510
   131
  if(report) std::cerr << "Run MaxMatching: " << ti << '\n';
alpar@510
   132
  if(report) std::cerr << "\nCardinality of max matching: "
alpar@510
   133
                       << mat.matchingSize() << '\n';  
alpar@510
   134
}
alpar@510
   135
alpar@510
   136
alpar@510
   137
template<class Value>
alpar@510
   138
void solve(ArgParser &ap, std::istream &is, std::ostream &os,
alpar@510
   139
           DimacsDescriptor &desc)
alpar@510
   140
{
alpar@510
   141
  switch(desc.type)
alpar@510
   142
    {
alpar@510
   143
    case DimacsDescriptor::MIN:
kpeter@594
   144
      solve_min<Value>(ap,is,os,desc);
alpar@510
   145
      break;
alpar@510
   146
    case DimacsDescriptor::MAX:
alpar@510
   147
      solve_max<Value>(ap,is,os,desc);
alpar@510
   148
      break;
alpar@510
   149
    case DimacsDescriptor::SP:
alpar@510
   150
      solve_sp<Value>(ap,is,os,desc);
alpar@510
   151
      break;
alpar@510
   152
    case DimacsDescriptor::MAT:
alpar@510
   153
      solve_mat(ap,is,os,desc);
alpar@510
   154
      break;
alpar@510
   155
    default:
alpar@510
   156
      break;
alpar@510
   157
    }
alpar@510
   158
}
alpar@385
   159
alpar@385
   160
int main(int argc, const char *argv[]) {
alpar@385
   161
  typedef SmartDigraph Digraph;
alpar@385
   162
alpar@385
   163
  typedef Digraph::Arc Arc;
alpar@385
   164
alpar@385
   165
  std::string inputName;
alpar@385
   166
  std::string outputName;
alpar@385
   167
alpar@385
   168
  ArgParser ap(argc, argv);
alpar@387
   169
  ap.other("[INFILE [OUTFILE]]",
alpar@387
   170
           "If either the INFILE or OUTFILE file is missing the standard\n"
alpar@387
   171
           "     input/output will be used instead.")
alpar@510
   172
    .boolOption("q", "Do not print any report")
alpar@510
   173
    .boolOption("int","Use 'int' for capacities, costs etc. (default)")
alpar@510
   174
    .optionGroup("datatype","int")
alpar@510
   175
#ifdef HAVE_LONG_LONG
alpar@510
   176
    .boolOption("long","Use 'long long' for capacities, costs etc.")
alpar@510
   177
    .optionGroup("datatype","long")
alpar@510
   178
#endif
alpar@510
   179
    .boolOption("double","Use 'double' for capacities, costs etc.")
alpar@510
   180
    .optionGroup("datatype","double")
alpar@510
   181
    .boolOption("ldouble","Use 'long double' for capacities, costs etc.")
alpar@510
   182
    .optionGroup("datatype","ldouble")
alpar@510
   183
    .onlyOneGroup("datatype")
alpar@385
   184
    .run();
alpar@385
   185
alpar@510
   186
  std::ifstream input;
alpar@510
   187
  std::ofstream output;
alpar@387
   188
alpar@387
   189
  switch(ap.files().size())
alpar@387
   190
    {
alpar@387
   191
    case 2:
alpar@387
   192
      output.open(ap.files()[1].c_str());
alpar@387
   193
      if (!output) {
alpar@387
   194
        throw IoError("Cannot open the file for writing", ap.files()[1]);
alpar@387
   195
      }
alpar@387
   196
    case 1:
alpar@387
   197
      input.open(ap.files()[0].c_str());
alpar@387
   198
      if (!input) {
alpar@387
   199
        throw IoError("File cannot be found", ap.files()[0]);
alpar@387
   200
      }
alpar@387
   201
    case 0:
alpar@387
   202
      break;
alpar@387
   203
    default:
alpar@510
   204
      std::cerr << ap.commandName() << ": too many arguments\n";
alpar@387
   205
      return 1;
kpeter@518
   206
    }
alpar@510
   207
  std::istream& is = (ap.files().size()<1 ? std::cin : input);
alpar@510
   208
  std::ostream& os = (ap.files().size()<2 ? std::cout : output);
alpar@387
   209
alpar@387
   210
  DimacsDescriptor desc = dimacsType(is);
alpar@510
   211
  
alpar@510
   212
  if(!ap.given("q"))
alpar@387
   213
    {
alpar@510
   214
      std::cout << "Problem type: ";
alpar@510
   215
      switch(desc.type)
alpar@510
   216
        {
alpar@510
   217
        case DimacsDescriptor::MIN:
alpar@510
   218
          std::cout << "min";
alpar@510
   219
          break;
alpar@510
   220
        case DimacsDescriptor::MAX:
alpar@510
   221
          std::cout << "max";
alpar@510
   222
          break;
alpar@510
   223
        case DimacsDescriptor::SP:
alpar@510
   224
          std::cout << "sp";
alpar@510
   225
        case DimacsDescriptor::MAT:
alpar@510
   226
          std::cout << "mat";
alpar@510
   227
          break;
alpar@510
   228
        default:
alpar@510
   229
          exit(1);
alpar@510
   230
          break;
alpar@510
   231
        }
alpar@510
   232
      std::cout << "\nNum of nodes: " << desc.nodeNum;
alpar@510
   233
      std::cout << "\nNum of arcs:  " << desc.edgeNum;
kpeter@518
   234
      std::cout << "\n\n";
alpar@385
   235
    }
alpar@510
   236
    
alpar@510
   237
  if(ap.given("double"))
alpar@510
   238
    solve<double>(ap,is,os,desc);
alpar@510
   239
  else if(ap.given("ldouble"))
alpar@510
   240
    solve<long double>(ap,is,os,desc);
alpar@510
   241
#ifdef HAVE_LONG_LONG
alpar@510
   242
  else if(ap.given("long"))
alpar@510
   243
    solve<long long>(ap,is,os,desc);
alpar@510
   244
#endif
alpar@510
   245
  else solve<int>(ap,is,os,desc);
alpar@510
   246
alpar@385
   247
  return 0;
alpar@385
   248
}