790 lines
24 KiB
C
790 lines
24 KiB
C
|
|
/*
|
|
Mixed integer programming optimization drivers for lp_solve v5.0+
|
|
----------------------------------------------------------------------------------
|
|
Author: Michel Berkelaar (to lp_solve v3.2),
|
|
Kjell Eikland
|
|
Contact:
|
|
License terms: LGPL.
|
|
|
|
Requires: stdarg.h, lp_lib.h
|
|
|
|
Release notes:
|
|
v5.0.0 3 1 January 2004 New unit isolating reporting routines.
|
|
v5.2.0.0 1 December 2005 Addition of Matrix Market writing function.
|
|
|
|
----------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "lp_lib.h"
|
|
#include "lp_scale.h"
|
|
#include "commonlib.h"
|
|
#include "lp_report.h"
|
|
|
|
#include "mmio.h"
|
|
|
|
#ifdef FORTIFY
|
|
# include "lp_fortify.h"
|
|
#endif
|
|
|
|
/* Define buffer-size controled function mapping */
|
|
# if defined _MSC_VER
|
|
# define vsnprintf _vsnprintf
|
|
# endif
|
|
|
|
/* Various reporting functions for lp_solve */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* First define general utilties for reporting and output */
|
|
char * __VACALL explain(lprec *lp, char *format, ...)
|
|
{
|
|
char buff[DEF_STRBUFSIZE+1];
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
vsnprintf(buff, DEF_STRBUFSIZE, format, ap);
|
|
allocCHAR(lp, &(lp->ex_status), (int) strlen(buff), AUTOMATIC);
|
|
strcpy(lp->ex_status, buff);
|
|
va_end(ap);
|
|
return( lp->ex_status );
|
|
}
|
|
void __VACALL report(lprec *lp, int level, char *format, ...)
|
|
{
|
|
static char buff[DEF_STRBUFSIZE+1];
|
|
static va_list ap;
|
|
|
|
if(lp == NULL) {
|
|
va_start(ap, format);
|
|
vfprintf(stderr, format, ap);
|
|
va_end(ap);
|
|
}
|
|
else if(level <= lp->verbose) {
|
|
va_start(ap, format);
|
|
if(lp->writelog != NULL) {
|
|
vsnprintf(buff, DEF_STRBUFSIZE, format, ap);
|
|
lp->writelog(lp, lp->loghandle, buff);
|
|
}
|
|
if(lp->outstream != NULL) {
|
|
vfprintf(lp->outstream, format, ap);
|
|
if(lp->outstream != stdout)
|
|
fflush(lp->outstream);
|
|
}
|
|
va_end(ap);
|
|
}
|
|
#ifdef xParanoia
|
|
if(level == CRITICAL)
|
|
raise(SIGSEGV);
|
|
#endif
|
|
}
|
|
|
|
STATIC void print_indent(lprec *lp)
|
|
{
|
|
int i;
|
|
|
|
report(lp, NEUTRAL, "%2d", lp->bb_level);
|
|
if(lp->bb_level < 50) /* useless otherwise */
|
|
for(i = lp->bb_level; i > 0; i--)
|
|
report(lp, NEUTRAL, "--");
|
|
else
|
|
report(lp, NEUTRAL, " *** too deep ***");
|
|
report(lp, NEUTRAL, "> ");
|
|
} /* print_indent */
|
|
|
|
STATIC void debug_print(lprec *lp, char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if(lp->bb_trace) {
|
|
print_indent(lp);
|
|
va_start(ap, format);
|
|
if (lp == NULL)
|
|
{
|
|
vfprintf(stderr, format, ap);
|
|
fputc('\n', stderr);
|
|
}
|
|
else if(lp->debuginfo != NULL)
|
|
{
|
|
char buff[DEF_STRBUFSIZE+1];
|
|
vsnprintf(buff, DEF_STRBUFSIZE, format, ap);
|
|
lp->debuginfo(lp, lp->loghandle, buff);
|
|
}
|
|
va_end(ap);
|
|
}
|
|
} /* debug_print */
|
|
|
|
STATIC void debug_print_solution(lprec *lp)
|
|
{
|
|
int i;
|
|
|
|
if(lp->bb_trace)
|
|
for (i = lp->rows + 1; i <= lp->sum; i++) {
|
|
print_indent(lp);
|
|
report(lp, NEUTRAL, "%s " RESULTVALUEMASK "\n",
|
|
get_col_name(lp, i - lp->rows),
|
|
(double)lp->solution[i]);
|
|
}
|
|
} /* debug_print_solution */
|
|
|
|
STATIC void debug_print_bounds(lprec *lp, REAL *upbo, REAL *lowbo)
|
|
{
|
|
int i;
|
|
|
|
if(lp->bb_trace)
|
|
for(i = lp->rows + 1; i <= lp->sum; i++) {
|
|
if(lowbo[i] == upbo[i]) {
|
|
print_indent(lp);
|
|
report(lp, NEUTRAL, "%s = " RESULTVALUEMASK "\n", get_col_name(lp, i - lp->rows),
|
|
(double)lowbo[i]);
|
|
}
|
|
else {
|
|
if(lowbo[i] != 0) {
|
|
print_indent(lp);
|
|
report(lp, NEUTRAL, "%s > " RESULTVALUEMASK "\n", get_col_name(lp, i - lp->rows),
|
|
(double)lowbo[i]);
|
|
}
|
|
if(upbo[i] != lp->infinite) {
|
|
print_indent(lp);
|
|
report(lp, NEUTRAL, "%s < " RESULTVALUEMASK "\n", get_col_name(lp, i - lp->rows),
|
|
(double)upbo[i]);
|
|
}
|
|
}
|
|
}
|
|
} /* debug_print_bounds */
|
|
|
|
/* List a vector of LREAL values for the given index range */
|
|
void blockWriteLREAL(FILE *output, char *label, LREAL *vector, int first, int last)
|
|
{
|
|
int i, k = 0;
|
|
|
|
fprintf(output, label);
|
|
fprintf(output, "\n");
|
|
for(i = first; i <= last; i++) {
|
|
fprintf(output, " %18g", vector[i]);
|
|
k++;
|
|
if(my_mod(k, 4) == 0) {
|
|
fprintf(output, "\n");
|
|
k = 0;
|
|
}
|
|
}
|
|
if(my_mod(k, 4) != 0)
|
|
fprintf(output, "\n");
|
|
}
|
|
|
|
/* List the current user data matrix columns over the selected row range */
|
|
void blockWriteAMAT(FILE *output, const char *label, lprec* lp, int first, int last)
|
|
{
|
|
int i, j, k = 0;
|
|
int nzb, nze, jb;
|
|
double hold;
|
|
MATrec *mat = lp->matA;
|
|
|
|
if(!mat_validate(mat))
|
|
return;
|
|
if(first < 0)
|
|
first = 0;
|
|
if(last < 0)
|
|
last = lp->rows;
|
|
|
|
fprintf(output, label);
|
|
fprintf(output, "\n");
|
|
|
|
if(first == 0) {
|
|
for(j = 1; j <= lp->columns; j++) {
|
|
hold = get_mat(lp, 0, j);
|
|
fprintf(output, " %18g", hold);
|
|
k++;
|
|
if(my_mod(k, 4) == 0) {
|
|
fprintf(output, "\n");
|
|
k = 0;
|
|
}
|
|
}
|
|
if(my_mod(k, 4) != 0) {
|
|
fprintf(output, "\n");
|
|
k = 0;
|
|
}
|
|
first++;
|
|
}
|
|
nze = mat->row_end[first-1];
|
|
for(i = first; i <= last; i++) {
|
|
nzb = nze;
|
|
nze = mat->row_end[i];
|
|
if(nzb >= nze)
|
|
jb = lp->columns+1;
|
|
else
|
|
jb = ROW_MAT_COLNR(nzb);
|
|
for(j = 1; j <= lp->columns; j++) {
|
|
if(j < jb)
|
|
hold = 0;
|
|
else {
|
|
hold = get_mat(lp, i, j);
|
|
nzb++;
|
|
if(nzb < nze)
|
|
jb = ROW_MAT_COLNR(nzb);
|
|
else
|
|
jb = lp->columns+1;
|
|
}
|
|
fprintf(output, " %18g", hold);
|
|
k++;
|
|
if(my_mod(k, 4) == 0) {
|
|
fprintf(output, "\n");
|
|
k = 0;
|
|
}
|
|
}
|
|
if(my_mod(k, 4) != 0) {
|
|
fprintf(output, "\n");
|
|
k = 0;
|
|
}
|
|
}
|
|
if(my_mod(k, 4) != 0)
|
|
fprintf(output, "\n");
|
|
}
|
|
|
|
/* List the current basis matrix columns over the selected row range */
|
|
void blockWriteBMAT(FILE *output, const char *label, lprec* lp, int first, int last)
|
|
{
|
|
int i, j, jb, k = 0;
|
|
double hold;
|
|
|
|
if(first < 0)
|
|
first = 0;
|
|
if(last < 0)
|
|
last = lp->rows;
|
|
|
|
fprintf(output, label);
|
|
fprintf(output, "\n");
|
|
|
|
for(i = first; i <= last; i++) {
|
|
for(j = 1; j <= lp->rows; j++) {
|
|
jb = lp->var_basic[j];
|
|
if(jb <= lp->rows) {
|
|
if(jb == i)
|
|
hold = 1;
|
|
else
|
|
hold = 0;
|
|
}
|
|
else
|
|
hold = get_mat(lp, i, j);
|
|
if(i == 0)
|
|
modifyOF1(lp, jb, &hold, 1);
|
|
hold = unscaled_mat(lp, hold, i, jb);
|
|
fprintf(output, " %18g", hold);
|
|
k++;
|
|
if(my_mod(k, 4) == 0) {
|
|
fprintf(output, "\n");
|
|
k = 0;
|
|
}
|
|
}
|
|
if(my_mod(k, 4) != 0) {
|
|
fprintf(output, "\n");
|
|
k = 0;
|
|
}
|
|
}
|
|
if(my_mod(k, 4) != 0)
|
|
fprintf(output, "\n");
|
|
}
|
|
|
|
/* Do a generic readable data dump of key lp_solve model variables;
|
|
principally for run difference and debugging purposes */
|
|
MYBOOL REPORT_debugdump(lprec *lp, char *filename, MYBOOL livedata)
|
|
{
|
|
FILE *output = stdout;
|
|
MYBOOL ok;
|
|
|
|
ok = (MYBOOL) ((filename == NULL) || ((output = fopen(filename,"w")) != NULL));
|
|
if(!ok)
|
|
return(ok);
|
|
if((filename == NULL) && (lp->outstream != NULL))
|
|
output = lp->outstream;
|
|
|
|
fprintf(output, "\nGENERAL INFORMATION\n-------------------\n\n");
|
|
fprintf(output, "Model size: %d rows (%d equalities, %d Lagrangean), %d columns (%d integers, %d SC, %d SOS, %d GUB)\n",
|
|
lp->rows, lp->equalities, get_Lrows(lp), lp->columns,
|
|
lp->int_vars, lp->sc_vars, SOS_count(lp), GUB_count(lp));
|
|
fprintf(output, "Data size: %d model non-zeros, %d invB non-zeros (engine is %s)\n",
|
|
get_nonzeros(lp), my_if(lp->invB == NULL, 0, lp->bfp_nonzeros(lp, FALSE)), lp->bfp_name());
|
|
fprintf(output, "Internal sizes: %d rows allocated, %d columns allocated, %d columns used, %d eta length\n",
|
|
lp->rows_alloc, lp->columns_alloc, lp->columns, my_if(lp->invB == NULL, 0, lp->bfp_colcount(lp)));
|
|
fprintf(output, "Memory use: %d sparse matrix, %d eta\n",
|
|
lp->matA->mat_alloc, my_if(lp->invB == NULL, 0, lp->bfp_memallocated(lp)));
|
|
fprintf(output, "Parameters: Maximize=%d, Names used=%d, Scalingmode=%d, Presolve=%d, SimplexPivot=%d\n",
|
|
is_maxim(lp), lp->names_used, lp->scalemode, lp->do_presolve, lp->piv_strategy);
|
|
fprintf(output, "Precision: EpsValue=%g, EpsPrimal=%g, EpsDual=%g, EpsPivot=%g, EpsPerturb=%g\n",
|
|
lp->epsvalue, lp->epsprimal, lp->epsdual, lp->epspivot, lp->epsperturb);
|
|
fprintf(output, "Stability: AntiDegen=%d, Improvement=%d, Split variables at=%g\n",
|
|
lp->improve, lp->anti_degen, lp->negrange);
|
|
fprintf(output, "B&B settings: BB pivot rule=%d, BB branching=%s, BB strategy=%d, Integer precision=%g, MIP gaps=%g,%g\n",
|
|
lp->bb_rule, my_boolstr(lp->bb_varbranch), lp->bb_floorfirst, lp->epsint, lp->mip_absgap, lp->mip_relgap);
|
|
|
|
fprintf(output, "\nCORE DATA\n---------\n\n");
|
|
blockWriteINT(output, "Column starts", lp->matA->col_end, 0, lp->columns);
|
|
blockWriteINT(output, "row_type", lp->row_type, 0, lp->rows);
|
|
blockWriteREAL(output, "orig_rhs", lp->orig_rhs, 0, lp->rows);
|
|
blockWriteREAL(output, "orig_lowbo", lp->orig_lowbo, 0, lp->sum);
|
|
blockWriteREAL(output, "orig_upbo", lp->orig_upbo, 0, lp->sum);
|
|
blockWriteINT(output, "row_type", lp->row_type, 0, lp->rows);
|
|
blockWriteBOOL(output, "var_type", lp->var_type, 0, lp->columns, TRUE);
|
|
blockWriteAMAT(output, "A", lp, 0, lp->rows);
|
|
|
|
if(livedata) {
|
|
fprintf(output, "\nPROCESS DATA\n------------\n\n");
|
|
blockWriteREAL(output, "Active rhs", lp->rhs, 0, lp->rows);
|
|
blockWriteINT(output, "Basic variables", lp->var_basic, 0, lp->rows);
|
|
blockWriteBOOL(output, "is_basic", lp->is_basic, 0, lp->sum, TRUE);
|
|
blockWriteREAL(output, "lowbo", lp->lowbo, 0, lp->sum);
|
|
blockWriteREAL(output, "upbo", lp->upbo, 0, lp->sum);
|
|
if(lp->scalars != NULL)
|
|
blockWriteREAL(output, "scalars", lp->scalars, 0, lp->sum);
|
|
}
|
|
|
|
if(filename != NULL)
|
|
fclose(output);
|
|
return(ok);
|
|
}
|
|
|
|
|
|
/* High level reports for model results */
|
|
|
|
void REPORT_objective(lprec *lp)
|
|
{
|
|
if(lp->outstream == NULL)
|
|
return;
|
|
fprintf(lp->outstream, "\nValue of objective function: %g\n",
|
|
(double)lp->best_solution[0]);
|
|
fflush(lp->outstream);
|
|
}
|
|
|
|
void REPORT_solution(lprec *lp, int columns)
|
|
{
|
|
int i, j, n;
|
|
REAL value;
|
|
presolveundorec *psundo = lp->presolve_undo;
|
|
MYBOOL NZonly = (MYBOOL) ((lp->print_sol & AUTOMATIC) > 0);
|
|
|
|
if(lp->outstream == NULL)
|
|
return;
|
|
|
|
fprintf(lp->outstream, "\nActual values of the variables:\n");
|
|
if(columns <= 0)
|
|
columns = 2;
|
|
n = 0;
|
|
for(i = 1; i <= psundo->orig_columns; i++) {
|
|
j = psundo->orig_rows + i;
|
|
value = get_var_primalresult(lp, j);
|
|
if(NZonly && (fabs(value) < lp->epsprimal))
|
|
continue;
|
|
n = (n+1) % columns;
|
|
fprintf(lp->outstream, "%-20s %12g", get_origcol_name(lp, i), (double) value);
|
|
if(n == 0)
|
|
fprintf(lp->outstream, "\n");
|
|
else
|
|
fprintf(lp->outstream, " ");
|
|
}
|
|
|
|
fflush(lp->outstream);
|
|
} /* REPORT_solution */
|
|
|
|
void REPORT_constraints(lprec *lp, int columns)
|
|
{
|
|
int i, n;
|
|
REAL value;
|
|
MYBOOL NZonly = (MYBOOL) ((lp->print_sol & AUTOMATIC) > 0);
|
|
|
|
if(lp->outstream == NULL)
|
|
return;
|
|
|
|
if(columns <= 0)
|
|
columns = 2;
|
|
|
|
fprintf(lp->outstream, "\nActual values of the constraints:\n");
|
|
n = 0;
|
|
for(i = 1; i <= lp->rows; i++) {
|
|
value = (double)lp->best_solution[i];
|
|
if(NZonly && (fabs(value) < lp->epsprimal))
|
|
continue;
|
|
n = (n+1) % columns;
|
|
fprintf(lp->outstream, "%-20s %12g", get_row_name(lp, i), value);
|
|
if(n == 0)
|
|
fprintf(lp->outstream, "\n");
|
|
else
|
|
fprintf(lp->outstream, " ");
|
|
}
|
|
|
|
fflush(lp->outstream);
|
|
}
|
|
|
|
void REPORT_duals(lprec *lp)
|
|
{
|
|
int i;
|
|
REAL *duals, *dualsfrom, *dualstill, *objfrom, *objtill, *objfromvalue;
|
|
MYBOOL ret;
|
|
|
|
if(lp->outstream == NULL)
|
|
return;
|
|
|
|
ret = get_ptr_sensitivity_objex(lp, &objfrom, &objtill, &objfromvalue, NULL);
|
|
if(ret) {
|
|
fprintf(lp->outstream, "\nObjective function limits:\n");
|
|
fprintf(lp->outstream, " From Till FromValue\n");
|
|
for(i = 1; i <= lp->columns; i++)
|
|
if(!is_splitvar(lp, i))
|
|
fprintf(lp->outstream, "%-20s %15.7g %15.7g %15.7g\n", get_col_name(lp, i),
|
|
(double)objfrom[i - 1], (double)objtill[i - 1], (double)objfromvalue[i - 1]);
|
|
}
|
|
|
|
ret = get_ptr_sensitivity_rhs(lp, &duals, &dualsfrom, &dualstill);
|
|
if(ret) {
|
|
fprintf(lp->outstream, "\nDual values with from - till limits:\n");
|
|
fprintf(lp->outstream, " Dual value From Till\n");
|
|
for(i = 1; i <= lp->sum; i++)
|
|
fprintf(lp->outstream, "%-20s %15.7g %15.7g %15.7g\n",
|
|
(i <= lp->rows) ? get_row_name(lp, i) : get_col_name(lp, i - lp->rows),
|
|
(double)duals[i - 1], (double)dualsfrom[i - 1], (double)dualstill[i - 1]);
|
|
fflush(lp->outstream);
|
|
}
|
|
}
|
|
|
|
/* Printing of sensitivity analysis reports */
|
|
void REPORT_extended(lprec *lp)
|
|
{
|
|
int i, j;
|
|
REAL hold;
|
|
REAL *duals, *dualsfrom, *dualstill, *objfrom, *objtill;
|
|
MYBOOL ret;
|
|
|
|
ret = get_ptr_sensitivity_obj(lp, &objfrom, &objtill);
|
|
report(lp, NORMAL, " \n");
|
|
report(lp, NORMAL, "Primal objective:\n");
|
|
report(lp, NORMAL, " \n");
|
|
report(lp, NORMAL, " Column name Value Objective Min Max\n");
|
|
report(lp, NORMAL, " --------------------------------------------------------------------------\n");
|
|
for(j = 1; j <= lp->columns; j++) {
|
|
hold = get_mat(lp,0,j);
|
|
report(lp, NORMAL, " %-25s " MPSVALUEMASK MPSVALUEMASK MPSVALUEMASK MPSVALUEMASK "\n",
|
|
get_col_name(lp,j),
|
|
my_precision(hold,lp->epsprimal),
|
|
my_precision(hold*lp->best_solution[lp->rows+j],lp->epsprimal),
|
|
my_precision((ret) ? objfrom[j - 1] : 0.0,lp->epsprimal),
|
|
my_precision((ret) ? objtill[j - 1] : 0.0,lp->epsprimal));
|
|
}
|
|
report(lp, NORMAL, " \n");
|
|
|
|
ret = get_ptr_sensitivity_rhs(lp, &duals, &dualsfrom, &dualstill);
|
|
report(lp, NORMAL, "Primal variables:\n");
|
|
report(lp, NORMAL, " \n");
|
|
report(lp, NORMAL, " Column name Value Slack Min Max\n");
|
|
report(lp, NORMAL, " --------------------------------------------------------------------------\n");
|
|
for(j = 1; j <= lp->columns; j++)
|
|
report(lp, NORMAL, " %-25s " MPSVALUEMASK MPSVALUEMASK MPSVALUEMASK MPSVALUEMASK "\n",
|
|
get_col_name(lp,j),
|
|
my_precision(lp->best_solution[lp->rows+j],lp->epsprimal),
|
|
my_precision(my_inflimit(lp, (ret) ? duals[lp->rows+j-1] : 0.0),lp->epsprimal),
|
|
my_precision((ret) ? dualsfrom[lp->rows+j-1] : 0.0,lp->epsprimal),
|
|
my_precision((ret) ? dualstill[lp->rows+j-1] : 0.0,lp->epsprimal));
|
|
|
|
report(lp, NORMAL, " \n");
|
|
report(lp, NORMAL, "Dual variables:\n");
|
|
report(lp, NORMAL, " \n");
|
|
report(lp, NORMAL, " Row name Value Slack Min Max\n");
|
|
report(lp, NORMAL, " --------------------------------------------------------------------------\n");
|
|
for(i = 1; i <= lp->rows; i++)
|
|
report(lp, NORMAL, " %-25s " MPSVALUEMASK MPSVALUEMASK MPSVALUEMASK MPSVALUEMASK "\n",
|
|
get_row_name(lp,i),
|
|
my_precision((ret) ? duals[i - 1] : 0.0, lp->epsprimal),
|
|
my_precision(lp->best_solution[i], lp->epsprimal),
|
|
my_precision((ret) ? dualsfrom[i - 1] : 0.0,lp->epsprimal),
|
|
my_precision((ret) ? dualstill[i - 1] : 0.0,lp->epsprimal));
|
|
|
|
report(lp, NORMAL, " \n");
|
|
}
|
|
|
|
/* A more readable lp-format report of the model; antiquated and not updated */
|
|
void REPORT_lp(lprec *lp)
|
|
{
|
|
int i, j;
|
|
|
|
if(lp->outstream == NULL)
|
|
return;
|
|
|
|
if(lp->matA->is_roworder) {
|
|
report(lp, IMPORTANT, "REPORT_lp: Cannot print lp while in row entry mode.\n");
|
|
return;
|
|
}
|
|
|
|
fprintf(lp->outstream, "Model name: %s\n", get_lp_name(lp));
|
|
fprintf(lp->outstream, " ");
|
|
|
|
for(j = 1; j <= lp->columns; j++)
|
|
fprintf(lp->outstream, "%8s ", get_col_name(lp,j));
|
|
|
|
fprintf(lp->outstream, "\n%simize ", (is_maxim(lp) ? "Max" : "Min"));
|
|
for(j = 1; j <= lp->columns; j++)
|
|
fprintf(lp->outstream, "%8g ", get_mat(lp, 0, j));
|
|
fprintf(lp->outstream, "\n");
|
|
|
|
for(i = 1; i <= lp->rows; i++) {
|
|
fprintf(lp->outstream, "%-9s ", get_row_name(lp, i));
|
|
for(j = 1; j <= lp->columns; j++)
|
|
fprintf(lp->outstream, "%8g ", get_mat(lp, i, j));
|
|
if(is_constr_type(lp, i, GE))
|
|
fprintf(lp->outstream, ">= ");
|
|
else if(is_constr_type(lp, i, LE))
|
|
fprintf(lp->outstream, "<= ");
|
|
else
|
|
fprintf(lp->outstream, " = ");
|
|
fprintf(lp->outstream, "%8g", get_rh(lp, i));
|
|
|
|
if(is_constr_type(lp, i, GE)) {
|
|
if(get_rh_upper(lp, i) < lp->infinite)
|
|
fprintf(lp->outstream, " %s = %8g", "upbo", get_rh_upper(lp, i));
|
|
}
|
|
else if(is_constr_type(lp, i, LE)) {
|
|
if(get_rh_lower(lp, i) > -lp->infinite)
|
|
fprintf(lp->outstream, " %s = %8g", "lowbo", get_rh_lower(lp, i));
|
|
}
|
|
fprintf(lp->outstream, "\n");
|
|
}
|
|
|
|
fprintf(lp->outstream, "Type ");
|
|
for(i = 1; i <= lp->columns; i++) {
|
|
if(is_int(lp,i))
|
|
fprintf(lp->outstream, " Int ");
|
|
else
|
|
fprintf(lp->outstream, " Real ");
|
|
}
|
|
|
|
fprintf(lp->outstream, "\nupbo ");
|
|
for(i = 1; i <= lp->columns; i++)
|
|
if(get_upbo(lp, i) >= lp->infinite)
|
|
fprintf(lp->outstream, " Inf ");
|
|
else
|
|
fprintf(lp->outstream, "%8g ", get_upbo(lp, i));
|
|
fprintf(lp->outstream, "\nlowbo ");
|
|
for(i = 1; i <= lp->columns; i++)
|
|
if(get_lowbo(lp, i) <= -lp->infinite)
|
|
fprintf(lp->outstream, " -Inf ");
|
|
else
|
|
fprintf(lp->outstream, "%8g ", get_lowbo(lp, i));
|
|
fprintf(lp->outstream, "\n");
|
|
|
|
fflush(lp->outstream);
|
|
}
|
|
|
|
/* Report the scaling factors used; extremely rarely used */
|
|
void REPORT_scales(lprec *lp)
|
|
{
|
|
int i, colMax;
|
|
|
|
colMax = lp->columns;
|
|
|
|
if(lp->outstream == NULL)
|
|
return;
|
|
|
|
if(lp->scaling_used) {
|
|
fprintf(lp->outstream, "\nScale factors:\n");
|
|
for(i = 0; i <= lp->rows + colMax; i++)
|
|
fprintf(lp->outstream, "%-20s scaled at %g\n",
|
|
(i <= lp->rows) ? get_row_name(lp, i) : get_col_name(lp, i - lp->rows),
|
|
(double)lp->scalars[i]);
|
|
}
|
|
fflush(lp->outstream);
|
|
}
|
|
|
|
/* Report the traditional tableau corresponding to the current basis */
|
|
MYBOOL REPORT_tableau(lprec *lp)
|
|
{
|
|
int j, row_nr, *coltarget;
|
|
REAL *prow = NULL;
|
|
FILE *stream = lp->outstream;
|
|
|
|
if(lp->outstream == NULL)
|
|
return(FALSE);
|
|
|
|
if(!lp->model_is_valid || !has_BFP(lp) ||
|
|
(get_total_iter(lp) == 0) || (lp->spx_status == NOTRUN)) {
|
|
lp->spx_status = NOTRUN;
|
|
return(FALSE);
|
|
}
|
|
if(!allocREAL(lp, &prow,lp->sum + 1, TRUE)) {
|
|
lp->spx_status = NOMEMORY;
|
|
return(FALSE);
|
|
}
|
|
|
|
fprintf(stream, "\n");
|
|
fprintf(stream, "Tableau at iter %.0f:\n", (double) get_total_iter(lp));
|
|
|
|
for(j = 1; j <= lp->sum; j++)
|
|
if (!lp->is_basic[j])
|
|
fprintf(stream, "%15d", (j <= lp->rows ?
|
|
(j + lp->columns) * ((lp->orig_upbo[j] == 0) ||
|
|
(is_chsign(lp, j)) ? 1 : -1) : j - lp->rows) *
|
|
(lp->is_lower[j] ? 1 : -1));
|
|
fprintf(stream, "\n");
|
|
|
|
coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->columns+1, sizeof(*coltarget));
|
|
if(!get_colIndexA(lp, SCAN_USERVARS+USE_NONBASICVARS, coltarget, FALSE)) {
|
|
mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
|
|
return(FALSE);
|
|
}
|
|
for(row_nr = 1; (row_nr <= lp->rows + 1); row_nr++) {
|
|
if (row_nr <= lp->rows)
|
|
fprintf(stream, "%3d", (lp->var_basic[row_nr] <= lp->rows ?
|
|
(lp->var_basic[row_nr] + lp->columns) * ((lp->orig_upbo[lp->var_basic [row_nr]] == 0) ||
|
|
(is_chsign(lp, lp->var_basic[row_nr])) ? 1 : -1) : lp->var_basic[row_nr] - lp->rows) *
|
|
(lp->is_lower[lp->var_basic [row_nr]] ? 1 : -1));
|
|
else
|
|
fprintf(stream, " ");
|
|
bsolve(lp, row_nr <= lp->rows ? row_nr : 0, prow, NULL, lp->epsmachine*DOUBLEROUND, 1.0);
|
|
prod_xA(lp, coltarget, prow, NULL, lp->epsmachine, 1.0,
|
|
prow, NULL, MAT_ROUNDDEFAULT);
|
|
|
|
for(j = 1; j <= lp->rows + lp->columns; j++)
|
|
if (!lp->is_basic[j])
|
|
fprintf(stream, "%15.7f", prow[j] * (lp->is_lower[j] ? 1 : -1) *
|
|
(row_nr <= lp->rows ? 1 : -1));
|
|
fprintf(stream, "%15.7f", lp->rhs[row_nr <= lp->rows ? row_nr : 0] *
|
|
(double) ((row_nr <= lp->rows) || (is_maxim(lp)) ? 1 : -1));
|
|
fprintf(stream, "\n");
|
|
}
|
|
fflush(stream);
|
|
|
|
mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
|
|
FREE(prow);
|
|
return(TRUE);
|
|
}
|
|
|
|
void REPORT_constraintinfo(lprec *lp, char *datainfo)
|
|
{
|
|
int i, tally[ROWCLASS_MAX+1];
|
|
|
|
MEMCLEAR(tally, ROWCLASS_MAX+1);
|
|
for(i = 1; i <= lp->rows; i++)
|
|
tally[get_constr_class(lp, i)]++;
|
|
|
|
if(datainfo != NULL)
|
|
report(lp, NORMAL, "%s\n", datainfo);
|
|
|
|
for(i = 0; i <= ROWCLASS_MAX; i++)
|
|
if(tally[i] > 0)
|
|
report(lp, NORMAL, "%-15s %4d\n", get_str_constr_class(lp, i), tally[i]);
|
|
}
|
|
|
|
void REPORT_modelinfo(lprec *lp, MYBOOL doName, char *datainfo)
|
|
{
|
|
if(doName) {
|
|
report(lp, NORMAL, "\nModel name: '%s' - run #%-5d\n",
|
|
get_lp_name(lp), lp->solvecount);
|
|
report(lp, NORMAL, "Objective: %simize(%s)\n",
|
|
my_if(is_maxim(lp), "Max", "Min"), get_row_name(lp, 0));
|
|
report(lp, NORMAL, " \n");
|
|
}
|
|
if(datainfo != NULL)
|
|
report(lp, NORMAL, "%s\n", datainfo);
|
|
|
|
report(lp, NORMAL, "Model size: %7d constraints, %7d variables, %12d non-zeros.\n",
|
|
lp->rows, lp->columns, get_nonzeros(lp));
|
|
if(GUB_count(lp)+SOS_count(lp) > 0)
|
|
report(lp, NORMAL, "Var-types: %7d integer, %7d semi-cont., %7d SOS.\n",
|
|
lp->int_vars, lp->sc_vars, lp->sos_vars);
|
|
report(lp, NORMAL, "Sets: %7d GUB, %7d SOS.\n",
|
|
GUB_count(lp), SOS_count(lp));
|
|
}
|
|
|
|
/* Save a matrix column subset to a MatrixMarket formatted file,
|
|
say to export the basis matrix for further numerical analysis.
|
|
If colndx is NULL, then the full constraint matrix is assumed. */
|
|
MYBOOL REPORT_mat_mmsave(lprec *lp, char *filename, int *colndx, MYBOOL includeOF, char *infotext)
|
|
{
|
|
int n, m, nz, i, j, k, kk;
|
|
MATrec *mat = lp->matA;
|
|
MM_typecode matcode;
|
|
FILE *output = stdout;
|
|
MYBOOL ok;
|
|
REAL *acol = NULL;
|
|
int *nzlist = NULL;
|
|
|
|
/* Open file */
|
|
ok = (MYBOOL) ((filename == NULL) || ((output = fopen(filename,"w")) != NULL));
|
|
if(!ok)
|
|
return(ok);
|
|
if((filename == NULL) && (lp->outstream != NULL))
|
|
output = lp->outstream;
|
|
|
|
/* Compute column and non-zero counts */
|
|
if(colndx == lp->var_basic) {
|
|
if(!lp->basis_valid)
|
|
return( FALSE );
|
|
m = lp->rows;
|
|
}
|
|
else if(colndx != NULL)
|
|
m = colndx[0];
|
|
else
|
|
m = lp->columns;
|
|
n = lp->rows;
|
|
nz = 0;
|
|
|
|
for(j = 1; j <= m; j++) {
|
|
k = (colndx == NULL ? n + j : colndx[j]);
|
|
if(k > n) {
|
|
k -= lp->rows;
|
|
nz += mat_collength(mat, k);
|
|
if(includeOF && is_OF_nz(lp, k))
|
|
nz++;
|
|
}
|
|
else
|
|
nz++;
|
|
}
|
|
kk = 0;
|
|
if(includeOF) {
|
|
n++; /* Row count */
|
|
kk++; /* Row index offset */
|
|
}
|
|
|
|
/* Initialize */
|
|
mm_initialize_typecode(&matcode);
|
|
mm_set_matrix(&matcode);
|
|
mm_set_coordinate(&matcode);
|
|
mm_set_real(&matcode);
|
|
|
|
mm_write_banner(output, matcode);
|
|
mm_write_mtx_crd_size(output, n+kk, m, nz+(colndx == lp->var_basic ? 1 : 0));
|
|
|
|
/* Allocate working arrays for sparse column storage */
|
|
allocREAL(lp, &acol, n+2, FALSE);
|
|
allocINT(lp, &nzlist, n+2, FALSE);
|
|
|
|
/* Write the matrix non-zero values column-by-column.
|
|
NOTE: matrixMarket files use 1-based indeces,
|
|
i.e. first row of a vector has index 1, not 0. */
|
|
if(infotext != NULL) {
|
|
fprintf(output, "%%\n");
|
|
fprintf(output, "%% %s\n", infotext);
|
|
fprintf(output, "%%\n");
|
|
}
|
|
if(includeOF && (colndx == lp->var_basic))
|
|
fprintf(output, "%d %d %g\n", 1, 1, 1.0);
|
|
for(j = 1; j <= m; j++) {
|
|
k = (colndx == NULL ? lp->rows + j : colndx[j]);
|
|
if(k == 0)
|
|
continue;
|
|
nz = obtain_column(lp, k, acol, nzlist, NULL);
|
|
for(i = 1; i <= nz; i++) {
|
|
if(!includeOF && (nzlist[i] == 0))
|
|
continue;
|
|
fprintf(output, "%d %d %g\n", nzlist[i]+kk, j+kk, acol[i]);
|
|
}
|
|
}
|
|
fprintf(output, "%% End of MatrixMarket file\n");
|
|
|
|
/* Finish */
|
|
FREE(acol);
|
|
FREE(nzlist);
|
|
fclose(output);
|
|
|
|
return(ok);
|
|
}
|
|
|