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