src/glpios06.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     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 
   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 
   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 
   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 
   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 
   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 
   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
   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 
   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
   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 
   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 
   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 
   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
   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 
   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 
   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 
   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 
   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 
   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
   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 
  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
  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 
  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 
  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 
  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 
  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 
  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 */