diff options
Diffstat (limited to 'demos/ppl_lpsol/ppl_lpsol.c')
-rw-r--r-- | demos/ppl_lpsol/ppl_lpsol.c | 1418 |
1 files changed, 1418 insertions, 0 deletions
diff --git a/demos/ppl_lpsol/ppl_lpsol.c b/demos/ppl_lpsol/ppl_lpsol.c new file mode 100644 index 000000000..cef707e3b --- /dev/null +++ b/demos/ppl_lpsol/ppl_lpsol.c @@ -0,0 +1,1418 @@ +/* Solve linear programming problems by either vertex/point enumeration + or the primal simplex algorithm. + Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> + Copyright (C) 2010-2011 BUGSENG srl (http://bugseng.com) + +This file is part of the Parma Polyhedra Library (PPL). + +The PPL is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +The PPL is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. + +For the most up-to-date information see the Parma Polyhedra Library +site: http://www.cs.unipr.it/ppl/ . */ + +#include <ppl-config.h> +#include "ppl_c.h" +#include <gmp.h> +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <time.h> +#include <stdarg.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <math.h> + +#if defined(PPL_HAVE_GLPK_GLPK_H) +#include <glpk/glpk.h> +#elif defined(PPL_HAVE_GLPK_H) +#include <glpk.h> +#endif + +#ifdef PPL_HAVE_GETOPT_H +# include <getopt.h> + +/* Try to accommodate non-GNU implementations of `getopt()'. */ +#if !defined(no_argument) && defined(NO_ARG) +#define no_argument NO_ARG +#endif + +#if !defined(required_argument) && defined(REQUIRED_ARG) +#define required_argument REQUIRED_ARG +#endif + +#if !defined(optional_argument) && defined(OPTIONAL_ARG) +#define optional_argument OPTIONAL_ARG +#endif + +#endif /* defined(PPL_HAVE_GETOPT_H) */ + +#ifdef PPL_HAVE_UNISTD_H +/* Include this for `getopt()': especially important if we do not have + <getopt.h>. */ +# include <unistd.h> +#endif + +#ifdef PPL_HAVE_SIGNAL_H +# include <signal.h> +#endif + +#ifdef PPL_HAVE_SYS_TIME_H +# include <sys/time.h> +#endif + +#ifdef PPL_HAVE_SYS_RESOURCE_H +/* This should be included after <time.h> and <sys/time.h> so as to make + sure we have the definitions for, e.g., `ru_utime'. */ +# include <sys/resource.h> +#endif + +#if PPL_VERSION_MAJOR == 0 && PPL_VERSION_MINOR < 10 +# error "PPL version 0.10 or following is required" +#endif + +static const char* ppl_source_version = PPL_VERSION; + +#ifdef __GNUC__ +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#else +# define ATTRIBUTE_UNUSED +#endif + +#if PPL_HAVE_DECL_GETRUSAGE +# define PPL_LPSOL_SUPPORTS_TIMINGS +#endif + +#if defined(PPL_HAVE_SYS_RESOURCE_H) \ + && (defined(SA_ONESHOT) || defined(SA_RESETHAND)) +# define PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME +#endif + +#ifdef PPL_HAVE_GETOPT_H +static struct option long_options[] = { + {"check", optional_argument, 0, 'c'}, + {"help", no_argument, 0, 'h'}, + {"incremental", no_argument, 0, 'i'}, + {"min", no_argument, 0, 'm'}, + {"max", no_argument, 0, 'M'}, + {"no-optimization", no_argument, 0, 'n'}, + {"no-mip", no_argument, 0, 'r'}, + {"max-cpu", required_argument, 0, 'C'}, + {"max-memory", required_argument, 0, 'R'}, + {"output", required_argument, 0, 'o'}, + {"pricing", required_argument, 0, 'p'}, + {"enumerate", no_argument, 0, 'e'}, + {"simplex", no_argument, 0, 's'}, +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + {"timings", no_argument, 0, 't'}, +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + {"verbosity", required_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0} +}; +#endif + +#define USAGE_STRING0 \ + "Usage: %s [OPTION]... [FILE]\n" \ + "Reads a file in MPS format and attempts solution using the optimization\n" \ + "algorithms provided by the PPL.\n\n" \ + "Options:\n" \ + " -c, --check[=THRESHOLD] checks the obtained results using GLPK;\n" \ + " optima are checked with a tolerance of\n" \ + " THRESHOLD (default %.10g); input data\n" \ + " are also perturbed the same way as GLPK does\n" \ + " -i, --incremental solves the problem incrementally\n" +#define USAGE_STRING1 \ + " -m, --min minimizes the objective function\n" \ + " -M, --max maximizes the objective function (default)\n" \ + " -n, --no-optimization checks for satisfiability only\n" \ + " -r, --no-mip consider integer variables as real variables\n" \ + " -CSECS, --max-cpu=SECS limits CPU usage to SECS seconds\n" \ + " -RMB, --max-memory=MB limits memory usage to MB megabytes\n" \ + " -h, --help prints this help text to stdout\n" \ + " -oPATH, --output=PATH appends output to PATH\n" +#define USAGE_STRING2 \ + " -e, --enumerate use the (expensive!) enumeration method\n" \ + " -pM, --pricing=M use pricing method M for simplex (assumes -s);\n" \ + " M is an int from 0 to 2, default 0:\n" \ + " 0 --> steepest-edge using floating point\n" \ + " 1 --> steepest-edge using exact arithmetic\n" \ + " 2 --> textbook\n" \ + " -s, --simplex use the simplex method\n" +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS +#define USAGE_STRING3 \ + " -t, --timings prints timings to stderr\n" +#else /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ +#define USAGE_STRING3 \ + "" +#endif /* !defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ +#define USAGE_STRING4 \ + " -v, --verbosity=LEVEL sets verbosity level (from 0 to 4, default 3):\n" \ + " 0 --> quiet: no output except for errors and\n" \ + " explicitly required notifications\n" \ + " 1 --> solver state only\n" \ + " 2 --> state + optimal value\n" \ + " 3 --> state + optimal value + optimum location\n" \ + " 4 --> lots of output\n" \ + " -V, --version prints version information to stdout\n" +#ifndef PPL_HAVE_GETOPT_H +#define USAGE_STRING5 \ + "\n" \ + "NOTE: this version does not support long options.\n" +#else /* defined(PPL_HAVE_GETOPT_H) */ +#define USAGE_STRING5 \ + "" +#endif /* !defined(PPL_HAVE_GETOPT_H) */ +#define USAGE_STRING6 \ + "\n" \ + "Report bugs to <ppl-devel@cs.unipr.it>.\n" + + +#define OPTION_LETTERS "bc::eimnMC:R:ho:p:rstVv:" + +static const char* program_name = 0; +static unsigned long max_bytes_of_virtual_memory = 0; +static const char* output_argument = 0; +FILE* output_file = NULL; +static int check_results = 0; +static int use_simplex = 0; +static int pricing_method = 0; +static int verbosity = 3; +static int maximize = 1; +static int incremental = 0; +static int no_optimization = 0; +static int no_mip = 0; +static int check_results_failed = 0; +static double check_threshold = 0.0; +static const double default_check_threshold = 0.000000001; + +#ifdef PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME +static unsigned long max_seconds_of_cpu_time = 0; +#endif /* defined (PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME) */ + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS +static int print_timings = 0; +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + +static void +my_exit(int status) { + (void) ppl_finalize(); + exit(status); +} + +void +fatal(const char* format, ...) { + va_list ap; + fprintf(stderr, "%s: ", program_name); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "\n"); + my_exit(1); +} + +#if 0 +static void +warning(const char* format, ...) { + va_list ap; + va_start(ap, format); + fprintf(stderr, "%s: warning: ", program_name); + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); +} +#endif + +static void +error(const char* format, ...) { + va_list ap; + fprintf(stderr, "%s: ", program_name); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "\n"); + if (output_argument) { + va_start(ap, format); + vfprintf(output_file, format, ap); + va_end(ap); + fprintf(output_file, "\n"); + } +} + +static const char* +get_ppl_version() { + const char* p; + (void) ppl_version(&p); + return p; +} + +static const char* +get_ppl_banner() { + const char* p; + (void) ppl_banner(&p); + return p; +} + +static void +process_options(int argc, char* argv[]) { +#ifdef PPL_HAVE_GETOPT_H + int option_index; +#endif + int enumerate_required = 0; + int simplex_required = 0; + int incremental_required = 0; + int no_optimization_required = 0; + int no_mip_required = 0; + int c; + char* endptr; + long l; + double d; + + while (1) { +#ifdef PPL_HAVE_GETOPT_H + option_index = 0; + c = getopt_long(argc, argv, OPTION_LETTERS, long_options, &option_index); +#else + c = getopt(argc, argv, OPTION_LETTERS); +#endif + if (c == EOF) + break; + + switch (c) { + case 0: + break; + + case 'c': + check_results = 1; + if (optarg) { + d = strtod(optarg, &endptr); + if (*endptr || errno == ERANGE || d < 0.0) + fatal("only a non-negative floating point number can `-c'"); + else + check_threshold = d; + } + else + check_threshold = default_check_threshold; + break; + + case 'm': + maximize = 0; + break; + + case 'M': + maximize = 1; + break; + + case '?': + case 'h': + fprintf(stdout, USAGE_STRING0, argv[0], default_check_threshold); + fputs(USAGE_STRING1, stdout); + fputs(USAGE_STRING2, stdout); + fputs(USAGE_STRING3, stdout); + fputs(USAGE_STRING4, stdout); + my_exit(0); + break; + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + case 'C': + l = strtol(optarg, &endptr, 10); + if (*endptr || l < 0) + fatal("a non-negative integer must follow `-C'"); + else + max_seconds_of_cpu_time = l; + break; + +#endif /* defined (PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME) */ + + case 'R': + l = strtol(optarg, &endptr, 10); + if (*endptr || l < 0) + fatal("a non-negative integer must follow `-R'"); + else if (((unsigned long) l) > ULONG_MAX/(1024*1024)) + max_bytes_of_virtual_memory = ULONG_MAX; + else + max_bytes_of_virtual_memory = l*1024*1024; + break; + + case 'o': + output_argument = optarg; + break; + + case 'p': + l = strtol(optarg, &endptr, 10); + if (*endptr || l < 0 || l > 2) + fatal("0 or 1 or 2 must follow `-p'"); + else + pricing_method = l; + break; + + case 'e': + enumerate_required = 1; + break; + + case 's': + simplex_required = 1; + break; + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + case 't': + print_timings = 1; + break; + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + case 'v': + l = strtol(optarg, &endptr, 10); + if (*endptr || l < 0 || l > 4) + fatal("verbosity must be an integer between 0 and 4"); + else + verbosity = l; + break; + + case 'V': + fprintf(stdout, "%s\n", PPL_VERSION); + my_exit(0); + break; + + case 'i': + incremental_required = 1; + break; + + case 'n': + no_optimization_required = 1; + break; + + case 'r': + no_mip_required = 1; + break; + + default: + abort(); + } + } + + if (enumerate_required + && (simplex_required + || incremental_required)) + fatal("-e option is incompatible with -i and -s"); + + if (enumerate_required) + use_simplex = 0; + else if (simplex_required) + use_simplex = 1; + + if (incremental_required) + incremental = 1; + + if (no_optimization_required) + no_optimization = 1; + + if (no_mip_required) + no_mip = 1; + + if (optind >= argc) { + if (verbosity >= 4) + fprintf(stderr, + "Parma Polyhedra Library version:\n%s\n\n" + "Parma Polyhedra Library banner:\n%s\n", + get_ppl_version(), + get_ppl_banner()); + else + fatal("no input files"); + } + + if (argc - optind > 1) + /* We have multiple input files. */ + fatal("only one input file is accepted"); + + if (output_argument) { + output_file = fopen(output_argument, "a"); + if (output_file == NULL) + fatal("cannot open output file `%s'", output_argument); + } + else + output_file = stdout; +} + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + +/* To save the time when start_clock is called. */ +static struct timeval saved_ru_utime; + +static void +start_clock() { + struct rusage rsg; + if (getrusage(RUSAGE_SELF, &rsg) != 0) + fatal("getrusage failed: %s", strerror(errno)); + else + saved_ru_utime = rsg.ru_utime; +} + +static void +print_clock(FILE* f) { + struct rusage rsg; + if (getrusage(RUSAGE_SELF, &rsg) != 0) + fatal("getrusage failed: %s", strerror(errno)); + else { + time_t current_secs = rsg.ru_utime.tv_sec; + time_t current_usecs = rsg.ru_utime.tv_usec; + time_t saved_secs = saved_ru_utime.tv_sec; + time_t saved_usecs = saved_ru_utime.tv_usec; + int secs; + int hsecs; + if (current_usecs < saved_usecs) { + hsecs = (((1000000 + current_usecs) - saved_usecs) + 5000) / 10000; + secs = (current_secs - saved_secs) -1; + } + else { + hsecs = ((current_usecs - saved_usecs) + 5000) / 10000; + secs = current_secs - saved_secs; + } + assert(hsecs >= 0 && hsecs < 100 && secs >= 0); + fprintf(f, "%d.%.2d", secs, hsecs); + } +} + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + +#ifdef PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME + +void +set_alarm_on_cpu_time(unsigned seconds, void (*handler)(int)) { + sigset_t mask; + struct sigaction s; + struct rlimit t; + + sigemptyset(&mask); + + s.sa_handler = handler; + s.sa_mask = mask; +#if defined(SA_ONESHOT) + s.sa_flags = SA_ONESHOT; +#elif defined(SA_RESETHAND) + s.sa_flags = SA_RESETHAND; +#else +# error "Either SA_ONESHOT or SA_RESETHAND must be defined." +#endif + + if (sigaction(SIGXCPU, &s, 0) != 0) + fatal("sigaction failed: %s", strerror(errno)); + + if (getrlimit(RLIMIT_CPU, &t) != 0) + fatal("getrlimit failed: %s", strerror(errno)); + + if (seconds < t.rlim_cur) { + t.rlim_cur = seconds; + if (setrlimit(RLIMIT_CPU, &t) != 0) + fatal("setrlimit failed: %s", strerror(errno)); + } +} + +#endif /* defined(PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME) */ + +#if PPL_HAVE_DECL_RLIMIT_AS + +void +limit_virtual_memory(unsigned long bytes) { + struct rlimit t; + + if (getrlimit(RLIMIT_AS, &t) != 0) + fatal("getrlimit failed: %s", strerror(errno)); + + if (bytes < t.rlim_cur) { + t.rlim_cur = bytes; + if (setrlimit(RLIMIT_AS, &t) != 0) + fatal("setrlimit failed: %s", strerror(errno)); + } +} + +#else + +void +limit_virtual_memory(unsigned long bytes ATTRIBUTE_UNUSED) { +} + +#endif /* !PPL_HAVE_DECL_RLIMIT_AS */ + +#ifdef PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME + +static void +my_timeout(int dummy ATTRIBUTE_UNUSED) { + fprintf(stderr, "TIMEOUT\n"); + if (output_argument) + fprintf(output_file, "TIMEOUT\n"); + my_exit(0); +} + +#endif /* defined(PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME) */ + +static mpz_t tmp_z; +static mpq_t tmp1_q; +static mpq_t tmp2_q; +static ppl_Coefficient_t ppl_coeff; +static LPX* glpk_lp; +static int glpk_lp_problem_kind; +static int glpk_lp_num_int; +static ppl_dimension_type* integer_variables; + +static void +maybe_check_results(const int ppl_status, const double ppl_optimum_value) { + const char* ppl_status_string; + const char* glpk_status_string; + int glpk_status; + int treat_as_lp = 0; + if (!check_results) + return; + + /* Disable GLPK output. */ + lpx_set_int_parm(glpk_lp, LPX_K_MSGLEV, 0); + + if (no_mip || glpk_lp_problem_kind == LPX_LP) + treat_as_lp = 1; + + lpx_set_obj_dir(glpk_lp, (maximize ? LPX_MAX : LPX_MIN)); + + if (treat_as_lp) { + /* Set the problem class to LP: MIP problems are thus treated as + LP ones. */ + lpx_set_class(glpk_lp, LPX_LP); + lpx_exact(glpk_lp); + glpk_status = lpx_get_status(glpk_lp); + } + else { + /* MIP case. */ + lpx_intopt(glpk_lp); + glpk_status = lpx_mip_status(glpk_lp); + } + /* If no_optimization is enabled, the second case is not possibile. */ + if (!((ppl_status == PPL_MIP_PROBLEM_STATUS_UNFEASIBLE + && (glpk_status == LPX_NOFEAS || glpk_status == LPX_I_NOFEAS)) + || (ppl_status == PPL_MIP_PROBLEM_STATUS_UNBOUNDED + && (glpk_status == LPX_UNBND || glpk_status == LPX_I_UNDEF)) + || (ppl_status == PPL_MIP_PROBLEM_STATUS_OPTIMIZED + && ((glpk_status == LPX_OPT || glpk_status == LPX_I_OPT) + /* If no_optimization is enabled, check if the problem is + unbounded for GLPK. */ + || (no_optimization && (glpk_status == LPX_UNBND + || glpk_status == LPX_I_UNDEF)))))) { + + if (ppl_status == PPL_MIP_PROBLEM_STATUS_UNFEASIBLE) + ppl_status_string = "unfeasible"; + else if (ppl_status == PPL_MIP_PROBLEM_STATUS_UNBOUNDED) + ppl_status_string = "unbounded"; + else if (ppl_status == PPL_MIP_PROBLEM_STATUS_OPTIMIZED) + ppl_status_string = "optimizable"; + else + ppl_status_string = "<?>"; + + switch (glpk_status) { + case LPX_NOFEAS: + glpk_status_string = "unfeasible"; + break; + case LPX_UNBND: + glpk_status_string = "unbounded"; + break; + case LPX_OPT: + glpk_status_string = "optimizable"; + break; + case LPX_I_NOFEAS: + glpk_status_string = "unfeasible"; + break; + case LPX_I_OPT: + glpk_status_string = "optimizable"; + break; + case LPX_I_UNDEF: + glpk_status_string = "undefined"; + break; + default: + glpk_status_string = "<?>"; + break; + } + + error("check failed: for GLPK the problem is %s, not %s", + glpk_status_string, ppl_status_string); + + check_results_failed = 1; + } + else if (!no_optimization + && ppl_status == PPL_MIP_PROBLEM_STATUS_OPTIMIZED) { + + double glpk_optimum_value = treat_as_lp ? lpx_get_obj_val(glpk_lp) + : lpx_mip_obj_val(glpk_lp); + + if (fabs(ppl_optimum_value - glpk_optimum_value) > check_threshold) { + error("check failed: for GLPK the problem's optimum is %.20g," + " not %.20g", glpk_optimum_value, ppl_optimum_value); + check_results_failed = 1; + } + } + return; +} + + +static const char* +variable_output_function(ppl_dimension_type var) { + const char* name = lpx_get_col_name(glpk_lp, var+1); + if (name != NULL) + return name; + else + return 0; +} + +static void +add_constraints(ppl_Linear_Expression_t ppl_le, + int type, mpq_t rational_lb, mpq_t rational_ub, mpz_t den_lcm, + ppl_Constraint_System_t ppl_cs) { + ppl_Constraint_t ppl_c; + ppl_Linear_Expression_t ppl_le2; + switch (type) { + case LPX_FR: + break; + + case LPX_LO: + mpz_mul(tmp_z, den_lcm, mpq_numref(rational_lb)); + mpz_divexact(tmp_z, tmp_z, mpq_denref(rational_lb)); + mpz_neg(tmp_z, tmp_z); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_inhomogeneous(ppl_le, ppl_coeff); + ppl_new_Constraint(&ppl_c, ppl_le, PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL); + if (verbosity >= 4) { + ppl_io_fprint_Constraint(output_file, ppl_c); + fprintf(output_file, "\n"); + } + ppl_Constraint_System_insert_Constraint(ppl_cs, ppl_c); + ppl_delete_Constraint(ppl_c); + break; + + case LPX_UP: + mpz_mul(tmp_z, den_lcm, mpq_numref(rational_ub)); + mpz_divexact(tmp_z, tmp_z, mpq_denref(rational_ub)); + mpz_neg(tmp_z, tmp_z); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_inhomogeneous(ppl_le, ppl_coeff); + ppl_new_Constraint(&ppl_c, ppl_le, + PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL); + if (verbosity >= 4) { + ppl_io_fprint_Constraint(output_file, ppl_c); + fprintf(output_file, "\n"); + } + ppl_Constraint_System_insert_Constraint(ppl_cs, ppl_c); + ppl_delete_Constraint(ppl_c); + break; + + case LPX_DB: + ppl_new_Linear_Expression_from_Linear_Expression(&ppl_le2, ppl_le); + + mpz_mul(tmp_z, den_lcm, mpq_numref(rational_lb)); + mpz_divexact(tmp_z, tmp_z, mpq_denref(rational_lb)); + mpz_neg(tmp_z, tmp_z); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_inhomogeneous(ppl_le, ppl_coeff); + ppl_new_Constraint(&ppl_c, ppl_le, PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL); + if (verbosity >= 4) { + ppl_io_fprint_Constraint(output_file, ppl_c); + fprintf(output_file, "\n"); + } + ppl_Constraint_System_insert_Constraint(ppl_cs, ppl_c); + ppl_delete_Constraint(ppl_c); + + mpz_mul(tmp_z, den_lcm, mpq_numref(rational_ub)); + mpz_divexact(tmp_z, tmp_z, mpq_denref(rational_ub)); + mpz_neg(tmp_z, tmp_z); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_inhomogeneous(ppl_le2, ppl_coeff); + ppl_new_Constraint(&ppl_c, ppl_le2, PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL); + ppl_delete_Linear_Expression(ppl_le2); + if (verbosity >= 4) { + ppl_io_fprint_Constraint(output_file, ppl_c); + fprintf(output_file, "\n"); + } + ppl_Constraint_System_insert_Constraint(ppl_cs, ppl_c); + ppl_delete_Constraint(ppl_c); + break; + + case LPX_FX: + mpz_mul(tmp_z, den_lcm, mpq_numref(rational_lb)); + mpz_divexact(tmp_z, tmp_z, mpq_denref(rational_lb)); + mpz_neg(tmp_z, tmp_z); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_inhomogeneous(ppl_le, ppl_coeff); + ppl_new_Constraint(&ppl_c, ppl_le, + PPL_CONSTRAINT_TYPE_EQUAL); + if (verbosity >= 4) { + ppl_io_fprint_Constraint(output_file, ppl_c); + fprintf(output_file, "\n"); + } + ppl_Constraint_System_insert_Constraint(ppl_cs, ppl_c); + ppl_delete_Constraint(ppl_c); + break; + + default: + fatal("internal error"); + break; + } +} + +static int +solve_with_generators(ppl_Constraint_System_t ppl_cs, + ppl_const_Linear_Expression_t ppl_objective_le, + ppl_Coefficient_t optimum_n, + ppl_Coefficient_t optimum_d, + ppl_Generator_t point) { + ppl_Polyhedron_t ppl_ph; + int optimum_found = 0; + int empty; + int unbounded; + int included; + + /* Create the polyhedron (recycling the data structures of ppl_cs). */ + ppl_new_C_Polyhedron_recycle_Constraint_System(&ppl_ph, ppl_cs); + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + if (print_timings) { + fprintf(stderr, "Time to create a PPL polyhedron: "); + print_clock(stderr); + fprintf(stderr, " s\n"); + start_clock(); + } + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + empty = ppl_Polyhedron_is_empty(ppl_ph); + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + if (print_timings) { + fprintf(stderr, "Time to check for emptiness: "); + print_clock(stderr); + fprintf(stderr, " s\n"); + start_clock(); + } + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + if (empty) { + if (verbosity >= 1) + fprintf(output_file, "Unfeasible problem.\n"); + maybe_check_results(PPL_MIP_PROBLEM_STATUS_UNFEASIBLE, 0.0); + goto exit; + } + + if (!empty && no_optimization) { + if (verbosity >= 1) + fprintf(output_file, "Feasible problem.\n"); + /* Kludge: let's pass PPL_MIP_PROBLEM_STATUS_OPTIMIZED, + to let work `maybe_check_results'. */ + maybe_check_results(PPL_MIP_PROBLEM_STATUS_OPTIMIZED, 0.0); + goto exit; + } + + /* Check whether the problem is unbounded. */ + unbounded = maximize + ? !ppl_Polyhedron_bounds_from_above(ppl_ph, ppl_objective_le) + : !ppl_Polyhedron_bounds_from_below(ppl_ph, ppl_objective_le); + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + if (print_timings) { + fprintf(stderr, "Time to check for unboundedness: "); + print_clock(stderr); + fprintf(stderr, " s\n"); + start_clock(); + } + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + if (unbounded) { + if (verbosity >= 1) + fprintf(output_file, "Unbounded problem.\n"); + maybe_check_results(PPL_MIP_PROBLEM_STATUS_UNBOUNDED, 0.0); + goto exit; + } + + optimum_found = maximize + ? ppl_Polyhedron_maximize_with_point(ppl_ph, ppl_objective_le, + optimum_n, optimum_d, &included, + point) + : ppl_Polyhedron_minimize_with_point(ppl_ph, ppl_objective_le, + optimum_n, optimum_d, &included, + point); + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + if (print_timings) { + fprintf(stderr, "Time to find the optimum: "); + print_clock(stderr); + fprintf(stderr, " s\n"); + start_clock(); + } + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + if (!optimum_found) + fatal("internal error"); + + if (!included) + fatal("internal error"); + + exit: + ppl_delete_Polyhedron(ppl_ph); + return optimum_found; +} + +static int +solve_with_simplex(ppl_const_Constraint_System_t cs, + ppl_const_Linear_Expression_t objective, + ppl_Coefficient_t optimum_n, + ppl_Coefficient_t optimum_d, + ppl_Generator_t point) { + ppl_MIP_Problem_t ppl_mip; + int optimum_found = 0; + int pricing = 0; + int status = 0; + int satisfiable = 0; + ppl_dimension_type space_dim; + ppl_const_Constraint_t c; + ppl_const_Generator_t g; + ppl_Constraint_System_const_iterator_t i; + ppl_Constraint_System_const_iterator_t iend; + int counter; + int mode = maximize + ? PPL_OPTIMIZATION_MODE_MAXIMIZATION + : PPL_OPTIMIZATION_MODE_MINIMIZATION; + + ppl_Constraint_System_space_dimension(cs, &space_dim); + ppl_new_MIP_Problem_from_space_dimension(&ppl_mip, space_dim); + switch (pricing_method) { + case 0: + pricing = PPL_MIP_PROBLEM_CONTROL_PARAMETER_PRICING_STEEPEST_EDGE_FLOAT; + break; + case 1: + pricing = PPL_MIP_PROBLEM_CONTROL_PARAMETER_PRICING_STEEPEST_EDGE_EXACT; + break; + case 2: + pricing = PPL_MIP_PROBLEM_CONTROL_PARAMETER_PRICING_TEXTBOOK; + break; + default: + fatal("ppl_lpsol internal error"); + } + ppl_MIP_Problem_set_control_parameter(ppl_mip, pricing); + ppl_MIP_Problem_set_objective_function(ppl_mip, objective); + ppl_MIP_Problem_set_optimization_mode(ppl_mip, mode); + if (!no_mip) + ppl_MIP_Problem_add_to_integer_space_dimensions(ppl_mip, integer_variables, + glpk_lp_num_int); + if (incremental) { + /* Add the constraints of `cs' one at a time. */ + ppl_new_Constraint_System_const_iterator(&i); + ppl_new_Constraint_System_const_iterator(&iend); + ppl_Constraint_System_begin(cs, i); + ppl_Constraint_System_end(cs, iend); + + counter = 0; + while (!ppl_Constraint_System_const_iterator_equal_test(i, iend)) { + ++counter; + if (verbosity >= 4) + fprintf(output_file, "\nSolving constraint %d\n", counter); + ppl_Constraint_System_const_iterator_dereference(i, &c); + ppl_MIP_Problem_add_constraint(ppl_mip, c); + + if (no_optimization) { + satisfiable = ppl_MIP_Problem_is_satisfiable(ppl_mip); + if (!satisfiable) + break; + } + else + status = ppl_MIP_Problem_solve(ppl_mip); + ppl_Constraint_System_const_iterator_increment(i); + } + ppl_delete_Constraint_System_const_iterator(i); + ppl_delete_Constraint_System_const_iterator(iend); + } + + else { + ppl_MIP_Problem_add_constraints(ppl_mip, cs); + if (no_optimization) + satisfiable = ppl_MIP_Problem_is_satisfiable(ppl_mip); + else + status = ppl_MIP_Problem_solve(ppl_mip); + } + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + if (print_timings) { + fprintf(stderr, "Time to solve the problem: "); + print_clock(stderr); + fprintf(stderr, " s\n"); + start_clock(); + } + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + if ((no_optimization && !satisfiable) + || (!no_optimization && status == PPL_MIP_PROBLEM_STATUS_UNFEASIBLE)) { + if (verbosity >= 1) + fprintf(output_file, "Unfeasible problem.\n"); + maybe_check_results(status, 0.0); + goto exit; + } + else if (no_optimization && satisfiable) { + if (verbosity >= 1) + fprintf(output_file, "Feasible problem.\n"); + /* Kludge: let's pass PPL_MIP_PROBLEM_STATUS_OPTIMIZED, + to let work `maybe_check_results'. */ + maybe_check_results(PPL_MIP_PROBLEM_STATUS_OPTIMIZED, 0.0); + goto exit; + } + else if (status == PPL_MIP_PROBLEM_STATUS_UNBOUNDED) { + if (verbosity >= 1) + fprintf(output_file, "Unbounded problem.\n"); + maybe_check_results(status, 0.0); + goto exit; + } + else if (status == PPL_MIP_PROBLEM_STATUS_OPTIMIZED) { + ppl_MIP_Problem_optimal_value(ppl_mip, optimum_n, optimum_d); + ppl_MIP_Problem_optimizing_point(ppl_mip, &g); + ppl_assign_Generator_from_Generator(point, g); + optimum_found = 1; + goto exit; + } + else + fatal("internal error"); + + exit: + ppl_delete_MIP_Problem(ppl_mip); + return optimum_found; +} + +static void +set_mpq_t_from_double(mpq_t q, double d) { + void set_d_eps(mpq_t x, double val); + if (check_results) + set_d_eps(q, d); + else + mpq_set_d(q, d); +} + +static void +solve(char* file_name) { + ppl_Constraint_System_t ppl_cs; +#ifndef NDEBUG + ppl_Constraint_System_t ppl_cs_copy; +#endif + ppl_Generator_t optimum_location; + ppl_Linear_Expression_t ppl_le; + int dimension, row, num_rows, column, nz, i, j, type; + int* coefficient_index; + double lb, ub; + double* coefficient_value; + mpq_t rational_lb, rational_ub; + mpq_t* rational_coefficient; + mpq_t* objective; + ppl_Linear_Expression_t ppl_objective_le; + ppl_Coefficient_t optimum_n; + ppl_Coefficient_t optimum_d; + mpq_t optimum; + mpz_t den_lcm; + int optimum_found; + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + if (print_timings) + start_clock(); + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + if (verbosity == 0) { + /* FIXME: find a way to suppress output from lpx_read_mps. */ + } + + glpk_lp = lpx_read_mps(file_name); + + if (glpk_lp == NULL) + fatal("cannot read MPS file `%s'", file_name); + +#ifdef PPL_LPSOL_SUPPORTS_TIMINGS + + if (print_timings) { + fprintf(stderr, "Time to read the input file: "); + print_clock(stderr); + fprintf(stderr, " s\n"); + start_clock(); + } + +#endif /* defined(PPL_LPSOL_SUPPORTS_TIMINGS) */ + + glpk_lp_problem_kind = lpx_get_class(glpk_lp); + if (glpk_lp_problem_kind == LPX_MIP && !no_mip && !use_simplex) + fatal("the enumeration solving method can not handle MIP problems"); + + dimension = lpx_get_num_cols(glpk_lp); + + /* Read variables constrained to be integer. */ + if (glpk_lp_problem_kind == LPX_MIP && !no_mip && use_simplex) { + if (verbosity >= 4) + fprintf(output_file, "Integer variables:\n"); + glpk_lp_num_int = lpx_get_num_int(glpk_lp); + integer_variables = (ppl_dimension_type*) + malloc((glpk_lp_num_int + 1)*sizeof(ppl_dimension_type)); + for (i = 0, j = 0; i < dimension; ++i) + if (lpx_get_col_kind(glpk_lp, i+1) == LPX_IV) { + integer_variables[j] = i; + if (verbosity >= 4) { + ppl_io_fprint_variable(output_file, i); + fprintf(output_file, " "); + } + ++j; + } + } + coefficient_index = (int*) malloc((dimension+1)*sizeof(int)); + coefficient_value = (double*) malloc((dimension+1)*sizeof(double)); + rational_coefficient = (mpq_t*) malloc((dimension+1)*sizeof(mpq_t)); + + + ppl_new_Constraint_System(&ppl_cs); + + mpq_init(rational_lb); + mpq_init(rational_ub); + for (i = 1; i <= dimension; ++i) + mpq_init(rational_coefficient[i]); + + mpz_init(den_lcm); + + if (verbosity >= 4) + fprintf(output_file, "\nConstraints:\n"); + + /* Set up the row (ordinary) constraints. */ + num_rows = lpx_get_num_rows(glpk_lp); + for (row = 1; row <= num_rows; ++row) { + /* Initialize the least common multiple computation. */ + mpz_set_si(den_lcm, 1); + /* Set `nz' to the number of non-zero coefficients. */ + nz = lpx_get_mat_row(glpk_lp, row, coefficient_index, coefficient_value); + for (i = 1; i <= nz; ++i) { + set_mpq_t_from_double(rational_coefficient[i], coefficient_value[i]); + /* Update den_lcm. */ + mpz_lcm(den_lcm, den_lcm, mpq_denref(rational_coefficient[i])); + } + lpx_get_row_bnds(glpk_lp, row, &type, &lb, &ub); + set_mpq_t_from_double(rational_lb, lb); + mpz_lcm(den_lcm, den_lcm, mpq_denref(rational_lb)); + set_mpq_t_from_double(rational_ub, ub); + mpz_lcm(den_lcm, den_lcm, mpq_denref(rational_ub)); + + ppl_new_Linear_Expression_with_dimension(&ppl_le, dimension); + + for (i = 1; i <= nz; ++i) { + mpz_mul(tmp_z, den_lcm, mpq_numref(rational_coefficient[i])); + mpz_divexact(tmp_z, tmp_z, mpq_denref(rational_coefficient[i])); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_coefficient(ppl_le, coefficient_index[i]-1, + ppl_coeff); + } + + add_constraints(ppl_le, type, rational_lb, rational_ub, den_lcm, ppl_cs); + + ppl_delete_Linear_Expression(ppl_le); + } + + free(coefficient_value); + for (i = 1; i <= dimension; ++i) + mpq_clear(rational_coefficient[i]); + free(rational_coefficient); + free(coefficient_index); + +#ifndef NDEBUG + ppl_new_Constraint_System_from_Constraint_System(&ppl_cs_copy, ppl_cs); +#endif + + /* + FIXME: here we could build the polyhedron and minimize it before + adding the variable bounds. + */ + + /* Set up the columns constraints, i.e., variable bounds. */ + for (column = 1; column <= dimension; ++column) { + lpx_get_col_bnds(glpk_lp, column, &type, &lb, &ub); + + set_mpq_t_from_double(rational_lb, lb); + set_mpq_t_from_double(rational_ub, ub); + + /* Initialize the least common multiple computation. */ + mpz_set_si(den_lcm, 1); + mpz_lcm(den_lcm, den_lcm, mpq_denref(rational_lb)); + mpz_lcm(den_lcm, den_lcm, mpq_denref(rational_ub)); + + ppl_new_Linear_Expression_with_dimension(&ppl_le, dimension); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, den_lcm); + ppl_Linear_Expression_add_to_coefficient(ppl_le, column-1, ppl_coeff); + + add_constraints(ppl_le, type, rational_lb, rational_ub, den_lcm, ppl_cs); + + ppl_delete_Linear_Expression(ppl_le); + } + + mpq_clear(rational_ub); + mpq_clear(rational_lb); + + /* Deal with the objective function. */ + objective = (mpq_t*) malloc((dimension+1)*sizeof(mpq_t)); + + /* Initialize the least common multiple computation. */ + mpz_set_si(den_lcm, 1); + + mpq_init(objective[0]); + set_mpq_t_from_double(objective[0], lpx_get_obj_coef(glpk_lp, 0)); + for (i = 1; i <= dimension; ++i) { + mpq_init(objective[i]); + set_mpq_t_from_double(objective[i], lpx_get_obj_coef(glpk_lp, i)); + /* Update den_lcm. */ + mpz_lcm(den_lcm, den_lcm, mpq_denref(objective[i])); + } + + /* Set the ppl_objective_le to be the objective function. */ + ppl_new_Linear_Expression_with_dimension(&ppl_objective_le, dimension); + /* Set value for objective function's inhomogeneous term. */ + mpz_mul(tmp_z, den_lcm, mpq_numref(objective[0])); + mpz_divexact(tmp_z, tmp_z, mpq_denref(objective[0])); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_inhomogeneous(ppl_objective_le, ppl_coeff); + /* Set values for objective function's variable coefficients. */ + for (i = 1; i <= dimension; ++i) { + mpz_mul(tmp_z, den_lcm, mpq_numref(objective[i])); + mpz_divexact(tmp_z, tmp_z, mpq_denref(objective[i])); + ppl_assign_Coefficient_from_mpz_t(ppl_coeff, tmp_z); + ppl_Linear_Expression_add_to_coefficient(ppl_objective_le, i-1, ppl_coeff); + } + + if (verbosity >= 4) { + fprintf(output_file, "Objective function:\n"); + if (mpz_cmp_si(den_lcm, 1) != 0) + fprintf(output_file, "("); + ppl_io_fprint_Linear_Expression(output_file, ppl_objective_le); + } + + for (i = 0; i <= dimension; ++i) + mpq_clear(objective[i]); + free(objective); + + if (verbosity >= 4) { + if (mpz_cmp_si(den_lcm, 1) != 0) { + fprintf(output_file, ")/"); + mpz_out_str(output_file, 10, den_lcm); + } + fprintf(output_file, "\n%s\n", + (maximize ? "Maximizing." : "Minimizing.")); + } + + ppl_new_Coefficient(&optimum_n); + ppl_new_Coefficient(&optimum_d); + ppl_new_Generator_zero_dim_point(&optimum_location); + + optimum_found = use_simplex + ? solve_with_simplex(ppl_cs, + ppl_objective_le, + optimum_n, + optimum_d, + optimum_location) + : solve_with_generators(ppl_cs, + ppl_objective_le, + optimum_n, + optimum_d, + optimum_location); + + ppl_delete_Linear_Expression(ppl_objective_le); + + if (glpk_lp_problem_kind == LPX_MIP) + free(integer_variables); + + if (optimum_found) { + mpq_init(optimum); + ppl_Coefficient_to_mpz_t(optimum_n, tmp_z); + mpq_set_num(optimum, tmp_z); + ppl_Coefficient_to_mpz_t(optimum_d, tmp_z); + mpz_mul(tmp_z, tmp_z, den_lcm); + mpq_set_den(optimum, tmp_z); + if (verbosity == 1) + fprintf(output_file, "Optimized problem.\n"); + if (verbosity >= 2) + fprintf(output_file, "Optimum value: %.10g\n", mpq_get_d(optimum)); + if (verbosity >= 3) { + fprintf(output_file, "Optimum location:\n"); + ppl_Generator_divisor(optimum_location, ppl_coeff); + ppl_Coefficient_to_mpz_t(ppl_coeff, tmp_z); + for (i = 0; i < dimension; ++i) { + mpz_set(mpq_denref(tmp1_q), tmp_z); + ppl_Generator_coefficient(optimum_location, i, ppl_coeff); + ppl_Coefficient_to_mpz_t(ppl_coeff, mpq_numref(tmp1_q)); + ppl_io_fprint_variable(output_file, i); + fprintf(output_file, " = %.10g\n", mpq_get_d(tmp1_q)); + } + } +#ifndef NDEBUG + { + ppl_Polyhedron_t ph; + unsigned int relation; + ppl_new_C_Polyhedron_recycle_Constraint_System(&ph, ppl_cs_copy); + ppl_delete_Constraint_System(ppl_cs_copy); + relation = ppl_Polyhedron_relation_with_Generator(ph, optimum_location); + ppl_delete_Polyhedron(ph); + assert(relation == PPL_POLY_GEN_RELATION_SUBSUMES); + } +#endif + maybe_check_results(PPL_MIP_PROBLEM_STATUS_OPTIMIZED, + mpq_get_d(optimum)); + mpq_clear(optimum); + } + + ppl_delete_Constraint_System(ppl_cs); + ppl_delete_Coefficient(optimum_d); + ppl_delete_Coefficient(optimum_n); + ppl_delete_Generator(optimum_location); + + lpx_delete_prob(glpk_lp); +} + +static void +error_handler(enum ppl_enum_error_code code, + const char* description) { + if (output_argument) + fprintf(output_file, "PPL error code %d: %s\n", code, description); + fatal("PPL error code %d: %s", code, description); +} + +#if !PPL_CXX_SUPPORTS_ATTRIBUTE_WEAK +void +ppl_set_GMP_memory_allocation_functions(void) { +} +#endif + +#if defined(NDEBUG) + +#if !(defined(PPL_GLPK_HAS_GLP_TERM_OUT) && defined(GLP_OFF)) + +#if defined(PPL_GLPK_HAS_GLP_TERM_HOOK) \ + || defined(PPL_GLPK_HAS__GLP_LIB_PRINT_HOOK) + +static int +glpk_message_interceptor(void* info, const char* msg) { + (void) info; + (void) msg; + return 1; +} + +#elif defined(PPL_GLPK_HAS_LIB_SET_PRINT_HOOK) + +static int +glpk_message_interceptor(void* info, char* msg) { + (void) info; + (void) msg; + return 1; +} + +#endif /* !(defined(PPL_GLPK_HAS_GLP_TERM_HOOK) + || defined(PPL_GLPK_HAS__GLP_LIB_PRINT_HOOK)) + && defined(PPL_GLPK_HAS_LIB_SET_PRINT_HOOK) */ + +#endif /* !(defined(PPL_GLPK_HAS_GLP_TERM_OUT) && defined(GLP_OFF)) */ + +#endif /* defined(NDEBUG) */ + +int +main(int argc, char* argv[]) { +#if defined(PPL_GLPK_HAS__GLP_LIB_PRINT_HOOK) + extern void _glp_lib_print_hook(int (*func)(void *info, const char *buf), + void *info); +#endif + program_name = argv[0]; + if (ppl_initialize() < 0) + fatal("cannot initialize the Parma Polyhedra Library"); + + /* The PPL solver does not use floating point numbers, except + perhaps for the steepest edge heuristics. In contrast, GLPK does + use them, so it is best to restore the rounding mode as it was + prior to the PPL initialization. */ + if (ppl_restore_pre_PPL_rounding() < 0) + fatal("cannot restore the rounding mode"); + + if (ppl_set_error_handler(error_handler) < 0) + fatal("cannot install the custom error handler"); + + if (strcmp(ppl_source_version, get_ppl_version()) != 0) + fatal("was compiled with PPL version %s, but linked with version %s", + ppl_source_version, get_ppl_version()); + + if (ppl_io_set_variable_output_function(variable_output_function) < 0) + fatal("cannot install the custom variable output function"); + +#if defined(NDEBUG) +#if defined(PPL_GLPK_HAS_GLP_TERM_OUT) && defined(GLP_OFF) + glp_term_out(GLP_OFF); +#elif defined(PPL_GLPK_HAS_GLP_TERM_HOOK) + glp_term_hook(glpk_message_interceptor, 0); +#elif defined(PPL_GLPK_HAS__GLP_LIB_PRINT_HOOK) + _glp_lib_print_hook(glpk_message_interceptor, 0); +#elif defined(PPL_GLPK_HAS_LIB_SET_PRINT_HOOK) + lib_set_print_hook(0, glpk_message_interceptor); +#endif +#endif + + /* Process command line options. */ + process_options(argc, argv); + + /* Initialize globals. */ + mpz_init(tmp_z); + mpq_init(tmp1_q); + mpq_init(tmp2_q); + ppl_new_Coefficient(&ppl_coeff); + +#ifdef PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME + + if (max_seconds_of_cpu_time > 0) + set_alarm_on_cpu_time(max_seconds_of_cpu_time, my_timeout); + +#endif /* defined (PPL_LPSOL_SUPPORTS_LIMIT_ON_CPU_TIME) */ + + if (max_bytes_of_virtual_memory > 0) + limit_virtual_memory(max_bytes_of_virtual_memory); + + while (optind < argc) { + if (check_results) + check_results_failed = 0; + + solve(argv[optind++]); + + if (check_results && check_results_failed) + break; + } + + /* Finalize globals. */ + ppl_delete_Coefficient(ppl_coeff); + mpq_clear(tmp2_q); + mpq_clear(tmp1_q); + mpz_clear(tmp_z); + + /* Close output file, if any. */ + if (output_argument) + fclose(output_file); + + my_exit((check_results && check_results_failed) ? 1 : 0); + + /* This is just to avoid a compiler warning. */ + return 0; +} |