mt_cutpool.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_cutpool.h"
00025 /** @file 
00026  * @ingroup MTgomory */
00027 /** @addtogroup MTgomory */
00028 /** @{ */
00029 /* ========================================================================= */
00030 void MTcutHeapInit(MTcutHeap_t*const cuth,size_t sz)
00031 {
00032   register int i;
00033   MTcutHeapCn_t*chcn;
00034   memset(cuth,0,sizeof(MTcutHeap_t));
00035   i = ((int)(cuth->all_sz = sz+1));
00036   dbl_EGeHeapInit(&(cuth->heap));
00037   dbl_EGeHeapChangeD(&(cuth->heap),2);
00038   dbl_EGeHeapResize(&(cuth->heap),cuth->all_sz);
00039   cuth->all_cn = EGsMalloc(MTcutHeapCn_t,cuth->all_sz); 
00040   EGeListInit(&(cuth->free_cn));
00041   for( ; i-- ; ){
00042     MTcutHeapCnInit(cuth->all_cn+i);
00043     EGeListAddAfter(&(cuth->all_cn[i].lcn),&(cuth->free_cn));
00044     }
00045   chcn = EGcontainerOf(cuth->free_cn.next,MTcutHeapCn_t,lcn);
00046   cuth->next_free = &(chcn->cut);
00047   EGeListDel(cuth->free_cn.next);
00048   cuth->control.cut_score = MTcsDefault;
00049   return;
00050 }
00051 /* ========================================================================= */
00052 void MTcutHeapClear(MTcutHeap_t*const cuth)
00053 {
00054   register int i = (int)(cuth->all_sz);
00055   dbl_EGeHeapResize(&(cuth->heap),0);
00056   dbl_EGeHeapClear(&(cuth->heap));
00057   for(;i--;) MTcutHeapCnClear(cuth->all_cn+i);
00058   EGfree(cuth->all_cn);
00059   memset(cuth,0,sizeof(MTcutHeap_t));
00060   return;
00061 }
00062 /* ========================================================================= */
00063 /** @brief given a #MTcutHeapCn_t compute the value asociated with the stored
00064  * cut and store it in #MTcutHeapCn_t::hcn, inside #dbl_EGeHeapCn_t::val, the
00065  * function used to evaluate depend on the configuration
00066  * for the cut heap.  The smallest the value, the worst the cut is.
00067  * @param chcn structure where we operate
00068  * @param cuth cutheap controling the cut heap connector 
00069  * @return zero on success, non-zero otherwise 
00070  * */
00071 static int MTcutHeapCn_compute_val( MTcutHeap_t*const cuth,
00072                                     MTcutHeapCn_t*const chcn)
00073 {
00074   register int i;
00075   double val = 0;
00076   int rval = 0;
00077   switch(cuth->control.cut_score)
00078   {
00079     case MTcsRAW:
00080       chcn->hcn.val = chcn->cut.score;
00081       break;
00082     case MTcsVIOL:
00083       chcn->hcn.val = chcn->cut.violation;
00084       break;
00085     case MTcsINVLINF:
00086       switch(chcn->cut.sense)
00087       {
00088         case 'L':
00089         case 'l':
00090           chcn->hcn.val = -chcn->cut.rhs/chcn->cut.max_abs;
00091           break;
00092         case 'G':
00093         case 'g':
00094           chcn->hcn.val = chcn->cut.rhs/chcn->cut.max_abs;
00095           break;
00096         default:
00097           FTESTG((rval=1),CLEANUP,"unexpected sense %c",chcn->cut.sense);
00098           break;
00099       }
00100       break;
00101     case MTcsINVL2:
00102       for( i = chcn->cut.nz ; i-- ; ) 
00103         val += chcn->cut.cutval[i]*chcn->cut.cutval[i];
00104       switch(chcn->cut.sense)
00105       {
00106         case 'L':
00107         case 'l':
00108           chcn->hcn.val = -chcn->cut.rhs*chcn->cut.rhs/val;
00109           break;
00110         case 'G':
00111         case 'g':
00112           chcn->hcn.val = chcn->cut.rhs*chcn->cut.rhs/val;
00113           break;
00114         default:
00115           FTESTG((rval=1),CLEANUP,"unexpected sense %c",chcn->cut.sense);
00116           break;
00117       }
00118       break;
00119     default:
00120       FTESTG((rval=1), CLEANUP, "Unknown function selection criteria %d", 
00121               cuth->control.cut_score);
00122       break;
00123   }
00124   CLEANUP:
00125   return rval;
00126 }
00127 /* ========================================================================= */
00128 /** @brief permutation sort for integers */
00129 void MTintPermSort( const int sz,
00130                     int*const perm,
00131                     const int*const elem)
00132 {
00133   int i, j, temp;
00134   int t;
00135   if (sz <= 1)
00136     return;
00137 
00138   EGswap (perm[0], perm[(sz - 1) / 2], temp);
00139   i = 0;
00140   j = sz;
00141   t = elem[perm[0]];
00142   for (;;)
00143   {
00144     do
00145       i++;
00146     while (i < sz && (elem[perm[i]] < t));
00147     do
00148       j--;
00149     while (t < elem[perm[j]]);
00150     if (j < i)
00151       break;
00152     EGswap (perm[i], perm[j], temp);
00153   }
00154   EGswap (perm[0], perm[j], temp);
00155   MTintPermSort (j, perm, elem);
00156   MTintPermSort (sz - i, perm + i, elem);
00157 }
00158 /* ========================================================================= */
00159 /** @brief internal memory for dominance check */
00160 static int* MTcut1_nz = 0;
00161 static int* MTcut2_nz = 0;
00162 void MTcutNzAlloc(void) __attribute__ ((constructor));
00163 void MTcutNzAlloc(void)
00164 {
00165   MTcut1_nz = int_EGlpNumAllocArray(100);
00166   MTcut2_nz = int_EGlpNumAllocArray(100);
00167 }
00168 void MTcutNzFree(void) __attribute__ ((destructor));
00169 void MTcutNzFree(void)
00170 {
00171   int_EGlpNumFreeArray(MTcut1_nz);
00172   int_EGlpNumFreeArray(MTcut2_nz);
00173 }
00174 /* ========================================================================= */
00175 /** @brief helper to set dominance */ 
00176 #define __MT_DOM do{\
00177   if(v2 + MT_ZERO_TOL < v1) \
00178   {\
00179     if(domset && dom != -1) return 0;\
00180     domset=1;\
00181     dom=-1;\
00182     equal = 0; \
00183   }\
00184   else if( v1 + MT_ZERO_TOL < v2)\
00185   {\
00186     if(domset && dom != 1) return 0;\
00187     domset=1;\
00188     dom=1;\
00189     equal = 0;\
00190   }\
00191   }while(0)
00192 /* ========================================================================= */
00193 int MTcut_check_dominance(const MTcut_t*const cut1, const MTcut_t*const cut2)
00194 {
00195   /* we work with ax >= rhs inequalities */
00196   const size_t c1nz = ((size_t)(cut1->nz));
00197   const size_t c2nz = ((size_t)(cut2->nz));
00198   const int sense1 = (cut1->sense == 'l' || cut1->sense == 'L') ? -1 : 1;
00199   const int sense2 = (cut2->sense == 'l' || cut2->sense == 'L') ? -1 : 1;
00200   int dom=0,domset=0,equal=1,p1,p2,c1,c2;
00201   register int i,j;
00202   double v1,v2;
00203   /* if either cut is an equation, we return 0 */
00204   if( cut1->sense == 'e' || cut1->sense == 'E' || 
00205       cut2->sense == 'e' || cut2->sense == 'E') return 0;
00206   /* allocate memory if necesary */
00207   if(__EGlpNumArraySize(MTcut1_nz) < c1nz)
00208     MTcut1_nz = int_EGlpNumReallocArray( &MTcut1_nz, c1nz);
00209   if(__EGlpNumArraySize(MTcut2_nz) < c2nz)
00210     MTcut2_nz = int_EGlpNumReallocArray( &MTcut2_nz, c2nz);
00211   /* sort the indices in the cut */ 
00212   for( i = cut1->nz ; i-- ; ) MTcut1_nz[i] = i;
00213   for( i = cut2->nz ; i-- ; ) MTcut2_nz[i] = i;
00214   MTintPermSort(cut1->nz, MTcut1_nz, cut1->cutind);
00215   MTintPermSort(cut2->nz, MTcut2_nz, cut2->cutind);
00216   /* first see if by checking RHS we can set a dominance direction */
00217   v1 = -1*sense1*cut1->rhs;
00218   v2 = -1*sense2*cut2->rhs;
00219   __MT_DOM;
00220   /* now we check the contents of both cuts */
00221   i = j = 0;
00222   while( i < cut1->nz || j < cut2->nz)
00223   {
00224     /* set the values to compare and advance in i and j */
00225     if( i < cut1->nz)
00226     {
00227       p1 = MTcut1_nz[i];
00228       c1 = cut1->cutind[p1];
00229       v1 = sense1*cut1->cutval[p1];
00230     }
00231     else
00232     {
00233       p1 = INT_MAX;
00234       c1 = INT_MAX;
00235       v1 = 0.0;
00236     }
00237     if( j < cut2->nz)
00238     {
00239       p2 = MTcut2_nz[j];
00240       c2 = cut2->cutind[p2];
00241       v2 = sense2*cut2->cutval[p2];
00242     }
00243     else
00244     {
00245       c2 = INT_MAX;
00246       p2 = INT_MAX;
00247       v2 = 0.0;
00248     }
00249     if(c1 < c2)
00250     {
00251       v2 = 0.0;
00252       j--;
00253     }
00254     else if(c1 > c2)
00255     {
00256       v1 = 0.0;
00257       i--;
00258     }
00259     i++;
00260     j++;
00261     /* compare the values */
00262     __MT_DOM;
00263   }
00264   /* ending */
00265   if(equal) dom=-1;
00266   return dom;
00267 }
00268 /* ========================================================================= */
00269 void MTcut_copy(MTcut_t*const dest,const MTcut_t*const src)
00270 {
00271   register int i = src->nz;
00272   dest->rhs = src->rhs;
00273   dest->violation = src->violation;
00274   dest->min_abs = src->min_abs;
00275   dest->max_abs = src->max_abs;
00276   dest->nz = src->nz;
00277   dest->sense = src->sense;
00278   dest->form = src->form;
00279   if(dest->nzspace < dest->nz)
00280     MTcut_rsz(dest,dest->nz);
00281   while(i--)
00282   {
00283     dest->cutind[i] = src->cutind[i];
00284     dest->cutval[i] = src->cutval[i];
00285   }
00286 }
00287 /* ========================================================================= */
00288 int MTcutHeap_add_cut(const MTlp_t*const lp, MTcutHeap_t*const cuth)
00289 {
00290   int rval = 0;
00291   register int i = ((int)(cuth->heap.sz));
00292   MTcutHeapCn_t*chcn = EGcontainerOf(cuth->next_free,MTcutHeapCn_t,cut);
00293   dbl_EGeHeapCn_t*ccn;
00294   MTcut_t *cut1 = &(chcn->cut),*cut2;
00295   /* now we compute the score for the cut, and add it to the heap */
00296   rval = MTcutHeapCn_compute_val(cuth,chcn);
00297   CHECKRVALG(rval, CLEANUP);
00298   /* check for dominated cuts */
00299   if(cuth->control.dominance_check)
00300   {
00301     for( ;i--;)
00302     {
00303       cut2 = &((EGcontainerOf(cuth->heap.cn[i], MTcutHeapCn_t,hcn))->cut);
00304       rval = MTcut_check_dominance(cut1,cut2);
00305       switch(rval)
00306       {
00307         case -1:
00308           MESSAGE(MT_VERB_LVL, "incomming cut is dominated, "
00309                   "score 1 %lf scrore 2 %lf",chcn->hcn.val, 
00310                   cuth->heap.cn[i]->val);
00311           rval = 0;
00312           goto CLEANUP;
00313           break;
00314         case 0:
00315           break;
00316         case 1:
00317           MTcut_copy(cut2,cut1);
00318           dbl_EGeHeapChangeVal(&(cuth->heap),cuth->heap.cn[i],chcn->hcn.val);
00319           MESSAGE(MT_VERB_LVL, "incomming cut dominate, "
00320                   "score 1 %lf scrore 2 %lf",chcn->hcn.val, 
00321                   cuth->heap.cn[i]->val);
00322           rval = 0;
00323           goto CLEANUP;
00324           break;
00325       }
00326       rval = 0;
00327     }
00328   }
00329   /* otherwise, we add it */
00330   rval = dbl_EGeHeapAdd(&(cuth->heap),&(chcn->hcn));
00331   CHECKRVALG(rval, CLEANUP);
00332   MESSAGE(MT_VERB_LVL, "Adding cut %p with score %lf",(void*)(&(chcn->cut)), 
00333           chcn->hcn.val);
00334   /* if we have no more empty cuts, we erase the worst from the heap */
00335   if(EGeListIsEmpty(&(cuth->free_cn)))
00336   {
00337     ccn = dbl_EGeHeapGetMin(&(cuth->heap));
00338     TESTG((rval = !ccn),CLEANUP,"Unexpected NULL pointer");
00339     dbl_EGeHeapDel(&(cuth->heap),ccn);
00340     chcn = EGcontainerOf(ccn,MTcutHeapCn_t,hcn);
00341     MESSAGE(MT_VERB_LVL, "Removing cut %p with score %lf",(void*)(&(chcn->cut)),
00342             ccn->val);
00343     EGeListAddAfter(&(chcn->lcn),&(cuth->free_cn));
00344     if((MT_VERB_LVL+3 <= DEBUG) && (&(chcn->cut) != cut1))
00345     {
00346       fprintf(stderr,"Adding new MTcut (compress+complemented): ");
00347       MTcplex_display_compress_tableau(stderr,lp,cut1->cutval, cut1->cutind, cut1->nz);
00348       fprintf(stderr,">=1\n");
00349     }
00350   }
00351   else if(MT_VERB_LVL+3 <= DEBUG)
00352   {
00353     fprintf(stderr,"Adding new MTcut (compress+complemented): ");
00354     MTcplex_display_compress_tableau(stderr,lp,cut1->cutval, cut1->cutind, cut1->nz);
00355     fprintf(stderr,">=1\n");
00356   }
00357   chcn = EGcontainerOf(cuth->free_cn.next,MTcutHeapCn_t,lcn);
00358   cuth->next_free = &(chcn->cut);
00359   EGeListDel(cuth->free_cn.next);
00360   CLEANUP:
00361   return rval;
00362 }
00363 /* ========================================================================= */
00364 MTcut_t* MTcutHeap_pop_cut(MTcutHeap_t*const cuth)
00365 {
00366   MTcutHeapCn_t*chcn=0;
00367   MTcut_t* cut=0;
00368   dbl_EGeHeapCn_t*ccn=0;
00369   ccn = dbl_EGeHeapGetMin(&(cuth->heap));
00370   if(ccn)
00371   {
00372     chcn = EGcontainerOf(ccn,MTcutHeapCn_t,hcn);
00373     cut = &(chcn->cut);
00374     dbl_EGeHeapDel(&(cuth->heap),ccn);
00375     EGeListAddAfter(&(chcn->lcn),&(cuth->free_cn));
00376   }
00377   return cut;
00378 }
00379 /* ========================================================================= */
00380 void MTcut_rsz(MTcut_t*const MTcut,
00381               const int MTnsz)
00382 {
00383   if(MTcut->nzspace < MTnsz)
00384   {
00385     MTcut->nzspace = MTnsz;
00386     MTcut->cutind = EGrealloc(MTcut->cutind, sizeof(int)*((size_t)MTnsz));
00387     MTcut->cutval = EGrealloc(MTcut->cutval, sizeof(double)*((size_t)MTnsz));
00388   }
00389   return;
00390 }
00391 /* ========================================================================= */
00392 void MTcut_clear(MTcut_t*const MTcut)
00393 {
00394   EGfree(MTcut->cutval);
00395   EGfree(MTcut->cutind);
00396   memset(MTcut,0,sizeof(MTcut_t));
00397   return;
00398 }
00399 
00400 /* ========================================================================= */
00401 /** @} */
00402 /* end of mt_cutpool.c */
00403 /* ========================================================================= */

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