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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
multirow/infinity/benchmark/src/main.c

468 lines
12 KiB

/* Copyright (c) 2015 Alinson Xavier
*
* This program 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.
*
* This program 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, see <http://www.gnu.org/licenses/>.
*/
#define _XOPEN_SOURCE 500
#include <getopt.h>
#include <unistd.h>
#include <time.h>
#include <multirow/cg.h>
#include <multirow/mir.h>
#include <multirow/stats.h>
#include <multirow/util.h>
#include <infinity/greedy.h>
int ENABLE_LIFTING = 0;
int MIN_N_ROWS = 2;
int MAX_N_ROWS = 2;
int DUMP_CUT = 0;
int DUMP_CUT_N = 0;
int GENERATE_MIR = 0;
int GENERATE_GREEDY = 0;
int KEEP_INTEGRALITY = 0;
int N_ROUNDS = 1;
char BASIS_FILENAME[1000] = {0};
char PROBLEM_FILENAME[1000] = {0};
char KNOWN_SOLUTION_FILENAME[1000] = {0};
char OUTPUT_SOLUTION_FILENAME[1000] = {0};
char OUTPUT_BASIS_FILENAME[1000] = {0};
char LOG_FILENAME[1000] = {0};
char STATS_FILENAME[1000] = {0};
FILE *LOG_FILE;
int BOOST_VAR = -1;
double BOOST_FACTOR = 0.01;
#define OPTION_WRITE_BASIS 1000
#define OPTION_WRITE_SOLUTION 1001
static const struct option options_tab[] =
{
{"help", no_argument, 0, 'h'},
{"problem", required_argument, 0, 'p'},
{"solution", required_argument, 0, 'x'},
{"mir", no_argument, 0, 'm'},
{"greedy", no_argument, 0, 'g'},
{"rounds", required_argument, 0, 'r'},
{"keep-integrality", no_argument, 0, 'k'},
{"write-solution", required_argument, 0, OPTION_WRITE_SOLUTION},
{"write-basis", required_argument, 0, OPTION_WRITE_BASIS},
{"basis", required_argument, 0, 'b'},
{"log", required_argument, 0, 'l'},
{"stats", required_argument, 0, 's'},
{"boost", required_argument, 0, 't'},
{"lift", no_argument, 0, 'i'},
{"rows", required_argument, 0, 'a'},
{0, 0, 0, 0}
};
static void print_usage(char **argv)
{
printf("Usage: %s [OPTION]...\n", argv[0]);
printf("Solves the given MILP using specified cutting-planes.\n\n");
printf("Parameters:\n");
printf("%4s %-20s %s\n", "-b", "--basis=FILE",
"BAS file containing an optimal basis for the linear relaxation of "
"the problem");
printf("%4s %-20s %s\n", "-g", "--greedy",
"generate greedy intersection cuts");
printf("%4s %-20s %s\n", "-k", "--keep-integrality",
"do not relax integrality of variables");
printf("%4s %-20s %s\n", "-l", "--log=FILE",
"write log to the specified file");
printf("%4s %-20s %s\n", "-m", "--mir", "generate MIR cuts");
printf("%4s %-20s %s\n", "-p", "--problem=FILE", "problem to be solved");
printf("%4s %-20s %s\n", "-r", "--rounds=NUM",
"number of rounds of cutting planes to add");
printf("%4s %-20s %s\n", "-s", "--stats=FILE",
"write statistics to the specified file");
printf("%4s %-20s %s\n", "-x", "--solution=FILE",
"known integral solution (to check the validity of the cuts)");
printf("%4s %-20s %s\n", "", "--write-solution=FILE",
"write solution found at the end of the procedure to given file");
printf("%4s %-20s %s\n", "", "--write-basis=FILE",
"write optimal LP basis to given file");
printf("%4s %-20s %s\n", "", "--lift", "enable trivial lifting");
printf("%4s %-20s %s\n", "", "--rows=N",
"generate multi-row cuts from up to N rows");
}
static int parse_args(int argc,
char **argv)
{
int rval = 0;
opterr = 0;
while (1)
{
int c = 0;
int option_index = 0;
c = getopt_long(argc, argv, "l:p:s:x:hmgr:kb:t:ia:", options_tab,
&option_index);
if (c < 0) break;
switch (c)
{
case 'l':
strcpy(LOG_FILENAME, optarg);
break;
case 'b':
strcpy(BASIS_FILENAME, optarg);
break;
case 'g':
GENERATE_GREEDY = 1;
break;
case 'k':
KEEP_INTEGRALITY = 1;
break;
case 'm':
GENERATE_MIR = 1;
break;
case 't':
BOOST_VAR = atoi(optarg);
break;
case 'r':
N_ROUNDS = atoi(optarg);
break;
case 'a':
MAX_N_ROWS = atoi(optarg);
break;
case OPTION_WRITE_SOLUTION:
strcpy(OUTPUT_SOLUTION_FILENAME, optarg);
break;
case OPTION_WRITE_BASIS:
strcpy(OUTPUT_BASIS_FILENAME, optarg);
break;
case 'p':
strcpy(PROBLEM_FILENAME, optarg);
break;
case 's':
strcpy(STATS_FILENAME, optarg);
break;
case 'x':
strcpy(KNOWN_SOLUTION_FILENAME, optarg);
break;
case 'h':
print_usage(argv);
exit(0);
case 'i':
ENABLE_LIFTING = 1;
break;
case ':':
fprintf(stderr, "%s: option '-%c' requires an argument\n",
argv[0], optopt);
rval = 1;
goto CLEANUP;
case '?':
default:
fprintf(stderr, "%s: option '-%c' is invalid\n", argv[0],
optopt);
rval = 1;
goto CLEANUP;
}
}
if ((strlen(PROBLEM_FILENAME) == 0))
{
fprintf(stderr, "You must specify the problem.\n");
rval = 1;
}
if (KEEP_INTEGRALITY && (GENERATE_GREEDY + GENERATE_MIR > 0))
{
fprintf(stderr, "Cutting planes cannot be added when integrality is "
"kept\n");
rval = 1;
}
if (N_ROUNDS < 1)
{
fprintf(stderr, "Invalid number of rounds.\n");
rval = 1;
}
CLEANUP:
if (rval)
fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
return rval;
}
void print_header(int argc,
char *const *argv)
{
char hostname[3000];
gethostname(hostname, 1024);
time_t now;
time(&now);
struct tm *ttm = localtime(&now);
time_printf("multirow\n");
time_printf("%s %04d-%02d-%02d %02d:%02d\n", hostname, ttm->tm_year + 1900,
ttm->tm_mon + 1, ttm->tm_mday, ttm->tm_hour, ttm->tm_min);
time_printf("Compile-time parameters:\n");
time_printf(" EPSILON: %e\n", EPSILON);
time_printf(" GREEDY_BIG_E: %e\n", GREEDY_BIG_E);
time_printf(" GREEDY_MAX_GAP: %e\n", GREEDY_MAX_GAP);
char cmdline[5000] = {0};
for (int i = 0; i < argc; i++)
sprintf(cmdline + strlen(cmdline), "%s ", argv[i]);
time_printf("Command line arguments:\n");
time_printf(" %s\n", cmdline);
}
int main(int argc,
char **argv)
{
int rval = 0;
double *x = 0;
struct CG *cg = 0;
struct LP lp;
char *column_types = 0;
rval = parse_args(argc, argv);
if (rval) return 1;
if (LOG_FILENAME[0])
{
LOG_FILE = fopen(LOG_FILENAME, "w");
abort_if(!LOG_FILE, "could not open log file");
}
if_info_level
{
print_header(argc, argv);
}
STATS_init();
STATS_set_input_filename(PROBLEM_FILENAME);
progress_title(PROBLEM_FILENAME);
rval = LP_open(&lp);
abort_if(rval, "LP_open failed");
rval = LP_create(&lp, "multirow");
abort_if(rval, "LP_create failed");
rval = LP_read_problem(&lp, PROBLEM_FILENAME);
abort_if(rval, "LP_read_problem failed");
int ncols = LP_get_num_cols(&lp);
int nrows = LP_get_num_rows(&lp);
log_info(" %d rows, %d cols\n", nrows, ncols);
x = (double *) malloc(ncols * sizeof(double));
abort_if(!x, "could not allocate x");
if (!KEEP_INTEGRALITY)
{
column_types = (char *) malloc(ncols * sizeof(char));
abort_if(!column_types, "could not allocate column_types");
log_info("Storing column types...\n");
rval = LP_get_column_types(&lp, column_types);
abort_if(rval, "LP_get_column_types failed");
log_info("Relaxing integrality...\n");
rval = LP_relax(&lp);
abort_if(rval, "LP_relax failed");
log_info("Disabling presolve...\n");
LP_disable_presolve(&lp);
}
if(BASIS_FILENAME[0])
{
rval = LP_read_basis(&lp, BASIS_FILENAME);
abort_if(rval, "LP_read_basis failed");
}
log_info("Optimizing...\n");
int infeasible;
rval = LP_optimize(&lp, &infeasible);
abort_if(rval, "LP_optimize failed");
double cost = 0, xboost = 0;
if(BOOST_VAR > 0)
{
rval = LP_get_x(&lp, x);
abort_if(rval, "LP_get_x failed");
xboost = x[BOOST_VAR];
for (int i = 0; i < ncols; i++)
log_info("x[%3d] = %12.8lf\n", i, x[i]);
}
double obj;
rval = LP_get_obj_val(&lp, &obj);
abort_if(rval, "LP_get_obj_val failed");
log_info(" opt = %lf\n", obj);
STATS_set_obj_value(obj);
STATS_finish_round();
if(BOOST_VAR >= 0)
log_info("Boosting variable %d by %.2lf\n", BOOST_VAR, BOOST_FACTOR);
if(OUTPUT_BASIS_FILENAME[0])
{
rval = LP_write_basis(&lp, OUTPUT_BASIS_FILENAME);
abort_if(rval, "LP_write_basis failed");
}
if(GENERATE_MIR || GENERATE_GREEDY)
{
cg = (struct CG *) malloc(sizeof(struct CG));
abort_if(!cg, "could not allocate cg");
log_info("Reading tableau rows...\n");
rval = CG_init(&lp, column_types, cg);
abort_if(rval, "CG_init failed");
if (strlen(KNOWN_SOLUTION_FILENAME) > 0)
{
if(access(KNOWN_SOLUTION_FILENAME, F_OK) != -1)
{
rval = LP_read_solution(&lp, KNOWN_SOLUTION_FILENAME, x);
abort_if(rval, "LP_read_solution failed");
rval = CG_set_integral_solution(cg, x);
abort_if(rval, "CG_set_integral_solution failed");
}
else
{
log_error("ERROR: Could not read solution file!\n");
}
}
rval = LP_get_x(&lp, x);
abort_if(rval, "LP_get_x failed");
rval = CG_set_basic_solution(cg, x);
abort_if(rval, "CG_set_basic_solution failed");
if (GENERATE_MIR)
{
log_info("Adding MIR cuts...\n");
rval = CG_add_single_row_cuts(
cg,
(SingleRowGeneratorCallback)
MIR_generate_cut);
abort_if(rval, "CG_add_single_row_cuts failed");
log_info("Optimizing...\n");
rval = LP_optimize(&lp, &infeasible);
abort_if(rval, "LP_optimize failed");
rval = LP_get_obj_val(&lp, &obj);
abort_if(rval, "LP_get_obj_val failed");
log_info(" opt = %lf\n", obj);
STATS_set_obj_value(obj);
STATS_finish_round();
}
if (GENERATE_GREEDY)
{
for(int k = MIN_N_ROWS; k <= MAX_N_ROWS; k++)
{
log_info("Adding greedy intersection cuts (%d rows)...\n", k);
rval = CG_add_multirow_cuts(cg, k, (MultirowGeneratorCallback)
GREEDY_generate_cut);
abort_if(rval, "CG_add_multirow_cuts failed");
}
log_info("Optimizing...\n");
rval = LP_optimize(&lp, &infeasible);
abort_if(rval, "LP_optimize failed");
rval = LP_get_obj_val(&lp, &obj);
abort_if(rval, "LP_get_obj_val failed");
log_info(" opt = %lf\n", obj);
STATS_set_obj_value(obj);
STATS_finish_round();
}
CG_free(cg);
}
if(BOOST_VAR > 0)
{
FILE *boost = fopen("boost.csv", "a");
fprintf(boost, "%d, %.8lf, %.8lf, %.8lf\n", BOOST_VAR, obj, cost,
xboost);
}
if(OUTPUT_SOLUTION_FILENAME[0])
{
rval = LP_write_solution(&lp, OUTPUT_SOLUTION_FILENAME);
abort_if(rval, "LP_write_solution failed");
}
if(STATS_FILENAME[0])
{
log_info("Writing stats to file %s...\n", STATS_FILENAME);
rval = STATS_print_yaml(STATS_FILENAME);
abort_if(rval, "STATS_print_yaml failed");
}
CLEANUP:
if (LOG_FILE) fclose(LOG_FILE);
if (x) free(x);
if (column_types) free(column_types);
LP_free(&lp);
return rval;
}