1 /* glpios06.c (MIR cut generator) */
2 
3 /***********************************************************************
4 *  This code is part of GLPK (GNU Linear Programming Kit).
5 *
6 *  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 *  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
8 *  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
9 *  E-mail: <mao@gnu.org>.
10 *
11 *  GLPK is free software: you can redistribute it and/or modify it
12 *  under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation, either version 3 of the License, or
14 *  (at your option) any later version.
15 *
16 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
17 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 *  License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
23 ***********************************************************************/
24 
25 #include "glpios.h"
26 
27 #define _MIR_DEBUG 0
28 
29 #define MAXAGGR 5
30 /* maximal number of rows which can be aggregated */
31 
32 struct MIR
33 {     /* MIR cut generator working area */
34       /*--------------------------------------------------------------*/
35       /* global information valid for the root subproblem */
36       int m;
37       /* number of rows (in the root subproblem) */
38       int n;
39       /* number of columns */
40       char *skip; /* char skip[1+m]; */
41       /* skip[i], 1 <= i <= m, is a flag that means that row i should
42          not be used because (1) it is not suitable, or (2) because it
43          has been used in the aggregated constraint */
44       char *isint; /* char isint[1+m+n]; */
45       /* isint[k], 1 <= k <= m+n, is a flag that means that variable
46          x[k] is integer (otherwise, continuous) */
47       double *lb; /* double lb[1+m+n]; */
48       /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
49          that x[k] has no lower bound */
50       int *vlb; /* int vlb[1+m+n]; */
51       /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
52          which defines variable lower bound x[k] >= lb[k] * x[k']; zero
53          means that x[k] has simple lower bound */
54       double *ub; /* double ub[1+m+n]; */
55       /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
56          that x[k] has no upper bound */
57       int *vub; /* int vub[1+m+n]; */
58       /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
59          which defines variable upper bound x[k] <= ub[k] * x[k']; zero
60          means that x[k] has simple upper bound */
61       /*--------------------------------------------------------------*/
62       /* current (fractional) point to be separated */
63       double *x; /* double x[1+m+n]; */
64       /* x[k] is current value of auxiliary (1 <= k <= m) or structural
65          (m+1 <= k <= m+n) variable */
66       /*--------------------------------------------------------------*/
67       /* aggregated constraint sum a[k] * x[k] = b, which is a linear
68          combination of original constraints transformed to equalities
69          by introducing auxiliary variables */
70       int agg_cnt;
71       /* number of rows (original constraints) used to build aggregated
72          constraint, 1 <= agg_cnt <= MAXAGGR */
73       int *agg_row; /* int agg_row[1+MAXAGGR]; */
74       /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
75          aggregated constraint */
76       IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */
77       /* sparse vector of aggregated constraint coefficients, a[k] */
78       double agg_rhs;
79       /* right-hand side of the aggregated constraint, b */
80       /*--------------------------------------------------------------*/
81       /* bound substitution flags for modified constraint */
82       char *subst; /* char subst[1+m+n]; */
83       /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
84          variable x[k]:
85          '?' - x[k] is missing in modified constraint
86          'L' - x[k] = (lower bound) + x'[k]
87          'U' - x[k] = (upper bound) - x'[k] */
88       /*--------------------------------------------------------------*/
89       /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
90          derived from aggregated constraint by substituting bounds;
91          note that due to substitution of variable bounds there may be
92          additional terms in the modified constraint */
93       IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */
94       /* sparse vector of modified constraint coefficients, a'[k] */
95       double mod_rhs;
96       /* right-hand side of the modified constraint, b' */
97       /*--------------------------------------------------------------*/
98       /* cutting plane sum alpha[k] * x[k] <= beta */
99       IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */
100       /* sparse vector of cutting plane coefficients, alpha[k] */
101       double cut_rhs;
102       /* right-hand size of the cutting plane, beta */
103 };
104 
105 /***********************************************************************
106 *  NAME
107 *
108 *  ios_mir_init - initialize MIR cut generator
109 *
110 *  SYNOPSIS
111 *
112 *  #include "glpios.h"
113 *  void *ios_mir_init(glp_tree *tree);
114 *
115 *  DESCRIPTION
116 *
117 *  The routine ios_mir_init initializes the MIR cut generator assuming
118 *  that the current subproblem is the root subproblem.
119 *
120 *  RETURNS
121 *
122 *  The routine ios_mir_init returns a pointer to the MIR cut generator
123 *  working area. */
124 
set_row_attrib(glp_tree * tree,struct MIR * mir)125 static void set_row_attrib(glp_tree *tree, struct MIR *mir)
126 {     /* set global row attributes */
127       glp_prob *mip = tree->mip;
128       int m = mir->m;
129       int k;
130       for (k = 1; k <= m; k++)
131       {  GLPROW *row = mip->row[k];
132          mir->skip[k] = 0;
133          mir->isint[k] = 0;
134          switch (row->type)
135          {  case GLP_FR:
136                mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
137             case GLP_LO:
138                mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
139             case GLP_UP:
140                mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
141             case GLP_DB:
142                mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
143             case GLP_FX:
144                mir->lb[k] = mir->ub[k] = row->lb; break;
145             default:
146                xassert(row != row);
147          }
148          mir->vlb[k] = mir->vub[k] = 0;
149       }
150       return;
151 }
152 
set_col_attrib(glp_tree * tree,struct MIR * mir)153 static void set_col_attrib(glp_tree *tree, struct MIR *mir)
154 {     /* set global column attributes */
155       glp_prob *mip = tree->mip;
156       int m = mir->m;
157       int n = mir->n;
158       int k;
159       for (k = m+1; k <= m+n; k++)
160       {  GLPCOL *col = mip->col[k-m];
161          switch (col->kind)
162          {  case GLP_CV:
163                mir->isint[k] = 0; break;
164             case GLP_IV:
165                mir->isint[k] = 1; break;
166             default:
167                xassert(col != col);
168          }
169          switch (col->type)
170          {  case GLP_FR:
171                mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
172             case GLP_LO:
173                mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
174             case GLP_UP:
175                mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
176             case GLP_DB:
177                mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
178             case GLP_FX:
179                mir->lb[k] = mir->ub[k] = col->lb; break;
180             default:
181                xassert(col != col);
182          }
183          mir->vlb[k] = mir->vub[k] = 0;
184       }
185       return;
186 }
187 
set_var_bounds(glp_tree * tree,struct MIR * mir)188 static void set_var_bounds(glp_tree *tree, struct MIR *mir)
189 {     /* set variable bounds */
190       glp_prob *mip = tree->mip;
191       int m = mir->m;
192       GLPAIJ *aij;
193       int i, k1, k2;
194       double a1, a2;
195       for (i = 1; i <= m; i++)
196       {  /* we need the row to be '>= 0' or '<= 0' */
197          if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
198                mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
199          /* take first term */
200          aij = mip->row[i]->ptr;
201          if (aij == NULL) continue;
202          k1 = m + aij->col->j, a1 = aij->val;
203          /* take second term */
204          aij = aij->r_next;
205          if (aij == NULL) continue;
206          k2 = m + aij->col->j, a2 = aij->val;
207          /* there must be only two terms */
208          if (aij->r_next != NULL) continue;
209          /* interchange terms, if needed */
210          if (!mir->isint[k1] && mir->isint[k2])
211             ;
212          else if (mir->isint[k1] && !mir->isint[k2])
213          {  k2 = k1, a2 = a1;
214             k1 = m + aij->col->j, a1 = aij->val;
215          }
216          else
217          {  /* both terms are either continuous or integer */
218             continue;
219          }
220          /* x[k2] should be double-bounded */
221          if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
222              mir->lb[k2] == mir->ub[k2]) continue;
223          /* change signs, if necessary */
224          if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
225          /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
226             is continuous, x2 is integer */
227          if (a1 > 0.0)
228          {  /* x1 >= - (a2 / a1) * x2 */
229             if (mir->vlb[k1] == 0)
230             {  /* set variable lower bound for x1 */
231                mir->lb[k1] = - a2 / a1;
232                mir->vlb[k1] = k2;
233                /* the row should not be used */
234                mir->skip[i] = 1;
235             }
236          }
237          else /* a1 < 0.0 */
238          {  /* x1 <= - (a2 / a1) * x2 */
239             if (mir->vub[k1] == 0)
240             {  /* set variable upper bound for x1 */
241                mir->ub[k1] = - a2 / a1;
242                mir->vub[k1] = k2;
243                /* the row should not be used */
244                mir->skip[i] = 1;
245             }
246          }
247       }
248       return;
249 }
250 
mark_useless_rows(glp_tree * tree,struct MIR * mir)251 static void mark_useless_rows(glp_tree *tree, struct MIR *mir)
252 {     /* mark rows which should not be used */
253       glp_prob *mip = tree->mip;
254       int m = mir->m;
255       GLPAIJ *aij;
256       int i, k, nv;
257       for (i = 1; i <= m; i++)
258       {  /* free rows should not be used */
259          if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
260          {  mir->skip[i] = 1;
261             continue;
262          }
263          nv = 0;
264          for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
265          {  k = m + aij->col->j;
266             /* rows with free variables should not be used */
267             if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
268             {  mir->skip[i] = 1;
269                break;
270             }
271             /* rows with integer variables having infinite (lower or
272                upper) bound should not be used */
273             if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
274                 mir->isint[k] && mir->ub[k] == +DBL_MAX)
275             {  mir->skip[i] = 1;
276                break;
277             }
278             /* count non-fixed variables */
279             if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
280                   mir->lb[k] == mir->ub[k])) nv++;
281          }
282          /* rows with all variables fixed should not be used */
283          if (nv == 0)
284          {  mir->skip[i] = 1;
285             continue;
286          }
287       }
288       return;
289 }
290 
ios_mir_init(glp_tree * tree)291 void *ios_mir_init(glp_tree *tree)
292 {     /* initialize MIR cut generator */
293       glp_prob *mip = tree->mip;
294       int m = mip->m;
295       int n = mip->n;
296       struct MIR *mir;
297 #if _MIR_DEBUG
298       xprintf("ios_mir_init: warning: debug mode enabled\n");
299 #endif
300       /* allocate working area */
301       mir = xmalloc(sizeof(struct MIR));
302       mir->m = m;
303       mir->n = n;
304       mir->skip = xcalloc(1+m, sizeof(char));
305       mir->isint = xcalloc(1+m+n, sizeof(char));
306       mir->lb = xcalloc(1+m+n, sizeof(double));
307       mir->vlb = xcalloc(1+m+n, sizeof(int));
308       mir->ub = xcalloc(1+m+n, sizeof(double));
309       mir->vub = xcalloc(1+m+n, sizeof(int));
310       mir->x = xcalloc(1+m+n, sizeof(double));
311       mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
312       mir->agg_vec = ios_create_vec(m+n);
313       mir->subst = xcalloc(1+m+n, sizeof(char));
314       mir->mod_vec = ios_create_vec(m+n);
315       mir->cut_vec = ios_create_vec(m+n);
316       /* set global row attributes */
317       set_row_attrib(tree, mir);
318       /* set global column attributes */
319       set_col_attrib(tree, mir);
320       /* set variable bounds */
321       set_var_bounds(tree, mir);
322       /* mark rows which should not be used */
323       mark_useless_rows(tree, mir);
324       return mir;
325 }
326 
327 /***********************************************************************
328 *  NAME
329 *
330 *  ios_mir_gen - generate MIR cuts
331 *
332 *  SYNOPSIS
333 *
334 *  #include "glpios.h"
335 *  void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool);
336 *
337 *  DESCRIPTION
338 *
339 *  The routine ios_mir_gen generates MIR cuts for the current point and
340 *  adds them to the cut pool. */
341 
get_current_point(glp_tree * tree,struct MIR * mir)342 static void get_current_point(glp_tree *tree, struct MIR *mir)
343 {     /* obtain current point */
344       glp_prob *mip = tree->mip;
345       int m = mir->m;
346       int n = mir->n;
347       int k;
348       for (k = 1; k <= m; k++)
349          mir->x[k] = mip->row[k]->prim;
350       for (k = m+1; k <= m+n; k++)
351          mir->x[k] = mip->col[k-m]->prim;
352       return;
353 }
354 
355 #if _MIR_DEBUG
check_current_point(struct MIR * mir)356 static void check_current_point(struct MIR *mir)
357 {     /* check current point */
358       int m = mir->m;
359       int n = mir->n;
360       int k, kk;
361       double lb, ub, eps;
362       for (k = 1; k <= m+n; k++)
363       {  /* determine lower bound */
364          lb = mir->lb[k];
365          kk = mir->vlb[k];
366          if (kk != 0)
367          {  xassert(lb != -DBL_MAX);
368             xassert(!mir->isint[k]);
369             xassert(mir->isint[kk]);
370             lb *= mir->x[kk];
371          }
372          /* check lower bound */
373          if (lb != -DBL_MAX)
374          {  eps = 1e-6 * (1.0 + fabs(lb));
375             xassert(mir->x[k] >= lb - eps);
376          }
377          /* determine upper bound */
378          ub = mir->ub[k];
379          kk = mir->vub[k];
380          if (kk != 0)
381          {  xassert(ub != +DBL_MAX);
382             xassert(!mir->isint[k]);
383             xassert(mir->isint[kk]);
384             ub *= mir->x[kk];
385          }
386          /* check upper bound */
387          if (ub != +DBL_MAX)
388          {  eps = 1e-6 * (1.0 + fabs(ub));
389             xassert(mir->x[k] <= ub + eps);
390          }
391       }
392       return;
393 }
394 #endif
395 
initial_agg_row(glp_tree * tree,struct MIR * mir,int i)396 static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i)
397 {     /* use original i-th row as initial aggregated constraint */
398       glp_prob *mip = tree->mip;
399       int m = mir->m;
400       GLPAIJ *aij;
401       xassert(1 <= i && i <= m);
402       xassert(!mir->skip[i]);
403       /* mark i-th row in order not to use it in the same aggregated
404          constraint */
405       mir->skip[i] = 2;
406       mir->agg_cnt = 1;
407       mir->agg_row[1] = i;
408       /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
409          variable of row i, x[m+j] are structural variables */
410       ios_clear_vec(mir->agg_vec);
411       ios_set_vj(mir->agg_vec, i, 1.0);
412       for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
413          ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
414       mir->agg_rhs = 0.0;
415 #if _MIR_DEBUG
416       ios_check_vec(mir->agg_vec);
417 #endif
418       return;
419 }
420 
421 #if _MIR_DEBUG
check_agg_row(struct MIR * mir)422 static void check_agg_row(struct MIR *mir)
423 {     /* check aggregated constraint */
424       int m = mir->m;
425       int n = mir->n;
426       int j, k;
427       double r, big;
428       /* compute the residual r = sum a[k] * x[k] - b and determine
429          big = max(1, |a[k]|, |b|) */
430       r = 0.0, big = 1.0;
431       for (j = 1; j <= mir->agg_vec->nnz; j++)
432       {  k = mir->agg_vec->ind[j];
433          xassert(1 <= k && k <= m+n);
434          r += mir->agg_vec->val[j] * mir->x[k];
435          if (big < fabs(mir->agg_vec->val[j]))
436             big = fabs(mir->agg_vec->val[j]);
437       }
438       r -= mir->agg_rhs;
439       if (big < fabs(mir->agg_rhs))
440          big = fabs(mir->agg_rhs);
441       /* the residual must be close to zero */
442       xassert(fabs(r) <= 1e-6 * big);
443       return;
444 }
445 #endif
446 
subst_fixed_vars(struct MIR * mir)447 static void subst_fixed_vars(struct MIR *mir)
448 {     /* substitute fixed variables into aggregated constraint */
449       int m = mir->m;
450       int n = mir->n;
451       int j, k;
452       for (j = 1; j <= mir->agg_vec->nnz; j++)
453       {  k = mir->agg_vec->ind[j];
454          xassert(1 <= k && k <= m+n);
455          if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
456              mir->lb[k] == mir->ub[k])
457          {  /* x[k] is fixed */
458             mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
459             mir->agg_vec->val[j] = 0.0;
460          }
461       }
462       /* remove terms corresponding to fixed variables */
463       ios_clean_vec(mir->agg_vec, DBL_EPSILON);
464 #if _MIR_DEBUG
465       ios_check_vec(mir->agg_vec);
466 #endif
467       return;
468 }
469 
bound_subst_heur(struct MIR * mir)470 static void bound_subst_heur(struct MIR *mir)
471 {     /* bound substitution heuristic */
472       int m = mir->m;
473       int n = mir->n;
474       int j, k, kk;
475       double d1, d2;
476       for (j = 1; j <= mir->agg_vec->nnz; j++)
477       {  k = mir->agg_vec->ind[j];
478          xassert(1 <= k && k <= m+n);
479          if (mir->isint[k]) continue; /* skip integer variable */
480          /* compute distance from x[k] to its lower bound */
481          kk = mir->vlb[k];
482          if (kk == 0)
483          {  if (mir->lb[k] == -DBL_MAX)
484                d1 = DBL_MAX;
485             else
486                d1 = mir->x[k] - mir->lb[k];
487          }
488          else
489          {  xassert(1 <= kk && kk <= m+n);
490             xassert(mir->isint[kk]);
491             xassert(mir->lb[k] != -DBL_MAX);
492             d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
493          }
494          /* compute distance from x[k] to its upper bound */
495          kk = mir->vub[k];
496          if (kk == 0)
497          {  if (mir->vub[k] == +DBL_MAX)
498                d2 = DBL_MAX;
499             else
500                d2 = mir->ub[k] - mir->x[k];
501          }
502          else
503          {  xassert(1 <= kk && kk <= m+n);
504             xassert(mir->isint[kk]);
505             xassert(mir->ub[k] != +DBL_MAX);
506             d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
507          }
508          /* x[k] cannot be free */
509          xassert(d1 != DBL_MAX || d2 != DBL_MAX);
510          /* choose the bound which is closer to x[k] */
511          xassert(mir->subst[k] == '?');
512          if (d1 <= d2)
513             mir->subst[k] = 'L';
514          else
515             mir->subst[k] = 'U';
516       }
517       return;
518 }
519 
build_mod_row(struct MIR * mir)520 static void build_mod_row(struct MIR *mir)
521 {     /* substitute bounds and build modified constraint */
522       int m = mir->m;
523       int n = mir->n;
524       int j, jj, k, kk;
525       /* initially modified constraint is aggregated constraint */
526       ios_copy_vec(mir->mod_vec, mir->agg_vec);
527       mir->mod_rhs = mir->agg_rhs;
528 #if _MIR_DEBUG
529       ios_check_vec(mir->mod_vec);
530 #endif
531       /* substitute bounds for continuous variables; note that due to
532          substitution of variable bounds additional terms may appear in
533          modified constraint */
534       for (j = mir->mod_vec->nnz; j >= 1; j--)
535       {  k = mir->mod_vec->ind[j];
536          xassert(1 <= k && k <= m+n);
537          if (mir->isint[k]) continue; /* skip integer variable */
538          if (mir->subst[k] == 'L')
539          {  /* x[k] = (lower bound) + x'[k] */
540             xassert(mir->lb[k] != -DBL_MAX);
541             kk = mir->vlb[k];
542             if (kk == 0)
543             {  /* x[k] = lb[k] + x'[k] */
544                mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
545             }
546             else
547             {  /* x[k] = lb[k] * x[kk] + x'[k] */
548                xassert(mir->isint[kk]);
549                jj = mir->mod_vec->pos[kk];
550                if (jj == 0)
551                {  ios_set_vj(mir->mod_vec, kk, 1.0);
552                   jj = mir->mod_vec->pos[kk];
553                   mir->mod_vec->val[jj] = 0.0;
554                }
555                mir->mod_vec->val[jj] +=
556                   mir->mod_vec->val[j] * mir->lb[k];
557             }
558          }
559          else if (mir->subst[k] == 'U')
560          {  /* x[k] = (upper bound) - x'[k] */
561             xassert(mir->ub[k] != +DBL_MAX);
562             kk = mir->vub[k];
563             if (kk == 0)
564             {  /* x[k] = ub[k] - x'[k] */
565                mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
566             }
567             else
568             {  /* x[k] = ub[k] * x[kk] - x'[k] */
569                xassert(mir->isint[kk]);
570                jj = mir->mod_vec->pos[kk];
571                if (jj == 0)
572                {  ios_set_vj(mir->mod_vec, kk, 1.0);
573                   jj = mir->mod_vec->pos[kk];
574                   mir->mod_vec->val[jj] = 0.0;
575                }
576                mir->mod_vec->val[jj] +=
577                   mir->mod_vec->val[j] * mir->ub[k];
578             }
579             mir->mod_vec->val[j] = - mir->mod_vec->val[j];
580          }
581          else
582             xassert(k != k);
583       }
584 #if _MIR_DEBUG
585       ios_check_vec(mir->mod_vec);
586 #endif
587       /* substitute bounds for integer variables */
588       for (j = 1; j <= mir->mod_vec->nnz; j++)
589       {  k = mir->mod_vec->ind[j];
590          xassert(1 <= k && k <= m+n);
591          if (!mir->isint[k]) continue; /* skip continuous variable */
592          xassert(mir->subst[k] == '?');
593          xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
594          xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
595          if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
596          {  /* x[k] = lb[k] + x'[k] */
597             mir->subst[k] = 'L';
598             mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
599          }
600          else
601          {  /* x[k] = ub[k] - x'[k] */
602             mir->subst[k] = 'U';
603             mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
604             mir->mod_vec->val[j] = - mir->mod_vec->val[j];
605          }
606       }
607 #if _MIR_DEBUG
608       ios_check_vec(mir->mod_vec);
609 #endif
610       return;
611 }
612 
613 #if _MIR_DEBUG
check_mod_row(struct MIR * mir)614 static void check_mod_row(struct MIR *mir)
615 {     /* check modified constraint */
616       int m = mir->m;
617       int n = mir->n;
618       int j, k, kk;
619       double r, big, x;
620       /* compute the residual r = sum a'[k] * x'[k] - b' and determine
621          big = max(1, |a[k]|, |b|) */
622       r = 0.0, big = 1.0;
623       for (j = 1; j <= mir->mod_vec->nnz; j++)
624       {  k = mir->mod_vec->ind[j];
625          xassert(1 <= k && k <= m+n);
626          if (mir->subst[k] == 'L')
627          {  /* x'[k] = x[k] - (lower bound) */
628             xassert(mir->lb[k] != -DBL_MAX);
629             kk = mir->vlb[k];
630             if (kk == 0)
631                x = mir->x[k] - mir->lb[k];
632             else
633                x = mir->x[k] - mir->lb[k] * mir->x[kk];
634          }
635          else if (mir->subst[k] == 'U')
636          {  /* x'[k] = (upper bound) - x[k] */
637             xassert(mir->ub[k] != +DBL_MAX);
638             kk = mir->vub[k];
639             if (kk == 0)
640                x = mir->ub[k] - mir->x[k];
641             else
642                x = mir->ub[k] * mir->x[kk] - mir->x[k];
643          }
644          else
645             xassert(k != k);
646          r += mir->mod_vec->val[j] * x;
647          if (big < fabs(mir->mod_vec->val[j]))
648             big = fabs(mir->mod_vec->val[j]);
649       }
650       r -= mir->mod_rhs;
651       if (big < fabs(mir->mod_rhs))
652          big = fabs(mir->mod_rhs);
653       /* the residual must be close to zero */
654       xassert(fabs(r) <= 1e-6 * big);
655       return;
656 }
657 #endif
658 
659 /***********************************************************************
660 *  mir_ineq - construct MIR inequality
661 *
662 *  Given the single constraint mixed integer set
663 *
664 *                    |N|
665 *     X = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s},
666 *                    +      +  j in N
667 *
668 *  this routine constructs the mixed integer rounding (MIR) inequality
669 *
670 *     sum   alpha[j] * x[j] <= beta + gamma * s,
671 *    j in N
672 *
673 *  which is valid for X.
674 *
675 *  If the MIR inequality has been successfully constructed, the routine
676 *  returns zero. Otherwise, if b is close to nearest integer, there may
677 *  be numeric difficulties due to big coefficients; so in this case the
678 *  routine returns non-zero. */
679 
mir_ineq(const int n,const double a[],const double b,double alpha[],double * beta,double * gamma)680 static int mir_ineq(const int n, const double a[], const double b,
681       double alpha[], double *beta, double *gamma)
682 {     int j;
683       double f, t;
684       if (fabs(b - floor(b + .5)) < 0.01)
685          return 1;
686       f = b - floor(b);
687       for (j = 1; j <= n; j++)
688       {  t = (a[j] - floor(a[j])) - f;
689          if (t <= 0.0)
690             alpha[j] = floor(a[j]);
691          else
692             alpha[j] = floor(a[j]) + t / (1.0 - f);
693       }
694       *beta = floor(b);
695       *gamma = 1.0 / (1.0 - f);
696       return 0;
697 }
698 
699 /***********************************************************************
700 *  cmir_ineq - construct c-MIR inequality
701 *
702 *  Given the mixed knapsack set
703 *
704 *      MK              |N|
705 *     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
706 *                      +      +  j in N
707 *
708 *             x[j] <= u[j]},
709 *
710 *  a subset C of variables to be complemented, and a divisor delta > 0,
711 *  this routine constructs the complemented MIR (c-MIR) inequality
712 *
713 *     sum   alpha[j] * x[j] <= beta + gamma * s,
714 *    j in N
715 *                      MK
716 *  which is valid for X  .
717 *
718 *  If the c-MIR inequality has been successfully constructed, the
719 *  routine returns zero. Otherwise, if there is a risk of numerical
720 *  difficulties due to big coefficients (see comments to the routine
721 *  mir_ineq), the routine cmir_ineq returns non-zero. */
722 
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)723 static int cmir_ineq(const int n, const double a[], const double b,
724       const double u[], const char cset[], const double delta,
725       double alpha[], double *beta, double *gamma)
726 {     int j;
727       double *aa, bb;
728       aa = alpha, bb = b;
729       for (j = 1; j <= n; j++)
730       {  aa[j] = a[j] / delta;
731          if (cset[j])
732             aa[j] = - aa[j], bb -= a[j] * u[j];
733       }
734       bb /= delta;
735       if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
736       for (j = 1; j <= n; j++)
737       {  if (cset[j])
738             alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
739       }
740       *gamma /= delta;
741       return 0;
742 }
743 
744 /***********************************************************************
745 *  cmir_sep - c-MIR separation heuristic
746 *
747 *  Given the mixed knapsack set
748 *
749 *      MK              |N|
750 *     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
751 *                      +      +  j in N
752 *
753 *             x[j] <= u[j]}
754 *
755 *                           *   *
756 *  and a fractional point (x , s ), this routine tries to construct
757 *  c-MIR inequality
758 *
759 *     sum   alpha[j] * x[j] <= beta + gamma * s,
760 *    j in N
761 *                      MK
762 *  which is valid for X   and has (desirably maximal) violation at the
763 *  fractional point given. This is attained by choosing an appropriate
764 *  set C of variables to be complemented and a divisor delta > 0, which
765 *  together define corresponding c-MIR inequality.
766 *
767 *  If a violated c-MIR inequality has been successfully constructed,
768 *  the routine returns its violation:
769 *
770 *                       *                      *
771 *     sum   alpha[j] * x [j] - beta - gamma * s ,
772 *    j in N
773 *
774 *  which is positive. In case of failure the routine returns zero. */
775 
776 struct vset { int j; double v; };
777 
cmir_cmp(const void * p1,const void * p2)778 static int cmir_cmp(const void *p1, const void *p2)
779 {     const struct vset *v1 = p1, *v2 = p2;
780       if (v1->v < v2->v) return -1;
781       if (v1->v > v2->v) return +1;
782       return 0;
783 }
784 
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)785 static double cmir_sep(const int n, const double a[], const double b,
786       const double u[], const double x[], const double s,
787       double alpha[], double *beta, double *gamma)
788 {     int fail, j, k, nv, v;
789       double delta, eps, d_try[1+3], r, r_best;
790       char *cset;
791       struct vset *vset;
792       /* allocate working arrays */
793       cset = xcalloc(1+n, sizeof(char));
794       vset = xcalloc(1+n, sizeof(struct vset));
795       /* choose initial C */
796       for (j = 1; j <= n; j++)
797          cset[j] = (char)(x[j] >= 0.5 * u[j]);
798       /* choose initial delta */
799       r_best = delta = 0.0;
800       for (j = 1; j <= n; j++)
801       {  xassert(a[j] != 0.0);
802          /* if x[j] is close to its bounds, skip it */
803          eps = 1e-9 * (1.0 + fabs(u[j]));
804          if (x[j] < eps || x[j] > u[j] - eps) continue;
805          /* try delta = |a[j]| to construct c-MIR inequality */
806          fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
807             gamma);
808          if (fail) continue;
809          /* compute violation */
810          r = - (*beta) - (*gamma) * s;
811          for (k = 1; k <= n; k++) r += alpha[k] * x[k];
812          if (r_best < r) r_best = r, delta = fabs(a[j]);
813       }
814       if (r_best < 0.001) r_best = 0.0;
815       if (r_best == 0.0) goto done;
816       xassert(delta > 0.0);
817       /* try to increase violation by dividing delta by 2, 4, and 8,
818          respectively */
819       d_try[1] = delta / 2.0;
820       d_try[2] = delta / 4.0;
821       d_try[3] = delta / 8.0;
822       for (j = 1; j <= 3; j++)
823       {  /* construct c-MIR inequality */
824          fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
825             gamma);
826          if (fail) continue;
827          /* compute violation */
828          r = - (*beta) - (*gamma) * s;
829          for (k = 1; k <= n; k++) r += alpha[k] * x[k];
830          if (r_best < r) r_best = r, delta = d_try[j];
831       }
832       /* build subset of variables lying strictly between their bounds
833          and order it by nondecreasing values of |x[j] - u[j]/2| */
834       nv = 0;
835       for (j = 1; j <= n; j++)
836       {  /* if x[j] is close to its bounds, skip it */
837          eps = 1e-9 * (1.0 + fabs(u[j]));
838          if (x[j] < eps || x[j] > u[j] - eps) continue;
839          /* add x[j] to the subset */
840          nv++;
841          vset[nv].j = j;
842          vset[nv].v = fabs(x[j] - 0.5 * u[j]);
843       }
844       qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
845       /* try to increase violation by successively complementing each
846          variable in the subset */
847       for (v = 1; v <= nv; v++)
848       {  j = vset[v].j;
849          /* replace x[j] by its complement or vice versa */
850          cset[j] = (char)!cset[j];
851          /* construct c-MIR inequality */
852          fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
853          /* restore the variable */
854          cset[j] = (char)!cset[j];
855          /* do not replace the variable in case of failure */
856          if (fail) continue;
857          /* compute violation */
858          r = - (*beta) - (*gamma) * s;
859          for (k = 1; k <= n; k++) r += alpha[k] * x[k];
860          if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
861       }
862       /* construct the best c-MIR inequality chosen */
863       fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
864       xassert(!fail);
865 done: /* free working arrays */
866       xfree(cset);
867       xfree(vset);
868       /* return to the calling routine */
869       return r_best;
870 }
871 
generate(struct MIR * mir)872 static double generate(struct MIR *mir)
873 {     /* try to generate violated c-MIR cut for modified constraint */
874       int m = mir->m;
875       int n = mir->n;
876       int j, k, kk, nint;
877       double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
878       ios_copy_vec(mir->cut_vec, mir->mod_vec);
879       mir->cut_rhs = mir->mod_rhs;
880       /* remove small terms, which can appear due to substitution of
881          variable bounds */
882       ios_clean_vec(mir->cut_vec, DBL_EPSILON);
883 #if _MIR_DEBUG
884       ios_check_vec(mir->cut_vec);
885 #endif
886       /* remove positive continuous terms to obtain MK relaxation */
887       for (j = 1; j <= mir->cut_vec->nnz; j++)
888       {  k = mir->cut_vec->ind[j];
889          xassert(1 <= k && k <= m+n);
890          if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
891             mir->cut_vec->val[j] = 0.0;
892       }
893       ios_clean_vec(mir->cut_vec, 0.0);
894 #if _MIR_DEBUG
895       ios_check_vec(mir->cut_vec);
896 #endif
897       /* move integer terms to the beginning of the sparse vector and
898          determine the number of integer variables */
899       nint = 0;
900       for (j = 1; j <= mir->cut_vec->nnz; j++)
901       {  k = mir->cut_vec->ind[j];
902          xassert(1 <= k && k <= m+n);
903          if (mir->isint[k])
904          {  double temp;
905             nint++;
906             /* interchange elements [nint] and [j] */
907             kk = mir->cut_vec->ind[nint];
908             mir->cut_vec->pos[k] = nint;
909             mir->cut_vec->pos[kk] = j;
910             mir->cut_vec->ind[nint] = k;
911             mir->cut_vec->ind[j] = kk;
912             temp = mir->cut_vec->val[nint];
913             mir->cut_vec->val[nint] = mir->cut_vec->val[j];
914             mir->cut_vec->val[j] = temp;
915          }
916       }
917 #if _MIR_DEBUG
918       ios_check_vec(mir->cut_vec);
919 #endif
920       /* if there is no integer variable, nothing to generate */
921       if (nint == 0) goto done;
922       /* allocate working arrays */
923       u = xcalloc(1+nint, sizeof(double));
924       x = xcalloc(1+nint, sizeof(double));
925       alpha = xcalloc(1+nint, sizeof(double));
926       /* determine u and x */
927       for (j = 1; j <= nint; j++)
928       {  k = mir->cut_vec->ind[j];
929          xassert(m+1 <= k && k <= m+n);
930          xassert(mir->isint[k]);
931          u[j] = mir->ub[k] - mir->lb[k];
932          xassert(u[j] >= 1.0);
933          if (mir->subst[k] == 'L')
934             x[j] = mir->x[k] - mir->lb[k];
935          else if (mir->subst[k] == 'U')
936             x[j] = mir->ub[k] - mir->x[k];
937          else
938             xassert(k != k);
939          xassert(x[j] >= -0.001);
940          if (x[j] < 0.0) x[j] = 0.0;
941       }
942       /* compute s = - sum of continuous terms */
943       s = 0.0;
944       for (j = nint+1; j <= mir->cut_vec->nnz; j++)
945       {  double x;
946          k = mir->cut_vec->ind[j];
947          xassert(1 <= k && k <= m+n);
948          /* must be continuous */
949          xassert(!mir->isint[k]);
950          if (mir->subst[k] == 'L')
951          {  xassert(mir->lb[k] != -DBL_MAX);
952             kk = mir->vlb[k];
953             if (kk == 0)
954                x = mir->x[k] - mir->lb[k];
955             else
956                x = mir->x[k] - mir->lb[k] * mir->x[kk];
957          }
958          else if (mir->subst[k] == 'U')
959          {  xassert(mir->ub[k] != +DBL_MAX);
960             kk = mir->vub[k];
961             if (kk == 0)
962                x = mir->ub[k] - mir->x[k];
963             else
964                x = mir->ub[k] * mir->x[kk] - mir->x[k];
965          }
966          else
967             xassert(k != k);
968          xassert(x >= -0.001);
969          if (x < 0.0) x = 0.0;
970          s -= mir->cut_vec->val[j] * x;
971       }
972       xassert(s >= 0.0);
973       /* apply heuristic to obtain most violated c-MIR inequality */
974       b = mir->cut_rhs;
975       r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
976          &beta, &gamma);
977       if (r_best == 0.0) goto skip;
978       xassert(r_best > 0.0);
979       /* convert to raw cut */
980       /* sum alpha[j] * x[j] <= beta + gamma * s */
981       for (j = 1; j <= nint; j++)
982          mir->cut_vec->val[j] = alpha[j];
983       for (j = nint+1; j <= mir->cut_vec->nnz; j++)
984       {  k = mir->cut_vec->ind[j];
985          if (k <= m+n) mir->cut_vec->val[j] *= gamma;
986       }
987       mir->cut_rhs = beta;
988 #if _MIR_DEBUG
989       ios_check_vec(mir->cut_vec);
990 #endif
991 skip: /* free working arrays */
992       xfree(u);
993       xfree(x);
994       xfree(alpha);
995 done: return r_best;
996 }
997 
998 #if _MIR_DEBUG
check_raw_cut(struct MIR * mir,double r_best)999 static void check_raw_cut(struct MIR *mir, double r_best)
1000 {     /* check raw cut before back bound substitution */
1001       int m = mir->m;
1002       int n = mir->n;
1003       int j, k, kk;
1004       double r, big, x;
1005       /* compute the residual r = sum a[k] * x[k] - b and determine
1006          big = max(1, |a[k]|, |b|) */
1007       r = 0.0, big = 1.0;
1008       for (j = 1; j <= mir->cut_vec->nnz; j++)
1009       {  k = mir->cut_vec->ind[j];
1010          xassert(1 <= k && k <= m+n);
1011          if (mir->subst[k] == 'L')
1012          {  xassert(mir->lb[k] != -DBL_MAX);
1013             kk = mir->vlb[k];
1014             if (kk == 0)
1015                x = mir->x[k] - mir->lb[k];
1016             else
1017                x = mir->x[k] - mir->lb[k] * mir->x[kk];
1018          }
1019          else if (mir->subst[k] == 'U')
1020          {  xassert(mir->ub[k] != +DBL_MAX);
1021             kk = mir->vub[k];
1022             if (kk == 0)
1023                x = mir->ub[k] - mir->x[k];
1024             else
1025                x = mir->ub[k] * mir->x[kk] - mir->x[k];
1026          }
1027          else
1028             xassert(k != k);
1029          r += mir->cut_vec->val[j] * x;
1030          if (big < fabs(mir->cut_vec->val[j]))
1031             big = fabs(mir->cut_vec->val[j]);
1032       }
1033       r -= mir->cut_rhs;
1034       if (big < fabs(mir->cut_rhs))
1035          big = fabs(mir->cut_rhs);
1036       /* the residual must be close to r_best */
1037       xassert(fabs(r - r_best) <= 1e-6 * big);
1038       return;
1039 }
1040 #endif
1041 
back_subst(struct MIR * mir)1042 static void back_subst(struct MIR *mir)
1043 {     /* back substitution of original bounds */
1044       int m = mir->m;
1045       int n = mir->n;
1046       int j, jj, k, kk;
1047       /* at first, restore bounds of integer variables (because on
1048          restoring variable bounds of continuous variables we need
1049          original, not shifted, bounds of integer variables) */
1050       for (j = 1; j <= mir->cut_vec->nnz; j++)
1051       {  k = mir->cut_vec->ind[j];
1052          xassert(1 <= k && k <= m+n);
1053          if (!mir->isint[k]) continue; /* skip continuous */
1054          if (mir->subst[k] == 'L')
1055          {  /* x'[k] = x[k] - lb[k] */
1056             xassert(mir->lb[k] != -DBL_MAX);
1057             xassert(mir->vlb[k] == 0);
1058             mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
1059          }
1060          else if (mir->subst[k] == 'U')
1061          {  /* x'[k] = ub[k] - x[k] */
1062             xassert(mir->ub[k] != +DBL_MAX);
1063             xassert(mir->vub[k] == 0);
1064             mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
1065             mir->cut_vec->val[j] = - mir->cut_vec->val[j];
1066          }
1067          else
1068             xassert(k != k);
1069       }
1070       /* now restore bounds of continuous variables */
1071       for (j = 1; j <= mir->cut_vec->nnz; j++)
1072       {  k = mir->cut_vec->ind[j];
1073          xassert(1 <= k && k <= m+n);
1074          if (mir->isint[k]) continue; /* skip integer */
1075          if (mir->subst[k] == 'L')
1076          {  /* x'[k] = x[k] - (lower bound) */
1077             xassert(mir->lb[k] != -DBL_MAX);
1078             kk = mir->vlb[k];
1079             if (kk == 0)
1080             {  /* x'[k] = x[k] - lb[k] */
1081                mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
1082             }
1083             else
1084             {  /* x'[k] = x[k] - lb[k] * x[kk] */
1085                jj = mir->cut_vec->pos[kk];
1086 #if 0
1087                xassert(jj != 0);
1088 #else
1089                if (jj == 0)
1090                {  ios_set_vj(mir->cut_vec, kk, 1.0);
1091                   jj = mir->cut_vec->pos[kk];
1092                   xassert(jj != 0);
1093                   mir->cut_vec->val[jj] = 0.0;
1094                }
1095 #endif
1096                mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
1097                   mir->lb[k];
1098             }
1099          }
1100          else if (mir->subst[k] == 'U')
1101          {  /* x'[k] = (upper bound) - x[k] */
1102             xassert(mir->ub[k] != +DBL_MAX);
1103             kk = mir->vub[k];
1104             if (kk == 0)
1105             {  /* x'[k] = ub[k] - x[k] */
1106                mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
1107             }
1108             else
1109             {  /* x'[k] = ub[k] * x[kk] - x[k] */
1110                jj = mir->cut_vec->pos[kk];
1111                if (jj == 0)
1112                {  ios_set_vj(mir->cut_vec, kk, 1.0);
1113                   jj = mir->cut_vec->pos[kk];
1114                   xassert(jj != 0);
1115                   mir->cut_vec->val[jj] = 0.0;
1116                }
1117                mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
1118                   mir->ub[k];
1119             }
1120             mir->cut_vec->val[j] = - mir->cut_vec->val[j];
1121          }
1122          else
1123             xassert(k != k);
1124       }
1125 #if _MIR_DEBUG
1126       ios_check_vec(mir->cut_vec);
1127 #endif
1128       return;
1129 }
1130 
1131 #if _MIR_DEBUG
check_cut_row(struct MIR * mir,double r_best)1132 static void check_cut_row(struct MIR *mir, double r_best)
1133 {     /* check the cut after back bound substitution or elimination of
1134          auxiliary variables */
1135       int m = mir->m;
1136       int n = mir->n;
1137       int j, k;
1138       double r, big;
1139       /* compute the residual r = sum a[k] * x[k] - b and determine
1140          big = max(1, |a[k]|, |b|) */
1141       r = 0.0, big = 1.0;
1142       for (j = 1; j <= mir->cut_vec->nnz; j++)
1143       {  k = mir->cut_vec->ind[j];
1144          xassert(1 <= k && k <= m+n);
1145          r += mir->cut_vec->val[j] * mir->x[k];
1146          if (big < fabs(mir->cut_vec->val[j]))
1147             big = fabs(mir->cut_vec->val[j]);
1148       }
1149       r -= mir->cut_rhs;
1150       if (big < fabs(mir->cut_rhs))
1151          big = fabs(mir->cut_rhs);
1152       /* the residual must be close to r_best */
1153       xassert(fabs(r - r_best) <= 1e-6 * big);
1154       return;
1155 }
1156 #endif
1157 
subst_aux_vars(glp_tree * tree,struct MIR * mir)1158 static void subst_aux_vars(glp_tree *tree, struct MIR *mir)
1159 {     /* final substitution to eliminate auxiliary variables */
1160       glp_prob *mip = tree->mip;
1161       int m = mir->m;
1162       int n = mir->n;
1163       GLPAIJ *aij;
1164       int j, k, kk, jj;
1165       for (j = mir->cut_vec->nnz; j >= 1; j--)
1166       {  k = mir->cut_vec->ind[j];
1167          xassert(1 <= k && k <= m+n);
1168          if (k > m) continue; /* skip structurals */
1169          for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
1170          {  kk = m + aij->col->j; /* structural */
1171             jj = mir->cut_vec->pos[kk];
1172             if (jj == 0)
1173             {  ios_set_vj(mir->cut_vec, kk, 1.0);
1174                jj = mir->cut_vec->pos[kk];
1175                mir->cut_vec->val[jj] = 0.0;
1176             }
1177             mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
1178          }
1179          mir->cut_vec->val[j] = 0.0;
1180       }
1181       ios_clean_vec(mir->cut_vec, 0.0);
1182       return;
1183 }
1184 
add_cut(glp_tree * tree,struct MIR * mir)1185 static void add_cut(glp_tree *tree, struct MIR *mir)
1186 {     /* add constructed cut inequality to the cut pool */
1187       int m = mir->m;
1188       int n = mir->n;
1189       int j, k, len;
1190       int *ind = xcalloc(1+n, sizeof(int));
1191       double *val = xcalloc(1+n, sizeof(double));
1192       len = 0;
1193       for (j = mir->cut_vec->nnz; j >= 1; j--)
1194       {  k = mir->cut_vec->ind[j];
1195          xassert(m+1 <= k && k <= m+n);
1196          len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
1197       }
1198 #if 0
1199       ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
1200          mir->cut_rhs);
1201 #else
1202       glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
1203          mir->cut_rhs);
1204 #endif
1205       xfree(ind);
1206       xfree(val);
1207       return;
1208 }
1209 
aggregate_row(glp_tree * tree,struct MIR * mir)1210 static int aggregate_row(glp_tree *tree, struct MIR *mir)
1211 {     /* try to aggregate another row */
1212       glp_prob *mip = tree->mip;
1213       int m = mir->m;
1214       int n = mir->n;
1215       GLPAIJ *aij;
1216       IOSVEC *v;
1217       int ii, j, jj, k, kk, kappa = 0, ret = 0;
1218       double d1, d2, d, d_max = 0.0;
1219       /* choose appropriate structural variable in the aggregated row
1220          to be substituted */
1221       for (j = 1; j <= mir->agg_vec->nnz; j++)
1222       {  k = mir->agg_vec->ind[j];
1223          xassert(1 <= k && k <= m+n);
1224          if (k <= m) continue; /* skip auxiliary var */
1225          if (mir->isint[k]) continue; /* skip integer var */
1226          if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
1227          /* compute distance from x[k] to its lower bound */
1228          kk = mir->vlb[k];
1229          if (kk == 0)
1230          {  if (mir->lb[k] == -DBL_MAX)
1231                d1 = DBL_MAX;
1232             else
1233                d1 = mir->x[k] - mir->lb[k];
1234          }
1235          else
1236          {  xassert(1 <= kk && kk <= m+n);
1237             xassert(mir->isint[kk]);
1238             xassert(mir->lb[k] != -DBL_MAX);
1239             d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
1240          }
1241          /* compute distance from x[k] to its upper bound */
1242          kk = mir->vub[k];
1243          if (kk == 0)
1244          {  if (mir->vub[k] == +DBL_MAX)
1245                d2 = DBL_MAX;
1246             else
1247                d2 = mir->ub[k] - mir->x[k];
1248          }
1249          else
1250          {  xassert(1 <= kk && kk <= m+n);
1251             xassert(mir->isint[kk]);
1252             xassert(mir->ub[k] != +DBL_MAX);
1253             d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
1254          }
1255          /* x[k] cannot be free */
1256          xassert(d1 != DBL_MAX || d2 != DBL_MAX);
1257          /* d = min(d1, d2) */
1258          d = (d1 <= d2 ? d1 : d2);
1259          xassert(d != DBL_MAX);
1260          /* should not be close to corresponding bound */
1261          if (d < 0.001) continue;
1262          if (d_max < d) d_max = d, kappa = k;
1263       }
1264       if (kappa == 0)
1265       {  /* nothing chosen */
1266          ret = 1;
1267          goto done;
1268       }
1269       /* x[kappa] has been chosen */
1270       xassert(m+1 <= kappa && kappa <= m+n);
1271       xassert(!mir->isint[kappa]);
1272       /* find another row, which have not been used yet, to eliminate
1273          x[kappa] from the aggregated row */
1274       for (ii = 1; ii <= m; ii++)
1275       {  if (mir->skip[ii]) continue;
1276          for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
1277             if (aij->col->j == kappa - m) break;
1278          if (aij != NULL && fabs(aij->val) >= 0.001) break;
1279       }
1280       if (ii > m)
1281       {  /* nothing found */
1282          ret = 2;
1283          goto done;
1284       }
1285       /* row ii has been found; include it in the aggregated list */
1286       mir->agg_cnt++;
1287       xassert(mir->agg_cnt <= MAXAGGR);
1288       mir->agg_row[mir->agg_cnt] = ii;
1289       mir->skip[ii] = 2;
1290       /* v := new row */
1291       v = ios_create_vec(m+n);
1292       ios_set_vj(v, ii, 1.0);
1293       for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
1294          ios_set_vj(v, m + aij->col->j, - aij->val);
1295 #if _MIR_DEBUG
1296       ios_check_vec(v);
1297 #endif
1298       /* perform gaussian elimination to remove x[kappa] */
1299       j = mir->agg_vec->pos[kappa];
1300       xassert(j != 0);
1301       jj = v->pos[kappa];
1302       xassert(jj != 0);
1303       ios_linear_comb(mir->agg_vec,
1304          - mir->agg_vec->val[j] / v->val[jj], v);
1305       ios_delete_vec(v);
1306       ios_set_vj(mir->agg_vec, kappa, 0.0);
1307 #if _MIR_DEBUG
1308       ios_check_vec(mir->agg_vec);
1309 #endif
1310 done: return ret;
1311 }
1312 
ios_mir_gen(glp_tree * tree,void * gen)1313 void ios_mir_gen(glp_tree *tree, void *gen)
1314 {     /* main routine to generate MIR cuts */
1315       glp_prob *mip = tree->mip;
1316       struct MIR *mir = gen;
1317       int m = mir->m;
1318       int n = mir->n;
1319       int i;
1320       double r_best;
1321       xassert(mip->m >= m);
1322       xassert(mip->n == n);
1323       /* obtain current point */
1324       get_current_point(tree, mir);
1325 #if _MIR_DEBUG
1326       /* check current point */
1327       check_current_point(mir);
1328 #endif
1329       /* reset bound substitution flags */
1330       memset(&mir->subst[1], '?', m+n);
1331       /* try to generate a set of violated MIR cuts */
1332       for (i = 1; i <= m; i++)
1333       {  if (mir->skip[i]) continue;
1334          /* use original i-th row as initial aggregated constraint */
1335          initial_agg_row(tree, mir, i);
1336 loop:    ;
1337 #if _MIR_DEBUG
1338          /* check aggregated row */
1339          check_agg_row(mir);
1340 #endif
1341          /* substitute fixed variables into aggregated constraint */
1342          subst_fixed_vars(mir);
1343 #if _MIR_DEBUG
1344          /* check aggregated row */
1345          check_agg_row(mir);
1346 #endif
1347 #if _MIR_DEBUG
1348          /* check bound substitution flags */
1349          {  int k;
1350             for (k = 1; k <= m+n; k++)
1351                xassert(mir->subst[k] == '?');
1352          }
1353 #endif
1354          /* apply bound substitution heuristic */
1355          bound_subst_heur(mir);
1356          /* substitute bounds and build modified constraint */
1357          build_mod_row(mir);
1358 #if _MIR_DEBUG
1359          /* check modified row */
1360          check_mod_row(mir);
1361 #endif
1362          /* try to generate violated c-MIR cut for modified row */
1363          r_best = generate(mir);
1364          if (r_best > 0.0)
1365          {  /* success */
1366 #if _MIR_DEBUG
1367             /* check raw cut before back bound substitution */
1368             check_raw_cut(mir, r_best);
1369 #endif
1370             /* back substitution of original bounds */
1371             back_subst(mir);
1372 #if _MIR_DEBUG
1373             /* check the cut after back bound substitution */
1374             check_cut_row(mir, r_best);
1375 #endif
1376             /* final substitution to eliminate auxiliary variables */
1377             subst_aux_vars(tree, mir);
1378 #if _MIR_DEBUG
1379             /* check the cut after elimination of auxiliaries */
1380             check_cut_row(mir, r_best);
1381 #endif
1382             /* add constructed cut inequality to the cut pool */
1383             add_cut(tree, mir);
1384          }
1385          /* reset bound substitution flags */
1386          {  int j, k;
1387             for (j = 1; j <= mir->mod_vec->nnz; j++)
1388             {  k = mir->mod_vec->ind[j];
1389                xassert(1 <= k && k <= m+n);
1390                xassert(mir->subst[k] != '?');
1391                mir->subst[k] = '?';
1392             }
1393          }
1394          if (r_best == 0.0)
1395          {  /* failure */
1396             if (mir->agg_cnt < MAXAGGR)
1397             {  /* try to aggregate another row */
1398                if (aggregate_row(tree, mir) == 0) goto loop;
1399             }
1400          }
1401          /* unmark rows used in the aggregated constraint */
1402          {  int k, ii;
1403             for (k = 1; k <= mir->agg_cnt; k++)
1404             {  ii = mir->agg_row[k];
1405                xassert(1 <= ii && ii <= m);
1406                xassert(mir->skip[ii] == 2);
1407                mir->skip[ii] = 0;
1408             }
1409          }
1410       }
1411       return;
1412 }
1413 
1414 /***********************************************************************
1415 *  NAME
1416 *
1417 *  ios_mir_term - terminate MIR cut generator
1418 *
1419 *  SYNOPSIS
1420 *
1421 *  #include "glpios.h"
1422 *  void ios_mir_term(void *gen);
1423 *
1424 *  DESCRIPTION
1425 *
1426 *  The routine ios_mir_term deletes the MIR cut generator working area
1427 *  freeing all the memory allocated to it. */
1428 
ios_mir_term(void * gen)1429 void ios_mir_term(void *gen)
1430 {     struct MIR *mir = gen;
1431       xfree(mir->skip);
1432       xfree(mir->isint);
1433       xfree(mir->lb);
1434       xfree(mir->vlb);
1435       xfree(mir->ub);
1436       xfree(mir->vub);
1437       xfree(mir->x);
1438       xfree(mir->agg_row);
1439       ios_delete_vec(mir->agg_vec);
1440       xfree(mir->subst);
1441       ios_delete_vec(mir->mod_vec);
1442       ios_delete_vec(mir->cut_vec);
1443       xfree(mir);
1444       return;
1445 }
1446 
1447 /* eof */
1448