mt_SL.c

Go to the documentation of this file.
00001 /* MTgomory "multi tableau gomory cut" provides an implementation for gomory
00002  * cuts derived from multiple tableau rows in the spirit of the work of
00003  * Andersen et al (IPCO 2007), Cornuejols (es presented in George Nemhauser
00004  * Birthday Conference in Atlanta 2007) and Gomory (presented in the same
00005  * conference).
00006  *
00007  * Copyright (C) 2007 Daniel Espinoza.
00008  * 
00009  * This library is free software; you can redistribute it and/or modify it
00010  * under the terms of the GNU Lesser General Public License as published by the
00011  * Free Software Foundation; either version 2.1 of the License, or (at your
00012  * option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful, but 
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
00016  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
00017  * License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public License
00020  * along with this library; if not, write to the Free Software Foundation,
00021  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
00022  * */
00023 /* ========================================================================= */
00024 #include "mt_SL.h"
00025 #include "mt_cplex_cbk.h"
00026 /** @file 
00027  * @ingroup MTgomory */
00028 /** @addtogroup MTgomory */
00029 /** @{ */
00030 /* ========================================================================= */
00031 /** @brief compute in work the value ineq * r_i as described by the given
00032  * inequality and tableau, we assume that work is zero, moreover, given the
00033  * variable status (interger/binary) and an operation mode, try to do nothing
00034  * (mode 0), try to get ineq*r[i] >0 (mode 1) or try to get ineq*r[i] < 0 (mode
00035  * 2), note that mode != 0 will modify the tableau
00036  * @note We assume that the coefficients for integer variables in the tableau
00037  * are between ]-1:1[
00038  * @note when computing a new inequality, mode can be non-zero only at the
00039  * beggining, otherwise, the resulting inequality might be invalid.
00040  * @return zero on success, non-zero otherwise */
00041 int MTsl1(
00042     const double*const ineq,
00043     MTrowmatrix_t*const tb,
00044     double*const work,
00045     const char*const vtype,
00046     const int mode)
00047 {
00048   const int*const rowbeg = tb->rowbeg;
00049   const int*const rowind = tb->rowind;
00050   double*const rowval = tb->rowval;
00051   register int i, j;
00052   double dtmp;
00053   int col, isint, rval = 0;
00054   /* first tableau row */
00055   for( j = 0 ; j < tb->nrows ; j++)
00056   {
00057     dtmp = ineq[j];
00058     if(fabs(dtmp)<MT_ZERO_TOL) continue;
00059     for( i = rowbeg[j] ; i < rowbeg[j+1] ; i++)
00060     {
00061       col = rowind[i];
00062       work[col] += dtmp*rowval[i];
00063       isint = ((vtype[col]==CPX_BINARY) || (vtype[col]==CPX_INTEGER)) && (j==0);
00064       if(isint)
00065       {
00066         TESTGL( MT_DEBUG_LVL, (rval=(fabs(rowval[i])>1)), CLEANUP, "Imposible,"
00067                 " coefficients in the tableau for integer variables should"
00068                 " have |val = %lf| < 1", rowval[i]);
00069         if(mode > 0 && work[col] < 0)
00070         {
00071           work[col] -= dtmp*rowval[i];
00072           rowval[i] += (dtmp<0 ? -1.0 : 1.0);
00073           work[col] += dtmp*rowval[i];
00074         }
00075         else if( mode < 0 && work[col] > 0)
00076         {
00077           work[col] -= dtmp*rowval[i];
00078           rowval[i] += (dtmp<0 ? 1.0 : -1.0);
00079           work[col] += dtmp*rowval[i];
00080         }
00081       }/* end changing tableau according to signs */
00082     }/* end loop through non-zeros */
00083   }/* end loop through tableau rows */
00084   CLEANUP:
00085   return rval;
00086 }
00087 /* ========================================================================= */
00088 /** @brief, set cutval[i] = max(cutval[i],work[i] > 0 ? work[i]/ineq[3]: 0);
00089  * and reset work to zero */
00090 int MTsl2(
00091     const double*const ineq,
00092     double*const cutval,
00093     double*const work,
00094     const int * const active,
00095     const int nactive)
00096 {
00097   register int i;
00098   int ccol, count=0;
00099   double dtmp;
00100   for( i = nactive ; i-- ; )
00101   {
00102     ccol = active[i];
00103     if(work[ccol]>0)
00104     {
00105       dtmp = work[ccol]/ineq[3];
00106       if(dtmp > cutval[ccol])
00107       {
00108         cutval[ccol] = dtmp;
00109         count++;
00110       }
00111     }
00112     work[ccol] = 0;
00113   }
00114   MESSAGE(MT_VERB_LVL,"Updated %d cut coeff", count);
00115   return 0;
00116 }
00117 /* ========================================================================= */
00118 /** @brief given an inequality and f compute ineq[dim+1] and (possible change
00119  * signs) to ensure that ineq[dim+1] > 0; */
00120 int MTsl3(
00121     const double*const f,
00122     double*const ineq,
00123     const int dim)
00124 {
00125   register int i;
00126   int rval = 0;
00127   ineq[dim+1] = ineq[dim];
00128   for( i = dim ; i-- ; ) ineq[dim+1] -= ineq[i]*f[i];
00129   if(ineq[dim+1]<0)
00130   {
00131     MESSAGE(MT_VERB_LVL,"Change sign");
00132     for( i = dim+2; i-- ; ) ineq[i] = - ineq[i];
00133   }
00134   TESTG((rval=(fabs(ineq[dim+1])<MT_ZERO_TOL)), CLEANUP, 
00135         "f satisfy ax <= b at equality, a=[%lf,%lf] b = %lf f=[%lf,%lf]",
00136         ineq[0], ineq[1], ineq[dim], f[0], f[1]);
00137   CLEANUP:
00138   return rval;
00139 }
00140 /* ========================================================================= */
00141 /** @brief compute the line that pases through the two given points */
00142 int MTsl4(
00143   double*const ineq,
00144   const double x0,
00145   const double _y0,
00146   const double x1,
00147   const double _y1)
00148 {
00149   const double Dx = (x0 - x1);
00150   const double Dy = (_y0 - _y1);
00151   ineq[0] = Dy;
00152   ineq[1] = -Dx;
00153   ineq[2] = x0*Dy - _y0*Dx;
00154   MESSAGE(MT_VERB_LVL,"x*%lg + y*%lg = %lg", ineq[0], ineq[1], ineq[2]);
00155   return 0;
00156 }
00157 /* ========================================================================= */
00158 /** @brief compute active set from the given compresed 
00159  * vector set */
00160 int MTsl5(
00161   int*const nactive,
00162   int*const active,
00163   const int nvars,
00164   const int nz,
00165   const double*const compval,
00166   const int*const compind)
00167 {
00168   register int i;
00169   int cnt;
00170   memset(active,0,sizeof(int)*((size_t)nvars));
00171   for( i = nz ; i-- ; ) if(fabs(compval[i])>MT_ZERO_TOL) active[compind[i]] = 1;
00172   for(cnt = 0, i=0 ; i < nvars ; i++ ) if(active[i]) active[cnt++] = i;
00173   *nactive = cnt;
00174   return 0;
00175 }
00176 /* ========================================================================= */
00177 int MTslCut(
00178     MTgomory_ccbk_t*const data,
00179     CPXCENVptr env,
00180     CPXLPptr lp)
00181 {
00182   /* constant data */
00183   const MTsol_t*const sol = &(data->sol);
00184   const double*const x = sol->x;
00185   const double*const slack = sol->slack;
00186   const MTlp_t*const MTlp = &(data->lp);
00187   const int nrows = MTlp->nrows;
00188   const int ncols = MTlp->ncols;
00189   const int nvars = ncols + nrows;
00190   const char*const rtype = MTlp->rtype;
00191   const char*const ctype = MTlp->ctype;
00192   const int*const cstat = MTlp->cstat;
00193   MTcutHeap_t*const cuth = &(data->cuth);
00194   MTrowmatrix_t*const tb = &(data->tb);
00195   double*const f = data->f;
00196   double*const work = data->work;
00197   double*const cutval = data->extcut;
00198   /* local data */
00199   register int i, j;
00200   MTcut_t*cut = 0;
00201   int nfrac = 0;/* fractional integer variables in current solution*/
00202   int nint = 0;/* integer basic variables */
00203   int*frac_ind = EGsMalloc(int,ncols);/* fractional index set */
00204   int*int_ind = 0;  /* basic integral index set */
00205   double*binvrow = EGsMalloc(double, nrows);
00206   int rval = 0, icol, fcol, ccol, brow, *tabind = 0, status, tnz, fit, iit, onz;
00207   double*tableau = 0, ratio, minratio = DBL_MAX, dtmp, ineq[3][4], mval[2], util[2];
00208   int*active = EGsMalloc(int,nvars);
00209   char*vtype = EGsMalloc(char,nvars);
00210   int nactive = 0;
00211   /* build vtype */
00212   for( i = ncols ; i-- ; ) vtype[i] = ctype[i];
00213   vtype += ncols;
00214   for( i = nrows ; i-- ; ) vtype[i] = rtype[i];
00215   vtype -= ncols;
00216   /* identify integer fractional and integer variables */
00217   rval = MTcompute_fractional_vars( MTlp, x, frac_ind, &nfrac, 
00218                                     MT_CCBK_MIN_FRAC);
00219   CHECKRVALG(rval,CLEANUP);
00220   int_ind = frac_ind + nfrac;
00221   rval = MTcompute_integer_vars(MTlp, x, int_ind, &nint, 
00222                                 MT_CCBK_MIN_FRAC);
00223   CHECKRVALG(rval,CLEANUP);
00224   /* allocate memory */
00225   MTrowmatrix_rsz(tb,nrows,0);
00226   tb->rowbeg[0] = 0;
00227   /* we double loop on fractional variables and in integer valued basic
00228    * variables tableau, and generate the two dimmensional lifted gomory cut */
00229   for( iit = nint; iit-- ; )
00230   {
00231     tb->nz = tb->nrows = 0;
00232     tb->ncols = nvars;
00233     icol = int_ind[iit];
00234     if(cstat[icol] != CPX_BASIC) continue;
00235     /* get asociated basic row */
00236     rval = CPXgetijrow(env, lp, -1, icol, &brow);
00237     MTcplexCHECKRVALG(env,rval,CLEANUP);
00238     rval = CPXbinvrow(env, lp, brow, binvrow);
00239     MTcplexCHECKRVALG(env,rval,CLEANUP);
00240     MTrowmatrix_rsz(tb,nrows,tb->ncols);
00241     tableau = tb->rowval;
00242     tabind = tb->rowind;
00243     rval = MTcplex_binv_to_tableau(MTlp, binvrow, tableau);
00244     CHECKRVALG(rval,CLEANUP);
00245     if(MT_VERB_LVL+10 < DEBUG) 
00246       MTcplex_display_tableau(stderr, MTlp, tableau);
00247     /* check that the asociated tableau is right */
00248     rval = MTcheckTabrow(MTlp,tableau,&status,&ratio,&tnz);
00249     CHECKRVALG(rval,CLEANUP);
00250     /* discard bad tableau rows */
00251     if(status) continue;
00252     if(minratio > ratio) minratio = ratio;
00253     /* compute f */
00254     MTcompute_f(MTlp, tableau, x, slack, f);
00255     /* now we compress the tableau */
00256     rval = MTcompressTabRow(MTlp, sol, tableau, tabind, f, &tnz);
00257     CHECKRVALG(rval,CLEANUP);
00258     MESSAGE(MT_VERB_LVL+5,"Tableau %d has %d non-zeros",icol,tnz);
00259     /* since these are integer tableau rows, they may end up being empty, in
00260      * such cases, we discard them */
00261     if(!tnz)
00262     {
00263       MESSAGE(MT_VERB_LVL,"Discarded empty integer tableau row %d",icol);
00264       continue;
00265     }
00266     /* up to now we have (but for integer factors) ax = f, and we want 
00267      * Z = f + Ax, moreover f[0] should be (about) zero */
00268     f[0] = round(f[0]) - f[0];
00269     if(fabs(f[0])>MT_CCBK_MIN_FRAC)
00270     {
00271       MTccbk_fail_tableau_frac++;
00272       MESSAGE(MT_VERB_LVL, "Discarding tableau %d, because f[%d] = %.4lf", 
00273           icol, 0, f[0]);
00274       continue;
00275     }
00276     tb->nrows = 1;
00277     onz = tb->nz = tnz;
00278     tb->rowbeg[1] = onz;
00279     /* now we loop through all fractional integer variables */
00280     for( fit = nfrac ; fit-- ; )
00281     {
00282       fcol = frac_ind[fit];
00283       /* check that the variable is basic */
00284       TESTG((rval=(cstat[fcol] != CPX_BASIC)), CLEANUP, "Variable[%d] = %lf,"
00285           " status %d isnt basic (%d)", fcol, x[fcol], cstat[fcol], CPX_BASIC); 
00286       /* get asociated basic row */
00287       rval = CPXgetijrow(env, lp, -1, fcol, &brow);
00288       MTcplexCHECKRVALG(env,rval,CLEANUP);
00289       rval = CPXbinvrow(env, lp, brow, binvrow);
00290       MTcplexCHECKRVALG(env,rval,CLEANUP);
00291       MTrowmatrix_rsz(tb,nrows,tb->nz+tb->ncols);
00292       tableau = tb->rowval+onz;
00293       tabind = tb->rowind+onz;
00294       rval = MTcplex_binv_to_tableau(MTlp, binvrow, tableau);
00295       CHECKRVALG(rval,CLEANUP);
00296       if(MT_VERB_LVL+10 < DEBUG) 
00297         MTcplex_display_tableau(stderr, MTlp, tableau);
00298       /* check that the asociated tableau is right */
00299       rval = MTcheckTabrow(MTlp,tableau,&status,&ratio,&tnz);
00300       CHECKRVALG(rval,CLEANUP);
00301       /* discard bad tableau rows */
00302       if(status) continue;
00303       if(minratio > ratio) minratio = ratio;
00304       /* store computed tableau */
00305       /* now we know that the tableau is good, and its length, so we save it */
00306       MTcompute_f(MTlp, tableau, x, slack, f+1);
00307       /* now we compress the tableau */
00308       rval = MTcompressTabRow(MTlp, sol, tableau, tabind, f+1, &tnz);
00309       CHECKRVALG(rval,CLEANUP);
00310       MESSAGE(MT_VERB_LVL+5,"Tableau %d has %d non-zeros",fcol,tnz);
00311       /* up to now we have (but for integer factors) ax = f, and we want 
00312        * Z = f + Ax */
00313       f[1] = -f[1] + round(f[1]);
00314       dtmp = fabs(f[1]);
00315       if(dtmp<MT_CCBK_MIN_FRAC)
00316       {
00317         MTccbk_fail_tableau_frac++;
00318         MESSAGE(MT_VERB_LVL, "Discarding tableau %d, because f[%d] = %.4lf", 
00319             fcol, 1, f[1]);
00320         continue;
00321       }
00322       /* f[1] should be between ]0,1[ */
00323       if(f[1]<0) f[1] += 1;
00324       /* now we passed all test for the tableau, so we save it */
00325       tb->nrows = 2;
00326       tb->nz = onz + tnz;
00327       tb->rowbeg[2] = tb->nz;
00328       #warning we could do a better job on integer variables in the second tableau row
00329       /* now we have the two row relaxation stored in tb, we now compute the 
00330        * cut */
00331       /* first see what active vars we have and reset work[active] == 0 */
00332       MESSAGE( MT_VERB_LVL, "joint tableau has %d rows and %d nonz", tb->nrows,
00333               tb->nz);
00334       rval = MTsl5(&nactive, active, nvars, tb->nz, tb->rowval, tb->rowind);
00335       CHECKRVALG(rval,CLEANUP);
00336       MESSAGE( MT_VERB_LVL, "Active cols %d %.3lf%%", nactive, 
00337               100*((double)nactive)/ncols);
00338       /* if nactive >= tb->nz, no intersection in tableau is possible */
00339       if(nactive >= tb->nz)
00340       {
00341         MESSAGE(MT_VERB_LVL,"Discarded, no intersection");
00342         continue;
00343       }
00344       #if MT_DEBUG_LVL +5 <= DEBUG
00345       FILE* fout = EGsfopen("cur_tableau.txt","w+");
00346       rval = MTwriteRTableau(fout, tb->nrows, tb->ncols, tb->rowval, tb->rowind, tb->rowbeg, f);
00347       CHECKRVALG(rval,CLEANUP);
00348       fclose(fout);
00349       #endif
00350       for( j = -1 ; j<2 ; j+=2 )
00351       {
00352         /* reset work and cutval */
00353         memset(work,0,sizeof(double)*((size_t)nvars));
00354         memset(cutval,0,sizeof(double)*((size_t)nvars));
00355         /* case j, set ineq[0] to j*x[0] <= 1 */
00356         /* set ineq[0] */
00357         MTsl4(ineq[0], (double)j, 1.0, (double)j, 0.0);
00358         /* b_i - a_i*f */
00359         rval = MTsl3(f,ineq[0],2);
00360         CHECKRVALG(rval,CLEANUP);
00361         /* compute in work[i] the value ineq[0] * r[i] */
00362         rval = MTsl1(ineq[0], tb, work, vtype, 1);
00363         CHECKRVALG(rval,CLEANUP);
00364         /* re-compute active */
00365         rval = MTsl5(&nactive, active, nvars, tb->nz, tb->rowval, tb->rowind);
00366         CHECKRVALG(rval,CLEANUP);
00367         MESSAGE(MT_VERB_LVL,"Active cols %d %.3lf%%", nactive, 
00368                 100*((double)nactive)/ncols);
00369         /* compute current cutval and reset work */
00370         rval = MTsl2(ineq[0], cutval, work, active, nactive);
00371         CHECKRVALG(rval,CLEANUP);
00372         if(MT_VERB_LVL+5<=DEBUG) MTcplex_display_tableau(stderr,MTlp,cutval);
00373         /* compute mval */
00374         mval[0] = 1;
00375         mval[1] = 0;
00376         util[0] = 0;
00377         util[1] = 1;
00378         /* compute in work[i] the value util * r[i], and resero work to zero */
00379         rval = MTsl1(util, tb, work, vtype, 0);
00380         CHECKRVALG(rval,CLEANUP);
00381         for( i = nactive ; i-- ; )
00382         {
00383           ccol = active[i];
00384           dtmp = work[ccol]*cutval[ccol];
00385           if(dtmp > 0)
00386           {
00387             mval[0] = EGmax(mval[0],dtmp+f[1]);
00388           }
00389           else
00390           {
00391             mval[1] = EGmin(mval[1],dtmp+f[1]);
00392           }
00393           work[ccol] = 0;
00394         }
00395         /* if Delta mval is small, discard lifting */
00396         #if 1
00397         dtmp = mval[0] - mval[1];
00398         if(dtmp < 1.01)
00399         {
00400           MESSAGE(MT_VERB_LVL, "Discarding lifting Delta mval = %lg < 1.1", dtmp);
00401           continue;
00402         }
00403         #endif
00404         /* now we can compute ineq[1] as passing through (j,mval[0]) 
00405          * and (0,1), while ineq[2] as passing through (j,mval[1]) 
00406          * and (0,0) */
00407         MESSAGE(MT_VERB_LVL, "computing ineq for points (%lf,%lf) to (%lf,%lf)",
00408                 (double)j, mval[0], 0.0, 1.0);
00409         MTsl4(ineq[1], (double)j, mval[0], 0.0, 1.0);
00410         /* b_i - a_i*f */
00411         rval = MTsl3(f,ineq[1],2);
00412         CHECKRVALG(rval,CLEANUP);
00413         /* compute in work[i] the value ineq[0] * r[i] */
00414         rval = MTsl1(ineq[1], tb, work, vtype, 0);
00415         CHECKRVALG(rval,CLEANUP);
00416         /* compute current cutval and reset work */
00417         rval = MTsl2(ineq[1], cutval, work, active, nactive);
00418         CHECKRVALG(rval,CLEANUP);
00419         if(MT_VERB_LVL+5<=DEBUG) MTcplex_display_tableau(stderr,MTlp,cutval);
00420         MESSAGE(MT_VERB_LVL, "computing ineq for points (%lf,%lf) to (%lf,%lf)",
00421                 (double)j, mval[1], 0.0, 0.0);
00422         MTsl4(ineq[2], (double)j, mval[1], 0.0, 0.0);
00423         /* b_i - a_i*f */
00424         rval = MTsl3(f,ineq[2],2);
00425         CHECKRVALG(rval,CLEANUP);
00426         /* compute in work[i] the value ineq[0] * r[i] */
00427         rval = MTsl1(ineq[2], tb, work, vtype, 0);
00428         CHECKRVALG(rval,CLEANUP);
00429         /* compute current cutval and reset work */
00430         rval = MTsl2(ineq[2], cutval, work, active, nactive);
00431         CHECKRVALG(rval,CLEANUP);
00432         if(MT_VERB_LVL+5<=DEBUG) MTcplex_display_tableau(stderr,MTlp,cutval);
00433         /* now we must process the cut at hand */
00434         cut = MTcutHeap_get_free_cut(cuth);
00435         rval = MTraw_to_uncomplemented_cut( MTlp, cutval, nactive, active, 
00436                                             cut, &status);
00437         CHECKRVALG(rval,CLEANUP);
00438         TESTG((rval=(cut->nz != nactive)), CLEANUP, 
00439               "Imposible, cutnz = %d active %d", cut->nz, nactive);
00440         /* now we add the cut to the cutheap */
00441         if(status == 0)
00442         {
00443           rval = MTcutHeap_add_cut(MTlp,cuth);
00444           CHECKRVALG(rval,CLEANUP);
00445         }
00446       }/* end looping through both possible simple siftings */
00447     }/* end loop through set of fractional integer variables */
00448   }/* end loop through the set of integer vaariables */
00449   /* initialize values */
00450   CLEANUP:
00451   EGfree(frac_ind);
00452   EGfree(binvrow);
00453   EGfree(vtype);
00454   EGfree(active);
00455   return rval;
00456 }
00457 /* ========================================================================= */
00458 int MTsl_ccbk(CPXCENVptr env,
00459               void*cbdata,
00460               int wherefrom,
00461               void*cbhandle,
00462               int*useraction_p)
00463 {
00464   MTgomory_ccbk_t*const data=(MTgomory_ccbk_t*)cbhandle;
00465   MTcutHeap_t*const cuth = &(data->cuth);
00466   MTcut_t*cut=0;
00467   int rval = 0, action = 0;
00468   CPXLPptr lp = 0;
00469   int ncols,nrows; 
00470   /* set default action */ 
00471   MESSAGE(MT_VERB_LVL,"Entering");
00472   *useraction_p = CPX_CALLBACK_DEFAULT; 
00473   /* process callback info */
00474   rval = MTccbk_info_process(&(data->info), env, cbdata, wherefrom, &action);
00475   CHECKRVALG(rval,CLEANUP);
00476   if(action) goto CLEANUP;
00477   /* get the LP */
00478   rval = CPXgetcallbacknodelp (env, cbdata, wherefrom, &lp); 
00479   MTcplexCHECKRVALG(env,rval,CLEANUP);
00480   /* if we are verbose, write the problem to a file */
00481   if(MT_VERB_LVL +5 <= DEBUG)
00482   {
00483     rval = CPXwriteprob(env,lp,"node_lp.lp.gz","LP");
00484     MTcplexCHECKRVALG(env,rval,CLEANUP);
00485   }
00486   /* and get its description */
00487   rval = MTlp_load_problem(env, &(data->lp), lp, cbdata, wherefrom);
00488   CHECKRVALG(rval,CLEANUP);
00489   /* get numrows and numcols */
00490   ncols = CPXgetnumcols(env,lp);
00491   nrows = CPXgetnumrows(env,lp);
00492   MESSAGE(MT_VERB_LVL+3,"Problem has %d vars and %d constr",ncols,nrows);
00493   /* resize */
00494   rval = EGmax(nrows,ncols);
00495   MTgomory_ccbk_rsz(data,nrows,ncols+nrows,rval);
00496   /* now we get the current X and slack */
00497   rval = MTget_sol(&(data->lp), env, lp, cbdata, wherefrom, &(data->sol));
00498   CHECKRVALG(rval,CLEANUP);
00499   /* if we are debugging, display variable information */
00500   if(MT_VERB_LVL + 10 <= DEBUG)
00501     MTdisplay_lp(&(data->lp), &(data->sol), stderr);
00502   /* now we get the cuts */
00503   rval = MTslCut(data, env, lp);
00504   CHECKRVALG(rval,CLEANUP);
00505   /* now we add the cuts in the cutheap */
00506   data->info.added_cuts += MTcutHeap_get_ncuts(cuth);
00507   data->info.node_cuts += MTcutHeap_get_ncuts(cuth);
00508   /* now we are in shape to add the cut to CPLEX */
00509   while((cut=MTcutHeap_pop_cut(cuth)))
00510   {
00511     rval = MTuncomplemented_to_complemented_cut(&(data->lp), &(data->sol), cut);
00512     CHECKRVALG(rval,CLEANUP);
00513     WARNINGL(MT_VERB_LVL,!cut->nz,"empty cut!");
00514     if(!cut->nz) continue;
00515     /* test the cut extensivewlly if needed */
00516     if(MT_DEBUG_LVL + 10 <= DEBUG)
00517     {
00518       rval = MTcplex_test_cut(cut, &(data->lp));
00519       CHECKRVALG(rval,CLEANUP);
00520     }
00521     rval = CPXcutcallbackaddlocal( env, cbdata, wherefrom, cut->nz, cut->rhs, 
00522                               cut->sense , cut->cutind, cut->cutval);
00523     MTcplexCHECKRVALG(env,rval,CLEANUP);
00524     MESSAGE(MT_VERB_LVL, "Node %zd LP:(%d,%d,%d) Constr %p: %d nz, %.2lf rhs,"
00525           " ratio %.2lf, violation (>0) %lf", data->info.node_cnt, 
00526           data->lp.nrows, data->lp.ncols, data->lp.nz, (void*)cut, cut->nz,
00527           cut->rhs, cut->max_abs/cut->min_abs, cut->violation);
00528   }
00529   CLEANUP:
00530   MESSAGE(MT_VERB_LVL,"Done, status %d",rval);
00531   return rval;
00532 }
00533 /** @} */
00534 /* end of mt_SL.c */
00535 /* ========================================================================= */

Generated on Mon Oct 26 09:16:29 2009 for MTgomory by  doxygen 1.4.6