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.
1284 lines
34 KiB
1284 lines
34 KiB
/*
|
|
============================================================================
|
|
NAME : yacc_read.c
|
|
|
|
PURPOSE : translation of lp-problem and storage in sparse matrix
|
|
|
|
SHORT : Subroutines for yacc program to store the input in an intermediate
|
|
data-structure. The yacc and lex programs translate the input. First the
|
|
problemsize is determined and the date is read into an intermediate
|
|
structure, then readinput fills the sparse matrix.
|
|
|
|
USAGE : call yyparse(); to start reading the input. call readinput(); to
|
|
fill the sparse matrix.
|
|
============================================================================
|
|
Rows : contains the amount of rows + 1. Rows-1 is the amount of constraints
|
|
(no bounds) Rows also contains the rownr 0 which is the objective function
|
|
|
|
Columns : contains the amount of columns (different variable names found in
|
|
the constraints)
|
|
|
|
Nonnuls : contains the amount of nonnuls = sum of different entries of all
|
|
columns in the constraints and in the objectfunction
|
|
|
|
Hash_tab : contains all columnnames on the first level of the structure the
|
|
row information is kept under each column structure in a linked list (also
|
|
the objective funtion is in this structure) Bound information is also
|
|
stored under under the column name
|
|
|
|
First_rside : points to a linked list containing all relational operators
|
|
and the righthandside values of the constraints the linked list is in
|
|
reversed order with respect to the rownumbers
|
|
============================================================================ */
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <setjmp.h>
|
|
#include "lpkit.h"
|
|
#include "yacc_read.h"
|
|
|
|
#ifdef FORTIFY
|
|
# include "lp_fortify.h"
|
|
#endif
|
|
|
|
#define tol 1.0e-10
|
|
#define coldatastep 100
|
|
|
|
#define HASHSIZE 10007 /* A prime number! */
|
|
|
|
struct structSOSvars {
|
|
char *name;
|
|
int col;
|
|
REAL weight;
|
|
struct structSOSvars *next;
|
|
};
|
|
|
|
struct structSOS {
|
|
char *name;
|
|
short type;
|
|
int Nvars;
|
|
int weight;
|
|
struct structSOSvars *SOSvars, *LastSOSvars;
|
|
struct structSOS *next;
|
|
};
|
|
|
|
struct SOSrow {
|
|
int col;
|
|
REAL value;
|
|
struct SOSrow *next;
|
|
};
|
|
|
|
struct SOSrowdata {
|
|
short type;
|
|
char *name;
|
|
struct SOSrow *SOSrow;
|
|
};
|
|
|
|
struct rside /* contains relational operator and rhs value */
|
|
{
|
|
int row;
|
|
REAL value;
|
|
REAL range_value;
|
|
struct rside *next;
|
|
short relat;
|
|
short range_relat;
|
|
char negate;
|
|
short SOStype;
|
|
};
|
|
|
|
struct column
|
|
{
|
|
int row;
|
|
REAL value;
|
|
struct column *next;
|
|
struct column *prev;
|
|
};
|
|
|
|
struct structcoldata {
|
|
int must_be_int;
|
|
int must_be_sec;
|
|
int must_be_free;
|
|
REAL upbo;
|
|
REAL lowbo;
|
|
struct column *firstcol;
|
|
struct column *col;
|
|
};
|
|
|
|
static void error(parse_parm *pp, int verbose, char *string)
|
|
{
|
|
if(pp == NULL)
|
|
report(NULL, CRITICAL, string);
|
|
else if(pp->Verbose >= verbose)
|
|
report(NULL, verbose, "%s on line %d\n", string, pp->lineno);
|
|
}
|
|
|
|
/*
|
|
* error handling routine for yyparse()
|
|
*/
|
|
void read_error(parse_parm *pp, void *scanner, char *string)
|
|
{
|
|
error(pp, CRITICAL, string);
|
|
}
|
|
|
|
/* called when lex gets a fatal error */
|
|
void lex_fatal_error(parse_parm *pp, void *scanner, char *msg)
|
|
{
|
|
read_error(pp, scanner, msg);
|
|
longjmp(pp->jump_buf, 1);
|
|
}
|
|
|
|
void add_row(parse_parm *pp)
|
|
{
|
|
pp->Rows++;
|
|
pp->rs = NULL;
|
|
pp->Lin_term_count = 0;
|
|
}
|
|
|
|
void add_sos_row(parse_parm *pp, short SOStype)
|
|
{
|
|
if (pp->rs != NULL)
|
|
pp->rs->SOStype = SOStype;
|
|
pp->Rows++;
|
|
pp->rs = NULL;
|
|
pp->Lin_term_count = 0;
|
|
}
|
|
|
|
void check_int_sec_sos_free_decl(parse_parm *pp, int within_int_decl, int within_sec_decl, int sos_decl0, int within_free_decl)
|
|
{
|
|
pp->Ignore_int_decl = TRUE;
|
|
pp->Ignore_sec_decl = TRUE;
|
|
pp->Ignore_free_decl = TRUE;
|
|
pp->sos_decl = 0;
|
|
if(within_int_decl) {
|
|
pp->Ignore_int_decl = FALSE;
|
|
pp->int_decl = (char) within_int_decl;
|
|
if(within_sec_decl)
|
|
pp->Ignore_sec_decl = FALSE;
|
|
}
|
|
else if(within_sec_decl) {
|
|
pp->Ignore_sec_decl = FALSE;
|
|
}
|
|
else if(sos_decl0) {
|
|
pp->sos_decl = (char) sos_decl0;
|
|
}
|
|
else if(within_free_decl) {
|
|
pp->Ignore_free_decl = FALSE;
|
|
}
|
|
}
|
|
|
|
static void add_int_var(parse_parm *pp, char *name, short int_decl)
|
|
{
|
|
hashelem *hp;
|
|
|
|
if((hp = findhash(name, pp->Hash_tab)) == NULL) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Unknown variable %s declared integer, ignored", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
else if(pp->coldata[hp->index].must_be_int) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Variable %s declared integer more than once, ignored", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
else {
|
|
pp->coldata[hp->index].must_be_int = TRUE;
|
|
if(int_decl == 2) {
|
|
if(pp->coldata[hp->index].lowbo != -DEF_INFINITE * (REAL) 10.0) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Variable %s: lower bound on variable redefined", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
pp->coldata[hp->index].lowbo = 0;
|
|
if(pp->coldata[hp->index].upbo < DEF_INFINITE) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Variable %s: upper bound on variable redefined", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
pp->coldata[hp->index].upbo = 1;
|
|
}
|
|
else if(int_decl == 3) {
|
|
if(pp->coldata[hp->index].upbo == DEF_INFINITE * (REAL) 10.0)
|
|
pp->coldata[hp->index].upbo = 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void add_sec_var(parse_parm *pp, char *name)
|
|
{
|
|
hashelem *hp;
|
|
|
|
if((hp = findhash(name, pp->Hash_tab)) == NULL) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Unknown variable %s declared semi-continuous, ignored", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
else if(pp->coldata[hp->index].must_be_sec) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Variable %s declared semi-continuous more than once, ignored", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
else
|
|
pp->coldata[hp->index].must_be_sec = TRUE;
|
|
}
|
|
|
|
int set_sec_threshold(parse_parm *pp, char *name, REAL threshold)
|
|
{
|
|
hashelem *hp;
|
|
|
|
if((hp = findhash(name, pp->Hash_tab)) == NULL) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Unknown variable %s declared semi-continuous, ignored", name);
|
|
error(pp, NORMAL, buf);
|
|
return(FALSE);
|
|
}
|
|
|
|
if ((pp->coldata[hp->index].lowbo > 0.0) && (threshold > 0.0)) {
|
|
char buf[256];
|
|
|
|
pp->coldata[hp->index].must_be_sec = FALSE;
|
|
sprintf(buf, "Variable %s declared semi-continuous, but it has a non-negative lower bound (%f), ignored", name, pp->coldata[hp->index].lowbo);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
if (threshold > pp->coldata[hp->index].lowbo)
|
|
pp->coldata[hp->index].lowbo = threshold;
|
|
|
|
return(pp->coldata[hp->index].must_be_sec);
|
|
}
|
|
|
|
static void add_free_var(parse_parm *pp, char *name)
|
|
{
|
|
hashelem *hp;
|
|
|
|
if((hp = findhash(name, pp->Hash_tab)) == NULL) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Unknown variable %s declared free, ignored", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
else if(pp->coldata[hp->index].must_be_free) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Variable %s declared free more than once, ignored", name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
else
|
|
pp->coldata[hp->index].must_be_free = TRUE;
|
|
}
|
|
|
|
static int add_sos_name(parse_parm *pp, char *name)
|
|
{
|
|
struct structSOS *SOS;
|
|
|
|
if(CALLOC(SOS, 1, struct structSOS) == NULL)
|
|
return(FALSE);
|
|
|
|
if(MALLOC(SOS->name, strlen(name) + 1, char) == NULL)
|
|
{
|
|
FREE(SOS);
|
|
return(FALSE);
|
|
}
|
|
strcpy(SOS->name, name);
|
|
SOS->type = 0;
|
|
|
|
if(pp->FirstSOS == NULL)
|
|
pp->FirstSOS = SOS;
|
|
else
|
|
pp->LastSOS->next = SOS;
|
|
pp->LastSOS = SOS;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
static int add_sos_var(parse_parm *pp, char *name)
|
|
{
|
|
struct structSOSvars *SOSvar;
|
|
|
|
if(name != NULL) {
|
|
if(CALLOC(SOSvar, 1, struct structSOSvars) == NULL)
|
|
return(FALSE);
|
|
|
|
if(MALLOC(SOSvar->name, strlen(name) + 1, char) == NULL)
|
|
{
|
|
FREE(SOSvar);
|
|
return(FALSE);
|
|
}
|
|
strcpy(SOSvar->name, name);
|
|
|
|
if(pp->LastSOS->SOSvars == NULL)
|
|
pp->LastSOS->SOSvars = SOSvar;
|
|
else
|
|
pp->LastSOS->LastSOSvars->next = SOSvar;
|
|
pp->LastSOS->LastSOSvars = SOSvar;
|
|
pp->LastSOS->Nvars = pp->LastSOS->Nvars + 1;
|
|
}
|
|
pp->LastSOS->LastSOSvars->weight = 0;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
void storevarandweight(parse_parm *pp, char *name)
|
|
{
|
|
if(!pp->Ignore_int_decl) {
|
|
add_int_var(pp, name, pp->int_decl);
|
|
if(!pp->Ignore_sec_decl)
|
|
add_sec_var(pp, name);
|
|
}
|
|
else if(!pp->Ignore_sec_decl)
|
|
add_sec_var(pp, name);
|
|
else if(pp->sos_decl==1)
|
|
add_sos_name(pp, name);
|
|
else if(pp->sos_decl==2)
|
|
add_sos_var(pp, name);
|
|
else if(!pp->Ignore_free_decl)
|
|
add_free_var(pp, name);
|
|
}
|
|
|
|
int set_sos_type(parse_parm *pp, int SOStype)
|
|
{
|
|
if(pp->LastSOS != NULL)
|
|
pp->LastSOS->type = (short) SOStype;
|
|
return(TRUE);
|
|
}
|
|
|
|
int set_sos_weight(parse_parm *pp, double weight, int sos_decl)
|
|
{
|
|
if(pp->LastSOS != NULL) {
|
|
if(sos_decl==1)
|
|
pp->LastSOS->weight = (int) (weight+.1);
|
|
else
|
|
pp->LastSOS->LastSOSvars->weight = weight;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
static int inccoldata(parse_parm *pp)
|
|
{
|
|
long Columns = pp->Columns;
|
|
|
|
if(Columns == 0)
|
|
CALLOC(pp->coldata, coldatastep, struct structcoldata);
|
|
else if((Columns%coldatastep) == 0)
|
|
REALLOC(pp->coldata, Columns + coldatastep, struct structcoldata);
|
|
|
|
if(pp->coldata != NULL) {
|
|
pp->coldata[Columns].upbo = (REAL) DEF_INFINITE * (REAL) 10.0;
|
|
pp->coldata[Columns].lowbo = (REAL) -DEF_INFINITE * (REAL) 10.0; /* temporary. If still this value then 0 will be taken */
|
|
pp->coldata[Columns].col = NULL;
|
|
pp->coldata[Columns].firstcol = NULL;
|
|
pp->coldata[Columns].must_be_int = FALSE;
|
|
pp->coldata[Columns].must_be_sec = FALSE;
|
|
pp->coldata[Columns].must_be_free = FALSE;
|
|
}
|
|
|
|
return(pp->coldata != NULL);
|
|
}
|
|
|
|
/*
|
|
* initialisation of hashstruct and globals.
|
|
*/
|
|
static int init_read(parse_parm *pp, int verbose)
|
|
{
|
|
int ok = FALSE;
|
|
|
|
pp->Verbose = verbose;
|
|
set_obj_dir(pp, TRUE);
|
|
pp->Rows = 0;
|
|
pp->Non_zeros = 0;
|
|
pp->Columns = 0;
|
|
pp->FirstSOS = pp->LastSOS = NULL;
|
|
pp->Lin_term_count = 0;
|
|
if (CALLOC(pp->First_rside, 1, struct rside) != NULL) {
|
|
pp->rs = pp->First_rside;
|
|
pp->rs->value = pp->rs->range_value = 0;
|
|
/* first row (nr 0) is always the objective function */
|
|
pp->rs->relat = OF;
|
|
pp->rs->range_relat = -1;
|
|
pp->rs->SOStype = 0;
|
|
pp->Hash_tab = NULL;
|
|
pp->Hash_constraints = NULL;
|
|
if (((pp->Hash_tab = create_hash_table(HASHSIZE, 0)) == NULL) ||
|
|
((pp->Hash_constraints = create_hash_table(HASHSIZE, 0)) == NULL)){
|
|
FREE(pp->First_rside);
|
|
FREE(pp->Hash_tab);
|
|
FREE(pp->Hash_constraints);
|
|
}
|
|
else
|
|
ok = TRUE;
|
|
}
|
|
return(ok);
|
|
} /* init */
|
|
|
|
/*
|
|
* clears the tmp_store variable after all information has been copied
|
|
*/
|
|
void null_tmp_store(parse_parm *pp, int init_Lin_term_count)
|
|
{
|
|
pp->tmp_store.value = 0;
|
|
pp->tmp_store.rhs_value = 0;
|
|
FREE(pp->tmp_store.name);
|
|
if(init_Lin_term_count)
|
|
pp->Lin_term_count = 0;
|
|
}
|
|
|
|
/*
|
|
* variable : pointer to text array with name of variable
|
|
* row : the rownumber of the constraint
|
|
* value : value of matrixelement
|
|
* A(row, variable).
|
|
* Sign : (global) determines the sign of value.
|
|
* store() : stores value in matrix
|
|
* A(row, variable). If A(row, variable) already contains data,
|
|
* value is added to the existing value.
|
|
*/
|
|
static int store(parse_parm *pp, char *variable,
|
|
int row,
|
|
REAL value)
|
|
{
|
|
hashelem *h_tab_p;
|
|
struct column *col_p;
|
|
|
|
if(value == 0) {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "(store) Warning, variable %s has an effective coefficient of 0, Ignored", variable);
|
|
error(pp, NORMAL, buf);
|
|
/* return(TRUE); */
|
|
}
|
|
|
|
if((h_tab_p = findhash(variable, pp->Hash_tab)) == NULL) {
|
|
if (((h_tab_p = puthash(variable, pp->Columns, NULL, pp->Hash_tab)) == NULL)
|
|
) return(FALSE);
|
|
inccoldata(pp);
|
|
pp->Columns++; /* counter for calloc of final array */
|
|
if(value) {
|
|
if (CALLOC(col_p, 1, struct column) == NULL)
|
|
return(FALSE);
|
|
pp->Non_zeros++; /* for calloc of final arrays */
|
|
col_p->row = row;
|
|
col_p->value = value;
|
|
pp->coldata[h_tab_p->index].firstcol = pp->coldata[h_tab_p->index].col = col_p;
|
|
}
|
|
}
|
|
else if((pp->coldata[h_tab_p->index].col == NULL) || (pp->coldata[h_tab_p->index].col->row != row)) {
|
|
if(value) {
|
|
if (CALLOC(col_p, 1, struct column) == NULL)
|
|
return(FALSE);
|
|
pp->Non_zeros++; /* for calloc of final arrays */
|
|
if(pp->coldata[h_tab_p->index].col != NULL)
|
|
pp->coldata[h_tab_p->index].col->prev = col_p;
|
|
else
|
|
pp->coldata[h_tab_p->index].firstcol = col_p;
|
|
col_p->value = value;
|
|
col_p->row = row;
|
|
col_p->next = pp->coldata[h_tab_p->index].col;
|
|
pp->coldata[h_tab_p->index].col = col_p;
|
|
}
|
|
}
|
|
else if(value) {
|
|
pp->coldata[h_tab_p->index].col->value += value;
|
|
if(fabs(pp->coldata[h_tab_p->index].col->value) < tol) /* eliminitate rounding errors */
|
|
pp->coldata[h_tab_p->index].col->value = 0;
|
|
}
|
|
return(TRUE);
|
|
} /* store */
|
|
|
|
static int storefirst(parse_parm *pp)
|
|
{
|
|
struct rside *rp;
|
|
|
|
if ((pp->rs != NULL) && (pp->rs->row == pp->tmp_store.row))
|
|
return(TRUE);
|
|
|
|
/* make space for the rhs information */
|
|
if (CALLOC(rp, 1, struct rside) == NULL)
|
|
return(FALSE);
|
|
rp->next = pp->First_rside;
|
|
pp->First_rside = pp->rs = rp;
|
|
pp->rs->row = /* row */ pp->tmp_store.row;
|
|
pp->rs->value = pp->tmp_store.rhs_value;
|
|
pp->rs->relat = pp->tmp_store.relat;
|
|
pp->rs->range_relat = -1;
|
|
pp->rs->SOStype = 0;
|
|
|
|
if(pp->tmp_store.name != NULL) {
|
|
if(pp->tmp_store.value != 0) {
|
|
if (!store(pp, pp->tmp_store.name, pp->tmp_store.row, pp->tmp_store.value))
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Warning, variable %s has an effective coefficient of 0, ignored", pp->tmp_store.name);
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
}
|
|
null_tmp_store(pp, FALSE);
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* store relational operator given in yylex[0] in the rightside list.
|
|
* Also checks if it constraint was a bound and if so stores it in the
|
|
* boundslist
|
|
*/
|
|
int store_re_op(parse_parm *pp, char OP, int HadConstraint, int HadVar, int Had_lineair_sum)
|
|
{
|
|
short tmp_relat;
|
|
|
|
switch(OP) {
|
|
|
|
case '=':
|
|
tmp_relat = EQ;
|
|
break;
|
|
|
|
case '>':
|
|
tmp_relat = GE;
|
|
break;
|
|
|
|
case '<':
|
|
tmp_relat = LE;
|
|
break;
|
|
|
|
case 0:
|
|
if(pp->rs != NULL)
|
|
tmp_relat = pp->rs->relat;
|
|
else
|
|
tmp_relat = pp->tmp_store.relat;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
char buf[256];
|
|
|
|
sprintf(buf, "Error: unknown relational operator %c", OP);
|
|
error(pp, CRITICAL, buf);
|
|
}
|
|
return(FALSE);
|
|
break;
|
|
}
|
|
|
|
if(/* pp->Lin_term_count > 1 */ HadConstraint && HadVar) {/* it is not a bound */
|
|
if(pp->Lin_term_count <= 1)
|
|
if(!storefirst(pp))
|
|
return(FALSE);
|
|
pp->rs->relat = tmp_relat;
|
|
}
|
|
else if(/* pp->Lin_term_count == 0 */ HadConstraint && !Had_lineair_sum /* HadVar */ /* && (pp->rs != NULL) */) { /* it is a range */
|
|
if(pp->Lin_term_count == 1)
|
|
if(!storefirst(pp))
|
|
return(FALSE);
|
|
if(pp->rs == NULL) { /* range before row, already reported */
|
|
error(pp, CRITICAL, "Error: range for undefined row");
|
|
return(FALSE);
|
|
}
|
|
|
|
if(pp->rs->negate)
|
|
switch (tmp_relat) {
|
|
case LE:
|
|
tmp_relat = GE;
|
|
break;
|
|
case GE:
|
|
tmp_relat = LE;
|
|
break;
|
|
}
|
|
|
|
if(pp->rs->range_relat != -1) {
|
|
error(pp, CRITICAL, "Error: There was already a range for this row");
|
|
return(FALSE);
|
|
}
|
|
else if(tmp_relat == pp->rs->relat) {
|
|
error(pp, CRITICAL, "Error: relational operator for range is the same as relation operator for equation");
|
|
return(FALSE);
|
|
}
|
|
else
|
|
pp->rs->range_relat = tmp_relat;
|
|
}
|
|
else /* could be a bound */
|
|
pp->tmp_store.relat = tmp_relat;
|
|
|
|
return(TRUE);
|
|
} /* store_re_op */
|
|
|
|
int negate_constraint(parse_parm *pp)
|
|
{
|
|
if(pp->rs != NULL)
|
|
pp->rs->negate = TRUE;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* store RHS value in the rightside structure
|
|
* if type = true then
|
|
*/
|
|
int rhs_store(parse_parm *pp, REAL value, int HadConstraint, int HadVar, int Had_lineair_sum)
|
|
{
|
|
if(/* pp->Lin_term_count > 1 */ (HadConstraint && HadVar) || (pp->Rows == 0)){ /* not a bound */
|
|
if (pp->Rows == 0)
|
|
value = -value;
|
|
/* if(pp->Lin_term_count < 2) */
|
|
if(pp->rs == NULL)
|
|
pp->tmp_store.rhs_value += value;
|
|
else
|
|
|
|
if(pp->rs == NULL) {
|
|
error(pp, CRITICAL, "Error: No variable specified");
|
|
return(FALSE);
|
|
}
|
|
else
|
|
pp->rs->value += value;
|
|
}
|
|
else if(/* pp->Lin_term_count == 0 */ HadConstraint && !HadVar) { /* a range */
|
|
if(pp->rs == NULL) /* if range before row, already reported */
|
|
pp->tmp_store.rhs_value += value;
|
|
else if(pp->rs->range_relat < 0) /* was a bad range; ignore */;
|
|
else {
|
|
if(pp->rs->negate)
|
|
value = -value;
|
|
if(((pp->rs->relat == LE) && (pp->rs->range_relat == GE) &&
|
|
(pp->rs->value < value)) ||
|
|
((pp->rs->relat == GE) && (pp->rs->range_relat == LE) &&
|
|
(pp->rs->value > value)) ||
|
|
((pp->rs->relat == EQ) || (pp->rs->range_relat == EQ))) {
|
|
pp->rs->range_relat = -2;
|
|
error(pp, CRITICAL, "Error: range restriction conflicts");
|
|
return(FALSE);
|
|
}
|
|
else
|
|
pp->rs->range_value += value;
|
|
}
|
|
}
|
|
else /* a bound */
|
|
pp->tmp_store.rhs_value += value;
|
|
return(TRUE);
|
|
} /* RHS_store */
|
|
|
|
/*
|
|
* store all data in the right place
|
|
* count the amount of lineair terms in a constraint
|
|
* only store in data-structure if the constraint is not a bound
|
|
*/
|
|
int var_store(parse_parm *pp, char *var, REAL value, int HadConstraint, int HadVar, int Had_lineair_sum)
|
|
{
|
|
int row;
|
|
|
|
row = pp->Rows;
|
|
|
|
/* also in a bound the same var name can occur more than once. Check for
|
|
this. Don't increment Lin_term_count */
|
|
|
|
if(pp->Lin_term_count != 1 || pp->tmp_store.name == NULL || strcmp(pp->tmp_store.name, var) != 0)
|
|
pp->Lin_term_count++;
|
|
|
|
/* always store objective function with rownr == 0. */
|
|
if(row == 0)
|
|
return(store(pp, var, row, value));
|
|
|
|
if(pp->Lin_term_count == 1) { /* don't store yet. could be a bound */
|
|
if(MALLOC(pp->tmp_store.name, strlen(var) + 1, char) != NULL)
|
|
strcpy(pp->tmp_store.name, var);
|
|
pp->tmp_store.row = row;
|
|
pp->tmp_store.value += value;
|
|
return(TRUE);
|
|
}
|
|
|
|
if(pp->Lin_term_count == 2) { /* now you can also store the first variable */
|
|
if(!storefirst(pp))
|
|
return(FALSE);
|
|
/* null_tmp_store(pp, FALSE); */
|
|
}
|
|
|
|
return(store(pp, var, row, value));
|
|
} /* var_store */
|
|
|
|
|
|
|
|
/*
|
|
* store the information in tmp_store because it is a bound
|
|
*/
|
|
int store_bounds(parse_parm *pp, int warn)
|
|
{
|
|
if(pp->tmp_store.value != 0) {
|
|
hashelem *h_tab_p;
|
|
REAL boundvalue;
|
|
|
|
if((h_tab_p = findhash(pp->tmp_store.name, pp->Hash_tab)) == NULL) {
|
|
/* a new columnname is found, create an entry in the hashlist */
|
|
if ((h_tab_p = puthash(pp->tmp_store.name, pp->Columns, NULL, pp->Hash_tab)) == NULL) {
|
|
error(pp, CRITICAL, "Not enough memory");
|
|
return(FALSE);
|
|
}
|
|
inccoldata(pp);
|
|
pp->Columns++; /* counter for calloc of final array */
|
|
}
|
|
|
|
if(pp->tmp_store.value < 0) { /* divide by negative number, */
|
|
/* relational operator may change */
|
|
if(pp->tmp_store.relat == GE)
|
|
pp->tmp_store.relat = LE;
|
|
else if(pp->tmp_store.relat == LE)
|
|
pp->tmp_store.relat = GE;
|
|
}
|
|
|
|
boundvalue = pp->tmp_store.rhs_value / pp->tmp_store.value;
|
|
|
|
#if FALSE
|
|
/* Check sanity of bound; all variables should be positive */
|
|
if( ((pp->tmp_store.relat == EQ) && (boundvalue < 0))
|
|
|| ((pp->tmp_store.relat == LE) && (boundvalue < 0))) { /* Error */
|
|
error(pp, CRITICAL, "Error: variables must always be non-negative");
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if FALSE
|
|
if((pp->tmp_store.relat == GE) && (boundvalue <= 0)) /* Warning */
|
|
error(pp, NORMAL, "Warning: useless bound; variables are always >= 0");
|
|
#endif
|
|
|
|
/* bound seems to be sane, add it */
|
|
if((pp->tmp_store.relat == GE) || (pp->tmp_store.relat == EQ)) {
|
|
if(boundvalue > pp->coldata[h_tab_p->index].lowbo - tol)
|
|
pp->coldata[h_tab_p->index].lowbo = boundvalue;
|
|
else if(warn)
|
|
error(pp, NORMAL, "Ineffective lower bound, ignored");
|
|
}
|
|
if((pp->tmp_store.relat == LE) || (pp->tmp_store.relat == EQ)) {
|
|
if(boundvalue < pp->coldata[h_tab_p->index].upbo + tol)
|
|
pp->coldata[h_tab_p->index].upbo = boundvalue;
|
|
else if (warn)
|
|
error(pp, NORMAL, "Ineffective upper bound, ignored");
|
|
}
|
|
|
|
/* check for empty range */
|
|
if((warn) && (pp->coldata[h_tab_p->index].upbo + tol < pp->coldata[h_tab_p->index].lowbo)) {
|
|
error(pp, CRITICAL, "Error: bound contradicts earlier bounds");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else /* pp->tmp_store.value = 0 ! */ {
|
|
char buf[256];
|
|
|
|
if((pp->tmp_store.rhs_value == 0) ||
|
|
((pp->tmp_store.rhs_value > 0) && (pp->tmp_store.relat == LE)) ||
|
|
((pp->tmp_store.rhs_value < 0) && (pp->tmp_store.relat == GE))) {
|
|
sprintf(buf, "Variable %s has an effective coefficient of 0 in bound, ignored",
|
|
pp->tmp_store.name);
|
|
if(warn)
|
|
error(pp, NORMAL, buf);
|
|
}
|
|
else {
|
|
sprintf(buf, "Error, variable %s has an effective coefficient of 0 in bound",
|
|
pp->tmp_store.name);
|
|
error(pp, CRITICAL, buf);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
/* null_tmp_store(pp, FALSE); */
|
|
pp->tmp_store.rhs_value = 0;
|
|
|
|
return(TRUE);
|
|
} /* store_bounds */
|
|
|
|
int set_title(parse_parm *pp, char *name)
|
|
{
|
|
pp->title = strdup(name);
|
|
return(TRUE);
|
|
}
|
|
|
|
int add_constraint_name(parse_parm *pp, char *name)
|
|
{
|
|
int row;
|
|
hashelem *hp;
|
|
|
|
if((hp = findhash(name, pp->Hash_constraints)) != NULL) {
|
|
row = hp->index;
|
|
pp->rs = pp->First_rside;
|
|
while ((pp->rs != NULL) && (pp->rs->row != row))
|
|
pp->rs = pp->rs->next;
|
|
}
|
|
else {
|
|
row = pp->Rows;
|
|
if (((hp = puthash(name, row, NULL, pp->Hash_constraints)) == NULL)
|
|
) return(FALSE);
|
|
if(row)
|
|
pp->rs = NULL;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* transport the data from the intermediate structure to the sparse matrix
|
|
* and free the intermediate structure
|
|
*/
|
|
static int readinput(parse_parm *pp, lprec *lp)
|
|
{
|
|
int i, i1, count, index, col;
|
|
struct column *cp, *tcp;
|
|
hashelem *hp;
|
|
struct rside *rp;
|
|
signed char *negateAndSOS = NULL;
|
|
REAL *row = NULL, a;
|
|
int *rowno = NULL;
|
|
MYBOOL SOSinMatrix = FALSE;
|
|
struct SOSrowdata *SOSrowdata = NULL;
|
|
struct SOSrow *SOSrow, *SOSrow1;
|
|
|
|
if(lp != NULL) {
|
|
if (CALLOC(negateAndSOS, 1 + pp->Rows, signed char) == NULL)
|
|
return(FALSE);
|
|
|
|
rp = pp->First_rside;
|
|
for(i = pp->Rows; (i >= 0) && (rp != NULL); i--) {
|
|
if(rp->SOStype == 0)
|
|
negateAndSOS[i] = (rp->negate ? -1 : 0);
|
|
else
|
|
negateAndSOS[i] = (signed char) rp->SOStype;
|
|
|
|
rp = rp->next;
|
|
}
|
|
|
|
/* fill names with the rownames */
|
|
hp = pp->Hash_constraints->first;
|
|
while(hp != NULL) {
|
|
if (/* (negateAndSOS[hp->index] <= 0) && */ (!set_row_name(lp, hp->index, hp->name)))
|
|
return(FALSE);
|
|
hp = hp->nextelem;
|
|
}
|
|
}
|
|
|
|
for(i = pp->Rows; i >= 0; i--) {
|
|
rp = pp->First_rside;
|
|
if((lp != NULL) && (rp != NULL)) {
|
|
if(rp->SOStype == 0) {
|
|
if (rp->negate) {
|
|
switch (rp->relat) {
|
|
case LE:
|
|
rp->relat = GE;
|
|
break;
|
|
case GE:
|
|
rp->relat = LE;
|
|
break;
|
|
}
|
|
switch (rp->range_relat) {
|
|
case LE:
|
|
rp->range_relat = GE;
|
|
break;
|
|
case GE:
|
|
rp->range_relat = LE;
|
|
break;
|
|
}
|
|
rp->range_value = -rp->range_value;
|
|
rp->value = -rp->value;
|
|
}
|
|
|
|
if((rp->range_relat >= 0) && (rp->value == lp->infinite)) {
|
|
rp->value = rp->range_value;
|
|
rp->relat = rp->range_relat;
|
|
rp->range_relat = -1;
|
|
}
|
|
else if((rp->range_relat >= 0) && (rp->value == -lp->infinite)) {
|
|
rp->value = rp->range_value;
|
|
rp->relat = rp->range_relat;
|
|
rp->range_relat = -1;
|
|
}
|
|
if ((rp->range_relat >= 0) && (rp->range_value == rp->value)) {
|
|
rp->relat = EQ;
|
|
rp->range_relat = EQ;
|
|
}
|
|
if(i) {
|
|
set_constr_type(lp, i, rp->relat);
|
|
pp->relat[i] = rp->relat;
|
|
}
|
|
set_rh(lp, i, rp->value);
|
|
if (rp->range_relat >= 0)
|
|
set_rh_range(lp, i, rp->range_value - rp->value);
|
|
}
|
|
else {
|
|
SOSinMatrix = TRUE;
|
|
if(i)
|
|
pp->relat[i] = rp->relat;
|
|
}
|
|
}
|
|
if(rp != NULL) {
|
|
pp->First_rside = rp->next;
|
|
free(rp); /* free memory when data has been read */
|
|
}
|
|
else
|
|
pp->First_rside = NULL;
|
|
}
|
|
|
|
while(pp->First_rside != NULL) {
|
|
rp = pp->First_rside;
|
|
pp->First_rside = rp->next;
|
|
free(rp); /* free memory when data has been read */
|
|
}
|
|
|
|
/* start reading the Hash_list structure */
|
|
index = 0;
|
|
|
|
if((SOSinMatrix) && (CALLOC(SOSrowdata, 1 + pp->Rows, struct SOSrowdata) == NULL)) {
|
|
FREE(negateAndSOS);
|
|
FREE(row);
|
|
FREE(rowno);
|
|
return(FALSE);
|
|
}
|
|
|
|
if((lp != NULL) &&
|
|
((MALLOC(row, 1 + pp->Rows, REAL) == NULL) || (MALLOC(rowno, 1 + pp->Rows, int) == NULL))) {
|
|
FREE(SOSrowdata);
|
|
FREE(negateAndSOS);
|
|
FREE(row);
|
|
FREE(rowno);
|
|
return(FALSE);
|
|
}
|
|
|
|
/* for(i = 0; i < pp->Hash_tab->size; i++) {
|
|
hp = pp->Hash_tab->table[i]; */
|
|
hp = pp->Hash_tab->first;
|
|
while(hp != NULL) {
|
|
count = 0;
|
|
index++;
|
|
cp = pp->coldata[hp->index].firstcol;
|
|
col = hp->index + 1;
|
|
while(cp != NULL) {
|
|
if(lp != NULL) {
|
|
if (negateAndSOS[cp->row] <= 0) {
|
|
rowno[count] = cp->row;
|
|
a = cp->value;
|
|
if (negateAndSOS[cp->row])
|
|
a = -a;
|
|
row[count++] = a;
|
|
}
|
|
else {
|
|
if (MALLOC(SOSrow, 1, struct SOSrow) == NULL) {
|
|
FREE(SOSrowdata);
|
|
FREE(negateAndSOS);
|
|
FREE(row);
|
|
FREE(rowno);
|
|
return(FALSE);
|
|
}
|
|
if(SOSrowdata[cp->row].SOSrow == NULL)
|
|
SOSrowdata[cp->row].name = strdup(get_row_name(lp, cp->row));
|
|
SOSrow->next = SOSrowdata[cp->row].SOSrow;
|
|
SOSrowdata[cp->row].SOSrow = SOSrow;
|
|
SOSrowdata[cp->row].type = negateAndSOS[cp->row];
|
|
SOSrow->col = col;
|
|
SOSrow->value = cp->value;
|
|
}
|
|
}
|
|
tcp = cp;
|
|
/* cp = cp->next; */
|
|
cp = cp->prev;
|
|
free(tcp); /* free memory when data has been read */
|
|
}
|
|
|
|
if(lp != NULL) {
|
|
add_columnex(lp, count, row, rowno);
|
|
/* check for bound */
|
|
if(pp->coldata[hp->index].lowbo == -DEF_INFINITE * 10.0)
|
|
/* lp->orig_lowbo[pp->Rows+index] = 0.0; */
|
|
set_lowbo(lp, index, 0);
|
|
else
|
|
/* lp->orig_lowbo[pp->Rows+index] = pp->coldata[hp->index].lowbo; */
|
|
set_lowbo(lp, index, pp->coldata[hp->index].lowbo);
|
|
/* lp->orig_upbo[pp->Rows+index] = pp->coldata[hp->index].upbo; */
|
|
if(pp->coldata[hp->index].upbo >= DEF_INFINITE)
|
|
set_upbo(lp, index, DEF_INFINITE);
|
|
else
|
|
set_upbo(lp, index, pp->coldata[hp->index].upbo);
|
|
|
|
/* check if it must be an integer variable */
|
|
if(pp->coldata[hp->index].must_be_int) {
|
|
/* lp->must_be_int[pp->Rows + index]=TRUE; */
|
|
set_int(lp, index, TRUE);
|
|
}
|
|
if(pp->coldata[hp->index].must_be_sec) {
|
|
set_semicont(lp, index, TRUE);
|
|
}
|
|
if(pp->coldata[hp->index].must_be_free) {
|
|
set_unbounded(lp, index);
|
|
}
|
|
|
|
/* copy name of column variable */
|
|
if (!set_col_name(lp, index, hp->name)) {
|
|
FREE(SOSrowdata);
|
|
FREE(negateAndSOS);
|
|
FREE(row);
|
|
FREE(rowno);
|
|
return(FALSE);
|
|
}
|
|
|
|
/* put matrix values in intermediate row */
|
|
/* cp = hp->col; */
|
|
/* cp = hp->firstcol; */
|
|
}
|
|
|
|
/* thp = hp; */
|
|
/* hp = hp->next; */
|
|
/* free(thp->name); */
|
|
/* free(thp); */ /* free memory when data has been read */
|
|
|
|
hp = hp->nextelem;
|
|
|
|
}
|
|
/* pp->Hash_tab->table[i] = NULL; */
|
|
|
|
FREE(pp->coldata);
|
|
|
|
if(SOSrowdata != NULL) {
|
|
struct structSOS *structSOS;
|
|
struct structSOSvars *SOSvars, *SOSvars1;
|
|
int SOSweight = 0;
|
|
|
|
for(i = 1; i <= pp->Rows; i++) {
|
|
SOSrow = SOSrowdata[i].SOSrow;
|
|
if(SOSrow != NULL) {
|
|
if(MALLOC(structSOS, 1, struct structSOS) == NULL) {
|
|
FREE(SOSrowdata);
|
|
FREE(negateAndSOS);
|
|
FREE(row);
|
|
FREE(rowno);
|
|
return(FALSE);
|
|
}
|
|
structSOS->Nvars = 0;
|
|
structSOS->type = SOSrowdata[i].type;
|
|
structSOS->weight = ++SOSweight;
|
|
structSOS->name = strdup(SOSrowdata[i].name);
|
|
structSOS->LastSOSvars = NULL;
|
|
structSOS->next = pp->FirstSOS;
|
|
pp->FirstSOS = structSOS;
|
|
SOSvars = NULL;
|
|
while(SOSrow != NULL) {
|
|
SOSvars1 = SOSvars;
|
|
MALLOC(SOSvars, 1, struct structSOSvars);
|
|
SOSvars->next = SOSvars1;
|
|
SOSvars->col = SOSrow->col;
|
|
SOSvars->weight = SOSrow->value;
|
|
SOSvars->name = NULL;
|
|
structSOS->Nvars++;
|
|
SOSrow1 = SOSrow->next;
|
|
FREE(SOSrow);
|
|
SOSrow = SOSrow1;
|
|
}
|
|
structSOS->SOSvars = SOSvars;
|
|
}
|
|
}
|
|
FREE(SOSrowdata);
|
|
}
|
|
|
|
while(pp->FirstSOS != NULL)
|
|
{
|
|
struct structSOSvars *SOSvars, *SOSvars1;
|
|
int *sosvars, n, col;
|
|
REAL *weights;
|
|
hashelem *hp;
|
|
|
|
pp->LastSOS = pp->FirstSOS;
|
|
pp->FirstSOS = pp->FirstSOS->next;
|
|
SOSvars = pp->LastSOS->SOSvars;
|
|
if(lp != NULL) {
|
|
MALLOC(sosvars, pp->LastSOS->Nvars, int);
|
|
MALLOC(weights, pp->LastSOS->Nvars, double);
|
|
}
|
|
else {
|
|
sosvars = NULL;
|
|
weights = NULL;
|
|
}
|
|
n = 0;
|
|
while(SOSvars != NULL)
|
|
{
|
|
SOSvars1 = SOSvars;
|
|
SOSvars = SOSvars->next;
|
|
if(lp != NULL) {
|
|
col = SOSvars1->col;
|
|
if(col == 0)
|
|
if((hp = findhash(SOSvars1->name, lp->colname_hashtab)) != NULL)
|
|
col = hp->index;
|
|
if (col) {
|
|
sosvars[n] = col;
|
|
weights[n++] = SOSvars1->weight;
|
|
}
|
|
}
|
|
FREE(SOSvars1->name);
|
|
FREE(SOSvars1);
|
|
}
|
|
if(lp != NULL) {
|
|
add_SOS(lp, pp->LastSOS->name, pp->LastSOS->type, pp->LastSOS->weight, n, sosvars, weights);
|
|
FREE(weights);
|
|
FREE(sosvars);
|
|
}
|
|
FREE(pp->LastSOS->name);
|
|
FREE(pp->LastSOS);
|
|
}
|
|
|
|
if(negateAndSOS != NULL) {
|
|
for(i1 = 0, i = 1; i <= pp->Rows; i++)
|
|
if(negateAndSOS[i] <= 0)
|
|
pp->relat[++i1] = pp->relat[i];
|
|
|
|
#if 01
|
|
for(i = pp->Rows; i > 0; i--)
|
|
if(negateAndSOS[i] > 0) {
|
|
del_constraint(lp, i);
|
|
pp->Rows--;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* the following should be replaced by a call to the MPS print routine MB */
|
|
|
|
#if 0
|
|
if(pp->Verbose) {
|
|
int j;
|
|
|
|
printf("\n");
|
|
printf("**********Data read**********\n");
|
|
printf("Rows : %d\n", pp->Rows);
|
|
printf("Columns : %d\n", pp->Columns);
|
|
printf("Nonnuls : %d\n", pp->Non_zeros);
|
|
printf("NAME LPPROB\n");
|
|
printf("ROWS\n");
|
|
for(i = 0; i <= pp->Rows; i++) {
|
|
if(pp->relat[i] == LE)
|
|
printf(" L ");
|
|
else if(pp->relat[i] == EQ)
|
|
printf(" E ");
|
|
else if(pp->relat[i] == GE)
|
|
printf(" G ");
|
|
else if(pp->relat[i] == OF)
|
|
printf(" N ");
|
|
printf("%s\n", get_row_name(lp, i));
|
|
}
|
|
|
|
printf("COLUMNS\n");
|
|
j = 0;
|
|
for(i = 0; i < pp->Non_zeros; i++) {
|
|
if(i == lp->col_end[j])
|
|
j++;
|
|
printf(" %-8s %-8s %g\n", get_col_name(lp, j),
|
|
get_row_name(lp, lp->mat[i].row_nr), (double)lp->mat[i].value);
|
|
}
|
|
|
|
printf("RHS\n");
|
|
for(i = 0; i <= pp->Rows; i++) {
|
|
printf(" RHS %-8s %g\n", get_row_name(lp, i),
|
|
(double)lp->orig_rhs[i]);
|
|
}
|
|
|
|
printf("RANGES\n");
|
|
for(i = 1; i <= pp->Rows; i++)
|
|
if((lp->orig_upbo[i] != lp->infinite) && (lp->orig_upbo[i] != 0)) {
|
|
printf(" RGS %-8s %g\n", get_row_name(lp, i),
|
|
(double)lp->orig_upbo[i]);
|
|
}
|
|
else if((lp->orig_lowbo[i] != 0)) {
|
|
printf(" RGS %-8s %g\n", get_row_name(lp, i),
|
|
(double)-lp->orig_lowbo[i]);
|
|
}
|
|
|
|
printf("BOUNDS\n");
|
|
for(i = pp->Rows + 1; i <= pp->Rows + pp->Columns; i++) {
|
|
if((lp->orig_lowbo[i] != 0) && (lp->orig_upbo[i] < lp->infinite) &&
|
|
(lp->orig_lowbo[i] == lp->orig_upbo[i])) {
|
|
printf(" FX BND %-8s %g\n", get_col_name(lp, i - pp->Rows),
|
|
(double)lp->orig_upbo[i]);
|
|
}
|
|
else {
|
|
if(lp->orig_upbo[i] < lp->infinite)
|
|
printf(" UP BND %-8s %g\n", get_col_name(lp, i - pp->Rows),
|
|
(double)lp->orig_upbo[i]);
|
|
if(lp->orig_lowbo[i] > 0)
|
|
printf(" LO BND %-8s %g\n", get_col_name(lp, i - pp->Rows),
|
|
(double)lp->orig_lowbo[i]);
|
|
}
|
|
}
|
|
|
|
printf("ENDATA\n");
|
|
}
|
|
#endif
|
|
|
|
FREE(row);
|
|
FREE(rowno);
|
|
FREE(negateAndSOS);
|
|
return(TRUE);
|
|
} /* readinput */
|
|
|
|
lprec *yacc_read(lprec *lp, int verbose, char *lp_name, int (*parse) (parse_parm *pp), parse_parm *pp, void (*delete_allocated_memory) (parse_parm *pp))
|
|
{
|
|
REAL *orig_upbo;
|
|
int stat = -1;
|
|
lprec *lp0 = lp;
|
|
|
|
pp->title = lp_name;
|
|
|
|
if(!init_read(pp, verbose))
|
|
error(pp, CRITICAL, "init_read failed");
|
|
else if (setjmp(pp->jump_buf) == 0)
|
|
stat = parse(pp);
|
|
|
|
delete_allocated_memory(pp);
|
|
|
|
pp->Rows--;
|
|
|
|
pp->relat = NULL;
|
|
if((stat != 0) || (CALLOC(pp->relat, pp->Rows + 1, short) != NULL)) {
|
|
if(stat == 0) {
|
|
if(lp == NULL) {
|
|
lp = make_lp(pp->Rows, 0);
|
|
}
|
|
else {
|
|
int NRows;
|
|
|
|
for(NRows = get_Nrows(lp); NRows < pp->Rows; NRows++)
|
|
add_constraintex(lp, 0, NULL, NULL, LE, 0);
|
|
}
|
|
}
|
|
else
|
|
lp = NULL;
|
|
if ((stat != 0) || (lp != NULL)) {
|
|
if(lp != NULL) {
|
|
set_verbose(lp, pp->Verbose);
|
|
}
|
|
|
|
if (!readinput(pp, lp)) {
|
|
if((lp != NULL) && (lp0 == NULL))
|
|
delete_lp(lp);
|
|
lp = NULL;
|
|
}
|
|
|
|
if(lp != NULL) {
|
|
set_lp_name(lp, pp->title);
|
|
if(pp->Maximise)
|
|
set_maxim(lp);
|
|
|
|
if(pp->Rows) {
|
|
int row;
|
|
|
|
MALLOCCPY(orig_upbo, lp->orig_upbo, 1 + pp->Rows, REAL);
|
|
for(row = 1; row <= pp->Rows; row++)
|
|
set_constr_type(lp, row, pp->relat[row]);
|
|
|
|
memcpy(lp->orig_upbo, orig_upbo, (1 + pp->Rows) * sizeof(*orig_upbo)); /* restore upper bounds (range) */
|
|
FREE(orig_upbo);
|
|
}
|
|
}
|
|
if((pp->title != NULL) && (pp->title != lp_name))
|
|
free(pp->title);
|
|
|
|
free_hash_table(pp->Hash_tab);
|
|
free_hash_table(pp->Hash_constraints);
|
|
}
|
|
FREE(pp->relat);
|
|
}
|
|
null_tmp_store(pp, FALSE);
|
|
return(lp);
|
|
}
|