src/glpios06.c
changeset 1 c445c931472f
equal deleted inserted replaced
-1:000000000000 0:bcb5f657cd82
       
     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 */