src/glpios07.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* glpios07.c (mixed cover 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
/*----------------------------------------------------------------------
alpar@1
    28
-- COVER INEQUALITIES
alpar@1
    29
--
alpar@1
    30
-- Consider the set of feasible solutions to 0-1 knapsack problem:
alpar@1
    31
--
alpar@1
    32
--    sum a[j]*x[j] <= b,                                            (1)
alpar@1
    33
--  j in J
alpar@1
    34
--
alpar@1
    35
--    x[j] is binary,                                                (2)
alpar@1
    36
--
alpar@1
    37
-- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be
alpar@1
    38
-- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0).
alpar@1
    39
--
alpar@1
    40
-- A set C within J is called a cover if
alpar@1
    41
--
alpar@1
    42
--    sum a[j] > b.                                                  (3)
alpar@1
    43
--  j in C
alpar@1
    44
--
alpar@1
    45
-- For any cover C the inequality
alpar@1
    46
--
alpar@1
    47
--    sum x[j] <= |C| - 1                                            (4)
alpar@1
    48
--  j in C
alpar@1
    49
--
alpar@1
    50
-- is called a cover inequality and is valid for (1)-(2).
alpar@1
    51
--
alpar@1
    52
-- MIXED COVER INEQUALITIES
alpar@1
    53
--
alpar@1
    54
-- Consider the set of feasible solutions to mixed knapsack problem:
alpar@1
    55
--
alpar@1
    56
--    sum a[j]*x[j] + y <= b,                                        (5)
alpar@1
    57
--  j in J
alpar@1
    58
--
alpar@1
    59
--    x[j] is binary,                                                (6)
alpar@1
    60
--
alpar@1
    61
--    0 <= y <= u is continuous,                                     (7)
alpar@1
    62
--
alpar@1
    63
-- where again we assume that a[j] > 0.
alpar@1
    64
--
alpar@1
    65
-- Let C within J be some set. From (1)-(4) it follows that
alpar@1
    66
--
alpar@1
    67
--    sum a[j] > b - y                                               (8)
alpar@1
    68
--  j in C
alpar@1
    69
--
alpar@1
    70
-- implies
alpar@1
    71
--
alpar@1
    72
--    sum x[j] <= |C| - 1.                                           (9)
alpar@1
    73
--  j in C
alpar@1
    74
--
alpar@1
    75
-- Thus, we need to modify the inequality (9) in such a way that it be
alpar@1
    76
-- a constraint only if the condition (8) is satisfied.
alpar@1
    77
--
alpar@1
    78
-- Consider the following inequality:
alpar@1
    79
--
alpar@1
    80
--    sum x[j] <= |C| - t.                                          (10)
alpar@1
    81
--  j in C
alpar@1
    82
--
alpar@1
    83
-- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are
alpar@1
    84
-- binary variables. On the other hand, if t <= 0, (10) being satisfied
alpar@1
    85
-- for any values of x[j] is not a constraint.
alpar@1
    86
--
alpar@1
    87
-- Let
alpar@1
    88
--
alpar@1
    89
--    t' = sum a[j] + y - b.                                        (11)
alpar@1
    90
--       j in C
alpar@1
    91
--
alpar@1
    92
-- It is understood that the condition t' > 0 is equivalent to (8).
alpar@1
    93
-- Besides, from (6)-(7) it follows that t' has an implied upper bound:
alpar@1
    94
--
alpar@1
    95
--    t'max = sum a[j] + u - b.                                     (12)
alpar@1
    96
--          j in C
alpar@1
    97
--
alpar@1
    98
-- This allows to express the parameter t having desired properties:
alpar@1
    99
--
alpar@1
   100
--    t = t' / t'max.                                               (13)
alpar@1
   101
--
alpar@1
   102
-- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0
alpar@1
   103
-- is equivalent to (8).
alpar@1
   104
--
alpar@1
   105
-- Thus, the inequality (10), where t is given by formula (13) is valid
alpar@1
   106
-- for (5)-(7).
alpar@1
   107
--
alpar@1
   108
-- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and
alpar@1
   109
-- (10) is transformed to the conditions (3) and (4).
alpar@1
   110
--
alpar@1
   111
-- GENERATING MIXED COVER CUTS
alpar@1
   112
--
alpar@1
   113
-- To generate a mixed cover cut in the form (10) we need to find such
alpar@1
   114
-- set C which satisfies to the inequality (8) and for which, in turn,
alpar@1
   115
-- the inequality (10) is violated in the current point.
alpar@1
   116
--
alpar@1
   117
-- Substituting t from (13) to (10) gives:
alpar@1
   118
--
alpar@1
   119
--                        1
alpar@1
   120
--    sum x[j] <= |C| - -----  (sum a[j] + y - b),                  (14)
alpar@1
   121
--  j in C              t'max j in C
alpar@1
   122
--
alpar@1
   123
-- and finally we have the cut inequality in the standard form:
alpar@1
   124
--
alpar@1
   125
--    sum x[j] + alfa * y <= beta,                                  (15)
alpar@1
   126
--  j in C
alpar@1
   127
--
alpar@1
   128
-- where:
alpar@1
   129
--
alpar@1
   130
--    alfa = 1 / t'max,                                             (16)
alpar@1
   131
--
alpar@1
   132
--    beta = |C| - alfa *  (sum a[j] - b).                          (17)
alpar@1
   133
--                        j in C                                      */
alpar@1
   134
alpar@1
   135
#if 1
alpar@1
   136
#define MAXTRY 1000
alpar@1
   137
#else
alpar@1
   138
#define MAXTRY 10000
alpar@1
   139
#endif
alpar@1
   140
alpar@1
   141
static int cover2(int n, double a[], double b, double u, double x[],
alpar@1
   142
      double y, int cov[], double *_alfa, double *_beta)
alpar@1
   143
{     /* try to generate mixed cover cut using two-element cover */
alpar@1
   144
      int i, j, try = 0, ret = 0;
alpar@1
   145
      double eps, alfa, beta, temp, rmax = 0.001;
alpar@1
   146
      eps = 0.001 * (1.0 + fabs(b));
alpar@1
   147
      for (i = 0+1; i <= n; i++)
alpar@1
   148
      for (j = i+1; j <= n; j++)
alpar@1
   149
      {  /* C = {i, j} */
alpar@1
   150
         try++;
alpar@1
   151
         if (try > MAXTRY) goto done;
alpar@1
   152
         /* check if condition (8) is satisfied */
alpar@1
   153
         if (a[i] + a[j] + y > b + eps)
alpar@1
   154
         {  /* compute parameters for inequality (15) */
alpar@1
   155
            temp = a[i] + a[j] - b;
alpar@1
   156
            alfa = 1.0 / (temp + u);
alpar@1
   157
            beta = 2.0 - alfa * temp;
alpar@1
   158
            /* compute violation of inequality (15) */
alpar@1
   159
            temp = x[i] + x[j] + alfa * y - beta;
alpar@1
   160
            /* choose C providing maximum violation */
alpar@1
   161
            if (rmax < temp)
alpar@1
   162
            {  rmax = temp;
alpar@1
   163
               cov[1] = i;
alpar@1
   164
               cov[2] = j;
alpar@1
   165
               *_alfa = alfa;
alpar@1
   166
               *_beta = beta;
alpar@1
   167
               ret = 1;
alpar@1
   168
            }
alpar@1
   169
         }
alpar@1
   170
      }
alpar@1
   171
done: return ret;
alpar@1
   172
}
alpar@1
   173
alpar@1
   174
static int cover3(int n, double a[], double b, double u, double x[],
alpar@1
   175
      double y, int cov[], double *_alfa, double *_beta)
alpar@1
   176
{     /* try to generate mixed cover cut using three-element cover */
alpar@1
   177
      int i, j, k, try = 0, ret = 0;
alpar@1
   178
      double eps, alfa, beta, temp, rmax = 0.001;
alpar@1
   179
      eps = 0.001 * (1.0 + fabs(b));
alpar@1
   180
      for (i = 0+1; i <= n; i++)
alpar@1
   181
      for (j = i+1; j <= n; j++)
alpar@1
   182
      for (k = j+1; k <= n; k++)
alpar@1
   183
      {  /* C = {i, j, k} */
alpar@1
   184
         try++;
alpar@1
   185
         if (try > MAXTRY) goto done;
alpar@1
   186
         /* check if condition (8) is satisfied */
alpar@1
   187
         if (a[i] + a[j] + a[k] + y > b + eps)
alpar@1
   188
         {  /* compute parameters for inequality (15) */
alpar@1
   189
            temp = a[i] + a[j] + a[k] - b;
alpar@1
   190
            alfa = 1.0 / (temp + u);
alpar@1
   191
            beta = 3.0 - alfa * temp;
alpar@1
   192
            /* compute violation of inequality (15) */
alpar@1
   193
            temp = x[i] + x[j] + x[k] + alfa * y - beta;
alpar@1
   194
            /* choose C providing maximum violation */
alpar@1
   195
            if (rmax < temp)
alpar@1
   196
            {  rmax = temp;
alpar@1
   197
               cov[1] = i;
alpar@1
   198
               cov[2] = j;
alpar@1
   199
               cov[3] = k;
alpar@1
   200
               *_alfa = alfa;
alpar@1
   201
               *_beta = beta;
alpar@1
   202
               ret = 1;
alpar@1
   203
            }
alpar@1
   204
         }
alpar@1
   205
      }
alpar@1
   206
done: return ret;
alpar@1
   207
}
alpar@1
   208
alpar@1
   209
static int cover4(int n, double a[], double b, double u, double x[],
alpar@1
   210
      double y, int cov[], double *_alfa, double *_beta)
alpar@1
   211
{     /* try to generate mixed cover cut using four-element cover */
alpar@1
   212
      int i, j, k, l, try = 0, ret = 0;
alpar@1
   213
      double eps, alfa, beta, temp, rmax = 0.001;
alpar@1
   214
      eps = 0.001 * (1.0 + fabs(b));
alpar@1
   215
      for (i = 0+1; i <= n; i++)
alpar@1
   216
      for (j = i+1; j <= n; j++)
alpar@1
   217
      for (k = j+1; k <= n; k++)
alpar@1
   218
      for (l = k+1; l <= n; l++)
alpar@1
   219
      {  /* C = {i, j, k, l} */
alpar@1
   220
         try++;
alpar@1
   221
         if (try > MAXTRY) goto done;
alpar@1
   222
         /* check if condition (8) is satisfied */
alpar@1
   223
         if (a[i] + a[j] + a[k] + a[l] + y > b + eps)
alpar@1
   224
         {  /* compute parameters for inequality (15) */
alpar@1
   225
            temp = a[i] + a[j] + a[k] + a[l] - b;
alpar@1
   226
            alfa = 1.0 / (temp + u);
alpar@1
   227
            beta = 4.0 - alfa * temp;
alpar@1
   228
            /* compute violation of inequality (15) */
alpar@1
   229
            temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta;
alpar@1
   230
            /* choose C providing maximum violation */
alpar@1
   231
            if (rmax < temp)
alpar@1
   232
            {  rmax = temp;
alpar@1
   233
               cov[1] = i;
alpar@1
   234
               cov[2] = j;
alpar@1
   235
               cov[3] = k;
alpar@1
   236
               cov[4] = l;
alpar@1
   237
               *_alfa = alfa;
alpar@1
   238
               *_beta = beta;
alpar@1
   239
               ret = 1;
alpar@1
   240
            }
alpar@1
   241
         }
alpar@1
   242
      }
alpar@1
   243
done: return ret;
alpar@1
   244
}
alpar@1
   245
alpar@1
   246
static int cover(int n, double a[], double b, double u, double x[],
alpar@1
   247
      double y, int cov[], double *alfa, double *beta)
alpar@1
   248
{     /* try to generate mixed cover cut;
alpar@1
   249
         input (see (5)):
alpar@1
   250
         n        is the number of binary variables;
alpar@1
   251
         a[1:n]   are coefficients at binary variables;
alpar@1
   252
         b        is the right-hand side;
alpar@1
   253
         u        is upper bound of continuous variable;
alpar@1
   254
         x[1:n]   are values of binary variables at current point;
alpar@1
   255
         y        is value of continuous variable at current point;
alpar@1
   256
         output (see (15), (16), (17)):
alpar@1
   257
         cov[1:r] are indices of binary variables included in cover C,
alpar@1
   258
                  where r is the set cardinality returned on exit;
alpar@1
   259
         alfa     coefficient at continuous variable;
alpar@1
   260
         beta     is the right-hand side; */
alpar@1
   261
      int j;
alpar@1
   262
      /* perform some sanity checks */
alpar@1
   263
      xassert(n >= 2);
alpar@1
   264
      for (j = 1; j <= n; j++) xassert(a[j] > 0.0);
alpar@1
   265
#if 1 /* ??? */
alpar@1
   266
      xassert(b > -1e-5);
alpar@1
   267
#else
alpar@1
   268
      xassert(b > 0.0);
alpar@1
   269
#endif
alpar@1
   270
      xassert(u >= 0.0);
alpar@1
   271
      for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0);
alpar@1
   272
      xassert(0.0 <= y && y <= u);
alpar@1
   273
      /* try to generate mixed cover cut */
alpar@1
   274
      if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2;
alpar@1
   275
      if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3;
alpar@1
   276
      if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4;
alpar@1
   277
      return 0;
alpar@1
   278
}
alpar@1
   279
alpar@1
   280
/*----------------------------------------------------------------------
alpar@1
   281
-- lpx_cover_cut - generate mixed cover cut.
alpar@1
   282
--
alpar@1
   283
-- SYNOPSIS
alpar@1
   284
--
alpar@1
   285
-- #include "glplpx.h"
alpar@1
   286
-- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
alpar@1
   287
--    double work[]);
alpar@1
   288
--
alpar@1
   289
-- DESCRIPTION
alpar@1
   290
--
alpar@1
   291
-- The routine lpx_cover_cut generates a mixed cover cut for a given
alpar@1
   292
-- row of the MIP problem.
alpar@1
   293
--
alpar@1
   294
-- The given row of the MIP problem should be explicitly specified in
alpar@1
   295
-- the form:
alpar@1
   296
--
alpar@1
   297
--    sum{j in J} a[j]*x[j] <= b.                                    (1)
alpar@1
   298
--
alpar@1
   299
-- On entry indices (ordinal numbers) of structural variables, which
alpar@1
   300
-- have non-zero constraint coefficients, should be placed in locations
alpar@1
   301
-- ind[1], ..., ind[len], and corresponding constraint coefficients
alpar@1
   302
-- should be placed in locations val[1], ..., val[len]. The right-hand
alpar@1
   303
-- side b should be stored in location val[0].
alpar@1
   304
--
alpar@1
   305
-- The working array work should have at least nb locations, where nb
alpar@1
   306
-- is the number of binary variables in (1).
alpar@1
   307
--
alpar@1
   308
-- The routine generates a mixed cover cut in the same form as (1) and
alpar@1
   309
-- stores the cut coefficients and right-hand side in the same way as
alpar@1
   310
-- just described above.
alpar@1
   311
--
alpar@1
   312
-- RETURNS
alpar@1
   313
--
alpar@1
   314
-- If the cutting plane has been successfully generated, the routine
alpar@1
   315
-- returns 1 <= len' <= n, which is the number of non-zero coefficients
alpar@1
   316
-- in the inequality constraint. Otherwise, the routine returns zero. */
alpar@1
   317
alpar@1
   318
static int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
alpar@1
   319
      double work[])
alpar@1
   320
{     int cov[1+4], j, k, nb, newlen, r;
alpar@1
   321
      double f_min, f_max, alfa, beta, u, *x = work, y;
alpar@1
   322
      /* substitute and remove fixed variables */
alpar@1
   323
      newlen = 0;
alpar@1
   324
      for (k = 1; k <= len; k++)
alpar@1
   325
      {  j = ind[k];
alpar@1
   326
         if (lpx_get_col_type(lp, j) == LPX_FX)
alpar@1
   327
            val[0] -= val[k] * lpx_get_col_lb(lp, j);
alpar@1
   328
         else
alpar@1
   329
         {  newlen++;
alpar@1
   330
            ind[newlen] = ind[k];
alpar@1
   331
            val[newlen] = val[k];
alpar@1
   332
         }
alpar@1
   333
      }
alpar@1
   334
      len = newlen;
alpar@1
   335
      /* move binary variables to the beginning of the list so that
alpar@1
   336
         elements 1, 2, ..., nb correspond to binary variables, and
alpar@1
   337
         elements nb+1, nb+2, ..., len correspond to rest variables */
alpar@1
   338
      nb = 0;
alpar@1
   339
      for (k = 1; k <= len; k++)
alpar@1
   340
      {  j = ind[k];
alpar@1
   341
         if (lpx_get_col_kind(lp, j) == LPX_IV &&
alpar@1
   342
             lpx_get_col_type(lp, j) == LPX_DB &&
alpar@1
   343
             lpx_get_col_lb(lp, j) == 0.0 &&
alpar@1
   344
             lpx_get_col_ub(lp, j) == 1.0)
alpar@1
   345
         {  /* binary variable */
alpar@1
   346
            int ind_k;
alpar@1
   347
            double val_k;
alpar@1
   348
            nb++;
alpar@1
   349
            ind_k = ind[nb], val_k = val[nb];
alpar@1
   350
            ind[nb] = ind[k], val[nb] = val[k];
alpar@1
   351
            ind[k] = ind_k, val[k] = val_k;
alpar@1
   352
         }
alpar@1
   353
      }
alpar@1
   354
      /* now the specified row has the form:
alpar@1
   355
         sum a[j]*x[j] + sum a[j]*y[j] <= b,
alpar@1
   356
         where x[j] are binary variables, y[j] are rest variables */
alpar@1
   357
      /* at least two binary variables are needed */
alpar@1
   358
      if (nb < 2) return 0;
alpar@1
   359
      /* compute implied lower and upper bounds for sum a[j]*y[j] */
alpar@1
   360
      f_min = f_max = 0.0;
alpar@1
   361
      for (k = nb+1; k <= len; k++)
alpar@1
   362
      {  j = ind[k];
alpar@1
   363
         /* both bounds must be finite */
alpar@1
   364
         if (lpx_get_col_type(lp, j) != LPX_DB) return 0;
alpar@1
   365
         if (val[k] > 0.0)
alpar@1
   366
         {  f_min += val[k] * lpx_get_col_lb(lp, j);
alpar@1
   367
            f_max += val[k] * lpx_get_col_ub(lp, j);
alpar@1
   368
         }
alpar@1
   369
         else
alpar@1
   370
         {  f_min += val[k] * lpx_get_col_ub(lp, j);
alpar@1
   371
            f_max += val[k] * lpx_get_col_lb(lp, j);
alpar@1
   372
         }
alpar@1
   373
      }
alpar@1
   374
      /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===>
alpar@1
   375
         sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===>
alpar@1
   376
         sum a[j]*x[j] + y <= b - f_min,
alpar@1
   377
         where y = sum a[j]*y[j] - f_min;
alpar@1
   378
         note that 0 <= y <= u, u = f_max - f_min */
alpar@1
   379
      /* determine upper bound of y */
alpar@1
   380
      u = f_max - f_min;
alpar@1
   381
      /* determine value of y at the current point */
alpar@1
   382
      y = 0.0;
alpar@1
   383
      for (k = nb+1; k <= len; k++)
alpar@1
   384
      {  j = ind[k];
alpar@1
   385
         y += val[k] * lpx_get_col_prim(lp, j);
alpar@1
   386
      }
alpar@1
   387
      y -= f_min;
alpar@1
   388
      if (y < 0.0) y = 0.0;
alpar@1
   389
      if (y > u) y = u;
alpar@1
   390
      /* modify the right-hand side b */
alpar@1
   391
      val[0] -= f_min;
alpar@1
   392
      /* now the transformed row has the form:
alpar@1
   393
         sum a[j]*x[j] + y <= b, where 0 <= y <= u */
alpar@1
   394
      /* determine values of x[j] at the current point */
alpar@1
   395
      for (k = 1; k <= nb; k++)
alpar@1
   396
      {  j = ind[k];
alpar@1
   397
         x[k] = lpx_get_col_prim(lp, j);
alpar@1
   398
         if (x[k] < 0.0) x[k] = 0.0;
alpar@1
   399
         if (x[k] > 1.0) x[k] = 1.0;
alpar@1
   400
      }
alpar@1
   401
      /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */
alpar@1
   402
      for (k = 1; k <= nb; k++)
alpar@1
   403
      {  if (val[k] < 0.0)
alpar@1
   404
         {  ind[k] = - ind[k];
alpar@1
   405
            val[k] = - val[k];
alpar@1
   406
            val[0] += val[k];
alpar@1
   407
            x[k] = 1.0 - x[k];
alpar@1
   408
         }
alpar@1
   409
      }
alpar@1
   410
      /* try to generate a mixed cover cut for the transformed row */
alpar@1
   411
      r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta);
alpar@1
   412
      if (r == 0) return 0;
alpar@1
   413
      xassert(2 <= r && r <= 4);
alpar@1
   414
      /* now the cut is in the form:
alpar@1
   415
         sum{j in C} x[j] + alfa * y <= beta */
alpar@1
   416
      /* store the right-hand side beta */
alpar@1
   417
      ind[0] = 0, val[0] = beta;
alpar@1
   418
      /* restore the original ordinal numbers of x[j] */
alpar@1
   419
      for (j = 1; j <= r; j++) cov[j] = ind[cov[j]];
alpar@1
   420
      /* store cut coefficients at binary variables complementing back
alpar@1
   421
         the variables having negative row coefficients */
alpar@1
   422
      xassert(r <= nb);
alpar@1
   423
      for (k = 1; k <= r; k++)
alpar@1
   424
      {  if (cov[k] > 0)
alpar@1
   425
         {  ind[k] = +cov[k];
alpar@1
   426
            val[k] = +1.0;
alpar@1
   427
         }
alpar@1
   428
         else
alpar@1
   429
         {  ind[k] = -cov[k];
alpar@1
   430
            val[k] = -1.0;
alpar@1
   431
            val[0] -= 1.0;
alpar@1
   432
         }
alpar@1
   433
      }
alpar@1
   434
      /* substitute y = sum a[j]*y[j] - f_min */
alpar@1
   435
      for (k = nb+1; k <= len; k++)
alpar@1
   436
      {  r++;
alpar@1
   437
         ind[r] = ind[k];
alpar@1
   438
         val[r] = alfa * val[k];
alpar@1
   439
      }
alpar@1
   440
      val[0] += alfa * f_min;
alpar@1
   441
      xassert(r <= len);
alpar@1
   442
      len = r;
alpar@1
   443
      return len;
alpar@1
   444
}
alpar@1
   445
alpar@1
   446
/*----------------------------------------------------------------------
alpar@1
   447
-- lpx_eval_row - compute explictily specified row.
alpar@1
   448
--
alpar@1
   449
-- SYNOPSIS
alpar@1
   450
--
alpar@1
   451
-- #include "glplpx.h"
alpar@1
   452
-- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]);
alpar@1
   453
--
alpar@1
   454
-- DESCRIPTION
alpar@1
   455
--
alpar@1
   456
-- The routine lpx_eval_row computes the primal value of an explicitly
alpar@1
   457
-- specified row using current values of structural variables.
alpar@1
   458
--
alpar@1
   459
-- The explicitly specified row may be thought as a linear form:
alpar@1
   460
--
alpar@1
   461
--    y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],
alpar@1
   462
--
alpar@1
   463
-- where y is an auxiliary variable for this row, a[j] are coefficients
alpar@1
   464
-- of the linear form, x[m+j] are structural variables.
alpar@1
   465
--
alpar@1
   466
-- On entry column indices and numerical values of non-zero elements of
alpar@1
   467
-- the row should be stored in locations ind[1], ..., ind[len] and
alpar@1
   468
-- val[1], ..., val[len], where len is the number of non-zero elements.
alpar@1
   469
-- The array ind and val are not changed on exit.
alpar@1
   470
--
alpar@1
   471
-- RETURNS
alpar@1
   472
--
alpar@1
   473
-- The routine returns a computed value of y, the auxiliary variable of
alpar@1
   474
-- the specified row. */
alpar@1
   475
alpar@1
   476
static double lpx_eval_row(LPX *lp, int len, int ind[], double val[])
alpar@1
   477
{     int n = lpx_get_num_cols(lp);
alpar@1
   478
      int j, k;
alpar@1
   479
      double sum = 0.0;
alpar@1
   480
      if (len < 0)
alpar@1
   481
         xerror("lpx_eval_row: len = %d; invalid row length\n", len);
alpar@1
   482
      for (k = 1; k <= len; k++)
alpar@1
   483
      {  j = ind[k];
alpar@1
   484
         if (!(1 <= j && j <= n))
alpar@1
   485
            xerror("lpx_eval_row: j = %d; column number out of range\n",
alpar@1
   486
               j);
alpar@1
   487
         sum += val[k] * lpx_get_col_prim(lp, j);
alpar@1
   488
      }
alpar@1
   489
      return sum;
alpar@1
   490
}
alpar@1
   491
alpar@1
   492
/***********************************************************************
alpar@1
   493
*  NAME
alpar@1
   494
*
alpar@1
   495
*  ios_cov_gen - generate mixed cover cuts
alpar@1
   496
*
alpar@1
   497
*  SYNOPSIS
alpar@1
   498
*
alpar@1
   499
*  #include "glpios.h"
alpar@1
   500
*  void ios_cov_gen(glp_tree *tree);
alpar@1
   501
*
alpar@1
   502
*  DESCRIPTION
alpar@1
   503
*
alpar@1
   504
*  The routine ios_cov_gen generates mixed cover cuts for the current
alpar@1
   505
*  point and adds them to the cut pool. */
alpar@1
   506
alpar@1
   507
void ios_cov_gen(glp_tree *tree)
alpar@1
   508
{     glp_prob *prob = tree->mip;
alpar@1
   509
      int m = lpx_get_num_rows(prob);
alpar@1
   510
      int n = lpx_get_num_cols(prob);
alpar@1
   511
      int i, k, type, kase, len, *ind;
alpar@1
   512
      double r, *val, *work;
alpar@1
   513
      xassert(lpx_get_status(prob) == LPX_OPT);
alpar@1
   514
      /* allocate working arrays */
alpar@1
   515
      ind = xcalloc(1+n, sizeof(int));
alpar@1
   516
      val = xcalloc(1+n, sizeof(double));
alpar@1
   517
      work = xcalloc(1+n, sizeof(double));
alpar@1
   518
      /* look through all rows */
alpar@1
   519
      for (i = 1; i <= m; i++)
alpar@1
   520
      for (kase = 1; kase <= 2; kase++)
alpar@1
   521
      {  type = lpx_get_row_type(prob, i);
alpar@1
   522
         if (kase == 1)
alpar@1
   523
         {  /* consider rows of '<=' type */
alpar@1
   524
            if (!(type == LPX_UP || type == LPX_DB)) continue;
alpar@1
   525
            len = lpx_get_mat_row(prob, i, ind, val);
alpar@1
   526
            val[0] = lpx_get_row_ub(prob, i);
alpar@1
   527
         }
alpar@1
   528
         else
alpar@1
   529
         {  /* consider rows of '>=' type */
alpar@1
   530
            if (!(type == LPX_LO || type == LPX_DB)) continue;
alpar@1
   531
            len = lpx_get_mat_row(prob, i, ind, val);
alpar@1
   532
            for (k = 1; k <= len; k++) val[k] = - val[k];
alpar@1
   533
            val[0] = - lpx_get_row_lb(prob, i);
alpar@1
   534
         }
alpar@1
   535
         /* generate mixed cover cut:
alpar@1
   536
            sum{j in J} a[j] * x[j] <= b */
alpar@1
   537
         len = lpx_cover_cut(prob, len, ind, val, work);
alpar@1
   538
         if (len == 0) continue;
alpar@1
   539
         /* at the current point the cut inequality is violated, i.e.
alpar@1
   540
            sum{j in J} a[j] * x[j] - b > 0 */
alpar@1
   541
         r = lpx_eval_row(prob, len, ind, val) - val[0];
alpar@1
   542
         if (r < 1e-3) continue;
alpar@1
   543
         /* add the cut to the cut pool */
alpar@1
   544
         glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val,
alpar@1
   545
            GLP_UP, val[0]);
alpar@1
   546
      }
alpar@1
   547
      /* free working arrays */
alpar@1
   548
      xfree(ind);
alpar@1
   549
      xfree(val);
alpar@1
   550
      xfree(work);
alpar@1
   551
      return;
alpar@1
   552
}
alpar@1
   553
alpar@1
   554
/* eof */