You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1584 lines
56 KiB
1584 lines
56 KiB
/* glpsol.c (stand-alone GLPK LP/MIP solver) */
|
|
|
|
/***********************************************************************
|
|
* This code is part of GLPK (GNU Linear Programming Kit).
|
|
*
|
|
* Copyright (C) 2000-2017 Andrew Makhorin, Department for Applied
|
|
* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
|
|
* reserved. E-mail: <mao@gnu.org>.
|
|
*
|
|
* GLPK 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.
|
|
*
|
|
* GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>.
|
|
***********************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <glpk.h>
|
|
|
|
#define xassert glp_assert
|
|
#define xerror glp_error
|
|
#define xprintf glp_printf
|
|
|
|
struct csa
|
|
{ /* common storage area */
|
|
glp_prob *prob;
|
|
/* LP/MIP problem object */
|
|
glp_bfcp bfcp;
|
|
/* basis factorization control parameters */
|
|
glp_smcp smcp;
|
|
/* simplex method control parameters */
|
|
glp_iptcp iptcp;
|
|
/* interior-point method control parameters */
|
|
glp_iocp iocp;
|
|
/* integer optimizer control parameters */
|
|
glp_tran *tran;
|
|
/* model translator workspace */
|
|
glp_graph *graph;
|
|
/* network problem object */
|
|
int format;
|
|
/* problem file format: */
|
|
#define FMT_MPS_DECK 1 /* fixed MPS */
|
|
#define FMT_MPS_FILE 2 /* free MPS */
|
|
#define FMT_LP 3 /* CPLEX LP */
|
|
#define FMT_GLP 4 /* GLPK LP/MIP */
|
|
#define FMT_MATHPROG 5 /* MathProg */
|
|
#define FMT_MIN_COST 6 /* DIMACS min-cost flow */
|
|
#define FMT_MAX_FLOW 7 /* DIMACS maximum flow */
|
|
#if 1 /* 06/VIII-2011 */
|
|
#define FMT_CNF 8 /* DIMACS CNF-SAT */
|
|
#endif
|
|
const char *in_file;
|
|
/* name of input problem file */
|
|
#define DATA_MAX 10
|
|
/* maximal number of input data files */
|
|
int ndf;
|
|
/* number of input data files specified */
|
|
const char *in_data[1+DATA_MAX];
|
|
/* name(s) of input data file(s) */
|
|
const char *out_dpy;
|
|
/* name of output file to send display output; NULL means the
|
|
display output is sent to the terminal */
|
|
int seed;
|
|
/* seed value to be passed to the MathProg translator; initially
|
|
set to 1; 0x80000000 means the value is omitted */
|
|
int solution;
|
|
/* solution type flag: */
|
|
#define SOL_BASIC 1 /* basic */
|
|
#define SOL_INTERIOR 2 /* interior-point */
|
|
#define SOL_INTEGER 3 /* mixed integer */
|
|
const char *in_res;
|
|
/* name of input solution file in raw format */
|
|
int dir;
|
|
/* optimization direction flag:
|
|
0 - not specified
|
|
GLP_MIN - minimization
|
|
GLP_MAX - maximization */
|
|
int scale;
|
|
/* automatic problem scaling flag */
|
|
const char *out_sol;
|
|
/* name of output solution file in printable format */
|
|
const char *out_res;
|
|
/* name of output solution file in raw format */
|
|
const char *out_ranges;
|
|
/* name of output file to write sensitivity analysis report */
|
|
int check;
|
|
/* input data checking flag; no solution is performed */
|
|
const char *new_name;
|
|
/* new name to be assigned to the problem */
|
|
#if 1 /* 18/I-2018 */
|
|
int hide;
|
|
/* clear all symbolic names in the problem object */
|
|
#endif
|
|
const char *out_mps;
|
|
/* name of output problem file in fixed MPS format */
|
|
const char *out_freemps;
|
|
/* name of output problem file in free MPS format */
|
|
const char *out_cpxlp;
|
|
/* name of output problem file in CPLEX LP format */
|
|
const char *out_glp;
|
|
/* name of output problem file in GLPK format */
|
|
#if 0
|
|
const char *out_pb;
|
|
/* name of output problem file in OPB format */
|
|
const char *out_npb;
|
|
/* name of output problem file in normalized OPB format */
|
|
#endif
|
|
#if 1 /* 06/VIII-2011 */
|
|
const char *out_cnf;
|
|
/* name of output problem file in DIMACS CNF-SAT format */
|
|
#endif
|
|
const char *log_file;
|
|
/* name of output file to hardcopy terminal output */
|
|
int crash;
|
|
/* initial basis option: */
|
|
#define USE_STD_BASIS 1 /* use standard basis */
|
|
#define USE_ADV_BASIS 2 /* use advanced basis */
|
|
#define USE_CPX_BASIS 3 /* use Bixby's basis */
|
|
#define USE_INI_BASIS 4 /* use initial basis from ini_file */
|
|
const char *ini_file;
|
|
/* name of input file containing initial basis */
|
|
int exact;
|
|
/* flag to use glp_exact rather than glp_simplex */
|
|
int xcheck;
|
|
/* flag to check final basis with glp_exact */
|
|
int nomip;
|
|
/* flag to consider MIP as pure LP */
|
|
#if 1 /* 15/VIII-2011 */
|
|
int minisat;
|
|
/* option to solve feasibility problem with MiniSat solver */
|
|
int use_bnd;
|
|
/* option to bound objective function */
|
|
int obj_bnd;
|
|
/* upper (minization) or lower (maximization) objective bound */
|
|
#endif
|
|
#if 1 /* 11/VII-2013 */
|
|
const char *use_sol;
|
|
/* name of input mip solution file in GLPK format */
|
|
#endif
|
|
};
|
|
|
|
static int str2int(const char *s, int *x)
|
|
{ /* convert string to integer */
|
|
long t;
|
|
char *endptr;
|
|
t = strtol(s, &endptr, 10);
|
|
if (*endptr != '\0')
|
|
return 2;
|
|
if (!(INT_MIN <= t && t <= INT_MAX))
|
|
return 1;
|
|
*x = t;
|
|
#if 0
|
|
xprintf("str2int: x = %d\n", *x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int str2num(const char *s, double *x)
|
|
{ /* convert string to floating point */
|
|
double t;
|
|
char *endptr;
|
|
t = strtod(s, &endptr);
|
|
if (*endptr != '\0')
|
|
return 2;
|
|
if (!(-DBL_MAX <= t && t <= +DBL_MAX))
|
|
return 1;
|
|
*x = t;
|
|
#if 0
|
|
xprintf("str2num: x = %g\n", *x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void print_help(const char *my_name)
|
|
{ /* print help information */
|
|
xprintf("Usage: %s [options...] filename\n", my_name);
|
|
xprintf("\n");
|
|
xprintf("General options:\n");
|
|
xprintf(" --mps read LP/MIP problem in fixed MPS fo"
|
|
"rmat\n");
|
|
xprintf(" --freemps read LP/MIP problem in free MPS for"
|
|
"mat (default)\n");
|
|
xprintf(" --lp read LP/MIP problem in CPLEX LP for"
|
|
"mat\n");
|
|
xprintf(" --glp read LP/MIP problem in GLPK format "
|
|
"\n");
|
|
xprintf(" --math read LP/MIP model written in GNU Ma"
|
|
"thProg modeling\n");
|
|
xprintf(" language\n");
|
|
xprintf(" -m filename, --model filename\n");
|
|
xprintf(" read model section and optional dat"
|
|
"a section from\n");
|
|
xprintf(" filename (same as --math)\n");
|
|
xprintf(" -d filename, --data filename\n");
|
|
xprintf(" read data section from filename (fo"
|
|
"r --math only);\n");
|
|
xprintf(" if model file also has data section"
|
|
", it is ignored\n");
|
|
xprintf(" -y filename, --display filename\n");
|
|
xprintf(" send display output to filename (fo"
|
|
"r --math only);\n");
|
|
xprintf(" by default the output is sent to te"
|
|
"rminal\n");
|
|
xprintf(" --seed value initialize pseudo-random number gen"
|
|
"erator used in\n");
|
|
xprintf(" MathProg model with specified seed "
|
|
"(any integer);\n");
|
|
xprintf(" if seed value is ?, some random see"
|
|
"d will be used\n");
|
|
xprintf(" --mincost read min-cost flow problem in DIMAC"
|
|
"S format\n");
|
|
xprintf(" --maxflow read maximum flow problem in DIMACS"
|
|
" format\n");
|
|
#if 1 /* 06/VIII-2011 */
|
|
xprintf(" --cnf read CNF-SAT problem in DIMACS form"
|
|
"at\n");
|
|
#endif
|
|
xprintf(" --simplex use simplex method (default)\n");
|
|
xprintf(" --interior use interior point method (LP only)"
|
|
"\n");
|
|
xprintf(" -r filename, --read filename\n");
|
|
xprintf(" read solution from filename rather "
|
|
"to find it with\n");
|
|
xprintf(" the solver\n");
|
|
xprintf(" --min minimization\n");
|
|
xprintf(" --max maximization\n");
|
|
xprintf(" --scale scale problem (default)\n");
|
|
xprintf(" --noscale do not scale problem\n");
|
|
xprintf(" -o filename, --output filename\n");
|
|
xprintf(" write solution to filename in print"
|
|
"able format\n");
|
|
xprintf(" -w filename, --write filename\n");
|
|
xprintf(" write solution to filename in plain"
|
|
" text format\n");
|
|
xprintf(" --ranges filename\n");
|
|
xprintf(" write sensitivity analysis report t"
|
|
"o filename in\n");
|
|
xprintf(" printable format (simplex only)\n");
|
|
xprintf(" --tmlim nnn limit solution time to nnn seconds "
|
|
"\n");
|
|
xprintf(" --memlim nnn limit available memory to nnn megab"
|
|
"ytes\n");
|
|
xprintf(" --check do not solve problem, check input d"
|
|
"ata only\n");
|
|
xprintf(" --name probname change problem name to probname\n");
|
|
#if 1 /* 18/I-2018 */
|
|
xprintf(" --hide remove all symbolic names from prob"
|
|
"lem object\n");
|
|
#endif
|
|
xprintf(" --wmps filename write problem to filename in fixed "
|
|
"MPS format\n");
|
|
xprintf(" --wfreemps filename\n");
|
|
xprintf(" write problem to filename in free M"
|
|
"PS format\n");
|
|
xprintf(" --wlp filename write problem to filename in CPLEX "
|
|
"LP format\n");
|
|
xprintf(" --wglp filename write problem to filename in GLPK f"
|
|
"ormat\n");
|
|
#if 0
|
|
xprintf(" --wpb filename write problem to filename in OPB fo"
|
|
"rmat\n");
|
|
xprintf(" --wnpb filename write problem to filename in normal"
|
|
"ized OPB format\n");
|
|
#endif
|
|
#if 1 /* 06/VIII-2011 */
|
|
xprintf(" --wcnf filename write problem to filename in DIMACS"
|
|
" CNF-SAT format\n");
|
|
#endif
|
|
xprintf(" --log filename write copy of terminal output to fi"
|
|
"lename\n");
|
|
xprintf(" -h, --help display this help information and e"
|
|
"xit\n");
|
|
xprintf(" -v, --version display program version and exit\n")
|
|
;
|
|
xprintf("\n");
|
|
xprintf("LP basis factorization options:\n");
|
|
#if 0 /* 08/III-2014 */
|
|
xprintf(" --luf LU + Forrest-Tomlin update\n");
|
|
xprintf(" (faster, less stable; default)\n");
|
|
xprintf(" --cbg LU + Schur complement + Bartels-Gol"
|
|
"ub update\n");
|
|
xprintf(" (slower, more stable)\n");
|
|
xprintf(" --cgr LU + Schur complement + Givens rota"
|
|
"tion update\n");
|
|
xprintf(" (slower, more stable)\n");
|
|
#else
|
|
xprintf(" --luf plain LU-factorization (default)\n")
|
|
;
|
|
xprintf(" --btf block triangular LU-factorization\n"
|
|
);
|
|
xprintf(" --ft Forrest-Tomlin update (requires --l"
|
|
"uf; default)\n");
|
|
xprintf(" --cbg Schur complement + Bartels-Golub up"
|
|
"date\n");
|
|
xprintf(" --cgr Schur complement + Givens rotation "
|
|
"update\n");
|
|
#endif
|
|
xprintf("\n");
|
|
xprintf("Options specific to simplex solver:\n");
|
|
xprintf(" --primal use primal simplex (default)\n");
|
|
xprintf(" --dual use dual simplex\n");
|
|
xprintf(" --std use standard initial basis of all s"
|
|
"lacks\n");
|
|
xprintf(" --adv use advanced initial basis (default"
|
|
")\n");
|
|
xprintf(" --bib use Bixby's initial basis\n");
|
|
xprintf(" --ini filename use as initial basis previously sav"
|
|
"ed with -w\n");
|
|
xprintf(" (disables LP presolver)\n");
|
|
xprintf(" --steep use steepest edge technique (defaul"
|
|
"t)\n");
|
|
xprintf(" --nosteep use standard \"textbook\" pricing\n"
|
|
);
|
|
xprintf(" --relax use Harris' two-pass ratio test (de"
|
|
"fault)\n");
|
|
xprintf(" --norelax use standard \"textbook\" ratio tes"
|
|
"t\n");
|
|
#if 0 /* 23/VI-2017 */
|
|
#if 1 /* 28/III-2016 */
|
|
xprintf(" --flip use flip-flop ratio test (assumes -"
|
|
"-dual)\n");
|
|
#endif
|
|
#else
|
|
/* now this option is implemented in both primal and dual */
|
|
xprintf(" --flip use long-step ratio test\n");
|
|
#endif
|
|
xprintf(" --presol use presolver (default; assumes --s"
|
|
"cale and --adv)\n");
|
|
xprintf(" --nopresol do not use presolver\n");
|
|
xprintf(" --exact use simplex method based on exact a"
|
|
"rithmetic\n");
|
|
xprintf(" --xcheck check final basis using exact arith"
|
|
"metic\n");
|
|
xprintf("\n");
|
|
xprintf("Options specific to interior-point solver:\n");
|
|
xprintf(" --nord use natural (original) ordering\n");
|
|
xprintf(" --qmd use quotient minimum degree orderin"
|
|
"g\n");
|
|
xprintf(" --amd use approximate minimum degree orde"
|
|
"ring (default)\n");
|
|
xprintf(" --symamd use approximate minimum degree orde"
|
|
"ring\n");
|
|
xprintf("\n");
|
|
xprintf("Options specific to MIP solver:\n");
|
|
xprintf(" --nomip consider all integer variables as c"
|
|
"ontinuous\n");
|
|
xprintf(" (allows solving MIP as pure LP)\n");
|
|
xprintf(" --first branch on first integer variable\n")
|
|
;
|
|
xprintf(" --last branch on last integer variable\n");
|
|
xprintf(" --mostf branch on most fractional variable "
|
|
"\n");
|
|
xprintf(" --drtom branch using heuristic by Driebeck "
|
|
"and Tomlin\n");
|
|
xprintf(" (default)\n");
|
|
xprintf(" --pcost branch using hybrid pseudocost heur"
|
|
"istic (may be\n");
|
|
xprintf(" useful for hard instances)\n");
|
|
xprintf(" --dfs backtrack using depth first search "
|
|
"\n");
|
|
xprintf(" --bfs backtrack using breadth first searc"
|
|
"h\n");
|
|
xprintf(" --bestp backtrack using the best projection"
|
|
" heuristic\n");
|
|
xprintf(" --bestb backtrack using node with best loca"
|
|
"l bound\n");
|
|
xprintf(" (default)\n");
|
|
xprintf(" --intopt use MIP presolver (default)\n");
|
|
xprintf(" --nointopt do not use MIP presolver\n");
|
|
xprintf(" --binarize replace general integer variables b"
|
|
"y binary ones\n");
|
|
xprintf(" (assumes --intopt)\n");
|
|
xprintf(" --fpump apply feasibility pump heuristic\n")
|
|
;
|
|
#if 1 /* 29/VI-2013 */
|
|
xprintf(" --proxy [nnn] apply proximity search heuristic (n"
|
|
"nn is time limit\n");
|
|
xprintf(" in seconds; default is 60)\n");
|
|
#endif
|
|
xprintf(" --gomory generate Gomory's mixed integer cut"
|
|
"s\n");
|
|
xprintf(" --mir generate MIR (mixed integer roundin"
|
|
"g) cuts\n");
|
|
xprintf(" --cover generate mixed cover cuts\n");
|
|
xprintf(" --clique generate clique cuts\n");
|
|
xprintf(" --cuts generate all cuts above\n");
|
|
xprintf(" --mipgap tol set relative mip gap tolerance to t"
|
|
"ol\n");
|
|
#if 1 /* 15/VIII-2011 */
|
|
xprintf(" --minisat translate integer feasibility probl"
|
|
"em to CNF-SAT\n");
|
|
xprintf(" and solve it with MiniSat solver\n")
|
|
;
|
|
xprintf(" --objbnd bound add inequality obj <= bound (minimi"
|
|
"zation) or\n");
|
|
xprintf(" obj >= bound (maximization) to inte"
|
|
"ger feasibility\n");
|
|
xprintf(" problem (assumes --minisat)\n");
|
|
#endif
|
|
xprintf("\n");
|
|
xprintf("For description of the MPS and CPLEX LP formats see Refe"
|
|
"rence Manual.\n");
|
|
xprintf("For description of the modeling language see \"GLPK: Mod"
|
|
"eling Language\n");
|
|
xprintf("GNU MathProg\". Both documents are included in the GLPK "
|
|
"distribution.\n");
|
|
xprintf("\n");
|
|
xprintf("See GLPK web page at <http://www.gnu.org/software/glpk/g"
|
|
"lpk.html>.\n");
|
|
xprintf("\n");
|
|
xprintf("Please report bugs to <bug-glpk@gnu.org>.\n");
|
|
return;
|
|
}
|
|
|
|
static void print_version(int briefly)
|
|
{ /* print version information */
|
|
xprintf("GLPSOL: GLPK LP/MIP Solver, v%s\n", glp_version());
|
|
if (briefly) goto done;
|
|
xprintf("Copyright (C) 2000-2017 Andrew Makhorin, Department for "
|
|
"Applied\n");
|
|
xprintf("Informatics, Moscow Aviation Institute, Moscow, Russia. "
|
|
"All rights\n");
|
|
xprintf("reserved. E-mail: <mao@gnu.org>.\n");
|
|
xprintf("\n");
|
|
xprintf("This program has ABSOLUTELY NO WARRANTY.\n");
|
|
xprintf("\n");
|
|
xprintf("This program is free software; you may re-distribute it "
|
|
"under the terms\n");
|
|
xprintf("of the GNU General Public License version 3 or later.\n")
|
|
;
|
|
done: return;
|
|
}
|
|
|
|
static int parse_cmdline(struct csa *csa, int argc, char *argv[])
|
|
{ /* parse command-line parameters */
|
|
int k;
|
|
#define p(str) (strcmp(argv[k], str) == 0)
|
|
for (k = 1; k < argc; k++)
|
|
{ if (p("--mps"))
|
|
csa->format = FMT_MPS_DECK;
|
|
else if (p("--freemps"))
|
|
csa->format = FMT_MPS_FILE;
|
|
else if (p("--lp") || p("--cpxlp"))
|
|
csa->format = FMT_LP;
|
|
else if (p("--glp"))
|
|
csa->format = FMT_GLP;
|
|
else if (p("--math") || p("-m") || p("--model"))
|
|
csa->format = FMT_MATHPROG;
|
|
else if (p("-d") || p("--data"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No input data file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->ndf == DATA_MAX)
|
|
{ xprintf("Too many input data files\n");
|
|
return 1;
|
|
}
|
|
csa->in_data[++(csa->ndf)] = argv[k];
|
|
}
|
|
else if (p("-y") || p("--display"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No display output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_dpy != NULL)
|
|
{ xprintf("Only one display output file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_dpy = argv[k];
|
|
}
|
|
else if (p("--seed"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' ||
|
|
argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
|
|
{ xprintf("No seed value specified\n");
|
|
return 1;
|
|
}
|
|
if (strcmp(argv[k], "?") == 0)
|
|
csa->seed = 0x80000000;
|
|
else if (str2int(argv[k], &csa->seed))
|
|
{ xprintf("Invalid seed value '%s'\n", argv[k]);
|
|
return 1;
|
|
}
|
|
}
|
|
else if (p("--mincost"))
|
|
csa->format = FMT_MIN_COST;
|
|
else if (p("--maxflow"))
|
|
csa->format = FMT_MAX_FLOW;
|
|
#if 1 /* 06/VIII-2011 */
|
|
else if (p("--cnf"))
|
|
csa->format = FMT_CNF;
|
|
#endif
|
|
else if (p("--simplex"))
|
|
csa->solution = SOL_BASIC;
|
|
else if (p("--interior"))
|
|
csa->solution = SOL_INTERIOR;
|
|
#if 1 /* 28/V-2010 */
|
|
else if (p("--alien"))
|
|
csa->iocp.alien = GLP_ON;
|
|
#endif
|
|
else if (p("-r") || p("--read"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No input solution file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->in_res != NULL)
|
|
{ xprintf("Only one input solution file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->in_res = argv[k];
|
|
}
|
|
else if (p("--min"))
|
|
csa->dir = GLP_MIN;
|
|
else if (p("--max"))
|
|
csa->dir = GLP_MAX;
|
|
else if (p("--scale"))
|
|
csa->scale = 1;
|
|
else if (p("--noscale"))
|
|
csa->scale = 0;
|
|
else if (p("-o") || p("--output"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No output solution file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_sol != NULL)
|
|
{ xprintf("Only one output solution file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_sol = argv[k];
|
|
}
|
|
else if (p("-w") || p("--write"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No output solution file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_res != NULL)
|
|
{ xprintf("Only one output solution file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_res = argv[k];
|
|
}
|
|
else if (p("--ranges") || p("--bounds"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No output file specified to write sensitivity a"
|
|
"nalysis report\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_ranges != NULL)
|
|
{ xprintf("Only one output file allowed to write sensitivi"
|
|
"ty analysis report\n");
|
|
return 1;
|
|
}
|
|
csa->out_ranges = argv[k];
|
|
}
|
|
else if (p("--tmlim"))
|
|
{ int tm_lim;
|
|
k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No time limit specified\n");
|
|
return 1;
|
|
}
|
|
if (str2int(argv[k], &tm_lim) || tm_lim < 0)
|
|
{ xprintf("Invalid time limit '%s'\n", argv[k]);
|
|
return 1;
|
|
}
|
|
if (tm_lim <= INT_MAX / 1000)
|
|
csa->smcp.tm_lim = csa->iocp.tm_lim = 1000 * tm_lim;
|
|
else
|
|
csa->smcp.tm_lim = csa->iocp.tm_lim = INT_MAX;
|
|
}
|
|
else if (p("--memlim"))
|
|
{ int mem_lim;
|
|
k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No memory limit specified\n");
|
|
return 1;
|
|
}
|
|
if (str2int(argv[k], &mem_lim) || mem_lim < 1)
|
|
{ xprintf("Invalid memory limit '%s'\n", argv[k]);
|
|
return 1;
|
|
}
|
|
glp_mem_limit(mem_lim);
|
|
}
|
|
else if (p("--check"))
|
|
csa->check = 1;
|
|
else if (p("--name"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No problem name specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->new_name != NULL)
|
|
{ xprintf("Only one problem name allowed\n");
|
|
return 1;
|
|
}
|
|
csa->new_name = argv[k];
|
|
}
|
|
#if 1 /* 18/I-2018 */
|
|
else if (p("--hide"))
|
|
csa->hide = 1;
|
|
#endif
|
|
else if (p("--wmps"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No fixed MPS output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_mps != NULL)
|
|
{ xprintf("Only one fixed MPS output file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_mps = argv[k];
|
|
}
|
|
else if (p("--wfreemps"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No free MPS output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_freemps != NULL)
|
|
{ xprintf("Only one free MPS output file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_freemps = argv[k];
|
|
}
|
|
else if (p("--wlp") || p("--wcpxlp") || p("--wlpt"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No CPLEX LP output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_cpxlp != NULL)
|
|
{ xprintf("Only one CPLEX LP output file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_cpxlp = argv[k];
|
|
}
|
|
else if (p("--wglp"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No GLPK LP/MIP output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_glp != NULL)
|
|
{ xprintf("Only one GLPK LP/MIP output file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_glp = argv[k];
|
|
}
|
|
#if 0
|
|
else if (p("--wpb"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No problem output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_pb != NULL)
|
|
{ xprintf("Only one OPB output file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_pb = argv[k];
|
|
}
|
|
else if (p("--wnpb"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No problem output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_npb != NULL)
|
|
{ xprintf("Only one normalized OPB output file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_npb = argv[k];
|
|
}
|
|
#endif
|
|
#if 1 /* 06/VIII-2011 */
|
|
else if (p("--wcnf"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No problem output file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->out_cnf != NULL)
|
|
{ xprintf("Only one output DIMACS CNF-SAT file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->out_cnf = argv[k];
|
|
}
|
|
#endif
|
|
else if (p("--log"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No log file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->log_file != NULL)
|
|
{ xprintf("Only one log file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->log_file = argv[k];
|
|
}
|
|
else if (p("-h") || p("--help"))
|
|
{ print_help(argv[0]);
|
|
return -1;
|
|
}
|
|
else if (p("-v") || p("--version"))
|
|
{ print_version(0);
|
|
return -1;
|
|
}
|
|
#if 0 /* 08/III-2014 */
|
|
else if (p("--luf"))
|
|
csa->bfcp.type = GLP_BF_FT;
|
|
else if (p("--cbg"))
|
|
csa->bfcp.type = GLP_BF_BG;
|
|
else if (p("--cgr"))
|
|
csa->bfcp.type = GLP_BF_GR;
|
|
#else
|
|
else if (p("--luf"))
|
|
{ csa->bfcp.type &= 0x0F;
|
|
csa->bfcp.type |= GLP_BF_LUF;
|
|
}
|
|
else if (p("--btf"))
|
|
{ csa->bfcp.type &= 0x0F;
|
|
csa->bfcp.type |= GLP_BF_BTF;
|
|
}
|
|
else if (p("--ft"))
|
|
{ csa->bfcp.type &= 0xF0;
|
|
csa->bfcp.type |= GLP_BF_FT;
|
|
}
|
|
else if (p("--cbg"))
|
|
{ csa->bfcp.type &= 0xF0;
|
|
csa->bfcp.type |= GLP_BF_BG;
|
|
}
|
|
else if (p("--cgr"))
|
|
{ csa->bfcp.type &= 0xF0;
|
|
csa->bfcp.type |= GLP_BF_GR;
|
|
}
|
|
#endif
|
|
else if (p("--primal"))
|
|
csa->smcp.meth = GLP_PRIMAL;
|
|
else if (p("--dual"))
|
|
csa->smcp.meth = GLP_DUAL;
|
|
else if (p("--std"))
|
|
csa->crash = USE_STD_BASIS;
|
|
else if (p("--adv"))
|
|
csa->crash = USE_ADV_BASIS;
|
|
else if (p("--bib"))
|
|
csa->crash = USE_CPX_BASIS;
|
|
else if (p("--ini"))
|
|
{ csa->crash = USE_INI_BASIS;
|
|
csa->smcp.presolve = GLP_OFF;
|
|
k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No initial basis file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->ini_file != NULL)
|
|
{ xprintf("Only one initial basis file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->ini_file = argv[k];
|
|
}
|
|
else if (p("--steep"))
|
|
csa->smcp.pricing = GLP_PT_PSE;
|
|
else if (p("--nosteep"))
|
|
csa->smcp.pricing = GLP_PT_STD;
|
|
else if (p("--relax"))
|
|
csa->smcp.r_test = GLP_RT_HAR;
|
|
else if (p("--norelax"))
|
|
csa->smcp.r_test = GLP_RT_STD;
|
|
#if 1 /* 28/III-2016 */
|
|
else if (p("--flip"))
|
|
#if 0 /* 23/VI-2017 */
|
|
{ csa->smcp.meth = GLP_DUAL;
|
|
#else
|
|
/* now this option is implemented in both primal and dual */
|
|
{
|
|
#endif
|
|
csa->smcp.r_test = GLP_RT_FLIP;
|
|
csa->iocp.flip = GLP_ON;
|
|
}
|
|
#endif
|
|
else if (p("--presol"))
|
|
csa->smcp.presolve = GLP_ON;
|
|
else if (p("--nopresol"))
|
|
csa->smcp.presolve = GLP_OFF;
|
|
else if (p("--exact"))
|
|
csa->exact = 1;
|
|
else if (p("--xcheck"))
|
|
csa->xcheck = 1;
|
|
else if (p("--nord"))
|
|
csa->iptcp.ord_alg = GLP_ORD_NONE;
|
|
else if (p("--qmd"))
|
|
csa->iptcp.ord_alg = GLP_ORD_QMD;
|
|
else if (p("--amd"))
|
|
csa->iptcp.ord_alg = GLP_ORD_AMD;
|
|
else if (p("--symamd"))
|
|
csa->iptcp.ord_alg = GLP_ORD_SYMAMD;
|
|
else if (p("--nomip"))
|
|
csa->nomip = 1;
|
|
else if (p("--first"))
|
|
csa->iocp.br_tech = GLP_BR_FFV;
|
|
else if (p("--last"))
|
|
csa->iocp.br_tech = GLP_BR_LFV;
|
|
else if (p("--drtom"))
|
|
csa->iocp.br_tech = GLP_BR_DTH;
|
|
else if (p("--mostf"))
|
|
csa->iocp.br_tech = GLP_BR_MFV;
|
|
else if (p("--pcost"))
|
|
csa->iocp.br_tech = GLP_BR_PCH;
|
|
else if (p("--dfs"))
|
|
csa->iocp.bt_tech = GLP_BT_DFS;
|
|
else if (p("--bfs"))
|
|
csa->iocp.bt_tech = GLP_BT_BFS;
|
|
else if (p("--bestp"))
|
|
csa->iocp.bt_tech = GLP_BT_BPH;
|
|
else if (p("--bestb"))
|
|
csa->iocp.bt_tech = GLP_BT_BLB;
|
|
else if (p("--intopt"))
|
|
csa->iocp.presolve = GLP_ON;
|
|
else if (p("--nointopt"))
|
|
csa->iocp.presolve = GLP_OFF;
|
|
else if (p("--binarize"))
|
|
csa->iocp.presolve = csa->iocp.binarize = GLP_ON;
|
|
else if (p("--fpump"))
|
|
csa->iocp.fp_heur = GLP_ON;
|
|
#if 1 /* 29/VI-2013 */
|
|
else if (p("--proxy"))
|
|
{ csa->iocp.ps_heur = GLP_ON;
|
|
if (argv[k+1] && isdigit((unsigned char)argv[k+1][0]))
|
|
{ int nnn;
|
|
k++;
|
|
if (str2int(argv[k], &nnn) || nnn < 1)
|
|
{ xprintf("Invalid proxy time limit '%s'\n", argv[k]);
|
|
return 1;
|
|
}
|
|
csa->iocp.ps_tm_lim = 1000 * nnn;
|
|
}
|
|
}
|
|
#endif
|
|
else if (p("--gomory"))
|
|
csa->iocp.gmi_cuts = GLP_ON;
|
|
else if (p("--mir"))
|
|
csa->iocp.mir_cuts = GLP_ON;
|
|
else if (p("--cover"))
|
|
csa->iocp.cov_cuts = GLP_ON;
|
|
else if (p("--clique"))
|
|
csa->iocp.clq_cuts = GLP_ON;
|
|
else if (p("--cuts"))
|
|
csa->iocp.gmi_cuts = csa->iocp.mir_cuts =
|
|
csa->iocp.cov_cuts = csa->iocp.clq_cuts = GLP_ON;
|
|
else if (p("--mipgap"))
|
|
{ double mip_gap;
|
|
k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No relative gap tolerance specified\n");
|
|
return 1;
|
|
}
|
|
if (str2num(argv[k], &mip_gap) || mip_gap < 0.0)
|
|
{ xprintf("Invalid relative mip gap tolerance '%s'\n",
|
|
argv[k]);
|
|
return 1;
|
|
}
|
|
csa->iocp.mip_gap = mip_gap;
|
|
}
|
|
#if 1 /* 15/VIII-2011 */
|
|
else if (p("--minisat"))
|
|
csa->minisat = 1;
|
|
else if (p("--objbnd"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' ||
|
|
argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
|
|
{ xprintf("No objective bound specified\n");
|
|
return 1;
|
|
}
|
|
csa->minisat = 1;
|
|
csa->use_bnd = 1;
|
|
if (str2int(argv[k], &csa->obj_bnd))
|
|
{ xprintf("Invalid objective bound '%s' (should be integer"
|
|
" value)\n", argv[k]);
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
#if 1 /* 11/VII-2013 */
|
|
else if (p("--use"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No input MIP solution file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->use_sol != NULL)
|
|
{ xprintf("Only one input MIP solution file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->use_sol = argv[k];
|
|
}
|
|
else if (p("--save"))
|
|
{ k++;
|
|
if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
|
|
{ xprintf("No output MIP solution file specified\n");
|
|
return 1;
|
|
}
|
|
if (csa->iocp.save_sol != NULL)
|
|
{ xprintf("Only one output MIP solution file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->iocp.save_sol = argv[k];
|
|
}
|
|
#endif
|
|
else if (argv[k][0] == '-' ||
|
|
(argv[k][0] == '-' && argv[k][1] == '-'))
|
|
{ xprintf("Invalid option '%s'; try %s --help\n",
|
|
argv[k], argv[0]);
|
|
return 1;
|
|
}
|
|
else
|
|
{ if (csa->in_file != NULL)
|
|
{ xprintf("Only one input problem file allowed\n");
|
|
return 1;
|
|
}
|
|
csa->in_file = argv[k];
|
|
}
|
|
}
|
|
#undef p
|
|
return 0;
|
|
}
|
|
|
|
typedef struct { double rhs, pi; } v_data;
|
|
typedef struct { double low, cap, cost, x; } a_data;
|
|
|
|
#ifndef __WOE__
|
|
int main(int argc, char *argv[])
|
|
#else
|
|
int __cdecl main(int argc, char *argv[])
|
|
#endif
|
|
{ /* stand-alone LP/MIP solver */
|
|
struct csa _csa, *csa = &_csa;
|
|
int ret;
|
|
#if 0 /* 10/VI-2013 */
|
|
glp_long start;
|
|
#else
|
|
double start;
|
|
#endif
|
|
/* perform initialization */
|
|
csa->prob = glp_create_prob();
|
|
glp_get_bfcp(csa->prob, &csa->bfcp);
|
|
glp_init_smcp(&csa->smcp);
|
|
csa->smcp.presolve = GLP_ON;
|
|
glp_init_iptcp(&csa->iptcp);
|
|
glp_init_iocp(&csa->iocp);
|
|
csa->iocp.presolve = GLP_ON;
|
|
csa->tran = NULL;
|
|
csa->graph = NULL;
|
|
csa->format = FMT_MPS_FILE;
|
|
csa->in_file = NULL;
|
|
csa->ndf = 0;
|
|
csa->out_dpy = NULL;
|
|
csa->seed = 1;
|
|
csa->solution = SOL_BASIC;
|
|
csa->in_res = NULL;
|
|
csa->dir = 0;
|
|
csa->scale = 1;
|
|
csa->out_sol = NULL;
|
|
csa->out_res = NULL;
|
|
csa->out_ranges = NULL;
|
|
csa->check = 0;
|
|
csa->new_name = NULL;
|
|
#if 1 /* 18/I-2018 */
|
|
csa->hide = 0;
|
|
#endif
|
|
csa->out_mps = NULL;
|
|
csa->out_freemps = NULL;
|
|
csa->out_cpxlp = NULL;
|
|
csa->out_glp = NULL;
|
|
#if 0
|
|
csa->out_pb = NULL;
|
|
csa->out_npb = NULL;
|
|
#endif
|
|
#if 1 /* 06/VIII-2011 */
|
|
csa->out_cnf = NULL;
|
|
#endif
|
|
csa->log_file = NULL;
|
|
csa->crash = USE_ADV_BASIS;
|
|
csa->ini_file = NULL;
|
|
csa->exact = 0;
|
|
csa->xcheck = 0;
|
|
csa->nomip = 0;
|
|
#if 1 /* 15/VIII-2011 */
|
|
csa->minisat = 0;
|
|
csa->use_bnd = 0;
|
|
csa->obj_bnd = 0;
|
|
#endif
|
|
#if 1 /* 11/VII-2013 */
|
|
csa->use_sol = NULL;
|
|
#endif
|
|
/* parse command-line parameters */
|
|
ret = parse_cmdline(csa, argc, argv);
|
|
if (ret < 0)
|
|
{ ret = EXIT_SUCCESS;
|
|
goto done;
|
|
}
|
|
if (ret > 0)
|
|
{ ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* remove all output files specified in the command line */
|
|
if (csa->out_dpy != NULL) remove(csa->out_dpy);
|
|
if (csa->out_sol != NULL) remove(csa->out_sol);
|
|
if (csa->out_res != NULL) remove(csa->out_res);
|
|
if (csa->out_ranges != NULL) remove(csa->out_ranges);
|
|
if (csa->out_mps != NULL) remove(csa->out_mps);
|
|
if (csa->out_freemps != NULL) remove(csa->out_freemps);
|
|
if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp);
|
|
if (csa->out_glp != NULL) remove(csa->out_glp);
|
|
#if 0
|
|
if (csa->out_pb != NULL) remove(csa->out_pb);
|
|
if (csa->out_npb != NULL) remove(csa->out_npb);
|
|
#endif
|
|
#if 1 /* 06/VIII-2011 */
|
|
if (csa->out_cnf != NULL) remove(csa->out_cnf);
|
|
#endif
|
|
if (csa->log_file != NULL) remove(csa->log_file);
|
|
/*--------------------------------------------------------------*/
|
|
/* open log file, if required */
|
|
if (csa->log_file != NULL)
|
|
{ if (glp_open_tee(csa->log_file))
|
|
{ xprintf("Unable to create log file\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* print version information */
|
|
print_version(1);
|
|
/*--------------------------------------------------------------*/
|
|
/* print parameters specified in the command line */
|
|
if (argc > 1)
|
|
{ int k, len = INT_MAX;
|
|
xprintf("Parameter(s) specified in the command line:");
|
|
for (k = 1; k < argc; k++)
|
|
{ if (len > 72)
|
|
xprintf("\n"), len = 0;
|
|
xprintf(" %s", argv[k]);
|
|
len += 1 + strlen(argv[k]);
|
|
}
|
|
xprintf("\n");
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* read problem data from the input file */
|
|
if (csa->in_file == NULL)
|
|
{ xprintf("No input problem file specified; try %s --help\n",
|
|
argv[0]);
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
if (csa->format == FMT_MPS_DECK)
|
|
{ ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL,
|
|
csa->in_file);
|
|
if (ret != 0)
|
|
err1: { xprintf("MPS file processing error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
else if (csa->format == FMT_MPS_FILE)
|
|
{ ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL,
|
|
csa->in_file);
|
|
if (ret != 0) goto err1;
|
|
}
|
|
else if (csa->format == FMT_LP)
|
|
{ ret = glp_read_lp(csa->prob, NULL, csa->in_file);
|
|
if (ret != 0)
|
|
{ xprintf("CPLEX LP file processing error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
else if (csa->format == FMT_GLP)
|
|
{ ret = glp_read_prob(csa->prob, 0, csa->in_file);
|
|
if (ret != 0)
|
|
{ xprintf("GLPK LP/MIP file processing error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
else if (csa->format == FMT_MATHPROG)
|
|
{ int k;
|
|
/* allocate the translator workspace */
|
|
csa->tran = glp_mpl_alloc_wksp();
|
|
/* set seed value */
|
|
if (csa->seed == 0x80000000)
|
|
#if 0 /* 10/VI-2013 */
|
|
{ csa->seed = glp_time().lo;
|
|
#else
|
|
{ csa->seed = (int)fmod(glp_time(), 1000000000.0);
|
|
#endif
|
|
xprintf("Seed value %d will be used\n", csa->seed);
|
|
}
|
|
glp_mpl_init_rand(csa->tran, csa->seed);
|
|
/* read model section and optional data section */
|
|
if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0))
|
|
err2: { xprintf("MathProg model processing error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
/* read optional data section(s), if necessary */
|
|
for (k = 1; k <= csa->ndf; k++)
|
|
{ if (glp_mpl_read_data(csa->tran, csa->in_data[k]))
|
|
goto err2;
|
|
}
|
|
/* generate the model */
|
|
if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2;
|
|
/* build the problem instance from the model */
|
|
glp_mpl_build_prob(csa->tran, csa->prob);
|
|
}
|
|
else if (csa->format == FMT_MIN_COST)
|
|
{ csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost), csa->in_file);
|
|
if (ret != 0)
|
|
{ xprintf("DIMACS file processing error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
glp_mincost_lp(csa->prob, csa->graph, GLP_ON,
|
|
offsetof(v_data, rhs), offsetof(a_data, low),
|
|
offsetof(a_data, cap), offsetof(a_data, cost));
|
|
glp_set_prob_name(csa->prob, csa->in_file);
|
|
}
|
|
else if (csa->format == FMT_MAX_FLOW)
|
|
{ int s, t;
|
|
csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
ret = glp_read_maxflow(csa->graph, &s, &t,
|
|
offsetof(a_data, cap), csa->in_file);
|
|
if (ret != 0)
|
|
{ xprintf("DIMACS file processing error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t,
|
|
offsetof(a_data, cap));
|
|
glp_set_prob_name(csa->prob, csa->in_file);
|
|
}
|
|
#if 1 /* 06/VIII-2011 */
|
|
else if (csa->format == FMT_CNF)
|
|
{ ret = glp_read_cnfsat(csa->prob, csa->in_file);
|
|
if (ret != 0)
|
|
{ xprintf("DIMACS file processing error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
glp_set_prob_name(csa->prob, csa->in_file);
|
|
}
|
|
#endif
|
|
else
|
|
xassert(csa != csa);
|
|
/*--------------------------------------------------------------*/
|
|
/* change problem name, if required */
|
|
if (csa->new_name != NULL)
|
|
glp_set_prob_name(csa->prob, csa->new_name);
|
|
/* change optimization direction, if required */
|
|
if (csa->dir != 0)
|
|
glp_set_obj_dir(csa->prob, csa->dir);
|
|
/* sort elements of the constraint matrix */
|
|
glp_sort_matrix(csa->prob);
|
|
#if 1 /* 18/I-2018 */
|
|
/*--------------------------------------------------------------*/
|
|
/* remove all symbolic names from problem object, if required */
|
|
if (csa->hide)
|
|
{ int i, j;
|
|
glp_set_obj_name(csa->prob, NULL);
|
|
glp_delete_index(csa->prob);
|
|
for (i = glp_get_num_rows(csa->prob); i >= 1; i--)
|
|
glp_set_row_name(csa->prob, i, NULL);
|
|
for (j = glp_get_num_cols(csa->prob); j >= 1; j--)
|
|
glp_set_col_name(csa->prob, j, NULL);
|
|
}
|
|
#endif
|
|
/*--------------------------------------------------------------*/
|
|
/* write problem data in fixed MPS format, if required */
|
|
if (csa->out_mps != NULL)
|
|
{ ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL,
|
|
csa->out_mps);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write problem in fixed MPS format\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/* write problem data in free MPS format, if required */
|
|
if (csa->out_freemps != NULL)
|
|
{ ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL,
|
|
csa->out_freemps);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write problem in free MPS format\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/* write problem data in CPLEX LP format, if required */
|
|
if (csa->out_cpxlp != NULL)
|
|
{ ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write problem in CPLEX LP format\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/* write problem data in GLPK format, if required */
|
|
if (csa->out_glp != NULL)
|
|
{ ret = glp_write_prob(csa->prob, 0, csa->out_glp);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write problem in GLPK format\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
#if 0
|
|
/* write problem data in OPB format, if required */
|
|
if (csa->out_pb != NULL)
|
|
{ ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write problem in OPB format\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/* write problem data in normalized OPB format, if required */
|
|
if (csa->out_npb != NULL)
|
|
{ ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1);
|
|
if (ret != 0)
|
|
{ xprintf(
|
|
"Unable to write problem in normalized OPB format\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
#if 1 /* 06/VIII-2011 */
|
|
/* write problem data in DIMACS CNF-SAT format, if required */
|
|
if (csa->out_cnf != NULL)
|
|
{ ret = glp_write_cnfsat(csa->prob, csa->out_cnf);
|
|
if (ret != 0)
|
|
{ xprintf(
|
|
"Unable to write problem in DIMACS CNF-SAT format\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
/*--------------------------------------------------------------*/
|
|
/* if only problem data check is required, skip computations */
|
|
if (csa->check)
|
|
{
|
|
#if 1 /* 29/III-2016 */
|
|
/* report problem characteristics */
|
|
int j, cnt = 0;
|
|
xprintf("--- Problem Characteristics ---\n");
|
|
xprintf("Number of rows = %8d\n",
|
|
glp_get_num_rows(csa->prob));
|
|
xprintf("Number of columns = %8d\n",
|
|
glp_get_num_cols(csa->prob));
|
|
xprintf("Number of non-zeros (matrix) = %8d\n",
|
|
glp_get_num_nz(csa->prob));
|
|
for (j = glp_get_num_cols(csa->prob); j >= 1; j--)
|
|
{ if (glp_get_obj_coef(csa->prob, j) != 0.0)
|
|
cnt++;
|
|
}
|
|
xprintf("Number of non-zeros (objrow) = %8d\n",
|
|
cnt);
|
|
#endif
|
|
ret = EXIT_SUCCESS;
|
|
goto done;
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* determine the solution type */
|
|
if (!csa->nomip &&
|
|
glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0)
|
|
{ if (csa->solution == SOL_INTERIOR)
|
|
{ xprintf("Interior-point method is not able to solve MIP pro"
|
|
"blem; use --simplex\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
csa->solution = SOL_INTEGER;
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* if solution is provided, read it and skip computations */
|
|
if (csa->in_res != NULL)
|
|
{ if (csa->solution == SOL_BASIC)
|
|
ret = glp_read_sol(csa->prob, csa->in_res);
|
|
else if (csa->solution == SOL_INTERIOR)
|
|
ret = glp_read_ipt(csa->prob, csa->in_res);
|
|
else if (csa->solution == SOL_INTEGER)
|
|
ret = glp_read_mip(csa->prob, csa->in_res);
|
|
else
|
|
xassert(csa != csa);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to read problem solution\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
goto skip;
|
|
}
|
|
#if 1 /* 11/VII-2013 */
|
|
/*--------------------------------------------------------------*/
|
|
/* if initial MIP solution is provided, read it */
|
|
if (csa->solution == SOL_INTEGER && csa->use_sol != NULL)
|
|
{ ret = glp_read_mip(csa->prob, csa->use_sol);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to read initial MIP solution\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
csa->iocp.use_sol = GLP_ON;
|
|
}
|
|
#endif
|
|
/*--------------------------------------------------------------*/
|
|
/* scale the problem data, if required */
|
|
if (csa->scale)
|
|
{ if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
|
|
csa->solution == SOL_INTERIOR ||
|
|
csa->solution == SOL_INTEGER && !csa->iocp.presolve)
|
|
glp_scale_prob(csa->prob, GLP_SF_AUTO);
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* construct starting LP basis */
|
|
if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
|
|
csa->solution == SOL_INTEGER && !csa->iocp.presolve)
|
|
{ if (csa->crash == USE_STD_BASIS)
|
|
glp_std_basis(csa->prob);
|
|
else if (csa->crash == USE_ADV_BASIS)
|
|
glp_adv_basis(csa->prob, 0);
|
|
else if (csa->crash == USE_CPX_BASIS)
|
|
glp_cpx_basis(csa->prob);
|
|
else if (csa->crash == USE_INI_BASIS)
|
|
{ ret = glp_read_sol(csa->prob, csa->ini_file);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to read initial basis\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
xassert(csa != csa);
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* solve the problem */
|
|
start = glp_time();
|
|
if (csa->solution == SOL_BASIC)
|
|
{ if (!csa->exact)
|
|
{ glp_set_bfcp(csa->prob, &csa->bfcp);
|
|
glp_simplex(csa->prob, &csa->smcp);
|
|
if (csa->xcheck)
|
|
{ if (csa->smcp.presolve &&
|
|
glp_get_status(csa->prob) != GLP_OPT)
|
|
xprintf("If you need to check final basis for non-opt"
|
|
"imal solution, use --nopresol\n");
|
|
else
|
|
glp_exact(csa->prob, &csa->smcp);
|
|
}
|
|
if (csa->out_sol != NULL || csa->out_res != NULL)
|
|
{ if (csa->smcp.presolve &&
|
|
glp_get_status(csa->prob) != GLP_OPT)
|
|
xprintf("If you need actual output for non-optimal solut"
|
|
"ion, use --nopresol\n");
|
|
}
|
|
}
|
|
else
|
|
glp_exact(csa->prob, &csa->smcp);
|
|
}
|
|
else if (csa->solution == SOL_INTERIOR)
|
|
glp_interior(csa->prob, &csa->iptcp);
|
|
#if 1 /* 15/VIII-2011 */
|
|
else if (csa->solution == SOL_INTEGER && csa->minisat)
|
|
{ if (glp_check_cnfsat(csa->prob) == 0)
|
|
glp_minisat1(csa->prob);
|
|
else
|
|
glp_intfeas1(csa->prob, csa->use_bnd, csa->obj_bnd);
|
|
}
|
|
#endif
|
|
else if (csa->solution == SOL_INTEGER)
|
|
{ glp_set_bfcp(csa->prob, &csa->bfcp);
|
|
if (!csa->iocp.presolve)
|
|
glp_simplex(csa->prob, &csa->smcp);
|
|
#if 0
|
|
csa->iocp.msg_lev = GLP_MSG_DBG;
|
|
csa->iocp.pp_tech = GLP_PP_NONE;
|
|
#endif
|
|
#ifdef GLP_CB_FUNC /* 05/IV-2016 */
|
|
{ extern void GLP_CB_FUNC(glp_tree *, void *);
|
|
csa->iocp.cb_func = GLP_CB_FUNC;
|
|
csa->iocp.cb_info = NULL;
|
|
}
|
|
#endif
|
|
glp_intopt(csa->prob, &csa->iocp);
|
|
}
|
|
else
|
|
xassert(csa != csa);
|
|
/*--------------------------------------------------------------*/
|
|
/* display statistics */
|
|
xprintf("Time used: %.1f secs\n", glp_difftime(glp_time(),
|
|
start));
|
|
#if 0 /* 16/II-2012 */
|
|
{ glp_long tpeak;
|
|
char buf[50];
|
|
glp_mem_usage(NULL, NULL, NULL, &tpeak);
|
|
xprintf("Memory used: %.1f Mb (%s bytes)\n",
|
|
xltod(tpeak) / 1048576.0, xltoa(tpeak, buf));
|
|
}
|
|
#else
|
|
{ size_t tpeak;
|
|
glp_mem_usage(NULL, NULL, NULL, &tpeak);
|
|
xprintf("Memory used: %.1f Mb (%.0f bytes)\n",
|
|
(double)tpeak / 1048576.0, (double)tpeak);
|
|
}
|
|
#endif
|
|
/*--------------------------------------------------------------*/
|
|
skip: /* postsolve the model, if necessary */
|
|
if (csa->tran != NULL)
|
|
{ if (csa->solution == SOL_BASIC)
|
|
{ if (!(glp_get_status(csa->prob) == GLP_OPT ||
|
|
glp_get_status(csa->prob) == GLP_FEAS))
|
|
ret = -1;
|
|
else
|
|
ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL);
|
|
}
|
|
else if (csa->solution == SOL_INTERIOR)
|
|
{ if (!(glp_ipt_status(csa->prob) == GLP_OPT ||
|
|
glp_ipt_status(csa->prob) == GLP_FEAS))
|
|
ret = -1;
|
|
else
|
|
ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT);
|
|
}
|
|
else if (csa->solution == SOL_INTEGER)
|
|
{ if (!(glp_mip_status(csa->prob) == GLP_OPT ||
|
|
glp_mip_status(csa->prob) == GLP_FEAS))
|
|
ret = -1;
|
|
else
|
|
ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP);
|
|
}
|
|
else
|
|
xassert(csa != csa);
|
|
if (ret > 0)
|
|
{ xprintf("Model postsolving error\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* write problem solution in printable format, if required */
|
|
if (csa->out_sol != NULL)
|
|
{ if (csa->solution == SOL_BASIC)
|
|
ret = glp_print_sol(csa->prob, csa->out_sol);
|
|
else if (csa->solution == SOL_INTERIOR)
|
|
ret = glp_print_ipt(csa->prob, csa->out_sol);
|
|
else if (csa->solution == SOL_INTEGER)
|
|
ret = glp_print_mip(csa->prob, csa->out_sol);
|
|
else
|
|
xassert(csa != csa);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write problem solution\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/* write problem solution in printable format, if required */
|
|
if (csa->out_res != NULL)
|
|
{ if (csa->solution == SOL_BASIC)
|
|
ret = glp_write_sol(csa->prob, csa->out_res);
|
|
else if (csa->solution == SOL_INTERIOR)
|
|
ret = glp_write_ipt(csa->prob, csa->out_res);
|
|
else if (csa->solution == SOL_INTEGER)
|
|
ret = glp_write_mip(csa->prob, csa->out_res);
|
|
else
|
|
xassert(csa != csa);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write problem solution\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/* write sensitivity analysis report, if required */
|
|
if (csa->out_ranges != NULL)
|
|
{ if (csa->solution == SOL_BASIC)
|
|
{ if (glp_get_status(csa->prob) == GLP_OPT)
|
|
{ if (glp_bf_exists(csa->prob))
|
|
ranges: { ret = glp_print_ranges(csa->prob, 0, NULL, 0,
|
|
csa->out_ranges);
|
|
if (ret != 0)
|
|
{ xprintf("Unable to write sensitivity analysis repo"
|
|
"rt\n");
|
|
ret = EXIT_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{ ret = glp_factorize(csa->prob);
|
|
if (ret == 0) goto ranges;
|
|
xprintf("Cannot produce sensitivity analysis report d"
|
|
"ue to error in basis factorization (glp_factorize"
|
|
" returned %d); try --nopresol\n", ret);
|
|
}
|
|
}
|
|
else
|
|
xprintf("Cannot produce sensitivity analysis report for "
|
|
"non-optimal basic solution\n");
|
|
}
|
|
else
|
|
xprintf("Cannot produce sensitivity analysis report for int"
|
|
"erior-point or MIP solution\n");
|
|
}
|
|
/*--------------------------------------------------------------*/
|
|
/* all seems to be ok */
|
|
ret = EXIT_SUCCESS;
|
|
/*--------------------------------------------------------------*/
|
|
done: /* delete the LP/MIP problem object */
|
|
if (csa->prob != NULL)
|
|
glp_delete_prob(csa->prob);
|
|
/* free the translator workspace, if necessary */
|
|
if (csa->tran != NULL)
|
|
glp_mpl_free_wksp(csa->tran);
|
|
/* delete the network problem object, if necessary */
|
|
if (csa->graph != NULL)
|
|
glp_delete_graph(csa->graph);
|
|
#if 0 /* 23/XI-2015 */
|
|
xassert(gmp_pool_count() == 0);
|
|
gmp_free_mem();
|
|
#endif
|
|
/* close log file, if necessary */
|
|
if (csa->log_file != NULL) glp_close_tee();
|
|
/* check that no memory blocks are still allocated */
|
|
#if 0 /* 16/II-2012 */
|
|
{ int count;
|
|
glp_long total;
|
|
glp_mem_usage(&count, NULL, &total, NULL);
|
|
if (count != 0)
|
|
xerror("Error: %d memory block(s) were lost\n", count);
|
|
xassert(count == 0);
|
|
xassert(total.lo == 0 && total.hi == 0);
|
|
}
|
|
#else
|
|
{ int count;
|
|
size_t total;
|
|
glp_mem_usage(&count, NULL, &total, NULL);
|
|
if (count != 0)
|
|
xerror("Error: %d memory block(s) were lost\n", count);
|
|
xassert(total == 0);
|
|
}
|
|
#endif
|
|
/* free the GLPK environment */
|
|
glp_free_env();
|
|
/* return to the control program */
|
|
return ret;
|
|
}
|
|
|
|
/* eof */
|