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.
810 lines
26 KiB
810 lines
26 KiB
/* glpnpp05.c */
|
|
|
|
/***********************************************************************
|
|
* This code is part of GLPK (GNU Linear Programming Kit).
|
|
*
|
|
* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
* 2009, 2010, 2011, 2013 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/>.
|
|
***********************************************************************/
|
|
|
|
#include "env.h"
|
|
#include "glpnpp.h"
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* npp_clean_prob - perform initial LP/MIP processing
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "glpnpp.h"
|
|
* void npp_clean_prob(NPP *npp);
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* The routine npp_clean_prob performs initial LP/MIP processing that
|
|
* currently includes:
|
|
*
|
|
* 1) removing free rows;
|
|
*
|
|
* 2) replacing double-sided constraint rows with almost identical
|
|
* bounds, by equality constraint rows;
|
|
*
|
|
* 3) removing fixed columns;
|
|
*
|
|
* 4) replacing double-bounded columns with almost identical bounds by
|
|
* fixed columns and removing those columns;
|
|
*
|
|
* 5) initial processing constraint coefficients (not implemented);
|
|
*
|
|
* 6) initial processing objective coefficients (not implemented). */
|
|
|
|
void npp_clean_prob(NPP *npp)
|
|
{ /* perform initial LP/MIP processing */
|
|
NPPROW *row, *next_row;
|
|
NPPCOL *col, *next_col;
|
|
int ret;
|
|
xassert(npp == npp);
|
|
/* process rows which originally are free */
|
|
for (row = npp->r_head; row != NULL; row = next_row)
|
|
{ next_row = row->next;
|
|
if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
|
|
{ /* process free row */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("1");
|
|
#endif
|
|
npp_free_row(npp, row);
|
|
/* row was deleted */
|
|
}
|
|
}
|
|
/* process rows which originally are double-sided inequalities */
|
|
for (row = npp->r_head; row != NULL; row = next_row)
|
|
{ next_row = row->next;
|
|
if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
|
|
row->lb < row->ub)
|
|
{ ret = npp_make_equality(npp, row);
|
|
if (ret == 0)
|
|
;
|
|
else if (ret == 1)
|
|
{ /* row was replaced by equality constraint */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("2");
|
|
#endif
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
}
|
|
}
|
|
/* process columns which are originally fixed */
|
|
for (col = npp->c_head; col != NULL; col = next_col)
|
|
{ next_col = col->next;
|
|
if (col->lb == col->ub)
|
|
{ /* process fixed column */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("3");
|
|
#endif
|
|
npp_fixed_col(npp, col);
|
|
/* column was deleted */
|
|
}
|
|
}
|
|
/* process columns which are originally double-bounded */
|
|
for (col = npp->c_head; col != NULL; col = next_col)
|
|
{ next_col = col->next;
|
|
if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
|
|
col->lb < col->ub)
|
|
{ ret = npp_make_fixed(npp, col);
|
|
if (ret == 0)
|
|
;
|
|
else if (ret == 1)
|
|
{ /* column was replaced by fixed column; process it */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("4");
|
|
#endif
|
|
npp_fixed_col(npp, col);
|
|
/* column was deleted */
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* npp_process_row - perform basic row processing
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "glpnpp.h"
|
|
* int npp_process_row(NPP *npp, NPPROW *row, int hard);
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* The routine npp_process_row performs basic row processing that
|
|
* currently includes:
|
|
*
|
|
* 1) removing empty row;
|
|
*
|
|
* 2) removing equality constraint row singleton and corresponding
|
|
* column;
|
|
*
|
|
* 3) removing inequality constraint row singleton and corresponding
|
|
* column if it was fixed;
|
|
*
|
|
* 4) performing general row analysis;
|
|
*
|
|
* 5) removing redundant row bounds;
|
|
*
|
|
* 6) removing forcing row and corresponding columns;
|
|
*
|
|
* 7) removing row which becomes free due to redundant bounds;
|
|
*
|
|
* 8) computing implied bounds for all columns in the row and using
|
|
* them to strengthen current column bounds (MIP only, optional,
|
|
* performed if the flag hard is on).
|
|
*
|
|
* Additionally the routine may activate affected rows and/or columns
|
|
* for further processing.
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 success;
|
|
*
|
|
* GLP_ENOPFS primal/integer infeasibility detected;
|
|
*
|
|
* GLP_ENODFS dual infeasibility detected. */
|
|
|
|
int npp_process_row(NPP *npp, NPPROW *row, int hard)
|
|
{ /* perform basic row processing */
|
|
NPPCOL *col;
|
|
NPPAIJ *aij, *next_aij, *aaa;
|
|
int ret;
|
|
/* row must not be free */
|
|
xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
|
|
/* start processing row */
|
|
if (row->ptr == NULL)
|
|
{ /* empty row */
|
|
ret = npp_empty_row(npp, row);
|
|
if (ret == 0)
|
|
{ /* row was deleted */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("A");
|
|
#endif
|
|
return 0;
|
|
}
|
|
else if (ret == 1)
|
|
{ /* primal infeasibility */
|
|
return GLP_ENOPFS;
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
}
|
|
if (row->ptr->r_next == NULL)
|
|
{ /* row singleton */
|
|
col = row->ptr->col;
|
|
if (row->lb == row->ub)
|
|
{ /* equality constraint */
|
|
ret = npp_eq_singlet(npp, row);
|
|
if (ret == 0)
|
|
{ /* column was fixed, row was deleted */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("B");
|
|
#endif
|
|
/* activate rows affected by column */
|
|
for (aij = col->ptr; aij != NULL; aij = aij->c_next)
|
|
npp_activate_row(npp, aij->row);
|
|
/* process fixed column */
|
|
npp_fixed_col(npp, col);
|
|
/* column was deleted */
|
|
return 0;
|
|
}
|
|
else if (ret == 1 || ret == 2)
|
|
{ /* primal/integer infeasibility */
|
|
return GLP_ENOPFS;
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
}
|
|
else
|
|
{ /* inequality constraint */
|
|
ret = npp_ineq_singlet(npp, row);
|
|
if (0 <= ret && ret <= 3)
|
|
{ /* row was deleted */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("C");
|
|
#endif
|
|
/* activate column, since its length was changed due to
|
|
row deletion */
|
|
npp_activate_col(npp, col);
|
|
if (ret >= 2)
|
|
{ /* column bounds changed significantly or column was
|
|
fixed */
|
|
/* activate rows affected by column */
|
|
for (aij = col->ptr; aij != NULL; aij = aij->c_next)
|
|
npp_activate_row(npp, aij->row);
|
|
}
|
|
if (ret == 3)
|
|
{ /* column was fixed; process it */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("D");
|
|
#endif
|
|
npp_fixed_col(npp, col);
|
|
/* column was deleted */
|
|
}
|
|
return 0;
|
|
}
|
|
else if (ret == 4)
|
|
{ /* primal infeasibility */
|
|
return GLP_ENOPFS;
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
}
|
|
}
|
|
#if 0
|
|
/* sometimes this causes too large round-off errors; probably
|
|
pivot coefficient should be chosen more carefully */
|
|
if (row->ptr->r_next->r_next == NULL)
|
|
{ /* row doubleton */
|
|
if (row->lb == row->ub)
|
|
{ /* equality constraint */
|
|
if (!(row->ptr->col->is_int ||
|
|
row->ptr->r_next->col->is_int))
|
|
{ /* both columns are continuous */
|
|
NPPCOL *q;
|
|
q = npp_eq_doublet(npp, row);
|
|
if (q != NULL)
|
|
{ /* column q was eliminated */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("E");
|
|
#endif
|
|
/* now column q is singleton of type "implied slack
|
|
variable"; we process it here to make sure that on
|
|
recovering basic solution the row is always active
|
|
equality constraint (as required by the routine
|
|
rcv_eq_doublet) */
|
|
xassert(npp_process_col(npp, q) == 0);
|
|
/* column q was deleted; note that row p also may be
|
|
deleted */
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/* general row analysis */
|
|
ret = npp_analyze_row(npp, row);
|
|
xassert(0x00 <= ret && ret <= 0xFF);
|
|
if (ret == 0x33)
|
|
{ /* row bounds are inconsistent with column bounds */
|
|
return GLP_ENOPFS;
|
|
}
|
|
if ((ret & 0x0F) == 0x00)
|
|
{ /* row lower bound does not exist or redundant */
|
|
if (row->lb != -DBL_MAX)
|
|
{ /* remove redundant row lower bound */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("F");
|
|
#endif
|
|
npp_inactive_bound(npp, row, 0);
|
|
}
|
|
}
|
|
else if ((ret & 0x0F) == 0x01)
|
|
{ /* row lower bound can be active */
|
|
/* see below */
|
|
}
|
|
else if ((ret & 0x0F) == 0x02)
|
|
{ /* row lower bound is a forcing bound */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("G");
|
|
#endif
|
|
/* process forcing row */
|
|
if (npp_forcing_row(npp, row, 0) == 0)
|
|
fixup: { /* columns were fixed, row was made free */
|
|
for (aij = row->ptr; aij != NULL; aij = next_aij)
|
|
{ /* process column fixed by forcing row */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("H");
|
|
#endif
|
|
col = aij->col;
|
|
next_aij = aij->r_next;
|
|
/* activate rows affected by column */
|
|
for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
|
|
npp_activate_row(npp, aaa->row);
|
|
/* process fixed column */
|
|
npp_fixed_col(npp, col);
|
|
/* column was deleted */
|
|
}
|
|
/* process free row (which now is empty due to deletion of
|
|
all its columns) */
|
|
npp_free_row(npp, row);
|
|
/* row was deleted */
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
if ((ret & 0xF0) == 0x00)
|
|
{ /* row upper bound does not exist or redundant */
|
|
if (row->ub != +DBL_MAX)
|
|
{ /* remove redundant row upper bound */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("I");
|
|
#endif
|
|
npp_inactive_bound(npp, row, 1);
|
|
}
|
|
}
|
|
else if ((ret & 0xF0) == 0x10)
|
|
{ /* row upper bound can be active */
|
|
/* see below */
|
|
}
|
|
else if ((ret & 0xF0) == 0x20)
|
|
{ /* row upper bound is a forcing bound */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("J");
|
|
#endif
|
|
/* process forcing row */
|
|
if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
|
|
{ /* row became free due to redundant bounds removal */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("K");
|
|
#endif
|
|
/* activate its columns, since their length will change due
|
|
to row deletion */
|
|
for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
|
npp_activate_col(npp, aij->col);
|
|
/* process free row */
|
|
npp_free_row(npp, row);
|
|
/* row was deleted */
|
|
return 0;
|
|
}
|
|
#if 1 /* 23/XII-2009 */
|
|
/* row lower and/or upper bounds can be active */
|
|
if (npp->sol == GLP_MIP && hard)
|
|
{ /* improve current column bounds (optional) */
|
|
if (npp_improve_bounds(npp, row, 1) < 0)
|
|
return GLP_ENOPFS;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* npp_improve_bounds - improve current column bounds
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "glpnpp.h"
|
|
* int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* The routine npp_improve_bounds analyzes specified row (inequality
|
|
* or equality constraint) to determine implied column bounds and then
|
|
* uses these bounds to improve (strengthen) current column bounds.
|
|
*
|
|
* If the flag is on and current column bounds changed significantly
|
|
* or the column was fixed, the routine activate rows affected by the
|
|
* column for further processing. (This feature is intended to be used
|
|
* in the main loop of the routine npp_process_row.)
|
|
*
|
|
* NOTE: This operation can be used for MIP problem only.
|
|
*
|
|
* RETURNS
|
|
*
|
|
* The routine npp_improve_bounds returns the number of significantly
|
|
* changed bounds plus the number of column having been fixed due to
|
|
* bound improvements. However, if the routine detects primal/integer
|
|
* infeasibility, it returns a negative value. */
|
|
|
|
int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
|
|
{ /* improve current column bounds */
|
|
NPPCOL *col;
|
|
NPPAIJ *aij, *next_aij, *aaa;
|
|
int kase, ret, count = 0;
|
|
double lb, ub;
|
|
xassert(npp->sol == GLP_MIP);
|
|
/* row must not be free */
|
|
xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
|
|
/* determine implied column bounds */
|
|
npp_implied_bounds(npp, row);
|
|
/* and use these bounds to strengthen current column bounds */
|
|
for (aij = row->ptr; aij != NULL; aij = next_aij)
|
|
{ col = aij->col;
|
|
next_aij = aij->r_next;
|
|
for (kase = 0; kase <= 1; kase++)
|
|
{ /* save current column bounds */
|
|
lb = col->lb, ub = col->ub;
|
|
if (kase == 0)
|
|
{ /* process implied column lower bound */
|
|
if (col->ll.ll == -DBL_MAX) continue;
|
|
ret = npp_implied_lower(npp, col, col->ll.ll);
|
|
}
|
|
else
|
|
{ /* process implied column upper bound */
|
|
if (col->uu.uu == +DBL_MAX) continue;
|
|
ret = npp_implied_upper(npp, col, col->uu.uu);
|
|
}
|
|
if (ret == 0 || ret == 1)
|
|
{ /* current column bounds did not change or changed, but
|
|
not significantly; restore current column bounds */
|
|
col->lb = lb, col->ub = ub;
|
|
}
|
|
else if (ret == 2 || ret == 3)
|
|
{ /* current column bounds changed significantly or column
|
|
was fixed */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("L");
|
|
#endif
|
|
count++;
|
|
/* activate other rows affected by column, if required */
|
|
if (flag)
|
|
{ for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
|
|
{ if (aaa->row != row)
|
|
npp_activate_row(npp, aaa->row);
|
|
}
|
|
}
|
|
if (ret == 3)
|
|
{ /* process fixed column */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("M");
|
|
#endif
|
|
npp_fixed_col(npp, col);
|
|
/* column was deleted */
|
|
break; /* for kase */
|
|
}
|
|
}
|
|
else if (ret == 4)
|
|
{ /* primal/integer infeasibility */
|
|
return -1;
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* npp_process_col - perform basic column processing
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "glpnpp.h"
|
|
* int npp_process_col(NPP *npp, NPPCOL *col);
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* The routine npp_process_col performs basic column processing that
|
|
* currently includes:
|
|
*
|
|
* 1) fixing and removing empty column;
|
|
*
|
|
* 2) removing column singleton, which is implied slack variable, and
|
|
* corresponding row if it becomes free;
|
|
*
|
|
* 3) removing bounds of column, which is implied free variable, and
|
|
* replacing corresponding row by equality constraint.
|
|
*
|
|
* Additionally the routine may activate affected rows and/or columns
|
|
* for further processing.
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 success;
|
|
*
|
|
* GLP_ENOPFS primal/integer infeasibility detected;
|
|
*
|
|
* GLP_ENODFS dual infeasibility detected. */
|
|
|
|
int npp_process_col(NPP *npp, NPPCOL *col)
|
|
{ /* perform basic column processing */
|
|
NPPROW *row;
|
|
NPPAIJ *aij;
|
|
int ret;
|
|
/* column must not be fixed */
|
|
xassert(col->lb < col->ub);
|
|
/* start processing column */
|
|
if (col->ptr == NULL)
|
|
{ /* empty column */
|
|
ret = npp_empty_col(npp, col);
|
|
if (ret == 0)
|
|
{ /* column was fixed and deleted */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("N");
|
|
#endif
|
|
return 0;
|
|
}
|
|
else if (ret == 1)
|
|
{ /* dual infeasibility */
|
|
return GLP_ENODFS;
|
|
}
|
|
else
|
|
xassert(ret != ret);
|
|
}
|
|
if (col->ptr->c_next == NULL)
|
|
{ /* column singleton */
|
|
row = col->ptr->row;
|
|
if (row->lb == row->ub)
|
|
{ /* equality constraint */
|
|
if (!col->is_int)
|
|
slack: { /* implied slack variable */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("O");
|
|
#endif
|
|
npp_implied_slack(npp, col);
|
|
/* column was deleted */
|
|
if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
|
|
{ /* row became free due to implied slack variable */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("P");
|
|
#endif
|
|
/* activate columns affected by row */
|
|
for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
|
npp_activate_col(npp, aij->col);
|
|
/* process free row */
|
|
npp_free_row(npp, row);
|
|
/* row was deleted */
|
|
}
|
|
else
|
|
{ /* row became inequality constraint; activate it
|
|
since its length changed due to column deletion */
|
|
npp_activate_row(npp, row);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{ /* inequality constraint */
|
|
if (!col->is_int)
|
|
{ ret = npp_implied_free(npp, col);
|
|
if (ret == 0)
|
|
{ /* implied free variable */
|
|
#ifdef GLP_DEBUG
|
|
xprintf("Q");
|
|
#endif
|
|
/* column bounds were removed, row was replaced by
|
|
equality constraint */
|
|
goto slack;
|
|
}
|
|
else if (ret == 1)
|
|
{ /* column is not implied free variable, because its
|
|
lower and/or upper bounds can be active */
|
|
}
|
|
else if (ret == 2)
|
|
{ /* dual infeasibility */
|
|
return GLP_ENODFS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* column still exists */
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* npp_process_prob - perform basic LP/MIP processing
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "glpnpp.h"
|
|
* int npp_process_prob(NPP *npp, int hard);
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* The routine npp_process_prob performs basic LP/MIP processing that
|
|
* currently includes:
|
|
*
|
|
* 1) initial LP/MIP processing (see the routine npp_clean_prob),
|
|
*
|
|
* 2) basic row processing (see the routine npp_process_row), and
|
|
*
|
|
* 3) basic column processing (see the routine npp_process_col).
|
|
*
|
|
* If the flag hard is on, the routine attempts to improve current
|
|
* column bounds multiple times within the main processing loop, in
|
|
* which case this feature may take a time. Otherwise, if the flag hard
|
|
* is off, improving column bounds is performed only once at the end of
|
|
* the main loop. (Note that this feature is used for MIP only.)
|
|
*
|
|
* The routine uses two sets: the set of active rows and the set of
|
|
* active columns. Rows/columns are marked by a flag (the field temp in
|
|
* NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
|
|
* in which case it is placed in the beginning of the row/column list;
|
|
* otherwise, if the flag is zero, the row/column is inactive, in which
|
|
* case it is placed in the end of the row/column list. If a row/column
|
|
* being currently processed may affect other rows/columns, the latters
|
|
* are activated for further processing.
|
|
*
|
|
* RETURNS
|
|
*
|
|
* 0 success;
|
|
*
|
|
* GLP_ENOPFS primal/integer infeasibility detected;
|
|
*
|
|
* GLP_ENODFS dual infeasibility detected. */
|
|
|
|
int npp_process_prob(NPP *npp, int hard)
|
|
{ /* perform basic LP/MIP processing */
|
|
NPPROW *row;
|
|
NPPCOL *col;
|
|
int processing, ret;
|
|
/* perform initial LP/MIP processing */
|
|
npp_clean_prob(npp);
|
|
/* activate all remaining rows and columns */
|
|
for (row = npp->r_head; row != NULL; row = row->next)
|
|
row->temp = 1;
|
|
for (col = npp->c_head; col != NULL; col = col->next)
|
|
col->temp = 1;
|
|
/* main processing loop */
|
|
processing = 1;
|
|
while (processing)
|
|
{ processing = 0;
|
|
/* process all active rows */
|
|
for (;;)
|
|
{ row = npp->r_head;
|
|
if (row == NULL || !row->temp) break;
|
|
npp_deactivate_row(npp, row);
|
|
ret = npp_process_row(npp, row, hard);
|
|
if (ret != 0) goto done;
|
|
processing = 1;
|
|
}
|
|
/* process all active columns */
|
|
for (;;)
|
|
{ col = npp->c_head;
|
|
if (col == NULL || !col->temp) break;
|
|
npp_deactivate_col(npp, col);
|
|
ret = npp_process_col(npp, col);
|
|
if (ret != 0) goto done;
|
|
processing = 1;
|
|
}
|
|
}
|
|
#if 1 /* 23/XII-2009 */
|
|
if (npp->sol == GLP_MIP && !hard)
|
|
{ /* improve current column bounds (optional) */
|
|
for (row = npp->r_head; row != NULL; row = row->next)
|
|
{ if (npp_improve_bounds(npp, row, 0) < 0)
|
|
{ ret = GLP_ENOPFS;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/* all seems ok */
|
|
ret = 0;
|
|
done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
|
|
#ifdef GLP_DEBUG
|
|
xprintf("\n");
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
int npp_simplex(NPP *npp, const glp_smcp *parm)
|
|
{ /* process LP prior to applying primal/dual simplex method */
|
|
int ret;
|
|
xassert(npp->sol == GLP_SOL);
|
|
xassert(parm == parm);
|
|
ret = npp_process_prob(npp, 0);
|
|
return ret;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
int npp_integer(NPP *npp, const glp_iocp *parm)
|
|
{ /* process MIP prior to applying branch-and-bound method */
|
|
NPPROW *row, *prev_row;
|
|
NPPCOL *col;
|
|
NPPAIJ *aij;
|
|
int count, ret;
|
|
xassert(npp->sol == GLP_MIP);
|
|
xassert(parm == parm);
|
|
/*==============================================================*/
|
|
/* perform basic MIP processing */
|
|
ret = npp_process_prob(npp, 1);
|
|
if (ret != 0) goto done;
|
|
/*==============================================================*/
|
|
/* binarize problem, if required */
|
|
if (parm->binarize)
|
|
npp_binarize_prob(npp);
|
|
/*==============================================================*/
|
|
/* identify hidden packing inequalities */
|
|
count = 0;
|
|
/* new rows will be added to the end of the row list, so we go
|
|
from the end to beginning of the row list */
|
|
for (row = npp->r_tail; row != NULL; row = prev_row)
|
|
{ prev_row = row->prev;
|
|
/* skip free row */
|
|
if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
|
|
/* skip equality constraint */
|
|
if (row->lb == row->ub) continue;
|
|
/* skip row having less than two variables */
|
|
if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
|
|
/* skip row having non-binary variables */
|
|
for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
|
{ col = aij->col;
|
|
if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
|
|
break;
|
|
}
|
|
if (aij != NULL) continue;
|
|
count += npp_hidden_packing(npp, row);
|
|
}
|
|
if (count > 0)
|
|
xprintf("%d hidden packing inequaliti(es) were detected\n",
|
|
count);
|
|
/*==============================================================*/
|
|
/* identify hidden covering inequalities */
|
|
count = 0;
|
|
/* new rows will be added to the end of the row list, so we go
|
|
from the end to beginning of the row list */
|
|
for (row = npp->r_tail; row != NULL; row = prev_row)
|
|
{ prev_row = row->prev;
|
|
/* skip free row */
|
|
if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
|
|
/* skip equality constraint */
|
|
if (row->lb == row->ub) continue;
|
|
/* skip row having less than three variables */
|
|
if (row->ptr == NULL || row->ptr->r_next == NULL ||
|
|
row->ptr->r_next->r_next == NULL) continue;
|
|
/* skip row having non-binary variables */
|
|
for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
|
{ col = aij->col;
|
|
if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
|
|
break;
|
|
}
|
|
if (aij != NULL) continue;
|
|
count += npp_hidden_covering(npp, row);
|
|
}
|
|
if (count > 0)
|
|
xprintf("%d hidden covering inequaliti(es) were detected\n",
|
|
count);
|
|
/*==============================================================*/
|
|
/* reduce inequality constraint coefficients */
|
|
count = 0;
|
|
/* new rows will be added to the end of the row list, so we go
|
|
from the end to beginning of the row list */
|
|
for (row = npp->r_tail; row != NULL; row = prev_row)
|
|
{ prev_row = row->prev;
|
|
/* skip equality constraint */
|
|
if (row->lb == row->ub) continue;
|
|
count += npp_reduce_ineq_coef(npp, row);
|
|
}
|
|
if (count > 0)
|
|
xprintf("%d constraint coefficient(s) were reduced\n", count);
|
|
/*==============================================================*/
|
|
#ifdef GLP_DEBUG
|
|
routine(npp);
|
|
#endif
|
|
/*==============================================================*/
|
|
/* all seems ok */
|
|
ret = 0;
|
|
done: return ret;
|
|
}
|
|
|
|
/* eof */
|