mt_T1.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_T1.h"
00025 /** @file 
00026  * @ingroup MTgomory */
00027 /** @addtogroup MTgomory */
00028 /** @{ */
00029 /* ========================================================================= */
00030 int MTt1Cut(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, cur_tabrow = nrows;
00044   int*active = EGsMalloc(int,ncols);
00045   int nactive = 0, status;
00046   MTcut_t*cut = 0;
00047   register int i,j;
00048   EGgcIt_t gc;
00049   double ratio = 0;
00050   #if MT_DEBUG_LVL +5 <= DEBUG
00051   FILE* fout = EGsfopen("cur_tableau.txt","w+");
00052   rval = MTwriteRTableau(fout, nrows, ncols, rowval, rowind, rowbeg, f);
00053   CHECKRVALG(rval,CLEANUP);
00054   fclose(fout);
00055   #endif
00056   memset(&gc,0,sizeof(EGgcIt_t));
00057   /* check some basic assumptions */
00058   if(MT_DEBUG_LVL <= DEBUG)
00059   {
00060     for(i = nrows ; i-- ; )
00061     {
00062       TESTG((rval=(f[i]<=(-0x1p-1+MT_ZERO_TOL))), CLEANUP, 
00063             "%d-th fractional value is outside bounds %lf <= %lf", 
00064             i, f[i], (-0x1p-1+MT_ZERO_TOL));
00065       TESTG((rval=(f[i]>=(0x1p-1-MT_ZERO_TOL))), CLEANUP, 
00066             "%d-th fractional value is outside bounds %lf >= %lf", 
00067             i, f[i], (0x1p-1-MT_ZERO_TOL));
00068     }
00069   }
00070   /* allocate memory */
00071   /* compute number of active columns in the tableau */
00072   memset(active,0,sizeof(int)*((size_t)ncols));
00073   for( i = rowbeg[nrows] ; i-- ;) active[rowind[i]] = 1;
00074   for(nactive=0, i = 0 ; i < ncols ; i++)
00075     if(active[i]) active[nactive++] = i;
00076   MESSAGE(MT_VERB_LVL,"Active cols %.3lf%%",100*((double)nactive)/ncols);
00077   /* initialize values */
00078   REDO:
00079   EGgcItInit(&gc,cur_tabrow);
00080   for( i = ncols ; i-- ; ) work[i] = 0.0;
00081   work[ncols] = 0.5*cur_tabrow;
00082   /* now we compute in works[ncols] = n/2 - f*\sigma  and compute in work[i] 
00083    * col_i*\sigma */
00084   for( j = cur_tabrow ; j-- ; )
00085   {
00086     sense = ((EGgcItGetTuple(&gc))[j]);
00087     if(sense){
00088       work[ncols] -= f[j];
00089       for( i = rowbeg[j] ; i < rowbeg[j+1] ; i++)
00090         work[rowind[i]] += rowval[i];
00091     }
00092     else
00093     {
00094       work[ncols] += f[j];
00095       for( i = rowbeg[j] ; i < rowbeg[j+1] ; i++)
00096         work[rowind[i]] -= rowval[i];
00097     }
00098   }
00099   /* now we start computing the inequalities */ 
00100   do
00101   {
00102     TESTG((rval=(work[ncols]<0)), CLEANUP, "Imposible!, n/2-sigma*f"
00103           " (%.6lf) < 0",work[ncols]);
00104     /* compute the cut values */
00105     for( i = ncols ; i-- ; ) cutval[i] = work[i] > MT_ZERO_TOL ? work[i]/work[ncols]:0.0;
00106     for( j = cur_tabrow ; j-- ; )
00107     {
00108       sense = ((EGgcItGetTuple(&gc))[j]);
00109       if(sense)
00110       {
00111         for( i = rowbeg[j] ; i < rowbeg[j+1] ; i++)
00112         {
00113           if((rowval[i] < -MT_ZERO_TOL) && 
00114             ((ratio = rowval[i]/(-0.5-f[j])) > cutval[rowind[i]]))
00115             cutval[rowind[i]] = ratio;
00116         }
00117       }
00118       else
00119       {
00120         for( i = rowbeg[j] ; i < rowbeg[j+1] ; i++)
00121         {
00122           if((rowval[i] > MT_ZERO_TOL) &&
00123             ((ratio = rowval[i]/(0.5-f[j])) > cutval[rowind[i]]))
00124             cutval[rowind[i]] = ratio;
00125         }
00126       }
00127     }
00128     /* now we must process the cut at hand */
00129     cut = MTcutHeap_get_free_cut(cuth);
00130     rval = MTraw_to_uncomplemented_cut( lp, cutval, nactive, active, cut, &status);
00131     CHECKRVALG(rval,CLEANUP);
00132     if(status) goto NEXT;
00133     /* now we add the cut to the cutheap */
00134     rval = MTcutHeap_add_cut(lp,cuth);
00135     CHECKRVALG(rval,CLEANUP);
00136     /* now we prepare for the next reorientation */
00137     NEXT:
00138     redo = EGgcItNext(&gc);
00139     if(!redo) break;
00140     /* now we should re-compute work[*] */
00141     pos = EGgcItGetChange(&gc);
00142     sense = ((EGgcItGetTuple(&gc))[pos]);
00143     if(sense)
00144     {
00145       work[ncols] -= 2*f[pos];
00146       for( i = rowbeg[pos] ; i < rowbeg[pos+1] ; i++)
00147         work[rowind[i]] += 2*rowval[i];
00148     }
00149     else
00150     {
00151       work[ncols] += 2*f[pos];
00152       for( i = rowbeg[pos] ; i < rowbeg[pos+1] ; i++)
00153         work[rowind[i]] -= 2*rowval[i];
00154     }
00155   }while(1);
00156   EGgcItClear(&gc);
00157   if(cut_style && cur_tabrow > 2)
00158   {
00159     cur_tabrow--;
00160     EGgcItClear(&gc);
00161     goto REDO;
00162   }
00163   CLEANUP:
00164   EGgcItClear(&gc);
00165   EGfree(active);
00166   return rval;
00167 }
00168 /* ========================================================================= */
00169 int MTt1_ccbk(CPXCENVptr env,
00170               void*cbdata,
00171               int wherefrom,
00172               void*cbhandle,
00173               int*useraction_p)
00174 {
00175   MTgomory_ccbk_t*const data=(MTgomory_ccbk_t*)cbhandle;
00176   MTcutHeap_t*const cuth = &(data->cuth);
00177   MTcut_t*cut=0;
00178   int rval = 0, action = 0;
00179   CPXLPptr lp = 0;
00180   int ncols,nrows; 
00181   /* set default action */ 
00182   MESSAGE(MT_VERB_LVL,"Entering");
00183   *useraction_p = CPX_CALLBACK_DEFAULT; 
00184   /* process callback info */
00185   rval = MTccbk_info_process(&(data->info), env, cbdata, wherefrom, &action);
00186   CHECKRVALG(rval,CLEANUP);
00187   if(action) goto CLEANUP;
00188   /* get the LP */
00189   rval = CPXgetcallbacknodelp (env, cbdata, wherefrom, &lp); 
00190   MTcplexCHECKRVALG(env,rval,CLEANUP);
00191   /* if we are verbose, write the problem to a file */
00192   if(MT_VERB_LVL +5 <= DEBUG)
00193   {
00194     rval = CPXwriteprob(env,lp,"node_lp.lp.gz","LP");
00195     MTcplexCHECKRVALG(env,rval,CLEANUP);
00196   }
00197   /* and get its description */
00198   rval = MTlp_load_problem(env, &(data->lp), lp, cbdata, wherefrom);
00199   CHECKRVALG(rval,CLEANUP);
00200   /* get numrows and numcols */
00201   ncols = CPXgetnumcols(env,lp);
00202   nrows = CPXgetnumrows(env,lp);
00203   MESSAGE(MT_VERB_LVL+3,"Problem has %d vars and %d constr",ncols,nrows);
00204   /* resize */
00205   rval = EGmax(nrows,ncols);
00206   MTgomory_ccbk_rsz(data,nrows,ncols+nrows,rval);
00207   /* now we get the current X and slack */
00208   rval = MTget_sol(&(data->lp), env, lp, cbdata, wherefrom, &(data->sol));
00209   CHECKRVALG(rval,CLEANUP);
00210   /* if we are debugging, display variable information */
00211   if(MT_VERB_LVL + 10 <= DEBUG)
00212     MTdisplay_lp(&(data->lp), &(data->sol), stderr);
00213   /* get the best MT_CCBK_MAX_VARS tableaus */
00214   rval = MTget_best_k_tableau_rows( &(data->lp), &(data->sol), 
00215                                     data->info.max_rows, env, lp, 
00216                                     &(data->tb), data->f);
00217   CHECKRVALG(rval,CLEANUP);
00218   if(!data->tb.nrows) goto CLEANUP;
00219   /* and now we should call the cut-generator routine */
00220   rval = MTt1Cut( &(data->tb), &(data->lp), cuth, data->f, 
00221                   data->extcut, data->work, data->info.cut_style);
00222   CHECKRVALG(rval,CLEANUP);
00223   /* now we add the cuts in the cutheap */
00224   data->info.added_cuts += MTcutHeap_get_ncuts(cuth);
00225   data->info.node_cuts += MTcutHeap_get_ncuts(cuth);
00226   /* now we are in shape to add the cut to CPLEX */
00227   while((cut=MTcutHeap_pop_cut(cuth)))
00228   {
00229     rval = MTuncomplemented_to_complemented_cut(&(data->lp), &(data->sol), cut);
00230     CHECKRVALG(rval,CLEANUP);
00231     /* test the cut extensivewlly if needed */
00232     if(MT_DEBUG_LVL + 10 <= DEBUG)
00233     {
00234       rval = MTcplex_test_cut(cut, &(data->lp));
00235       CHECKRVALG(rval,CLEANUP);
00236     }
00237     rval = CPXcutcallbackaddlocal( env, cbdata, wherefrom, cut->nz, cut->rhs, 
00238                               cut->sense , cut->cutind, cut->cutval);
00239     MTcplexCHECKRVALG(env,rval,CLEANUP);
00240     MESSAGE(MT_VERB_LVL, "Node %zd LP:(%d,%d,%d) Constr: %d nz, %.2lf rhs,"
00241           " ratio %.2lf, violation (>0) %lf", data->info.node_cnt, 
00242           data->lp.nrows, data->lp.ncols, data->lp.nz, cut->nz, cut->rhs, 
00243           cut->max_abs/cut->min_abs, cut->violation);
00244   }
00245   CLEANUP:
00246   MESSAGE(MT_VERB_LVL,"Done, status %d",rval);
00247   return rval;
00248 }
00249 /** @} */
00250 /* end of mt_T1.h */
00251 /* ========================================================================= */

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