123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810 |
- /* 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 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 "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 */
|