src/glpios06.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

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