12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448 |
- /* glpios06.c (MIR cut generator) */
- /***********************************************************************
- * 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 "glpios.h"
- #define _MIR_DEBUG 0
- #define MAXAGGR 5
- /* maximal number of rows which can be aggregated */
- struct MIR
- { /* MIR cut generator working area */
- /*--------------------------------------------------------------*/
- /* global information valid for the root subproblem */
- int m;
- /* number of rows (in the root subproblem) */
- int n;
- /* number of columns */
- char *skip; /* char skip[1+m]; */
- /* skip[i], 1 <= i <= m, is a flag that means that row i should
- not be used because (1) it is not suitable, or (2) because it
- has been used in the aggregated constraint */
- char *isint; /* char isint[1+m+n]; */
- /* isint[k], 1 <= k <= m+n, is a flag that means that variable
- x[k] is integer (otherwise, continuous) */
- double *lb; /* double lb[1+m+n]; */
- /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
- that x[k] has no lower bound */
- int *vlb; /* int vlb[1+m+n]; */
- /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
- which defines variable lower bound x[k] >= lb[k] * x[k']; zero
- means that x[k] has simple lower bound */
- double *ub; /* double ub[1+m+n]; */
- /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
- that x[k] has no upper bound */
- int *vub; /* int vub[1+m+n]; */
- /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
- which defines variable upper bound x[k] <= ub[k] * x[k']; zero
- means that x[k] has simple upper bound */
- /*--------------------------------------------------------------*/
- /* current (fractional) point to be separated */
- double *x; /* double x[1+m+n]; */
- /* x[k] is current value of auxiliary (1 <= k <= m) or structural
- (m+1 <= k <= m+n) variable */
- /*--------------------------------------------------------------*/
- /* aggregated constraint sum a[k] * x[k] = b, which is a linear
- combination of original constraints transformed to equalities
- by introducing auxiliary variables */
- int agg_cnt;
- /* number of rows (original constraints) used to build aggregated
- constraint, 1 <= agg_cnt <= MAXAGGR */
- int *agg_row; /* int agg_row[1+MAXAGGR]; */
- /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
- aggregated constraint */
- IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */
- /* sparse vector of aggregated constraint coefficients, a[k] */
- double agg_rhs;
- /* right-hand side of the aggregated constraint, b */
- /*--------------------------------------------------------------*/
- /* bound substitution flags for modified constraint */
- char *subst; /* char subst[1+m+n]; */
- /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
- variable x[k]:
- '?' - x[k] is missing in modified constraint
- 'L' - x[k] = (lower bound) + x'[k]
- 'U' - x[k] = (upper bound) - x'[k] */
- /*--------------------------------------------------------------*/
- /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
- derived from aggregated constraint by substituting bounds;
- note that due to substitution of variable bounds there may be
- additional terms in the modified constraint */
- IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */
- /* sparse vector of modified constraint coefficients, a'[k] */
- double mod_rhs;
- /* right-hand side of the modified constraint, b' */
- /*--------------------------------------------------------------*/
- /* cutting plane sum alpha[k] * x[k] <= beta */
- IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */
- /* sparse vector of cutting plane coefficients, alpha[k] */
- double cut_rhs;
- /* right-hand size of the cutting plane, beta */
- };
- /***********************************************************************
- * NAME
- *
- * ios_mir_init - initialize MIR cut generator
- *
- * SYNOPSIS
- *
- * #include "glpios.h"
- * void *ios_mir_init(glp_tree *tree);
- *
- * DESCRIPTION
- *
- * The routine ios_mir_init initializes the MIR cut generator assuming
- * that the current subproblem is the root subproblem.
- *
- * RETURNS
- *
- * The routine ios_mir_init returns a pointer to the MIR cut generator
- * working area. */
- static void set_row_attrib(glp_tree *tree, struct MIR *mir)
- { /* set global row attributes */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- int k;
- for (k = 1; k <= m; k++)
- { GLPROW *row = mip->row[k];
- mir->skip[k] = 0;
- mir->isint[k] = 0;
- switch (row->type)
- { case GLP_FR:
- mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
- case GLP_LO:
- mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
- case GLP_UP:
- mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
- case GLP_DB:
- mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
- case GLP_FX:
- mir->lb[k] = mir->ub[k] = row->lb; break;
- default:
- xassert(row != row);
- }
- mir->vlb[k] = mir->vub[k] = 0;
- }
- return;
- }
- static void set_col_attrib(glp_tree *tree, struct MIR *mir)
- { /* set global column attributes */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- int n = mir->n;
- int k;
- for (k = m+1; k <= m+n; k++)
- { GLPCOL *col = mip->col[k-m];
- switch (col->kind)
- { case GLP_CV:
- mir->isint[k] = 0; break;
- case GLP_IV:
- mir->isint[k] = 1; break;
- default:
- xassert(col != col);
- }
- switch (col->type)
- { case GLP_FR:
- mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
- case GLP_LO:
- mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
- case GLP_UP:
- mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
- case GLP_DB:
- mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
- case GLP_FX:
- mir->lb[k] = mir->ub[k] = col->lb; break;
- default:
- xassert(col != col);
- }
- mir->vlb[k] = mir->vub[k] = 0;
- }
- return;
- }
- static void set_var_bounds(glp_tree *tree, struct MIR *mir)
- { /* set variable bounds */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- GLPAIJ *aij;
- int i, k1, k2;
- double a1, a2;
- for (i = 1; i <= m; i++)
- { /* we need the row to be '>= 0' or '<= 0' */
- if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
- mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
- /* take first term */
- aij = mip->row[i]->ptr;
- if (aij == NULL) continue;
- k1 = m + aij->col->j, a1 = aij->val;
- /* take second term */
- aij = aij->r_next;
- if (aij == NULL) continue;
- k2 = m + aij->col->j, a2 = aij->val;
- /* there must be only two terms */
- if (aij->r_next != NULL) continue;
- /* interchange terms, if needed */
- if (!mir->isint[k1] && mir->isint[k2])
- ;
- else if (mir->isint[k1] && !mir->isint[k2])
- { k2 = k1, a2 = a1;
- k1 = m + aij->col->j, a1 = aij->val;
- }
- else
- { /* both terms are either continuous or integer */
- continue;
- }
- /* x[k2] should be double-bounded */
- if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
- mir->lb[k2] == mir->ub[k2]) continue;
- /* change signs, if necessary */
- if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
- /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
- is continuous, x2 is integer */
- if (a1 > 0.0)
- { /* x1 >= - (a2 / a1) * x2 */
- if (mir->vlb[k1] == 0)
- { /* set variable lower bound for x1 */
- mir->lb[k1] = - a2 / a1;
- mir->vlb[k1] = k2;
- /* the row should not be used */
- mir->skip[i] = 1;
- }
- }
- else /* a1 < 0.0 */
- { /* x1 <= - (a2 / a1) * x2 */
- if (mir->vub[k1] == 0)
- { /* set variable upper bound for x1 */
- mir->ub[k1] = - a2 / a1;
- mir->vub[k1] = k2;
- /* the row should not be used */
- mir->skip[i] = 1;
- }
- }
- }
- return;
- }
- static void mark_useless_rows(glp_tree *tree, struct MIR *mir)
- { /* mark rows which should not be used */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- GLPAIJ *aij;
- int i, k, nv;
- for (i = 1; i <= m; i++)
- { /* free rows should not be used */
- if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
- { mir->skip[i] = 1;
- continue;
- }
- nv = 0;
- for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
- { k = m + aij->col->j;
- /* rows with free variables should not be used */
- if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
- { mir->skip[i] = 1;
- break;
- }
- /* rows with integer variables having infinite (lower or
- upper) bound should not be used */
- if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
- mir->isint[k] && mir->ub[k] == +DBL_MAX)
- { mir->skip[i] = 1;
- break;
- }
- /* count non-fixed variables */
- if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
- mir->lb[k] == mir->ub[k])) nv++;
- }
- /* rows with all variables fixed should not be used */
- if (nv == 0)
- { mir->skip[i] = 1;
- continue;
- }
- }
- return;
- }
- void *ios_mir_init(glp_tree *tree)
- { /* initialize MIR cut generator */
- glp_prob *mip = tree->mip;
- int m = mip->m;
- int n = mip->n;
- struct MIR *mir;
- #if _MIR_DEBUG
- xprintf("ios_mir_init: warning: debug mode enabled\n");
- #endif
- /* allocate working area */
- mir = xmalloc(sizeof(struct MIR));
- mir->m = m;
- mir->n = n;
- mir->skip = xcalloc(1+m, sizeof(char));
- mir->isint = xcalloc(1+m+n, sizeof(char));
- mir->lb = xcalloc(1+m+n, sizeof(double));
- mir->vlb = xcalloc(1+m+n, sizeof(int));
- mir->ub = xcalloc(1+m+n, sizeof(double));
- mir->vub = xcalloc(1+m+n, sizeof(int));
- mir->x = xcalloc(1+m+n, sizeof(double));
- mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
- mir->agg_vec = ios_create_vec(m+n);
- mir->subst = xcalloc(1+m+n, sizeof(char));
- mir->mod_vec = ios_create_vec(m+n);
- mir->cut_vec = ios_create_vec(m+n);
- /* set global row attributes */
- set_row_attrib(tree, mir);
- /* set global column attributes */
- set_col_attrib(tree, mir);
- /* set variable bounds */
- set_var_bounds(tree, mir);
- /* mark rows which should not be used */
- mark_useless_rows(tree, mir);
- return mir;
- }
- /***********************************************************************
- * NAME
- *
- * ios_mir_gen - generate MIR cuts
- *
- * SYNOPSIS
- *
- * #include "glpios.h"
- * void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool);
- *
- * DESCRIPTION
- *
- * The routine ios_mir_gen generates MIR cuts for the current point and
- * adds them to the cut pool. */
- static void get_current_point(glp_tree *tree, struct MIR *mir)
- { /* obtain current point */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- int n = mir->n;
- int k;
- for (k = 1; k <= m; k++)
- mir->x[k] = mip->row[k]->prim;
- for (k = m+1; k <= m+n; k++)
- mir->x[k] = mip->col[k-m]->prim;
- return;
- }
- #if _MIR_DEBUG
- static void check_current_point(struct MIR *mir)
- { /* check current point */
- int m = mir->m;
- int n = mir->n;
- int k, kk;
- double lb, ub, eps;
- for (k = 1; k <= m+n; k++)
- { /* determine lower bound */
- lb = mir->lb[k];
- kk = mir->vlb[k];
- if (kk != 0)
- { xassert(lb != -DBL_MAX);
- xassert(!mir->isint[k]);
- xassert(mir->isint[kk]);
- lb *= mir->x[kk];
- }
- /* check lower bound */
- if (lb != -DBL_MAX)
- { eps = 1e-6 * (1.0 + fabs(lb));
- xassert(mir->x[k] >= lb - eps);
- }
- /* determine upper bound */
- ub = mir->ub[k];
- kk = mir->vub[k];
- if (kk != 0)
- { xassert(ub != +DBL_MAX);
- xassert(!mir->isint[k]);
- xassert(mir->isint[kk]);
- ub *= mir->x[kk];
- }
- /* check upper bound */
- if (ub != +DBL_MAX)
- { eps = 1e-6 * (1.0 + fabs(ub));
- xassert(mir->x[k] <= ub + eps);
- }
- }
- return;
- }
- #endif
- static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i)
- { /* use original i-th row as initial aggregated constraint */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- GLPAIJ *aij;
- xassert(1 <= i && i <= m);
- xassert(!mir->skip[i]);
- /* mark i-th row in order not to use it in the same aggregated
- constraint */
- mir->skip[i] = 2;
- mir->agg_cnt = 1;
- mir->agg_row[1] = i;
- /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
- variable of row i, x[m+j] are structural variables */
- ios_clear_vec(mir->agg_vec);
- ios_set_vj(mir->agg_vec, i, 1.0);
- for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
- ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
- mir->agg_rhs = 0.0;
- #if _MIR_DEBUG
- ios_check_vec(mir->agg_vec);
- #endif
- return;
- }
- #if _MIR_DEBUG
- static void check_agg_row(struct MIR *mir)
- { /* check aggregated constraint */
- int m = mir->m;
- int n = mir->n;
- int j, k;
- double r, big;
- /* compute the residual r = sum a[k] * x[k] - b and determine
- big = max(1, |a[k]|, |b|) */
- r = 0.0, big = 1.0;
- for (j = 1; j <= mir->agg_vec->nnz; j++)
- { k = mir->agg_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- r += mir->agg_vec->val[j] * mir->x[k];
- if (big < fabs(mir->agg_vec->val[j]))
- big = fabs(mir->agg_vec->val[j]);
- }
- r -= mir->agg_rhs;
- if (big < fabs(mir->agg_rhs))
- big = fabs(mir->agg_rhs);
- /* the residual must be close to zero */
- xassert(fabs(r) <= 1e-6 * big);
- return;
- }
- #endif
- static void subst_fixed_vars(struct MIR *mir)
- { /* substitute fixed variables into aggregated constraint */
- int m = mir->m;
- int n = mir->n;
- int j, k;
- for (j = 1; j <= mir->agg_vec->nnz; j++)
- { k = mir->agg_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
- mir->lb[k] == mir->ub[k])
- { /* x[k] is fixed */
- mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
- mir->agg_vec->val[j] = 0.0;
- }
- }
- /* remove terms corresponding to fixed variables */
- ios_clean_vec(mir->agg_vec, DBL_EPSILON);
- #if _MIR_DEBUG
- ios_check_vec(mir->agg_vec);
- #endif
- return;
- }
- static void bound_subst_heur(struct MIR *mir)
- { /* bound substitution heuristic */
- int m = mir->m;
- int n = mir->n;
- int j, k, kk;
- double d1, d2;
- for (j = 1; j <= mir->agg_vec->nnz; j++)
- { k = mir->agg_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (mir->isint[k]) continue; /* skip integer variable */
- /* compute distance from x[k] to its lower bound */
- kk = mir->vlb[k];
- if (kk == 0)
- { if (mir->lb[k] == -DBL_MAX)
- d1 = DBL_MAX;
- else
- d1 = mir->x[k] - mir->lb[k];
- }
- else
- { xassert(1 <= kk && kk <= m+n);
- xassert(mir->isint[kk]);
- xassert(mir->lb[k] != -DBL_MAX);
- d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
- }
- /* compute distance from x[k] to its upper bound */
- kk = mir->vub[k];
- if (kk == 0)
- { if (mir->vub[k] == +DBL_MAX)
- d2 = DBL_MAX;
- else
- d2 = mir->ub[k] - mir->x[k];
- }
- else
- { xassert(1 <= kk && kk <= m+n);
- xassert(mir->isint[kk]);
- xassert(mir->ub[k] != +DBL_MAX);
- d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
- }
- /* x[k] cannot be free */
- xassert(d1 != DBL_MAX || d2 != DBL_MAX);
- /* choose the bound which is closer to x[k] */
- xassert(mir->subst[k] == '?');
- if (d1 <= d2)
- mir->subst[k] = 'L';
- else
- mir->subst[k] = 'U';
- }
- return;
- }
- static void build_mod_row(struct MIR *mir)
- { /* substitute bounds and build modified constraint */
- int m = mir->m;
- int n = mir->n;
- int j, jj, k, kk;
- /* initially modified constraint is aggregated constraint */
- ios_copy_vec(mir->mod_vec, mir->agg_vec);
- mir->mod_rhs = mir->agg_rhs;
- #if _MIR_DEBUG
- ios_check_vec(mir->mod_vec);
- #endif
- /* substitute bounds for continuous variables; note that due to
- substitution of variable bounds additional terms may appear in
- modified constraint */
- for (j = mir->mod_vec->nnz; j >= 1; j--)
- { k = mir->mod_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (mir->isint[k]) continue; /* skip integer variable */
- if (mir->subst[k] == 'L')
- { /* x[k] = (lower bound) + x'[k] */
- xassert(mir->lb[k] != -DBL_MAX);
- kk = mir->vlb[k];
- if (kk == 0)
- { /* x[k] = lb[k] + x'[k] */
- mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
- }
- else
- { /* x[k] = lb[k] * x[kk] + x'[k] */
- xassert(mir->isint[kk]);
- jj = mir->mod_vec->pos[kk];
- if (jj == 0)
- { ios_set_vj(mir->mod_vec, kk, 1.0);
- jj = mir->mod_vec->pos[kk];
- mir->mod_vec->val[jj] = 0.0;
- }
- mir->mod_vec->val[jj] +=
- mir->mod_vec->val[j] * mir->lb[k];
- }
- }
- else if (mir->subst[k] == 'U')
- { /* x[k] = (upper bound) - x'[k] */
- xassert(mir->ub[k] != +DBL_MAX);
- kk = mir->vub[k];
- if (kk == 0)
- { /* x[k] = ub[k] - x'[k] */
- mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
- }
- else
- { /* x[k] = ub[k] * x[kk] - x'[k] */
- xassert(mir->isint[kk]);
- jj = mir->mod_vec->pos[kk];
- if (jj == 0)
- { ios_set_vj(mir->mod_vec, kk, 1.0);
- jj = mir->mod_vec->pos[kk];
- mir->mod_vec->val[jj] = 0.0;
- }
- mir->mod_vec->val[jj] +=
- mir->mod_vec->val[j] * mir->ub[k];
- }
- mir->mod_vec->val[j] = - mir->mod_vec->val[j];
- }
- else
- xassert(k != k);
- }
- #if _MIR_DEBUG
- ios_check_vec(mir->mod_vec);
- #endif
- /* substitute bounds for integer variables */
- for (j = 1; j <= mir->mod_vec->nnz; j++)
- { k = mir->mod_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (!mir->isint[k]) continue; /* skip continuous variable */
- xassert(mir->subst[k] == '?');
- xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
- xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
- if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
- { /* x[k] = lb[k] + x'[k] */
- mir->subst[k] = 'L';
- mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
- }
- else
- { /* x[k] = ub[k] - x'[k] */
- mir->subst[k] = 'U';
- mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
- mir->mod_vec->val[j] = - mir->mod_vec->val[j];
- }
- }
- #if _MIR_DEBUG
- ios_check_vec(mir->mod_vec);
- #endif
- return;
- }
- #if _MIR_DEBUG
- static void check_mod_row(struct MIR *mir)
- { /* check modified constraint */
- int m = mir->m;
- int n = mir->n;
- int j, k, kk;
- double r, big, x;
- /* compute the residual r = sum a'[k] * x'[k] - b' and determine
- big = max(1, |a[k]|, |b|) */
- r = 0.0, big = 1.0;
- for (j = 1; j <= mir->mod_vec->nnz; j++)
- { k = mir->mod_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (mir->subst[k] == 'L')
- { /* x'[k] = x[k] - (lower bound) */
- xassert(mir->lb[k] != -DBL_MAX);
- kk = mir->vlb[k];
- if (kk == 0)
- x = mir->x[k] - mir->lb[k];
- else
- x = mir->x[k] - mir->lb[k] * mir->x[kk];
- }
- else if (mir->subst[k] == 'U')
- { /* x'[k] = (upper bound) - x[k] */
- xassert(mir->ub[k] != +DBL_MAX);
- kk = mir->vub[k];
- if (kk == 0)
- x = mir->ub[k] - mir->x[k];
- else
- x = mir->ub[k] * mir->x[kk] - mir->x[k];
- }
- else
- xassert(k != k);
- r += mir->mod_vec->val[j] * x;
- if (big < fabs(mir->mod_vec->val[j]))
- big = fabs(mir->mod_vec->val[j]);
- }
- r -= mir->mod_rhs;
- if (big < fabs(mir->mod_rhs))
- big = fabs(mir->mod_rhs);
- /* the residual must be close to zero */
- xassert(fabs(r) <= 1e-6 * big);
- return;
- }
- #endif
- /***********************************************************************
- * mir_ineq - construct MIR inequality
- *
- * Given the single constraint mixed integer set
- *
- * |N|
- * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s},
- * + + j in N
- *
- * this routine constructs the mixed integer rounding (MIR) inequality
- *
- * sum alpha[j] * x[j] <= beta + gamma * s,
- * j in N
- *
- * which is valid for X.
- *
- * If the MIR inequality has been successfully constructed, the routine
- * returns zero. Otherwise, if b is close to nearest integer, there may
- * be numeric difficulties due to big coefficients; so in this case the
- * routine returns non-zero. */
- static int mir_ineq(const int n, const double a[], const double b,
- double alpha[], double *beta, double *gamma)
- { int j;
- double f, t;
- if (fabs(b - floor(b + .5)) < 0.01)
- return 1;
- f = b - floor(b);
- for (j = 1; j <= n; j++)
- { t = (a[j] - floor(a[j])) - f;
- if (t <= 0.0)
- alpha[j] = floor(a[j]);
- else
- alpha[j] = floor(a[j]) + t / (1.0 - f);
- }
- *beta = floor(b);
- *gamma = 1.0 / (1.0 - f);
- return 0;
- }
- /***********************************************************************
- * cmir_ineq - construct c-MIR inequality
- *
- * Given the mixed knapsack set
- *
- * MK |N|
- * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
- * + + j in N
- *
- * x[j] <= u[j]},
- *
- * a subset C of variables to be complemented, and a divisor delta > 0,
- * this routine constructs the complemented MIR (c-MIR) inequality
- *
- * sum alpha[j] * x[j] <= beta + gamma * s,
- * j in N
- * MK
- * which is valid for X .
- *
- * If the c-MIR inequality has been successfully constructed, the
- * routine returns zero. Otherwise, if there is a risk of numerical
- * difficulties due to big coefficients (see comments to the routine
- * mir_ineq), the routine cmir_ineq returns non-zero. */
- static int cmir_ineq(const int n, const double a[], const double b,
- const double u[], const char cset[], const double delta,
- double alpha[], double *beta, double *gamma)
- { int j;
- double *aa, bb;
- aa = alpha, bb = b;
- for (j = 1; j <= n; j++)
- { aa[j] = a[j] / delta;
- if (cset[j])
- aa[j] = - aa[j], bb -= a[j] * u[j];
- }
- bb /= delta;
- if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
- for (j = 1; j <= n; j++)
- { if (cset[j])
- alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
- }
- *gamma /= delta;
- return 0;
- }
- /***********************************************************************
- * cmir_sep - c-MIR separation heuristic
- *
- * Given the mixed knapsack set
- *
- * MK |N|
- * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
- * + + j in N
- *
- * x[j] <= u[j]}
- *
- * * *
- * and a fractional point (x , s ), this routine tries to construct
- * c-MIR inequality
- *
- * sum alpha[j] * x[j] <= beta + gamma * s,
- * j in N
- * MK
- * which is valid for X and has (desirably maximal) violation at the
- * fractional point given. This is attained by choosing an appropriate
- * set C of variables to be complemented and a divisor delta > 0, which
- * together define corresponding c-MIR inequality.
- *
- * If a violated c-MIR inequality has been successfully constructed,
- * the routine returns its violation:
- *
- * * *
- * sum alpha[j] * x [j] - beta - gamma * s ,
- * j in N
- *
- * which is positive. In case of failure the routine returns zero. */
- struct vset { int j; double v; };
- static int cmir_cmp(const void *p1, const void *p2)
- { const struct vset *v1 = p1, *v2 = p2;
- if (v1->v < v2->v) return -1;
- if (v1->v > v2->v) return +1;
- return 0;
- }
- static double cmir_sep(const int n, const double a[], const double b,
- const double u[], const double x[], const double s,
- double alpha[], double *beta, double *gamma)
- { int fail, j, k, nv, v;
- double delta, eps, d_try[1+3], r, r_best;
- char *cset;
- struct vset *vset;
- /* allocate working arrays */
- cset = xcalloc(1+n, sizeof(char));
- vset = xcalloc(1+n, sizeof(struct vset));
- /* choose initial C */
- for (j = 1; j <= n; j++)
- cset[j] = (char)(x[j] >= 0.5 * u[j]);
- /* choose initial delta */
- r_best = delta = 0.0;
- for (j = 1; j <= n; j++)
- { xassert(a[j] != 0.0);
- /* if x[j] is close to its bounds, skip it */
- eps = 1e-9 * (1.0 + fabs(u[j]));
- if (x[j] < eps || x[j] > u[j] - eps) continue;
- /* try delta = |a[j]| to construct c-MIR inequality */
- fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
- gamma);
- if (fail) continue;
- /* compute violation */
- r = - (*beta) - (*gamma) * s;
- for (k = 1; k <= n; k++) r += alpha[k] * x[k];
- if (r_best < r) r_best = r, delta = fabs(a[j]);
- }
- if (r_best < 0.001) r_best = 0.0;
- if (r_best == 0.0) goto done;
- xassert(delta > 0.0);
- /* try to increase violation by dividing delta by 2, 4, and 8,
- respectively */
- d_try[1] = delta / 2.0;
- d_try[2] = delta / 4.0;
- d_try[3] = delta / 8.0;
- for (j = 1; j <= 3; j++)
- { /* construct c-MIR inequality */
- fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
- gamma);
- if (fail) continue;
- /* compute violation */
- r = - (*beta) - (*gamma) * s;
- for (k = 1; k <= n; k++) r += alpha[k] * x[k];
- if (r_best < r) r_best = r, delta = d_try[j];
- }
- /* build subset of variables lying strictly between their bounds
- and order it by nondecreasing values of |x[j] - u[j]/2| */
- nv = 0;
- for (j = 1; j <= n; j++)
- { /* if x[j] is close to its bounds, skip it */
- eps = 1e-9 * (1.0 + fabs(u[j]));
- if (x[j] < eps || x[j] > u[j] - eps) continue;
- /* add x[j] to the subset */
- nv++;
- vset[nv].j = j;
- vset[nv].v = fabs(x[j] - 0.5 * u[j]);
- }
- qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
- /* try to increase violation by successively complementing each
- variable in the subset */
- for (v = 1; v <= nv; v++)
- { j = vset[v].j;
- /* replace x[j] by its complement or vice versa */
- cset[j] = (char)!cset[j];
- /* construct c-MIR inequality */
- fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
- /* restore the variable */
- cset[j] = (char)!cset[j];
- /* do not replace the variable in case of failure */
- if (fail) continue;
- /* compute violation */
- r = - (*beta) - (*gamma) * s;
- for (k = 1; k <= n; k++) r += alpha[k] * x[k];
- if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
- }
- /* construct the best c-MIR inequality chosen */
- fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
- xassert(!fail);
- done: /* free working arrays */
- xfree(cset);
- xfree(vset);
- /* return to the calling routine */
- return r_best;
- }
- static double generate(struct MIR *mir)
- { /* try to generate violated c-MIR cut for modified constraint */
- int m = mir->m;
- int n = mir->n;
- int j, k, kk, nint;
- double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
- ios_copy_vec(mir->cut_vec, mir->mod_vec);
- mir->cut_rhs = mir->mod_rhs;
- /* remove small terms, which can appear due to substitution of
- variable bounds */
- ios_clean_vec(mir->cut_vec, DBL_EPSILON);
- #if _MIR_DEBUG
- ios_check_vec(mir->cut_vec);
- #endif
- /* remove positive continuous terms to obtain MK relaxation */
- for (j = 1; j <= mir->cut_vec->nnz; j++)
- { k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
- mir->cut_vec->val[j] = 0.0;
- }
- ios_clean_vec(mir->cut_vec, 0.0);
- #if _MIR_DEBUG
- ios_check_vec(mir->cut_vec);
- #endif
- /* move integer terms to the beginning of the sparse vector and
- determine the number of integer variables */
- nint = 0;
- for (j = 1; j <= mir->cut_vec->nnz; j++)
- { k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (mir->isint[k])
- { double temp;
- nint++;
- /* interchange elements [nint] and [j] */
- kk = mir->cut_vec->ind[nint];
- mir->cut_vec->pos[k] = nint;
- mir->cut_vec->pos[kk] = j;
- mir->cut_vec->ind[nint] = k;
- mir->cut_vec->ind[j] = kk;
- temp = mir->cut_vec->val[nint];
- mir->cut_vec->val[nint] = mir->cut_vec->val[j];
- mir->cut_vec->val[j] = temp;
- }
- }
- #if _MIR_DEBUG
- ios_check_vec(mir->cut_vec);
- #endif
- /* if there is no integer variable, nothing to generate */
- if (nint == 0) goto done;
- /* allocate working arrays */
- u = xcalloc(1+nint, sizeof(double));
- x = xcalloc(1+nint, sizeof(double));
- alpha = xcalloc(1+nint, sizeof(double));
- /* determine u and x */
- for (j = 1; j <= nint; j++)
- { k = mir->cut_vec->ind[j];
- xassert(m+1 <= k && k <= m+n);
- xassert(mir->isint[k]);
- u[j] = mir->ub[k] - mir->lb[k];
- xassert(u[j] >= 1.0);
- if (mir->subst[k] == 'L')
- x[j] = mir->x[k] - mir->lb[k];
- else if (mir->subst[k] == 'U')
- x[j] = mir->ub[k] - mir->x[k];
- else
- xassert(k != k);
- xassert(x[j] >= -0.001);
- if (x[j] < 0.0) x[j] = 0.0;
- }
- /* compute s = - sum of continuous terms */
- s = 0.0;
- for (j = nint+1; j <= mir->cut_vec->nnz; j++)
- { double x;
- k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- /* must be continuous */
- xassert(!mir->isint[k]);
- if (mir->subst[k] == 'L')
- { xassert(mir->lb[k] != -DBL_MAX);
- kk = mir->vlb[k];
- if (kk == 0)
- x = mir->x[k] - mir->lb[k];
- else
- x = mir->x[k] - mir->lb[k] * mir->x[kk];
- }
- else if (mir->subst[k] == 'U')
- { xassert(mir->ub[k] != +DBL_MAX);
- kk = mir->vub[k];
- if (kk == 0)
- x = mir->ub[k] - mir->x[k];
- else
- x = mir->ub[k] * mir->x[kk] - mir->x[k];
- }
- else
- xassert(k != k);
- xassert(x >= -0.001);
- if (x < 0.0) x = 0.0;
- s -= mir->cut_vec->val[j] * x;
- }
- xassert(s >= 0.0);
- /* apply heuristic to obtain most violated c-MIR inequality */
- b = mir->cut_rhs;
- r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
- &beta, &gamma);
- if (r_best == 0.0) goto skip;
- xassert(r_best > 0.0);
- /* convert to raw cut */
- /* sum alpha[j] * x[j] <= beta + gamma * s */
- for (j = 1; j <= nint; j++)
- mir->cut_vec->val[j] = alpha[j];
- for (j = nint+1; j <= mir->cut_vec->nnz; j++)
- { k = mir->cut_vec->ind[j];
- if (k <= m+n) mir->cut_vec->val[j] *= gamma;
- }
- mir->cut_rhs = beta;
- #if _MIR_DEBUG
- ios_check_vec(mir->cut_vec);
- #endif
- skip: /* free working arrays */
- xfree(u);
- xfree(x);
- xfree(alpha);
- done: return r_best;
- }
- #if _MIR_DEBUG
- static void check_raw_cut(struct MIR *mir, double r_best)
- { /* check raw cut before back bound substitution */
- int m = mir->m;
- int n = mir->n;
- int j, k, kk;
- double r, big, x;
- /* compute the residual r = sum a[k] * x[k] - b and determine
- big = max(1, |a[k]|, |b|) */
- r = 0.0, big = 1.0;
- for (j = 1; j <= mir->cut_vec->nnz; j++)
- { k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (mir->subst[k] == 'L')
- { xassert(mir->lb[k] != -DBL_MAX);
- kk = mir->vlb[k];
- if (kk == 0)
- x = mir->x[k] - mir->lb[k];
- else
- x = mir->x[k] - mir->lb[k] * mir->x[kk];
- }
- else if (mir->subst[k] == 'U')
- { xassert(mir->ub[k] != +DBL_MAX);
- kk = mir->vub[k];
- if (kk == 0)
- x = mir->ub[k] - mir->x[k];
- else
- x = mir->ub[k] * mir->x[kk] - mir->x[k];
- }
- else
- xassert(k != k);
- r += mir->cut_vec->val[j] * x;
- if (big < fabs(mir->cut_vec->val[j]))
- big = fabs(mir->cut_vec->val[j]);
- }
- r -= mir->cut_rhs;
- if (big < fabs(mir->cut_rhs))
- big = fabs(mir->cut_rhs);
- /* the residual must be close to r_best */
- xassert(fabs(r - r_best) <= 1e-6 * big);
- return;
- }
- #endif
- static void back_subst(struct MIR *mir)
- { /* back substitution of original bounds */
- int m = mir->m;
- int n = mir->n;
- int j, jj, k, kk;
- /* at first, restore bounds of integer variables (because on
- restoring variable bounds of continuous variables we need
- original, not shifted, bounds of integer variables) */
- for (j = 1; j <= mir->cut_vec->nnz; j++)
- { k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (!mir->isint[k]) continue; /* skip continuous */
- if (mir->subst[k] == 'L')
- { /* x'[k] = x[k] - lb[k] */
- xassert(mir->lb[k] != -DBL_MAX);
- xassert(mir->vlb[k] == 0);
- mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
- }
- else if (mir->subst[k] == 'U')
- { /* x'[k] = ub[k] - x[k] */
- xassert(mir->ub[k] != +DBL_MAX);
- xassert(mir->vub[k] == 0);
- mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
- mir->cut_vec->val[j] = - mir->cut_vec->val[j];
- }
- else
- xassert(k != k);
- }
- /* now restore bounds of continuous variables */
- for (j = 1; j <= mir->cut_vec->nnz; j++)
- { k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (mir->isint[k]) continue; /* skip integer */
- if (mir->subst[k] == 'L')
- { /* x'[k] = x[k] - (lower bound) */
- xassert(mir->lb[k] != -DBL_MAX);
- kk = mir->vlb[k];
- if (kk == 0)
- { /* x'[k] = x[k] - lb[k] */
- mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
- }
- else
- { /* x'[k] = x[k] - lb[k] * x[kk] */
- jj = mir->cut_vec->pos[kk];
- #if 0
- xassert(jj != 0);
- #else
- if (jj == 0)
- { ios_set_vj(mir->cut_vec, kk, 1.0);
- jj = mir->cut_vec->pos[kk];
- xassert(jj != 0);
- mir->cut_vec->val[jj] = 0.0;
- }
- #endif
- mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
- mir->lb[k];
- }
- }
- else if (mir->subst[k] == 'U')
- { /* x'[k] = (upper bound) - x[k] */
- xassert(mir->ub[k] != +DBL_MAX);
- kk = mir->vub[k];
- if (kk == 0)
- { /* x'[k] = ub[k] - x[k] */
- mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
- }
- else
- { /* x'[k] = ub[k] * x[kk] - x[k] */
- jj = mir->cut_vec->pos[kk];
- if (jj == 0)
- { ios_set_vj(mir->cut_vec, kk, 1.0);
- jj = mir->cut_vec->pos[kk];
- xassert(jj != 0);
- mir->cut_vec->val[jj] = 0.0;
- }
- mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
- mir->ub[k];
- }
- mir->cut_vec->val[j] = - mir->cut_vec->val[j];
- }
- else
- xassert(k != k);
- }
- #if _MIR_DEBUG
- ios_check_vec(mir->cut_vec);
- #endif
- return;
- }
- #if _MIR_DEBUG
- static void check_cut_row(struct MIR *mir, double r_best)
- { /* check the cut after back bound substitution or elimination of
- auxiliary variables */
- int m = mir->m;
- int n = mir->n;
- int j, k;
- double r, big;
- /* compute the residual r = sum a[k] * x[k] - b and determine
- big = max(1, |a[k]|, |b|) */
- r = 0.0, big = 1.0;
- for (j = 1; j <= mir->cut_vec->nnz; j++)
- { k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- r += mir->cut_vec->val[j] * mir->x[k];
- if (big < fabs(mir->cut_vec->val[j]))
- big = fabs(mir->cut_vec->val[j]);
- }
- r -= mir->cut_rhs;
- if (big < fabs(mir->cut_rhs))
- big = fabs(mir->cut_rhs);
- /* the residual must be close to r_best */
- xassert(fabs(r - r_best) <= 1e-6 * big);
- return;
- }
- #endif
- static void subst_aux_vars(glp_tree *tree, struct MIR *mir)
- { /* final substitution to eliminate auxiliary variables */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- int n = mir->n;
- GLPAIJ *aij;
- int j, k, kk, jj;
- for (j = mir->cut_vec->nnz; j >= 1; j--)
- { k = mir->cut_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (k > m) continue; /* skip structurals */
- for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
- { kk = m + aij->col->j; /* structural */
- jj = mir->cut_vec->pos[kk];
- if (jj == 0)
- { ios_set_vj(mir->cut_vec, kk, 1.0);
- jj = mir->cut_vec->pos[kk];
- mir->cut_vec->val[jj] = 0.0;
- }
- mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
- }
- mir->cut_vec->val[j] = 0.0;
- }
- ios_clean_vec(mir->cut_vec, 0.0);
- return;
- }
- static void add_cut(glp_tree *tree, struct MIR *mir)
- { /* add constructed cut inequality to the cut pool */
- int m = mir->m;
- int n = mir->n;
- int j, k, len;
- int *ind = xcalloc(1+n, sizeof(int));
- double *val = xcalloc(1+n, sizeof(double));
- len = 0;
- for (j = mir->cut_vec->nnz; j >= 1; j--)
- { k = mir->cut_vec->ind[j];
- xassert(m+1 <= k && k <= m+n);
- len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
- }
- #if 0
- ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
- mir->cut_rhs);
- #else
- glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
- mir->cut_rhs);
- #endif
- xfree(ind);
- xfree(val);
- return;
- }
- static int aggregate_row(glp_tree *tree, struct MIR *mir)
- { /* try to aggregate another row */
- glp_prob *mip = tree->mip;
- int m = mir->m;
- int n = mir->n;
- GLPAIJ *aij;
- IOSVEC *v;
- int ii, j, jj, k, kk, kappa = 0, ret = 0;
- double d1, d2, d, d_max = 0.0;
- /* choose appropriate structural variable in the aggregated row
- to be substituted */
- for (j = 1; j <= mir->agg_vec->nnz; j++)
- { k = mir->agg_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- if (k <= m) continue; /* skip auxiliary var */
- if (mir->isint[k]) continue; /* skip integer var */
- if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
- /* compute distance from x[k] to its lower bound */
- kk = mir->vlb[k];
- if (kk == 0)
- { if (mir->lb[k] == -DBL_MAX)
- d1 = DBL_MAX;
- else
- d1 = mir->x[k] - mir->lb[k];
- }
- else
- { xassert(1 <= kk && kk <= m+n);
- xassert(mir->isint[kk]);
- xassert(mir->lb[k] != -DBL_MAX);
- d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
- }
- /* compute distance from x[k] to its upper bound */
- kk = mir->vub[k];
- if (kk == 0)
- { if (mir->vub[k] == +DBL_MAX)
- d2 = DBL_MAX;
- else
- d2 = mir->ub[k] - mir->x[k];
- }
- else
- { xassert(1 <= kk && kk <= m+n);
- xassert(mir->isint[kk]);
- xassert(mir->ub[k] != +DBL_MAX);
- d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
- }
- /* x[k] cannot be free */
- xassert(d1 != DBL_MAX || d2 != DBL_MAX);
- /* d = min(d1, d2) */
- d = (d1 <= d2 ? d1 : d2);
- xassert(d != DBL_MAX);
- /* should not be close to corresponding bound */
- if (d < 0.001) continue;
- if (d_max < d) d_max = d, kappa = k;
- }
- if (kappa == 0)
- { /* nothing chosen */
- ret = 1;
- goto done;
- }
- /* x[kappa] has been chosen */
- xassert(m+1 <= kappa && kappa <= m+n);
- xassert(!mir->isint[kappa]);
- /* find another row, which have not been used yet, to eliminate
- x[kappa] from the aggregated row */
- for (ii = 1; ii <= m; ii++)
- { if (mir->skip[ii]) continue;
- for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
- if (aij->col->j == kappa - m) break;
- if (aij != NULL && fabs(aij->val) >= 0.001) break;
- }
- if (ii > m)
- { /* nothing found */
- ret = 2;
- goto done;
- }
- /* row ii has been found; include it in the aggregated list */
- mir->agg_cnt++;
- xassert(mir->agg_cnt <= MAXAGGR);
- mir->agg_row[mir->agg_cnt] = ii;
- mir->skip[ii] = 2;
- /* v := new row */
- v = ios_create_vec(m+n);
- ios_set_vj(v, ii, 1.0);
- for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
- ios_set_vj(v, m + aij->col->j, - aij->val);
- #if _MIR_DEBUG
- ios_check_vec(v);
- #endif
- /* perform gaussian elimination to remove x[kappa] */
- j = mir->agg_vec->pos[kappa];
- xassert(j != 0);
- jj = v->pos[kappa];
- xassert(jj != 0);
- ios_linear_comb(mir->agg_vec,
- - mir->agg_vec->val[j] / v->val[jj], v);
- ios_delete_vec(v);
- ios_set_vj(mir->agg_vec, kappa, 0.0);
- #if _MIR_DEBUG
- ios_check_vec(mir->agg_vec);
- #endif
- done: return ret;
- }
- void ios_mir_gen(glp_tree *tree, void *gen)
- { /* main routine to generate MIR cuts */
- glp_prob *mip = tree->mip;
- struct MIR *mir = gen;
- int m = mir->m;
- int n = mir->n;
- int i;
- double r_best;
- xassert(mip->m >= m);
- xassert(mip->n == n);
- /* obtain current point */
- get_current_point(tree, mir);
- #if _MIR_DEBUG
- /* check current point */
- check_current_point(mir);
- #endif
- /* reset bound substitution flags */
- memset(&mir->subst[1], '?', m+n);
- /* try to generate a set of violated MIR cuts */
- for (i = 1; i <= m; i++)
- { if (mir->skip[i]) continue;
- /* use original i-th row as initial aggregated constraint */
- initial_agg_row(tree, mir, i);
- loop: ;
- #if _MIR_DEBUG
- /* check aggregated row */
- check_agg_row(mir);
- #endif
- /* substitute fixed variables into aggregated constraint */
- subst_fixed_vars(mir);
- #if _MIR_DEBUG
- /* check aggregated row */
- check_agg_row(mir);
- #endif
- #if _MIR_DEBUG
- /* check bound substitution flags */
- { int k;
- for (k = 1; k <= m+n; k++)
- xassert(mir->subst[k] == '?');
- }
- #endif
- /* apply bound substitution heuristic */
- bound_subst_heur(mir);
- /* substitute bounds and build modified constraint */
- build_mod_row(mir);
- #if _MIR_DEBUG
- /* check modified row */
- check_mod_row(mir);
- #endif
- /* try to generate violated c-MIR cut for modified row */
- r_best = generate(mir);
- if (r_best > 0.0)
- { /* success */
- #if _MIR_DEBUG
- /* check raw cut before back bound substitution */
- check_raw_cut(mir, r_best);
- #endif
- /* back substitution of original bounds */
- back_subst(mir);
- #if _MIR_DEBUG
- /* check the cut after back bound substitution */
- check_cut_row(mir, r_best);
- #endif
- /* final substitution to eliminate auxiliary variables */
- subst_aux_vars(tree, mir);
- #if _MIR_DEBUG
- /* check the cut after elimination of auxiliaries */
- check_cut_row(mir, r_best);
- #endif
- /* add constructed cut inequality to the cut pool */
- add_cut(tree, mir);
- }
- /* reset bound substitution flags */
- { int j, k;
- for (j = 1; j <= mir->mod_vec->nnz; j++)
- { k = mir->mod_vec->ind[j];
- xassert(1 <= k && k <= m+n);
- xassert(mir->subst[k] != '?');
- mir->subst[k] = '?';
- }
- }
- if (r_best == 0.0)
- { /* failure */
- if (mir->agg_cnt < MAXAGGR)
- { /* try to aggregate another row */
- if (aggregate_row(tree, mir) == 0) goto loop;
- }
- }
- /* unmark rows used in the aggregated constraint */
- { int k, ii;
- for (k = 1; k <= mir->agg_cnt; k++)
- { ii = mir->agg_row[k];
- xassert(1 <= ii && ii <= m);
- xassert(mir->skip[ii] == 2);
- mir->skip[ii] = 0;
- }
- }
- }
- return;
- }
- /***********************************************************************
- * NAME
- *
- * ios_mir_term - terminate MIR cut generator
- *
- * SYNOPSIS
- *
- * #include "glpios.h"
- * void ios_mir_term(void *gen);
- *
- * DESCRIPTION
- *
- * The routine ios_mir_term deletes the MIR cut generator working area
- * freeing all the memory allocated to it. */
- void ios_mir_term(void *gen)
- { struct MIR *mir = gen;
- xfree(mir->skip);
- xfree(mir->isint);
- xfree(mir->lb);
- xfree(mir->vlb);
- xfree(mir->ub);
- xfree(mir->vub);
- xfree(mir->x);
- xfree(mir->agg_row);
- ios_delete_vec(mir->agg_vec);
- xfree(mir->subst);
- ios_delete_vec(mir->mod_vec);
- ios_delete_vec(mir->cut_vec);
- xfree(mir);
- return;
- }
- /* eof */
|