mt_cplex.ex.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 "EGlib.h"
00025 #include "MTgomory.h"
00026 #include <signal.h>
00027 /** @file 
00028  * @ingroup MTgomory */
00029 /** @addtogroup MTgomory */
00030 /** @{ */
00031 /* ========================================================================= */
00032 /** @name static parameters for the main program */
00033 /*@{*/
00034 /** @brief CPLEX option file name */
00035 static char options[1024]="cplex.opt";
00036 /** @brief input problem file */
00037 static char problem[1024] = "";
00038 /** @brief global cplex environment */
00039 static CPXENVptr env = 0;
00040 /** @brief global lp pointer */
00041 static CPXLPptr  lp = 0;
00042 /** @brief max cuts per node */
00043 static int max_cuts_per_node = 1000;
00044 /** @brief max cuts per round */
00045 static int max_cuts_per_round = 10;
00046 /** @brief cuts at root only */
00047 static int cuts_at_root_only = 1;
00048 /** @brief cut selection strategy */
00049 static MTcutSelection_t cut_selection = MTcsDefault; 
00050 /** @brief cut dominance check enable */
00051 static int cut_dominance = 0;
00052 /** @brief maximum number of tableau-rows to use */
00053 static int max_tableau_rows = 5;
00054 /** @brief use callback cuts */
00055 static int use_cuts = 1;
00056 /** @brief use solve callback */
00057 static int use_solve_cbk = 0;
00058 /** @brief cut generation strategy */
00059 static int cut_style = 1;
00060 /** @brief maximum running time */
00061 static double max_rtime = INT_MAX;
00062 /** @brief maximum memory usage */
00063 static unsigned long memlimit = UINT_MAX;
00064 /*@}*/
00065 /* ========================================================================= */
00066 static void sighandler(int s)
00067 {
00068   switch(s)
00069   {
00070     case SIGXCPU:
00071       fprintf(stderr,"TIME_LIMIT_REACHED (ending now)\n");
00072       exit(EXIT_FAILURE);
00073     default:
00074       fprintf(stderr,"Unknown signal %d (ending now)\n",s);
00075       exit(EXIT_FAILURE);
00076   }
00077 }
00078 /* ========================================================================= */
00079 /** @brief function to handle resource usage limits */
00080 static int mem_limits(void)
00081 {
00082   int rval = 0;
00083   struct rlimit mlim;
00084   rval = getrlimit(RLIMIT_CPU,&mlim);
00085   CHECKRVAL(rval);
00086   fprintf(stderr, "Cur rtime limit %ld, trying to set to %lg\n", mlim.rlim_cur, max_rtime);
00087   if(max_rtime > mlim.rlim_max) max_rtime = (double)mlim.rlim_max;
00088   mlim.rlim_cur = (rlim_t)max_rtime;
00089   rval = setrlimit(RLIMIT_CPU,&mlim);
00090   TESTERRNOIF(rval);
00091   fprintf(stderr, "New rtime limit %ld (%.3lg)\n", mlim.rlim_cur, max_rtime);
00092   rval = getrlimit(RLIMIT_DATA,&mlim);
00093   TESTERRNOIF(rval);
00094   fprintf(stderr, "Cur data limit %ld,%ld (soft,hard)\n", mlim.rlim_cur, 
00095           mlim.rlim_max);
00096   mlim.rlim_cur = memlimit;       
00097   rval = setrlimit(RLIMIT_DATA,&mlim);        
00098   TESTERRNOIF(rval);
00099   rval = getrlimit(RLIMIT_DATA,&mlim);
00100   TESTERRNOIF(rval);
00101   fprintf(stderr, "New data limit %ld,%ld (soft,hard)\n", mlim.rlim_cur, 
00102           mlim.rlim_max);
00103   rval = getrlimit(RLIMIT_AS,&mlim);
00104   TESTERRNOIF(rval);
00105   fprintf(stderr, "Cur address space limit %ld,%ld (soft,hard)\n", 
00106           mlim.rlim_cur, mlim.rlim_max);
00107   mlim.rlim_cur = memlimit; 
00108   rval = setrlimit(RLIMIT_AS,&mlim);        
00109   TESTERRNOIF(rval);
00110   rval = getrlimit(RLIMIT_AS,&mlim);
00111   TESTERRNOIF(rval);
00112   fprintf(stderr, "New address space limit %ld,%ld (soft,hard)\n", 
00113           mlim.rlim_cur, mlim.rlim_max);
00114   mlim.rlim_cur = 0;
00115   rval = setrlimit(RLIMIT_CORE,&mlim);        
00116   TESTERRNOIF(rval);
00117   rval = getrlimit(RLIMIT_CORE,&mlim);
00118   TESTERRNOIF(rval);
00119   fprintf(stderr, "New core dump space limit %ld,%ld (soft,hard)\n", 
00120           mlim.rlim_cur, mlim.rlim_max);
00121   /* set signal handler for SIGXCPU */
00122   signal(SIGXCPU,sighandler);
00123   return rval;
00124 }
00125 /* ========================================================================= */
00126 /** @brief usage function */
00127 void usage(char*const prog)
00128 {
00129   fprintf(stderr,"Usage: %s [options]\n",prog);
00130   fprintf(stderr,"Options:\n");
00131   fprintf(stderr,"\t-c n Choose cut-generation procedure: 0 = none, \n"
00132                  "\t     1 = MTgomory, 2 = T1, 3 = T2. Default %d\n", 
00133                  use_cuts);
00134   fprintf(stderr,"\t-d n enable (=1) or not (=0) cut dominance check,\n"
00135                  "\t     default %d\n", cut_dominance);
00136   fprintf(stderr,"\t-f s file name of the problem to be optimized\n");
00137   fprintf(stderr,"\t-h   print this help and exit\n");
00138   fprintf(stderr,"\t-m n maximum memory usage allowed, default %lu\n", 
00139           memlimit);
00140   fprintf(stderr,"\t-n n maximum number of cuts to add at a given node in the\n"
00141                  "\t     B&B tree, default %d\n", max_cuts_per_node);
00142   fprintf(stderr,"\t-N n maximum number of cuts to add per round, default %d\n",
00143           max_cuts_per_round);
00144   fprintf(stderr,"\t-o s file name of the cplex option file, default %s\n",
00145           "cplex.opt");
00146   fprintf(stderr,"\t-r n add cuts only at the root node, default %d\n",
00147           cuts_at_root_only);
00148   fprintf(stderr,"\t-R n maximum running time allowed, default %lf\n",
00149           max_rtime);
00150   fprintf(stderr,"\t-s n cut selection strategy, %d for violation, %d for \n"
00151                  "\t     1/L_inf, %d for 1/L_2, %d for raw score, default %d\n", 
00152                  MTcsVIOL, MTcsINVLINF, MTcsINVL2, MTcsRAW, cut_selection);
00153   fprintf(stderr,"\t-S n use (1) solve callback or not (0), default %d\n",
00154                   use_solve_cbk); 
00155   fprintf(stderr,"\t-T n cut generation style 0 for one round, 1 for multiple\n"
00156                  "\t     rounds on the same set of best tableau rows, default %d\n",
00157                  cut_style);
00158   fprintf(stderr,"\t-t n maximum number of tableau to use while generating \n"
00159                  "\t     MTgomory cuts, default %d\n", max_tableau_rows);
00160 }
00161 /* ========================================================================= */
00162 /** @brief parsing parameters function, also read problem and options file */
00163 int parseargs(int argc,char**argv)
00164 {
00165   int has_problem=0;
00166   int c,rval;
00167   FILE* infile = 0;
00168   while((c=getopt(argc,argv,"f:ho:c:d:T:t:r:R:m:n:N:s:S:")) != EOF)
00169   {
00170     switch(c)
00171     {
00172       case 'h':
00173         usage(argv[0]);
00174         exit(0);
00175         break;
00176       case 'S':
00177         use_solve_cbk = atoi(optarg);
00178         break;
00179       case 's':
00180         cut_selection = atoi(optarg);
00181         break;
00182       case 'r':
00183         cuts_at_root_only = atoi(optarg);
00184         break;
00185       case 'R':
00186         max_rtime = strtod(optarg,0);
00187         break;
00188       case 'o':
00189         strncpy(options,optarg,(size_t)1023);
00190         break;
00191       case 'm':
00192         memlimit = strtoul(optarg,0,10);
00193         break;
00194       case 'n':
00195         max_cuts_per_node = atoi(optarg);
00196         break;
00197       case 'N':
00198         max_cuts_per_round = atoi(optarg);
00199         break;
00200       case 'T':
00201         cut_style = atoi(optarg);
00202         break;
00203       case 't':
00204         max_tableau_rows = atoi(optarg);
00205         break;
00206       case 'f':
00207         strncpy(problem,optarg,(size_t)1023);
00208         has_problem=1;
00209         break;
00210       case 'd':
00211         cut_dominance = atoi(optarg);
00212         break;
00213       case 'c':
00214         use_cuts = atoi(optarg);
00215         break;
00216       default:
00217         usage(argv[0]);
00218         return 1;
00219     }
00220   }
00221   FTESTG((rval = !has_problem),CLEANUP,"Should provide a problem name");
00222   /* display configuration */
00223   fprintf(stderr,"\tCplex option file        : %s\n",options);
00224   fprintf(stderr,"\tProblem file             : %s\n",problem);
00225   fprintf(stderr,"\tUsing multi-tableau cuts : %s\n",use_cuts == 1? "gomory": (use_cuts==2? "T1":(use_cuts==3 ? "T2":(use_cuts==4? "SL":"no"))));
00226   fprintf(stderr,"\tMax tableau              : %d\n",max_tableau_rows);
00227   fprintf(stderr,"\tMax cuts per node        : %d\n",max_cuts_per_node);
00228   fprintf(stderr,"\tMax cuts per round       : %d\n",max_cuts_per_round);
00229   fprintf(stderr,"\tCuts only at root        : %s\n",cuts_at_root_only ? "yes":"no");
00230   fprintf(stderr,"\tCuts Style               : %d\n",cut_style);
00231   fprintf(stderr,"\tCuts Selection Strategy  : %d\n",cut_selection);
00232   fprintf(stderr,"\tCut dominance check      : %d\n",cut_dominance);
00233   fprintf(stderr,"\tUse Solve Callback       : %s\n",use_solve_cbk ? "yes":"no");
00234   /* now we read option file */ 
00235   infile = EGsfopen(options,"r");
00236   rval = MTread_cplex_options(env,infile);
00237   CHECKRVALG(rval,CLEANUP);
00238   fclose(infile);
00239   /* set hard limits */
00240   rval = mem_limits();
00241   CHECKRVALG(rval,CLEANUP);
00242   /* now we are ready to roll! */
00243 CLEANUP:
00244   if(rval) usage(argv[0]);
00245   return rval;
00246 }
00247 /* ========================================================================= */
00248 /** @brief this function reads a problem file, set the cut-callback, and call
00249  * the MIP solver */
00250 int main (int argc, char**argv)
00251 {
00252   int rval = 0;
00253   int solstat;
00254   double objval,objbound;
00255   MTgomory_ccbk_t data;
00256   MTns_ccbk_t ns_data;
00257   EGtimer_t timer;
00258   /* initialize data */
00259   EGtimerReset(&timer);
00260   EGtimerStart(&timer);
00261   env = CPXopenCPLEX (&rval);
00262   MTcplexCHECKRVALG(env,rval,CLEANUP);
00263   MTgomory_ccbk_init(&data);
00264   MTns_ccbk_init(&ns_data);
00265   /* parse arguments and read option file */
00266   rval = parseargs(argc,argv);
00267   CHECKRVALG(rval,CLEANUP);
00268   MTccbkSetCuts(&data,use_cuts);
00269   MTccbkSetCutsAtRoot(&data,cuts_at_root_only);
00270   MTccbkSetCutDominance(&data,cut_dominance);
00271   MTccbkSetCutSel(&data,cut_selection);
00272   MTccbkSetCutStyle(&data,cut_style);
00273   MTccbkSetMaxNodeCuts(&data,max_cuts_per_node);
00274   MTccbkSetMaxRows(&data,max_tableau_rows);
00275   MTccbkSetMaxRoundCuts(&data,max_cuts_per_round);
00276   /* now we load the problem in memory */
00277   lp = CPXcreateprob (env, &rval, problem);
00278   MTcplexCHECKRVALG(env,rval,CLEANUP);
00279   rval = CPXreadcopyprob (env, lp, problem, 0);
00280   MTcplexCHECKRVALG(env,rval,CLEANUP);
00281   /* add node solve callback */
00282   if(use_solve_cbk)
00283   {
00284     rval = CPXsetsolvecallbackfunc(env,MTnode_solve,&ns_data);
00285     MTcplexCHECKRVALG(env,rval,CLEANUP);
00286   }
00287   /* add the callback */
00288   switch(use_cuts)
00289   {
00290     case 1:
00291       rval = CPXsetcutcallbackfunc(env,MTgomory_ccbk,&data);
00292       MTcplexCHECKRVALG(env,rval,CLEANUP);
00293       break;
00294     case 2:
00295       rval = CPXsetcutcallbackfunc(env,MTt1_ccbk,&data);
00296       MTcplexCHECKRVALG(env,rval,CLEANUP);
00297       break;
00298     case 3:
00299       rval = CPXsetcutcallbackfunc(env,MTt2_ccbk,&data);
00300       MTcplexCHECKRVALG(env,rval,CLEANUP);
00301       break;
00302     case 4:
00303       rval = CPXsetcutcallbackfunc(env,MTsl_ccbk,&data);
00304       MTcplexCHECKRVALG(env,rval,CLEANUP);
00305       break;
00306     case 0:
00307       rval = CPXsetcutcallbackfunc(env,MTgomory_ccbk,&data);
00308       MTcplexCHECKRVALG(env,rval,CLEANUP);
00309       break;
00310     default:
00311       FTESTG((rval=1),CLEANUP,"Unknown cut selection %d",use_cuts);
00312       usage(argv[0]);
00313       break;
00314   }
00315   /* Optimize the problem and obtain solution */
00316   rval = CPXmipopt (env, lp);
00317   EGtimerStop(&timer);
00318   MTcplexCHECKRVALG(env,rval,CLEANUP);
00319   solstat = CPXgetstat (env, lp);
00320   fprintf (stderr,"Solution status %d.\n", solstat);
00321   rval = CPXgetbestobjval (env, lp, &objbound);
00322   MTcplexCHECKRVALG(env,rval,CLEANUP);
00323   if(solstat == CPXMIP_OPTIMAL || solstat == CPXMIP_OPTIMAL_TOL)
00324   {
00325     rval = CPXgetobjval (env, lp, &objval);
00326     MTcplexCHECKRVALG(env,rval,CLEANUP);
00327   }
00328   else objval = objbound;
00329   fprintf (stderr,"Objective value %.10lg bound %.10lg GAP %10lg\nTime %.2lf\n", objval,objbound,100*fabs((objval-objbound)/(fabs(objbound)<1.0?1.0:objbound)), timer.time);
00330   MTccbk_info_display(&(data.info),stderr);
00331   MTccbk_display_sumary(stderr);
00332   if(use_solve_cbk) MTns_ccbk_display(&ns_data);
00333 CLEANUP:
00334 
00335   /* free all allocated memory */
00336   MTgomory_ccbk_clear(&data);
00337   MTns_ccbk_clear(&ns_data);
00338   /* free problem and close cplex */
00339   if(lp)
00340   {
00341     rval = CPXfreeprob(env,&lp);
00342     lp = 0;
00343     MTcplexCHECKRVALG(env,rval,CLEANUP);
00344   }
00345   if(env)
00346   {
00347     rval = CPXcloseCPLEX(&env);
00348     env=0;
00349     MTcplexCHECKRVALG(env,rval,CLEANUP);
00350   }
00351   return rval;
00352 
00353 }
00354 
00355 /* ========================================================================= */
00356 /** @} */
00357 /* end of mt_cplex.ex.c */

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