mt_T2.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_T2.h"
00025 /** @file 
00026  * @ingroup MTgomory */
00027 /** @addtogroup MTgomory */
00028 /** @{ */
00029 /* ========================================================================= */
00030 int MTt2Cut(const MTrowmatrix_t*const tb, 
00031             MTlp_t*const lp, 
00032             MTcutHeap_t*const cuth,
00033             const double*const f,
00034             double*const cutval,
00035             double*const work,
00036             const int cut_style)
00037 {
00038   const int nrows = tb->nrows;
00039   const int ncols = tb->ncols;
00040   const double*const rowval = tb->rowval;
00041   const int*const rowind = tb->rowind;
00042   const int*const rowbeg = tb->rowbeg;
00043   int rval=0,pos,sense,redo,redo2, cur_tabrows = nrows;
00044   double* ineq_val = EGsMalloc(double,(ncols+1)*(nrows+1));
00045   double* ineq = 0;
00046   const int*order = 0;
00047   const int*sign = 0;
00048   int*active = EGsMalloc(int,ncols);
00049   int nactive = 0, status;
00050   MTcut_t*cut;
00051   register int i,j,k;
00052   EGgcIt_t gc;
00053   EGpermIt_t prit;
00054   double ratio = 0;
00055   #if MT_DEBUG_LVL +5 <= DEBUG
00056   FILE* fout = EGsfopen("cur_tableau.txt","w+");
00057   rval = MTwriteRTableau(fout, nrows, ncols, rowval, rowind, rowbeg, f);
00058   CHECKRVALG(rval,CLEANUP);
00059   fclose(fout);
00060   #endif
00061   /* check some basic assumptions */
00062   if(MT_DEBUG_LVL <= DEBUG)
00063   {
00064     for(i = nrows ; i-- ; )
00065     {
00066       TESTG((rval=(f[i]<=(-0x1p-1+MT_ZERO_TOL))), CLEANUP, 
00067             "%d-th fractional value is outside bounds %lf <= %lf", 
00068             i, f[i], (-0x1p-1+MT_ZERO_TOL));
00069       TESTG((rval=(f[i]>=(0x1p-1-MT_ZERO_TOL))), CLEANUP, 
00070             "%d-th fractional value is outside bounds %lf >= %lf", 
00071             i, f[i], (0x1p-1-MT_ZERO_TOL));
00072     }
00073   }
00074   /* allocate memory */
00075   REDO:
00076   EGgcItInit(&gc,cur_tabrows);
00077   EGpermItInit(&prit,cur_tabrows);
00078   order = EGpermItGetTuple(&prit);
00079   sign = EGgcItGetTuple(&gc);
00080   /* compute number of active columns in the tableau */
00081   memset(active,0,sizeof(int)*((size_t)ncols));
00082   for( i = rowbeg[cur_tabrows] ; i-- ;)
00083     active[rowind[i]] = 1;
00084   for(nactive=0, i = 0 ; i < ncols ; i++)
00085     if(active[i]) active[nactive++] = i;
00086   MESSAGE(MT_VERB_LVL,"Active cols %.3lf%%",100*((double)nactive)/ncols);
00087   /* man iterations */
00088   do
00089   {
00090     /* re-initialize gc iterator */
00091     EGgcItReset(&gc);
00092     if(MT_DEBUG_LVL + 10 <= DEBUG)
00093     {
00094       fprintf(stderr,"\rUsing Order  ");
00095       for( i = 0 ; i<cur_tabrows ; i++ ) fprintf(stderr,"%d ",order[i]);
00096       fprintf(stderr,"\n");
00097     }
00098     /* now we have to initialize the value of each inequality for the current
00099      * permutation, position k*(ncols+1)+i , contains 
00100      * const[perm]_k*\sigma*col_i for i=0,ncols-1, and position 
00101      * k*(ncols+1)+ncols contains rhs_k - const[perm]_k*\sigma*f */
00102     memset(ineq_val,0,sizeof(double)*((size_t)((ncols+1)*(cur_tabrows+1))));
00103     /* initialize positions k*(ncols+1)+ncols */
00104     for( k = cur_tabrows ; k-- ; ) 
00105       ineq_val[k*(ncols+1)+ncols] = 0.5*((double)(k+1));
00106     ineq_val[cur_tabrows*(ncols+1)+ncols] = 0.5*((double)cur_tabrows);
00107     /* compute coefficients for each column and rhs in each constraint */
00108     for( j = cur_tabrows ; j-- ; )
00109     {
00110       sense = sign[j] ? -1:1;
00111       k = order[j];
00112       ineq_val[k*(ncols+1)+ncols] += sense*f[j];
00113       for( k++ ; k <= cur_tabrows ; k++)
00114         ineq_val[k*(ncols+1)+ncols] -= sense*f[j];
00115       for( i = rowbeg[j] ; i < rowbeg[j+1] ; i++)
00116       {
00117         k = order[j];
00118         ineq_val[k*(ncols+1)+rowind[i]] -= sense*rowval[i];
00119         for(k++ ; k <= cur_tabrows ; k++)
00120           ineq_val[k*(ncols+1)+rowind[i]] += sense*rowval[i];
00121       }
00122     }
00123     /* now we start computing inequalities for the current permutation in all
00124      * posible axis reorientations */
00125     do
00126     {
00127       if(MT_DEBUG_LVL + 10 <= DEBUG)
00128       {
00129         fprintf(stderr,"\tUsing orientation ");
00130         for( i = 0 ; i<cur_tabrows ; i++ ) fprintf(stderr,"%d ",sign[i]);
00131         fprintf(stderr,"\n");
00132       }
00133       /* we have all values, so we can compute the resulting cut */
00134       /* compute the current cut in cutval */
00135       memset(cutval,0,sizeof(double)*((size_t)ncols));
00136       for( k = cur_tabrows+1 ; k-- ; )
00137       {
00138         ineq = ineq_val+k*(ncols+1);
00139         TESTG((rval = (ineq[ncols]<0)), CLEANUP, 
00140               "Imposible rhs_k - const[perm]_k*\\sigma*f < 0!");
00141         for( i = nactive ; i-- ; ) 
00142         {
00143           pos = active[i];
00144           if(ineq[pos] < MT_ZERO_TOL) continue;
00145           ratio = ineq[pos]/ineq[ncols];
00146           if(cutval[pos] < ratio) cutval[pos] = ratio;
00147         }
00148       }
00149       /* at this stage we have the cut computed and ineq_val, so we just
00150        * process the cut at hand. */
00151       cut = MTcutHeap_get_free_cut(cuth);
00152       for( i = ncols ; i-- ; ) work[i] = cutval[i]; 
00153       rval = MTraw_to_uncomplemented_cut( lp, work, nactive, active, cut, &status);
00154       CHECKRVALG(rval,CLEANUP);
00155       if(status) goto NEXT;
00156       /* now we add the cut to the cutheap */
00157       rval = MTcutHeap_add_cut(lp,cuth);
00158       CHECKRVALG(rval,CLEANUP);
00159       /* now we prepare for the next reorientation */
00160       NEXT:
00161       /* test if there is a next reorientaation */
00162       redo = EGgcItNext(&gc);
00163       if(!redo) break;
00164       pos = EGgcItGetChange(&gc);
00165       sense = sign[pos] ? -1:1;
00166       /* update the values of ineq_val */
00167       k = order[pos];
00168       ineq_val[k*(ncols+1)+ncols] += 2*sense*f[pos];
00169       for( k++ ; k<= cur_tabrows ; k++)
00170         ineq_val[k*(ncols+1)+ncols] -= 2*sense*f[pos];
00171       for( i = rowbeg[pos]; i < rowbeg[pos+1] ; i++)
00172       {
00173         k = order[pos];
00174         ineq_val[k*(ncols+1)+rowind[i]] -= 2*sense*rowval[i];
00175         for(k++ ; k <= cur_tabrows ; k++)
00176           ineq_val[k*(ncols+1)+rowind[i]] += 2*sense*rowval[i];
00177       }
00178     } while(1);
00179     /* check if we have to do another permutation */
00180     redo2 = EGpermItNext(&prit);
00181     if(!redo2) break;
00182   } while(1);
00183   if(cut_style && cur_tabrows > 2)
00184   {
00185     EGgcItClear(&gc);
00186     EGpermItClear(&prit);
00187     cur_tabrows--;
00188     goto REDO;
00189   }
00190   /* and we are done! */
00191   CLEANUP:
00192   EGgcItClear(&gc);
00193   EGpermItClear(&prit);
00194   EGfree(ineq_val);
00195   EGfree(active);
00196   return rval;
00197 }
00198 /* ========================================================================= */
00199 int MTt2_ccbk(CPXCENVptr env,
00200               void*cbdata,
00201               int wherefrom,
00202               void*cbhandle,
00203               int*useraction_p)
00204 {
00205   MTgomory_ccbk_t*const data=(MTgomory_ccbk_t*)cbhandle;
00206   MTcutHeap_t*const cuth = &(data->cuth);
00207   MTcut_t*cut=0;
00208   int rval = 0, action = 0;
00209   CPXLPptr lp = 0;
00210   int ncols,nrows;
00211   size_t ncpr=0; 
00212   /* set default action */ 
00213   MESSAGE(MT_VERB_LVL,"Entering");
00214   *useraction_p = CPX_CALLBACK_DEFAULT; 
00215   /* process callback info */
00216   rval = MTccbk_info_process(&(data->info), env, cbdata, wherefrom, &action);
00217   CHECKRVALG(rval,CLEANUP);
00218   if(action) goto CLEANUP;
00219   /* get the LP */
00220   rval = CPXgetcallbacknodelp (env, cbdata, wherefrom, &lp); 
00221   MTcplexCHECKRVALG(env,rval,CLEANUP);
00222   /* if we are verbose, write the problem to a file */
00223   if(MT_VERB_LVL +5 <= DEBUG)
00224   {
00225     rval = CPXwriteprob(env,lp,"node_lp.lp.gz","LP");
00226     MTcplexCHECKRVALG(env,rval,CLEANUP);
00227   }
00228   /* and get its description */
00229   rval = MTlp_load_problem(env, &(data->lp), lp, cbdata, wherefrom);
00230   CHECKRVALG(rval,CLEANUP);
00231   /* get numrows and numcols */
00232   ncols = CPXgetnumcols(env,lp);
00233   nrows = CPXgetnumrows(env,lp);
00234   MESSAGE(MT_VERB_LVL+3,"Problem has %d vars and %d constr",ncols,nrows);
00235   /* resize */
00236   rval = EGmax(nrows,ncols);
00237   MTgomory_ccbk_rsz(data,nrows,ncols+nrows,rval);
00238   /* now we get the current X and slack */
00239   rval = MTget_sol(&(data->lp), env, lp, cbdata, wherefrom, &(data->sol));
00240   CHECKRVALG(rval,CLEANUP);
00241   /* if we are debugging, display variable information */
00242   if(MT_VERB_LVL + 10 <= DEBUG)
00243     MTdisplay_lp(&(data->lp), &(data->sol), stderr);
00244   /* get the best MT_CCBK_MAX_VARS tableaus */
00245   rval = MTget_best_k_tableau_rows( &(data->lp), &(data->sol), 
00246                                     data->info.max_rows, env, lp, 
00247                                     &(data->tb), data->f);
00248   CHECKRVALG(rval,CLEANUP);
00249   if(!data->tb.nrows) goto CLEANUP;
00250   /* and now we should call the cut-generator routine */
00251   rval = MTt2Cut( &(data->tb), &(data->lp), cuth, data->f, 
00252                   data->extcut, data->work, data->info.cut_style);
00253   CHECKRVALG(rval,CLEANUP);
00254   /* now we add the cuts in the cutheap */
00255   ncpr = MTcutHeap_get_ncuts(cuth);
00256   data->info.added_cuts += ncpr;
00257   data->info.node_cuts += ncpr;
00258   /* now we are in shape to add the cut to CPLEX */
00259   while((cut=MTcutHeap_pop_cut(cuth)))
00260   {
00261     rval = MTuncomplemented_to_complemented_cut(&(data->lp), &(data->sol), cut);
00262     CHECKRVALG(rval,CLEANUP);
00263     /* test the cut extensivewlly if needed */
00264       if(MT_DEBUG_LVL + 10 <= DEBUG)
00265     {
00266       rval = MTcplex_test_cut(cut, &(data->lp));
00267       if(rval)
00268       {
00269         fprintf(stderr,"Failing cut was:");
00270         MTcplex_display_compress_tableau( stderr, &(data->lp), cut->cutval, 
00271                                           cut->cutind, cut->nz);
00272         fprintf(stderr," >= %.3lf, max_abs %lf, min_abs %lf\n",cut->rhs, 
00273                 cut->max_abs, cut->min_abs);
00274       }
00275       CHECKRVALG(rval,CLEANUP);
00276       fprintf(stderr,"Adding cut with raw score %.7lg",cut->score);
00277       fprintf(stderr," MTcut: ");
00278       MTcplex_display_compress_tableau(stderr, &(data->lp), cut->cutval, cut->cutind, cut->nz);
00279       fprintf(stderr," >= %.4lf\n", cut->rhs);
00280     }
00281     rval = CPXcutcallbackaddlocal( env, cbdata, wherefrom, cut->nz, cut->rhs, 
00282                               cut->sense , cut->cutind, cut->cutval);
00283     MTcplexCHECKRVALG(env,rval,CLEANUP);
00284     MESSAGE(MT_VERB_LVL, "Node %zd LP:(%d,%d,%d) Constr: %d nz, %.2lf rhs,"
00285           " ratio %.2lf, violation (>0) %lf", data->info.node_cnt, 
00286           data->lp.nrows, data->lp.ncols, data->lp.nz, cut->nz, cut->rhs, 
00287           cut->max_abs/cut->min_abs, cut->violation);
00288   }
00289   CLEANUP:
00290   MESSAGE(MT_VERB_LVL,"Done, status %d, added %zd cuts",rval,ncpr);
00291   return rval;
00292 }
00293 /** @} */
00294 /* end of mt_T2.c */
00295 /* ========================================================================= */

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