1 /* A sort of clone of the cddlib test program `lcdd'.
2    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3    Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #if 0
25 #define USE_PIPLIB 1
26 #endif
27 
28 #if (!defined(USE_PPL) && !defined(USE_PIPLIB))
29 #define USE_PPL 1
30 #elif (defined(USE_PPL) && defined(USE_PIPLIB))
31 #error "Exactly one among USE_PPL and USE_PIPLIB must be defined"
32 #endif
33 
34 #if defined(USE_PPL)
35 
36 #include "ppl.hh"
37 
38 namespace PPL = Parma_Polyhedra_Library;
39 
40 #if PPL_VERSION_MAJOR == 0 && PPL_VERSION_MINOR < 11
41 #error "PPL version 0.11 or following is required"
42 #endif
43 
44 typedef PPL::C_Polyhedron POLYHEDRON_TYPE;
45 
46 #elif defined(USE_PIPLIB)
47 
48 #error "PipLib not supported yet"
49 
50 #endif
51 
52 #include "timings.hh"
53 #include <gmpxx.h>
54 #include <vector>
55 #include <set>
56 #include <climits>
57 #include <cassert>
58 #include <cstdarg>
59 #include <csignal>
60 #include <cerrno>
61 #include <cstring>
62 #include <cstdio>
63 #include <cstdlib>
64 #include <iostream>
65 #include <fstream>
66 #include <sstream>
67 #include <stdexcept>
68 #include <memory>
69 
70 #ifdef PPL_HAVE_GETOPT_H
71 #include <getopt.h>
72 
73 // Try to accommodate non-GNU implementations of `getopt()'.
74 #if !defined(no_argument) && defined(NO_ARG)
75 #define no_argument NO_ARG
76 #endif
77 
78 #if !defined(required_argument) && defined(REQUIRED_ARG)
79 #define required_argument REQUIRED_ARG
80 #endif
81 
82 #if !defined(optional_argument) && defined(OPTIONAL_ARG)
83 #define optional_argument OPTIONAL_ARG
84 #endif
85 
86 #endif // defined(PPL_HAVE_GETOPT_H)
87 
88 #ifdef PPL_HAVE_UNISTD_H
89 // Include this for `getopt()': especially important if we do not have
90 // <getopt.h>.
91 # include <unistd.h>
92 #endif
93 
94 #ifdef PPL_HAVE_SYS_TIME_H
95 # include <sys/time.h>
96 #endif
97 
98 #ifdef PPL_HAVE_SYS_RESOURCE_H
99 // This should be included after <time.h> and <sys/time.h> so as to make
100 // sure we have the definitions for, e.g., `ru_utime'.
101 # include <sys/resource.h>
102 #endif
103 
104 namespace {
105 
106 PPL::PIP_Problem::Control_Parameter_Value cutting_strategy
107   = PPL::PIP_Problem::CUTTING_STRATEGY_FIRST;
108 
109 PPL::PIP_Problem::Control_Parameter_Value pivot_row_strategy
110     = PPL::PIP_Problem::PIVOT_ROW_STRATEGY_FIRST;
111 
112 long loop_iterations = 1;
113 
114 void
pip_display_sol(std::ostream & out,const Parma_Polyhedra_Library::PIP_Tree pip,const Parma_Polyhedra_Library::Variables_Set & parameters,const Parma_Polyhedra_Library::Variables_Set & vars,Parma_Polyhedra_Library::dimension_type space_dimension,int indent=0)115 pip_display_sol(std::ostream& out,
116                 const Parma_Polyhedra_Library::PIP_Tree pip,
117                 const Parma_Polyhedra_Library::Variables_Set& parameters,
118                 const Parma_Polyhedra_Library::Variables_Set& vars,
119                 Parma_Polyhedra_Library::dimension_type space_dimension,
120                 int indent = 0) {
121   using namespace Parma_Polyhedra_Library::IO_Operators;
122 
123   if (!pip) {
124     out << std::setw(indent*2) << "" << "_|_" << std::endl;
125   }
126   else {
127     for (PPL::PIP_Tree_Node::Artificial_Parameter_Sequence::const_iterator
128            i = pip->art_parameter_begin(),
129            i_end = pip->art_parameter_end();
130          i != i_end;
131          ++i) {
132       out << std::setw(indent*2) << "" << "Parameter "
133           << PPL::Linear_Expression(PPL::Variable(space_dimension++))
134           << " = " << *i << std::endl;
135     }
136     const PPL::Constraint_System& constraints = pip->constraints();
137     const bool constraints_empty = constraints.empty();
138     if (!constraints_empty) {
139       out << std::setw(indent*2) << "" << "if ";
140       for (PPL::Constraint_System::const_iterator
141              cs_begin = constraints.begin(),
142              cs_end = constraints.end(),
143              i = cs_begin; i != cs_end; ++i) {
144         out << ((i == cs_begin) ? "" : " and ") << *i;
145       }
146       out << " then" << std::endl;
147     }
148     const PPL::PIP_Decision_Node* const decision_node_p = pip->as_decision();
149     if (decision_node_p) {
150       pip_display_sol(out, decision_node_p->child_node(true),
151                       parameters, vars, space_dimension, indent+1);
152       out << std::setw(indent*2) << "" << "else" << std::endl;
153       pip_display_sol(out, decision_node_p->child_node(false),
154                       parameters, vars, space_dimension, indent+1);
155     }
156     else {
157       const PPL::PIP_Solution_Node* const solution_node_p = pip->as_solution();
158       out << std::setw(indent*2 + (constraints_empty ? 0 : 2)) << "" << "{";
159       for (PPL::Variables_Set::const_iterator
160              v_begin = vars.begin(),
161              v_end = vars.end(),
162              i = v_begin; i != v_end; ++i) {
163         out << ((i == v_begin) ? "" : " ; ")
164             << solution_node_p->parametric_values(PPL::Variable(*i));
165       }
166       out << "}" << std::endl;
167       if (!constraints_empty) {
168         out << std::setw(indent*2) << "" << "else" << std::endl;
169         out << std::setw(indent*2 + 2) << "" << "_|_" << std::endl;
170       }
171     }
172   }
173 }
174 
175 class PIP_Parser {
176 public:
PIP_Parser()177   PIP_Parser() : pip() {
178     pip.set_control_parameter(cutting_strategy);
179     pip.set_control_parameter(pivot_row_strategy);
180   }
181 
~PIP_Parser()182   virtual ~PIP_Parser() {
183   }
184 
problem() const185   const PPL::PIP_Problem& problem() const {
186     return pip;
187   }
188 
189   virtual bool read(std::istream& in) = 0;
190 
191   //! Output the solution in "if-then-else" format.
output_solution_tree(std::ostream & out)192   void output_solution_tree(std::ostream& out) {
193     const PPL::Variables_Set& params = pip.parameter_space_dimensions();
194     PPL::Variables_Set vars;
195     for (PPL::dimension_type i = 0; i < pip.space_dimension(); ++i) {
196       if (params.count(i) == 0) {
197         vars.insert(i);
198       }
199     }
200     const PPL::PIP_Tree solution = pip.solution();
201     pip_display_sol(out, solution, params, vars, pip.space_dimension());
202   }
203 
204   typedef std::vector<PPL::Coefficient> Coeff_Vector;
205   typedef std::vector<int> Int_Vector;
206 
update_pip(PPL::dimension_type num_vars,PPL::dimension_type num_params,PPL::dimension_type num_constraints,PPL::dimension_type num_ctx_rows,const Coeff_Vector & constraints,const Coeff_Vector & context,const Int_Vector & constraint_type,const Int_Vector & ctx_type,PPL::dimension_type bignum_column)207   bool update_pip(PPL::dimension_type num_vars,
208                   PPL::dimension_type num_params,
209                   PPL::dimension_type num_constraints,
210                   PPL::dimension_type num_ctx_rows,
211                   const Coeff_Vector& constraints,
212                   const Coeff_Vector& context,
213                   const Int_Vector& constraint_type,
214                   const Int_Vector& ctx_type,
215                   PPL::dimension_type bignum_column) {
216     pip.add_space_dimensions_and_embed(num_vars, num_params);
217     for (PPL::dimension_type k = 0, i = 0; i < num_constraints; ++i) {
218       PPL::Linear_Expression expr;
219       for (PPL::dimension_type j = 0; j < num_vars + num_params; ++j) {
220         add_mul_assign(expr, constraints[k++], PPL::Variable(j));
221       }
222       expr += constraints[k++];
223       if (constraint_type[i]) {
224         pip.add_constraint(PPL::Constraint(expr >= 0));
225       }
226       else {
227         pip.add_constraint(PPL::Constraint(expr == 0));
228       }
229     }
230     if (num_params > 0) {
231       for (PPL::dimension_type k = 0, i = 0; i < num_ctx_rows; ++i) {
232         PPL::Linear_Expression expr;
233         for (PPL::dimension_type j = 0; j < num_params; ++j) {
234           add_mul_assign(expr, context[k++], PPL::Variable(num_vars+j));
235         }
236         expr += context[k++];
237         if (ctx_type[i]) {
238           pip.add_constraint(PPL::Constraint(expr >= 0));
239         }
240         else {
241           pip.add_constraint(PPL::Constraint(expr == 0));
242         }
243       }
244     }
245     if (bignum_column != PPL::not_a_dimension()) {
246       pip.set_big_parameter_dimension(bignum_column);
247     }
248     return true;
249   }
250 
251 protected:
252   //! The problem object.
253   PPL::PIP_Problem pip;
254 }; // class PIP_Parser
255 
256 class PIP_PolyLib_Parser : public PIP_Parser {
257 public:
PIP_PolyLib_Parser()258   PIP_PolyLib_Parser(): PIP_Parser() {
259   }
260 
read(std::istream & in)261   bool read(std::istream& in) {
262     std::string line;
263 
264     PPL::dimension_type num_ctx_rows;
265     PPL::dimension_type num_params;
266     getline_no_comment(in, line);
267     {
268       std::istringstream iss(line);
269       iss >> num_ctx_rows >> num_params;
270     }
271     PPL_ASSERT(num_params >= 2);
272     num_params -= 2;
273 
274     Coeff_Vector context(num_ctx_rows * (1+num_params));
275     Int_Vector ctx_type(num_ctx_rows);
276     for (PPL::dimension_type i = 0; i < num_ctx_rows; ++i) {
277       getline_no_comment(in, line);
278       std::istringstream iss(line);
279       iss >> ctx_type[i];
280       for (PPL::dimension_type j = 0; j <= num_params; ++j) {
281         iss >> context[i*num_ctx_rows + j];
282       }
283     }
284 
285     int bignum_column_coding;
286     getline_no_comment(in, line);
287     {
288       std::istringstream iss(line);
289       iss >> bignum_column_coding;
290     }
291     PPL_ASSERT(bignum_column_coding >= -1);
292 
293     PPL::dimension_type num_constraints;
294     PPL::dimension_type constraint_width;
295     PPL::dimension_type num_vars;
296     getline_no_comment(in, line);
297     {
298       std::istringstream iss(line);
299       iss >> num_constraints >> constraint_width;
300     }
301     constraint_width -= 1;
302     num_vars = constraint_width - num_params - 1;
303 
304     Coeff_Vector constraints(num_constraints * constraint_width);
305     Int_Vector constraint_type(num_constraints);
306     for (PPL::dimension_type i = 0; i < num_constraints; ++i) {
307       getline_no_comment(in, line);
308       std::istringstream iss(line);
309       iss >> constraint_type[i];
310       for (PPL::dimension_type j = 0; j < constraint_width; ++j) {
311         iss >> constraints[i*constraint_width + j];
312       }
313     }
314 
315     const PPL::dimension_type bignum_column
316       = (bignum_column_coding == -1)
317       ? PPL::not_a_dimension()
318       : (num_vars + PPL::dimension_type(bignum_column_coding - 1));
319 
320     const bool result = update_pip(num_vars, num_params,
321                                    num_constraints, num_ctx_rows,
322                                    constraints, context,
323                                    constraint_type, ctx_type,
324                                    bignum_column);
325     return result;
326   }
327 
328 protected:
getline_no_comment(std::istream & in,std::string & s)329   static void getline_no_comment(std::istream& in, std::string& s) {
330     do {
331       getline(in, s);
332     } while (s.size() == 0 || s[0] == '\r' || s[0] == '#');
333   }
334 }; // class PIP_PolyLib_Parser
335 
336 class PIP_PipLib_Parser : public PIP_Parser {
337 public:
PIP_PipLib_Parser()338   PIP_PipLib_Parser()
339     : PIP_Parser(), comment() {
340   }
341 
read(std::istream & in)342   bool read(std::istream& in) {
343     if (!expect(in, '(')) {
344       return false;
345     }
346     if (!expect(in, '(')) {
347       return false;
348     }
349     if (!read_comment(in)) {
350       return false;
351     }
352 
353     PPL::dimension_type num_vars;
354     PPL::dimension_type num_params;
355     in >> num_vars >> num_params;
356 
357     PPL::dimension_type num_constraints;
358     PPL::dimension_type num_ctx_rows;
359     in >> num_constraints >> num_ctx_rows;
360 
361     int bignum_column_coding;
362     in >> bignum_column_coding;
363     PPL_ASSERT(bignum_column_coding >= -1);
364     const PPL::dimension_type bignum_column
365       = (bignum_column_coding == -1)
366       ? PPL::not_a_dimension()
367       : PPL::dimension_type(bignum_column_coding - 1);
368 
369     int solve_integer;
370     in >> solve_integer;
371     if (solve_integer != 1) {
372       std::cerr << "Can only solve integer problems." << std::endl;
373       return false;
374     }
375 
376     if (!expect(in, '(')) {
377       return false;
378     }
379     const PPL::dimension_type constraint_width = num_vars+num_params+1;
380     Coeff_Vector constraints(num_constraints * constraint_width);
381     Int_Vector constraint_type(num_constraints);
382     for (PPL::dimension_type i = 0; i < num_constraints; ++i) {
383       constraint_type[i] = 1;
384     }
385     for (PPL::dimension_type i = 0; i < num_constraints; ++i) {
386       if (!read_vector(in, i, constraint_width, num_vars, constraints)) {
387         return false;
388       }
389     }
390 
391     Coeff_Vector context(num_ctx_rows * (1+num_params));
392     Int_Vector ctx_type(num_ctx_rows);
393     for (PPL::dimension_type i = 0; i < num_ctx_rows; ++i) {
394       ctx_type[i] = 1;
395     }
396     for (PPL::dimension_type i = 0; i < num_ctx_rows; ++i) {
397       if (!read_vector(in, i, num_params+1, num_params, context)) {
398         return false;
399       }
400     }
401 
402     const bool result = update_pip(num_vars, num_params,
403                                    num_constraints, num_ctx_rows,
404                                    constraints, context,
405                                    constraint_type, ctx_type,
406                                    bignum_column);
407     return result;
408   }
409 
410 protected:
read_comment(std::istream & in)411   bool read_comment(std::istream& in) {
412     comment = "";
413     int count = 1;
414     do {
415       char c;
416       if (!in.get(c)) {
417         return false;
418       }
419       if (c == '(') {
420         ++count;
421       }
422       else if (c == ')') {
423         --count;
424       }
425       if (count > 0) {
426         comment += c;
427       }
428     } while (count > 0);
429     return true;
430   }
431 
expect(std::istream & in,char c)432   static bool expect(std::istream& in, char c) {
433     char a;
434     do {
435       in >> a;
436     } while (a != c && in.good());
437     return a == c;
438   }
439 
read_vector(std::istream & in,PPL::dimension_type row_index,PPL::dimension_type row_size,PPL::dimension_type cst_col,Coeff_Vector & tab)440   static bool read_vector(std::istream& in,
441                           PPL::dimension_type row_index,
442                           PPL::dimension_type row_size,
443                           PPL::dimension_type cst_col,
444                           Coeff_Vector& tab) {
445     if (!expect(in, '#')) {
446       return false;
447     }
448     if (!expect(in, '[')) {
449       return false;
450     }
451     std::string s;
452     getline(in, s, ']');
453     if (in.fail()) {
454       return false;
455     }
456     std::istringstream iss(s);
457     const PPL::dimension_type start_index = row_index * row_size;
458     PPL::dimension_type k = start_index;
459     for (PPL::dimension_type i = 0; i < cst_col; ++i, ++k) {
460       iss >> tab[k];
461       if (iss.fail()) {
462         return false;
463       }
464     }
465     iss >> tab[start_index + row_size - 1];
466     if (iss.fail()) {
467       return false;
468     }
469     for (PPL::dimension_type i = cst_col + 1; i < row_size; ++i, ++k) {
470       iss >> tab[k];
471       if (iss.fail()) {
472         return false;
473       }
474     }
475     return true;
476   }
477 
478   // The comment string in the source file
479   std::string comment;
480 }; // class PIP_PipLib_Parser
481 
482 #ifdef PPL_HAVE_GETOPT_H
483 struct option long_options[] = {
484   {"max-cpu",        required_argument, 0, 'C'},
485   {"max-memory",     required_argument, 0, 'R'},
486   {"help",           no_argument,       0, 'h'},
487   {"output",         required_argument, 0, 'o'},
488   {"polylib",        no_argument,       0, 'P'},
489   {"piplib",         no_argument,       0, 'p'},
490   {"timings",        no_argument,       0, 't'},
491   {"verbose",        no_argument,       0, 'v'},
492   {"iterations",     required_argument, 0, 'i'},
493 #if defined(USE_PPL)
494   {"version",        no_argument,       0, 'V'},
495   {"check",          required_argument, 0, 'c'},
496 #endif
497   {"cut-first",      no_argument,       0, 'f'},
498   {"cut-deepest",    no_argument,       0, 'd'},
499   {"cut-all",        no_argument,       0, 'a'},
500   {"row-first",      no_argument,       0, 'F'},
501   {"row-max",        no_argument,       0, 'M'},
502   {0, 0, 0, 0}
503 };
504 #endif
505 
506 static const char* usage_string
507 = "Usage: %s [OPTION]... [FILE]\n"
508 "Reads the definition of a Parametric Integer Programming problem\n"
509 "and displays the lexicographic minimum in terms of the values of the\n"
510 "parameters.\n\n"
511 "Options:\n"
512 "  -RMB, --max-memory=MB   limits memory usage to MB megabytes\n"
513 "  -h, --help              prints this help text to stdout\n"
514 "  -oPATH, --output=PATH   appends output to PATH\n"
515 "  -P, --polylib           reads problem in PolyLib format (default)\n"
516 "  -p, --piplib            reads problem in PipLib format\n"
517 "  -t, --timings           prints timings to stderr\n"
518 "  -v, --verbose           produces lots of output\n"
519 "  -i, --iterations=N      executes the resolution N times (default=1)\n"
520 #if defined(USE_PPL)
521 "  -V, --version           prints version information to stdout\n"
522 "  -cPATH, --check=PATH    checks if the result is equal to what is in PATH\n"
523 #endif
524 "\nCut generation options:\n"
525 "  -f, --cut-first         uses the first non-integer row (default)\n"
526 "  -d, --cut-deepest       tries to generate the deepest cut\n"
527 "  -a, --cut-all           always generates all possible cuts\n"
528 "\nPivot row strategy options:\n"
529 "  -F, --row-first         uses the first row with negative parameter (default)\n"
530 "  -M, --row-max           chooses row generating the lexico-maximal pivot column\n"
531 #ifndef PPL_HAVE_GETOPT_H
532 "\n"
533 "NOTE: this version does not support long options.\n"
534 #endif
535 "\n"
536 "Report bugs to <ppl-devel@cs.unipr.it>.\n";
537 
538 #if defined(USE_PPL)
539 #define OPTION_LETTERS "R:ho:Pptvi:Vc:fdaFM"
540 #else
541 #define OPTION_LETTERS "R:ho:Pptvi:fdaFM"
542 #endif
543 
544 const char* program_name = 0;
545 
546 unsigned long max_bytes_of_virtual_memory = 0;
547 bool print_timings = false;
548 bool verbose = false;
549 const char* check_file_name = 0;
550 
551 void
fatal(const char * format,...)552 fatal(const char* format, ...) {
553   va_list ap;
554   va_start(ap, format);
555   fprintf(stderr, "%s: ", program_name);
556   vfprintf(stderr, format, ap);
557   fprintf(stderr, "\n");
558   va_end(ap);
559   exit(1);
560 }
561 
562 const char* input_file_name = 0;
563 std::istream* input_stream_p = 0;
564 
565 void
set_input(const char * file_name)566 set_input(const char* file_name) {
567   if (input_stream_p && (input_stream_p != &std::cin)) {
568     delete input_stream_p;
569   }
570   if (file_name) {
571     input_stream_p = new std::ifstream(file_name, std::ios_base::in);
572     if (!*input_stream_p) {
573       fatal("cannot open input file `%s'", file_name);
574     }
575     input_file_name = file_name;
576   }
577   else {
578     input_stream_p = &std::cin;
579     input_file_name = "<cin>";
580   }
581 }
582 
583 const char* output_file_name = 0;
584 std::ostream* output_stream_p = 0;
585 
586 void
set_output(const char * file_name)587 set_output(const char* file_name) {
588   if (output_stream_p && (output_stream_p != &std::cout)) {
589     delete output_stream_p;
590   }
591   if (file_name) {
592     output_stream_p = new std::ofstream(file_name,
593                                         std::ios_base::out
594                                         | std::ios_base::app);
595     if (!*output_stream_p) {
596       fatal("cannot open output file `%s'", file_name);
597     }
598     output_file_name = file_name;
599   }
600   else {
601     output_stream_p = &std::cout;
602     output_file_name = "<cout>";
603   }
604 }
605 
606 bool piplib_format = false;
607 
608 } // namespace
609 
610 void
error(const char * format,...)611 error(const char* format, ...) {
612   va_list ap;
613   va_start(ap, format);
614   fprintf(stderr, "%s: in `%s': ", program_name, input_file_name);
615   vfprintf(stderr, format, ap);
616   fprintf(stderr, "\n");
617   va_end(ap);
618   exit(1);
619 }
620 
621 void
warning(const char * format,...)622 warning(const char* format, ...) {
623   va_list ap;
624   va_start(ap, format);
625   fprintf(stderr, "%s: Warning: in `%s': ", program_name, input_file_name);
626   vfprintf(stderr, format, ap);
627   fprintf(stderr, "\n");
628   va_end(ap);
629 }
630 
631 #if PPL_CXX_SUPPORTS_LIMITING_MEMORY && PPL_HAVE_DECL_RLIMIT_AS
632 
633 void
limit_virtual_memory(const unsigned long bytes)634 limit_virtual_memory(const unsigned long bytes) {
635   struct rlimit t;
636 
637   if (getrlimit(RLIMIT_AS, &t) != 0) {
638     fatal("getrlimit failed: %s", strerror(errno));
639   }
640   if (bytes < t.rlim_cur) {
641     t.rlim_cur = bytes;
642     if (setrlimit(RLIMIT_AS, &t) != 0) {
643       fatal("setrlimit failed: %s", strerror(errno));
644     }
645   }
646 }
647 
648 #else
649 
650 void
limit_virtual_memory(unsigned long)651 limit_virtual_memory(unsigned long) {
652 }
653 
654 #endif // !PPL_HAVE_DECL_RLIMIT_AS
655 
656 void
process_options(int argc,char * argv[])657 process_options(int argc, char* argv[]) {
658   while (true) {
659 #ifdef PPL_HAVE_GETOPT_H
660     int option_index = 0;
661     const int c = getopt_long(argc, argv, OPTION_LETTERS, long_options,
662                         &option_index);
663 #else
664     const int c = getopt(argc, argv, OPTION_LETTERS);
665 #endif
666 
667     if (c == EOF) {
668       break;
669     }
670     char* endptr;
671     switch (c) {
672     case 0:
673       break;
674 
675     case '?':
676     case 'h':
677       fprintf(stdout, usage_string, argv[0]);
678       exit(0);
679       break;
680 
681     case 'R':
682       {
683         const unsigned long MEGA = 1024U*1024U;
684         const long l = strtol(optarg, &endptr, 10);
685         if (*endptr || l < 0) {
686           fatal("a non-negative integer must follow `-R'");
687         }
688         else if (static_cast<unsigned long>(l) > ULONG_MAX/MEGA) {
689           max_bytes_of_virtual_memory = ULONG_MAX;
690         }
691         else {
692           max_bytes_of_virtual_memory = static_cast<unsigned long>(l)*MEGA;
693         }
694       }
695       break;
696 
697     case 'o':
698       output_file_name = optarg;
699       break;
700 
701     case 'P':
702       piplib_format = false;
703       break;
704 
705     case 'p':
706       piplib_format = true;
707       break;
708 
709     case 't':
710       print_timings = true;
711       break;
712 
713     case 'v':
714       verbose = true;
715       break;
716 
717     case 'i':
718       loop_iterations = strtol(optarg, &endptr, 10);
719       if (*endptr || loop_iterations < 1) {
720         fatal("a positive integer must follow `-i'");
721       }
722       break;
723 
724 #if defined(USE_PPL)
725 
726     case 'V':
727       fprintf(stdout, "%s\n", PPL_VERSION);
728       exit(0);
729       break;
730 
731     case 'c':
732       check_file_name = optarg;
733       break;
734 
735 #endif
736 
737     case 'f':
738       cutting_strategy = PPL::PIP_Problem::CUTTING_STRATEGY_FIRST;
739       break;
740 
741     case 'd':
742       cutting_strategy = PPL::PIP_Problem::CUTTING_STRATEGY_DEEPEST;
743       break;
744 
745     case 'a':
746       cutting_strategy = PPL::PIP_Problem::CUTTING_STRATEGY_ALL;
747       break;
748 
749     case 'F':
750       pivot_row_strategy = PPL::PIP_Problem::PIVOT_ROW_STRATEGY_FIRST;
751       break;
752 
753     case 'M':
754       pivot_row_strategy = PPL::PIP_Problem::PIVOT_ROW_STRATEGY_MAX_COLUMN;
755       break;
756 
757     default:
758       abort();
759     }
760   }
761 
762   if (argc - optind > 1) {
763     // We have multiple input files.
764     fatal("at most one input file is accepted");
765   }
766   // We have one input files.
767   if (optind < argc) {
768     input_file_name = argv[optind];
769   }
770   else {
771     // If no input files have been specified: we will read from standard input.
772     assert(input_file_name == 0);
773   }
774 }
775 
776 void
maybe_start_clock()777 maybe_start_clock() {
778   if (print_timings) {
779     start_clock();
780   }
781 }
782 
783 void
maybe_print_clock()784 maybe_print_clock() {
785   if (print_timings) {
786     std::cerr << input_file_name << " ";
787     print_clock(std::cerr);
788     std::cerr << std::endl;
789   }
790 }
791 
792 int
main(int argc,char * argv[])793 main(int argc, char* argv[]) try {
794   program_name = argv[0];
795 
796 #if defined(USE_PPL)
797   if (strcmp(PPL_VERSION, PPL::version()) != 0) {
798     fatal("was compiled with PPL version %s, but linked with version %s",
799           PPL_VERSION, PPL::version());
800   }
801   if (verbose) {
802     std::cerr << "Parma Polyhedra Library version:\n" << PPL::version()
803               << "\n\nParma Polyhedra Library banner:\n" << PPL::banner()
804               << std::endl;
805   }
806 #endif
807 
808   // Process command line options.
809   process_options(argc, argv);
810 
811   if (max_bytes_of_virtual_memory > 0) {
812     limit_virtual_memory(max_bytes_of_virtual_memory);
813   }
814   // Set up the input and output streams.
815   set_input(input_file_name);
816   set_output(output_file_name);
817 
818 //  POLYHEDRON_TYPE ph;
819 //  Representation rep = read_polyhedron(input(), ph);
820   std::auto_ptr<PIP_Parser> parser;
821   if (piplib_format) {
822     parser.reset(new PIP_PipLib_Parser);
823   }
824   else{
825     parser.reset(new PIP_PolyLib_Parser);
826   }
827   if (!parser->read(*input_stream_p)) {
828     return 1;
829   }
830   maybe_start_clock();
831 
832   const PPL::PIP_Problem& pip = parser->problem();
833 
834   if (loop_iterations == 1) {
835     // Compute the dual simplex on the problem.
836     pip.solve();
837     // Write the solution.
838     parser->output_solution_tree(*output_stream_p);
839   }
840   else {
841     std::auto_ptr<PPL::PIP_Problem> pip_p;
842     // Perform a time benchmark loop executing the resolution several times.
843     for (long i = 0; i < loop_iterations; ++i) {
844       pip_p.reset(new PPL::PIP_Problem(pip));
845       pip_p->solve();
846     }
847   }
848 
849 #if defined(USE_PPL) || defined(USE_PIPLIB)
850   maybe_print_clock();
851 #endif
852 
853   return 0;
854 }
855 catch (const std::bad_alloc&) {
856   fatal("out of memory");
857   exit(1);
858 }
859 catch (const std::overflow_error& e) {
860   fatal("arithmetic overflow (%s)", e.what());
861   exit(1);
862 }
863 catch (...) {
864   fatal("internal error: please submit a bug report to ppl-devel@cs.unipr.it");
865   exit(1);
866 }
867