00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "mt_SL.h"
00025 #include "mt_cplex_cbk.h"
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
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
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 }
00082 }
00083 }
00084 CLEANUP:
00085 return rval;
00086 }
00087
00088
00089
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
00119
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
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
00159
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
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
00199 register int i, j;
00200 MTcut_t*cut = 0;
00201 int nfrac = 0;
00202 int nint = 0;
00203 int*frac_ind = EGsMalloc(int,ncols);
00204 int*int_ind = 0;
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
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
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
00225 MTrowmatrix_rsz(tb,nrows,0);
00226 tb->rowbeg[0] = 0;
00227
00228
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
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
00248 rval = MTcheckTabrow(MTlp,tableau,&status,&ratio,&tnz);
00249 CHECKRVALG(rval,CLEANUP);
00250
00251 if(status) continue;
00252 if(minratio > ratio) minratio = ratio;
00253
00254 MTcompute_f(MTlp, tableau, x, slack, f);
00255
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
00260
00261 if(!tnz)
00262 {
00263 MESSAGE(MT_VERB_LVL,"Discarded empty integer tableau row %d",icol);
00264 continue;
00265 }
00266
00267
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
00280 for( fit = nfrac ; fit-- ; )
00281 {
00282 fcol = frac_ind[fit];
00283
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
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
00299 rval = MTcheckTabrow(MTlp,tableau,&status,&ratio,&tnz);
00300 CHECKRVALG(rval,CLEANUP);
00301
00302 if(status) continue;
00303 if(minratio > ratio) minratio = ratio;
00304
00305
00306 MTcompute_f(MTlp, tableau, x, slack, f+1);
00307
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
00312
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
00323 if(f[1]<0) f[1] += 1;
00324
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
00330
00331
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
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
00353 memset(work,0,sizeof(double)*((size_t)nvars));
00354 memset(cutval,0,sizeof(double)*((size_t)nvars));
00355
00356
00357 MTsl4(ineq[0], (double)j, 1.0, (double)j, 0.0);
00358
00359 rval = MTsl3(f,ineq[0],2);
00360 CHECKRVALG(rval,CLEANUP);
00361
00362 rval = MTsl1(ineq[0], tb, work, vtype, 1);
00363 CHECKRVALG(rval,CLEANUP);
00364
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
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
00374 mval[0] = 1;
00375 mval[1] = 0;
00376 util[0] = 0;
00377 util[1] = 1;
00378
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
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
00405
00406
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
00411 rval = MTsl3(f,ineq[1],2);
00412 CHECKRVALG(rval,CLEANUP);
00413
00414 rval = MTsl1(ineq[1], tb, work, vtype, 0);
00415 CHECKRVALG(rval,CLEANUP);
00416
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
00424 rval = MTsl3(f,ineq[2],2);
00425 CHECKRVALG(rval,CLEANUP);
00426
00427 rval = MTsl1(ineq[2], tb, work, vtype, 0);
00428 CHECKRVALG(rval,CLEANUP);
00429
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
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
00441 if(status == 0)
00442 {
00443 rval = MTcutHeap_add_cut(MTlp,cuth);
00444 CHECKRVALG(rval,CLEANUP);
00445 }
00446 }
00447 }
00448 }
00449
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
00471 MESSAGE(MT_VERB_LVL,"Entering");
00472 *useraction_p = CPX_CALLBACK_DEFAULT;
00473
00474 rval = MTccbk_info_process(&(data->info), env, cbdata, wherefrom, &action);
00475 CHECKRVALG(rval,CLEANUP);
00476 if(action) goto CLEANUP;
00477
00478 rval = CPXgetcallbacknodelp (env, cbdata, wherefrom, &lp);
00479 MTcplexCHECKRVALG(env,rval,CLEANUP);
00480
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
00487 rval = MTlp_load_problem(env, &(data->lp), lp, cbdata, wherefrom);
00488 CHECKRVALG(rval,CLEANUP);
00489
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
00494 rval = EGmax(nrows,ncols);
00495 MTgomory_ccbk_rsz(data,nrows,ncols+nrows,rval);
00496
00497 rval = MTget_sol(&(data->lp), env, lp, cbdata, wherefrom, &(data->sol));
00498 CHECKRVALG(rval,CLEANUP);
00499
00500 if(MT_VERB_LVL + 10 <= DEBUG)
00501 MTdisplay_lp(&(data->lp), &(data->sol), stderr);
00502
00503 rval = MTslCut(data, env, lp);
00504 CHECKRVALG(rval,CLEANUP);
00505
00506 data->info.added_cuts += MTcutHeap_get_ncuts(cuth);
00507 data->info.node_cuts += MTcutHeap_get_ncuts(cuth);
00508
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
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
00535