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.
362 lines
12 KiB
362 lines
12 KiB
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "commonlib.h"
|
|
#include "lp_lib.h"
|
|
#include "lp_scale.h"
|
|
#include "lp_utils.h"
|
|
#include "lp_report.h"
|
|
#include "lp_wlp.h"
|
|
|
|
#ifdef FORTIFY
|
|
# include "lp_fortify.h"
|
|
#endif
|
|
|
|
/* Define buffer-size controled function mapping */
|
|
# if defined _MSC_VER
|
|
# define vsnprintf _vsnprintf
|
|
# endif
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Input and output of lp format model files for lp_solve */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static int write_data(void *userhandle, write_modeldata_func write_modeldata, char *format, ...)
|
|
{
|
|
char buff[DEF_STRBUFSIZE+1];
|
|
va_list ap;
|
|
int n;
|
|
|
|
va_start(ap, format);
|
|
vsnprintf(buff, DEF_STRBUFSIZE, format, ap);
|
|
va_end(ap);
|
|
n = write_modeldata(userhandle, buff);
|
|
return(n);
|
|
}
|
|
|
|
STATIC void write_lpcomment(void *userhandle, write_modeldata_func write_modeldata, char *string, MYBOOL newlinebefore)
|
|
{
|
|
write_data(userhandle, write_modeldata, "%s/* %s */\n", (newlinebefore) ? "\n" : "", string);
|
|
}
|
|
|
|
STATIC int write_lprow(lprec *lp, int rowno, void *userhandle, write_modeldata_func write_modeldata, int maxlen, int *idx, REAL *val)
|
|
{
|
|
int i, j, nchars, elements;
|
|
REAL a;
|
|
MYBOOL first = TRUE;
|
|
char buf[50];
|
|
|
|
elements = get_rowex(lp, rowno, val, idx);
|
|
if(write_modeldata != NULL) {
|
|
nchars = 0;
|
|
for(i = 0; i < elements; i++) {
|
|
j = idx[i];
|
|
if(is_splitvar(lp, j))
|
|
continue;
|
|
a = val[i];
|
|
if(!first)
|
|
nchars += write_data(userhandle, write_modeldata, " ");
|
|
else
|
|
first = FALSE;
|
|
sprintf(buf, "%+.12g", (double)a);
|
|
if(strcmp(buf, "-1") == 0)
|
|
nchars += write_data(userhandle, write_modeldata, "-");
|
|
else if(strcmp(buf, "+1") == 0)
|
|
nchars += write_data(userhandle, write_modeldata, "+");
|
|
else
|
|
nchars += write_data(userhandle, write_modeldata, "%s ", buf);
|
|
nchars += write_data(userhandle, write_modeldata, "%s", get_col_name(lp, j));
|
|
/* Check if we should add a linefeed */
|
|
if((maxlen > 0) && (nchars >= maxlen) && (i < elements-1)) {
|
|
write_data(userhandle, write_modeldata, "%s", "\n");
|
|
nchars = 0;
|
|
}
|
|
}
|
|
}
|
|
return(elements);
|
|
}
|
|
|
|
#if !defined LP_MAXLINELEN
|
|
# define LP_MAXLINELEN 100
|
|
#endif
|
|
|
|
MYBOOL __WINAPI write_lpex(lprec *lp, void *userhandle, write_modeldata_func write_modeldata)
|
|
{
|
|
int i, j, b,
|
|
nrows = lp->rows,
|
|
ncols = lp->columns,
|
|
nchars, maxlen = LP_MAXLINELEN,
|
|
*idx;
|
|
MYBOOL ok;
|
|
REAL a, *val;
|
|
char *ptr;
|
|
|
|
if(!mat_validate(lp->matA)) {
|
|
report(lp, IMPORTANT, "LP_writefile: Could not validate the data matrix.\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
/* Write name of model */
|
|
ptr = get_lp_name(lp);
|
|
if(ptr != NULL) {
|
|
if(*ptr)
|
|
write_lpcomment(userhandle, write_modeldata, ptr, FALSE);
|
|
else
|
|
ptr = NULL;
|
|
}
|
|
|
|
/* Write the objective function */
|
|
write_lpcomment(userhandle, write_modeldata, "Objective function", (MYBOOL) (ptr != NULL));
|
|
if(is_maxim(lp))
|
|
write_data(userhandle, write_modeldata, "max: ");
|
|
else
|
|
write_data(userhandle, write_modeldata, "min: ");
|
|
|
|
allocREAL(lp, &val, 1 + lp->columns, TRUE);
|
|
allocINT(lp, &idx, 1 + lp->columns, TRUE);
|
|
|
|
write_lprow(lp, 0, userhandle, write_modeldata, maxlen, idx, val);
|
|
a = get_rh(lp, 0);
|
|
if(a != 0)
|
|
write_data(userhandle, write_modeldata, " %+.12g", a);
|
|
write_data(userhandle, write_modeldata, ";\n");
|
|
|
|
/* Write constraints */
|
|
if(nrows > 0)
|
|
write_lpcomment(userhandle, write_modeldata, "Constraints", TRUE);
|
|
for(j = 1; j <= nrows; j++) {
|
|
if(((lp->names_used) && (lp->row_name[j] != NULL)) || (write_lprow(lp, j, userhandle, NULL, maxlen, idx, val) == 1))
|
|
ptr = get_row_name(lp, j);
|
|
else
|
|
ptr = NULL;
|
|
if((ptr != NULL) && (*ptr))
|
|
write_data(userhandle, write_modeldata, "%s: ", ptr);
|
|
|
|
#ifndef SingleBoundedRowInLP
|
|
/* Write the ranged part of the constraint, if specified */
|
|
if ((lp->orig_upbo[j]) && (lp->orig_upbo[j] < lp->infinite)) {
|
|
if(my_chsign(is_chsign(lp, j), lp->orig_rhs[j]) == -lp->infinite)
|
|
write_data(userhandle, write_modeldata, "-Inf %s ", (is_chsign(lp, j)) ? ">=" : "<=");
|
|
else if(my_chsign(is_chsign(lp, j), lp->orig_rhs[j]) == lp->infinite)
|
|
write_data(userhandle, write_modeldata, "+Inf %s ", (is_chsign(lp, j)) ? ">=" : "<=");
|
|
else
|
|
write_data(userhandle, write_modeldata, "%+.12g %s ",
|
|
(lp->orig_upbo[j]-lp->orig_rhs[j]) * (is_chsign(lp, j) ? 1.0 : -1.0) / (lp->scaling_used ? lp->scalars[j] : 1.0),
|
|
(is_chsign(lp, j)) ? ">=" : "<=");
|
|
}
|
|
#endif
|
|
|
|
if((!write_lprow(lp, j, userhandle, write_modeldata, maxlen, idx, val)) && (ncols >= 1))
|
|
write_data(userhandle, write_modeldata, "0 %s", get_col_name(lp, 1));
|
|
|
|
if(lp->orig_upbo[j] == 0)
|
|
write_data(userhandle, write_modeldata, " =");
|
|
else if(is_chsign(lp, j))
|
|
write_data(userhandle, write_modeldata, " >=");
|
|
else
|
|
write_data(userhandle, write_modeldata, " <=");
|
|
if(fabs(get_rh(lp, j) + lp->infinite) < 1)
|
|
write_data(userhandle, write_modeldata, " -Inf;\n");
|
|
else if(fabs(get_rh(lp, j) - lp->infinite) < 1)
|
|
write_data(userhandle, write_modeldata, " +Inf;\n");
|
|
else
|
|
write_data(userhandle, write_modeldata, " %.12g;\n", get_rh(lp, j));
|
|
|
|
#ifdef SingleBoundedRowInLP
|
|
/* Write the ranged part of the constraint, if specified */
|
|
if ((lp->orig_upbo[j]) && (lp->orig_upbo[j] < lp->infinite)) {
|
|
if(((lp->names_used) && (lp->row_name[j] != NULL)) || (write_lprow(lp, j, userhandle, NULL, maxlen, idx, val) == 1))
|
|
ptr = get_row_name(lp, j);
|
|
else
|
|
ptr = NULL;
|
|
if((ptr != NULL) && (*ptr))
|
|
write_data(userhandle, write_modeldata, "%s: ", ptr);
|
|
if((!write_lprow(lp, j, userhandle, write_modeldata, maxlen, idx, val)) && (get_Ncolumns(lp) >= 1))
|
|
write_data(userhandle, write_modeldata, "0 %s", get_col_name(lp, 1));
|
|
write_data(userhandle, write_modeldata, " %s %g;\n",
|
|
(is_chsign(lp, j)) ? "<=" : ">=",
|
|
(lp->orig_upbo[j]-lp->orig_rhs[j]) * (is_chsign(lp, j) ? 1.0 : -1.0) / (lp->scaling_used ? lp->scalars[j] : 1.0));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Write bounds on variables */
|
|
ok = FALSE;
|
|
for(i = nrows + 1; i <= lp->sum; i++)
|
|
if(!is_splitvar(lp, i - nrows)) {
|
|
if(lp->orig_lowbo[i] == lp->orig_upbo[i]) {
|
|
if(!ok) {
|
|
write_lpcomment(userhandle, write_modeldata, "Variable bounds", TRUE);
|
|
ok = TRUE;
|
|
}
|
|
write_data(userhandle, write_modeldata, "%s = %.12g;\n", get_col_name(lp, i - nrows), get_upbo(lp, i - nrows));
|
|
}
|
|
else {
|
|
#ifndef SingleBoundedRowInLP
|
|
if((lp->orig_lowbo[i] != 0) && (lp->orig_upbo[i] < lp->infinite)) {
|
|
if(!ok) {
|
|
write_lpcomment(userhandle, write_modeldata, "Variable bounds", TRUE);
|
|
ok = TRUE;
|
|
}
|
|
if(lp->orig_lowbo[i] == -lp->infinite)
|
|
write_data(userhandle, write_modeldata, "-Inf");
|
|
else
|
|
write_data(userhandle, write_modeldata, "%.12g", get_lowbo(lp, i - nrows));
|
|
write_data(userhandle, write_modeldata, " <= %s <= ", get_col_name(lp, i - nrows));
|
|
if(lp->orig_lowbo[i] == lp->infinite)
|
|
write_data(userhandle, write_modeldata, "+Inf");
|
|
else
|
|
write_data(userhandle, write_modeldata, "%.12g", get_upbo(lp, i - nrows));
|
|
write_data(userhandle, write_modeldata, ";\n");
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if(lp->orig_lowbo[i] != 0) {
|
|
if(!ok) {
|
|
write_lpcomment(userhandle, write_modeldata, "Variable bounds", TRUE);
|
|
ok = TRUE;
|
|
}
|
|
if(lp->orig_lowbo[i] == -lp->infinite)
|
|
write_data(userhandle, write_modeldata, "%s >= -Inf;\n", get_col_name(lp, i - nrows));
|
|
else if(lp->orig_lowbo[i] == lp->infinite)
|
|
write_data(userhandle, write_modeldata, "%s >= +Inf;\n", get_col_name(lp, i - nrows));
|
|
else
|
|
write_data(userhandle, write_modeldata, "%s >= %.12g;\n",
|
|
get_col_name(lp, i - nrows), get_lowbo(lp, i - nrows));
|
|
}
|
|
if(lp->orig_upbo[i] != lp->infinite) {
|
|
if(!ok) {
|
|
write_lpcomment(userhandle, write_modeldata, "Variable bounds", TRUE);
|
|
ok = TRUE;
|
|
}
|
|
write_data(userhandle, write_modeldata, "%s <= %.12g;\n",
|
|
get_col_name(lp, i - nrows), get_upbo(lp, i - nrows));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Write optional integer section */
|
|
if(lp->int_vars > 0) {
|
|
write_lpcomment(userhandle, write_modeldata, "Integer definitions", TRUE);
|
|
i = 1;
|
|
while((i <= ncols) && !is_int(lp, i))
|
|
i++;
|
|
if(i <= ncols) {
|
|
nchars = write_data(userhandle, write_modeldata, "int %s", get_col_name(lp, i));
|
|
i++;
|
|
for(; i <= ncols; i++)
|
|
if((!is_splitvar(lp, i)) && (is_int(lp, i))) {
|
|
if((maxlen!= 0) && (nchars > maxlen)) {
|
|
write_data(userhandle, write_modeldata, "%s", "\n");
|
|
nchars = 0;
|
|
}
|
|
write_data(userhandle, write_modeldata, ",%s", get_col_name(lp, i));
|
|
}
|
|
write_data(userhandle, write_modeldata, ";\n");
|
|
}
|
|
}
|
|
|
|
/* Write optional SEC section */
|
|
if(lp->sc_vars > 0) {
|
|
write_lpcomment(userhandle, write_modeldata, "Semi-continuous variables", TRUE);
|
|
i = 1;
|
|
while((i <= ncols) && !is_semicont(lp, i))
|
|
i++;
|
|
if(i <= ncols) {
|
|
nchars = write_data(userhandle, write_modeldata, "sec %s", get_col_name(lp, i));
|
|
i++;
|
|
for(; i <= ncols; i++)
|
|
if((!is_splitvar(lp, i)) && (is_semicont(lp, i))) {
|
|
if((maxlen != 0) && (nchars > maxlen)) {
|
|
write_data(userhandle, write_modeldata, "%s", "\n");
|
|
nchars = 0;
|
|
}
|
|
nchars += write_data(userhandle, write_modeldata, ",%s", get_col_name(lp, i));
|
|
}
|
|
write_data(userhandle, write_modeldata, ";\n");
|
|
}
|
|
}
|
|
|
|
/* Write optional SOS section */
|
|
if(SOS_count(lp) > 0) {
|
|
SOSgroup *SOS = lp->SOS;
|
|
write_lpcomment(userhandle, write_modeldata, "SOS definitions", TRUE);
|
|
write_data(userhandle, write_modeldata, "SOS\n");
|
|
for(b = 0, i = 0; i < SOS->sos_count; b = SOS->sos_list[i]->priority, i++) {
|
|
nchars = write_data(userhandle, write_modeldata, "%s: ",
|
|
(SOS->sos_list[i]->name == NULL) ||
|
|
(*SOS->sos_list[i]->name==0) ? "SOS" : SOS->sos_list[i]->name); /* formatnumber12((double) lp->sos_list[i]->priority) */
|
|
|
|
for(a = 0.0, j = 1; j <= SOS->sos_list[i]->size; a = SOS->sos_list[i]->weights[j], j++) {
|
|
if((maxlen != 0) && (nchars > maxlen)) {
|
|
write_data(userhandle, write_modeldata, "%s", "\n");
|
|
nchars = 0;
|
|
}
|
|
if(SOS->sos_list[i]->weights[j] == ++a)
|
|
nchars += write_data(userhandle, write_modeldata, "%s%s",
|
|
(j > 1) ? "," : "",
|
|
get_col_name(lp, SOS->sos_list[i]->members[j]));
|
|
else
|
|
nchars += write_data(userhandle, write_modeldata, "%s%s:%.12g",
|
|
(j > 1) ? "," : "",
|
|
get_col_name(lp, SOS->sos_list[i]->members[j]),
|
|
SOS->sos_list[i]->weights[j]);
|
|
}
|
|
if(SOS->sos_list[i]->priority == ++b)
|
|
nchars += write_data(userhandle, write_modeldata, " <= %d;\n", SOS->sos_list[i]->type);
|
|
else
|
|
nchars += write_data(userhandle, write_modeldata, " <= %d:%d;\n", SOS->sos_list[i]->type, SOS->sos_list[i]->priority);
|
|
}
|
|
}
|
|
|
|
FREE(val);
|
|
FREE(idx);
|
|
|
|
ok = TRUE;
|
|
|
|
return(ok);
|
|
}
|
|
|
|
static int __WINAPI write_lpdata(void *userhandle, char *buf)
|
|
{
|
|
return(fprintf((FILE *) userhandle, "%s", buf));
|
|
}
|
|
|
|
MYBOOL LP_writefile(lprec *lp, char *filename)
|
|
{
|
|
FILE *output = stdout;
|
|
MYBOOL ok;
|
|
|
|
if (filename != NULL) {
|
|
ok = (MYBOOL) ((output = fopen(filename, "w")) != NULL);
|
|
if(!ok)
|
|
return(ok);
|
|
}
|
|
else
|
|
output = lp->outstream;
|
|
|
|
ok = write_lpex(lp, (void *) output, write_lpdata);
|
|
|
|
if (filename != NULL)
|
|
fclose(output);
|
|
|
|
return(ok);
|
|
}
|
|
|
|
MYBOOL LP_writehandle(lprec *lp, FILE *output)
|
|
{
|
|
MYBOOL ok;
|
|
|
|
if (output != NULL)
|
|
set_outputstream(lp, output);
|
|
|
|
output = lp->outstream;
|
|
|
|
ok = write_lpex(lp, (void *) output, write_lpdata);
|
|
|
|
return(ok);
|
|
}
|