53 #define PROP_NAME "sdp-obbt"
54 #define PROP_DESC "optimization-based bound tightening for SDPs"
55 #define PROP_PRIORITY -1100000
57 #define PROP_DELAY FALSE
58 #define PROP_TIMING SCIP_PROPTIMING_AFTERLPLOOP
60 #define DEFAULT_PROPBIN FALSE
61 #define DEFAULT_PROPCONT TRUE
64 #define TOLERANCE_FACTOR 2000
79 long long int lastnode;
80 SCIP_Real lastcufoffbound;
81 SCIP_Real sdpsolvergaptol;
90 #if ( (SCIP_VERSION > 321 || SCIP_SUBVERSION > 0) )
92 SCIP_RETCODE addObjCutoff(
98 char rowname[SCIP_MAXSTRLEN];
102 assert( scip != NULL );
103 assert( SCIPinProbing(scip) );
105 SCIPdebugMsg(scip,
"create objective cutoff and add it to the LP-constraints\n");
107 nvars = SCIPgetNVars(scip);
108 vars = SCIPgetVars(scip);
111 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN,
"obbtsdp_objcutoff");
112 SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, rowname, -SCIPinfinity(scip), SCIPgetCutoffbound(scip), FALSE, FALSE, FALSE) );
113 SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
115 for( v = 0; v < nvars; v++ )
117 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[v], SCIPvarGetObj(vars[v])) );
119 SCIP_CALL( SCIPflushRowExtensions(scip, row) );
122 SCIP_CALL( SCIPaddRowProbing(scip, row) );
124 SCIP_CALL( SCIPreleaseRow(scip, &row) );
139 assert( scip != NULL );
140 assert( prop != NULL );
141 assert( strcmp(SCIPpropGetName(prop),
PROP_NAME) == 0 );
154 SCIP_PROPDATA* propdata;
156 propdata = SCIPpropGetData(prop);
157 assert(propdata != NULL);
159 SCIPfreeMemory(scip, &propdata);
160 SCIPpropSetData(prop, NULL);
169 SCIP_PROPDATA* propdata;
171 assert( prop != NULL );
173 propdata = SCIPpropGetData(prop);
175 propdata->lastnode = -1;
184 SCIP_PROPDATA* propdata;
186 assert( prop != NULL );
188 propdata = SCIPpropGetData(prop);
190 SCIP_CALL( SCIPgetRealParam(scip,
"relaxing/SDP/sdpsolvergaptol", &(propdata->sdpsolvergaptol)) );
200 #if ( (SCIP_VERSION > 321 || SCIP_SUBVERSION > 0) )
204 SCIP_PROPDATA* propdata;
207 SCIP_Bool oldobjlimitparam;
208 SCIP_Real probingval;
210 SCIP_RELAX* relaxsdp;
213 SCIP_Real* newbounds;
218 assert( scip != NULL );
219 assert( prop != NULL );
220 assert( result != NULL );
222 propdata = SCIPpropGetData(prop);
224 assert( propdata != NULL );
226 *result = SCIP_DIDNOTRUN;
228 SCIPdebugMsg(scip,
"Executing propExecSdpObbt! \n");
231 if ( SCIPgetStage(scip) != SCIP_STAGE_SOLVING || SCIPinRepropagation(scip) || SCIPinProbing(scip) || !SCIPallowObjProp(scip) || (SCIPgetSubscipDepth(scip) > 0) )
233 SCIPdebugMsg(scip,
"Aborting propExecSdpObbt because we are in presolving, repropagation, probing mode, a subscip or no objective "
234 "propagation is allowed!\n");
239 if ( SCIPisInfinity(scip, SCIPgetCutoffbound(scip)) || (! SCIPisRelaxSolValid(scip)) )
242 if ( propdata->delayed )
244 SCIPdebugMsg(scip,
"Aborting propExecSdpObbt since still cutoffbound is infinite or no relaxation solution exists\n");
247 *result = SCIP_DELAYED;
248 propdata->delayed = TRUE;
249 SCIPdebugMsg(scip,
"Delaying propExecSdpObbt since cutoffbound is infinite or no relaxation solution exists\n");
254 if ( (SCIPgetBestSol(scip) == NULL) || ((SCIPsolGetHeur(SCIPgetBestSol(scip)) != NULL) && (strcmp(SCIPheurGetName(SCIPsolGetHeur(SCIPgetBestSol(scip))),
"trivial") == 0)) )
257 if ( propdata->delayed )
259 SCIPdebugMsg(scip,
"Aborting propExecSdpObbt since still best solution was found by trivial heuristic or simple objective propagation, which will not be good enough\n");
262 *result = SCIP_DELAYED;
263 propdata->delayed = TRUE;
264 SCIPdebugMsg(scip,
"Delaying propExecSdpObbt since best solution was found by trivial heuristic or simple objective propagation, which will not be good enough\n");
268 if ( (SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnode) && (SCIPisEQ(scip, SCIPgetCutoffbound(scip), propdata->lastcufoffbound)) )
270 SCIPdebugMsg(scip,
"Not running again for node %lld with cutoffbound &f!\n", propdata->lastnode, propdata->lastcufoffbound);
275 propdata->lastnode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
276 propdata->lastcufoffbound = SCIPgetCutoffbound(scip);
279 propdata->delayed = FALSE;
281 vars = SCIPgetVars(scip);
282 nvars = SCIPgetNVars(scip);
285 SCIP_CALL( SCIPstartProbing(scip) );
286 SCIPdebugMsg(scip,
"start probing\n");
288 SCIP_CALL( addObjCutoff(scip) );
291 SCIP_CALL( SCIPgetBoolParam(scip,
"relaxing/SDP/objlimit", &oldobjlimitparam) );
292 SCIP_CALL( SCIPsetBoolParam(scip,
"relaxing/SDP/objlimit", FALSE) );
295 SCIP_CALL( SCIPallocBufferArray(scip, &newbounds, 2*nvars) );
296 SCIP_CALL( SCIPallocBufferArray(scip, &newboundinds, 2*nvars) );
298 *result = SCIP_DIDNOTFIND;
301 for( v = 0; v < nvars; ++v )
303 SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], 0.0) );
308 for (v = 0; v < nvars; v++)
311 if ( (( ! propdata->propbin ) && SCIPvarIsBinary(vars[v])) || (( ! propdata->propcont ) && ( ! SCIPvarIsIntegral(vars[v]))) )
313 #ifdef SCIP_MORE_DEBUG
314 if ( SCIPvarIsBinary(vars[v]) )
316 SCIPdebugMsg(scip,
"Skipping binary variable %s\n", SCIPvarGetName(vars[v]));
320 SCIPdebugMsg(scip,
"Skipping continuous variable %s\n", SCIPvarGetName(vars[v]));
327 relaxval = SCIPgetRelaxSolVal(scip, vars[v]);
330 if ( SCIPisFeasGT(scip, relaxval, SCIPvarGetLbLocal(vars[v])) )
333 SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], 1.0) );
336 SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
340 relaxsdp = SCIPfindRelax(scip,
"SDP");
344 SCIPdebugMsg(scip,
"Aborting sdp-obbt, as we were unable to solve a probing sdp!\n");
345 if ( *result != SCIP_REDUCEDDOM )
346 *result = SCIP_DIDNOTRUN;
353 SCIPdebugMsg(scip,
"Probing sdp infeasible, so there can't be a better solution for this problem!\n");
354 *result = SCIP_CUTOFF;
366 if ( SCIPisGT(scip, probingval -
TOLERANCE_FACTOR * propdata->sdpsolvergaptol, SCIPvarGetLbLocal(vars[v])) )
369 SCIPdebugMsg(scip,
"Obbt-Sdp tightened lower bound of variable %s from %f to %f !\n",
370 SCIPvarGetName(vars[v]), SCIPvarGetLbLocal(vars[v]), probingval - propdata->sdpsolvergaptol);
372 newbounds[nnewbounds] = probingval;
373 newboundinds[nnewbounds] = -1 * (v+1);
375 *result = SCIP_REDUCEDDOM;
377 #ifdef SCIP_MORE_DEBUG
380 SCIPdebugMsg(scip,
"Obbt-Sdp found lower bound of %f for variable %s, worse than old bound %f !\n",
381 probingval, SCIPvarGetName(vars[v]), SCIPvarGetLbLocal(vars[v]));
385 #ifdef SCIP_MORE_DEBUG
388 SCIPdebugMsg(scip,
"Obbt-Sdp problem unbounded for variable %s!\n", SCIPvarGetName(vars[v]));
392 #ifdef SCIP_MORE_DEBUG
395 SCIPdebugMsg(scip,
"Skipping obbt for lower bound %f of variable %s, as current relaxation's solution is tight.\n",
396 SCIPvarGetLbLocal(vars[v]), SCIPvarGetName(vars[v]));
401 if ( SCIPisFeasLT(scip, relaxval, SCIPvarGetUbLocal(vars[v])) )
404 SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], -1.0) );
407 SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
411 relaxsdp = SCIPfindRelax(scip,
"SDP");
415 SCIPdebugMsg(scip,
"Aborting sdp-obbt, as we were unable to solve a probing sdp!\n");
416 if ( *result != SCIP_REDUCEDDOM )
417 *result = SCIP_DIDNOTRUN;
424 SCIPdebugMsg(scip,
"Probing sdp infeasible, so there can't be a better solution for this problem!\n");
425 *result = SCIP_CUTOFF;
438 if ( SCIPisLT(scip, -probingval +
TOLERANCE_FACTOR * propdata->sdpsolvergaptol, SCIPvarGetUbLocal(vars[v])) )
440 SCIPdebugMsg(scip,
"Obbt-Sdp tightened upper bound of variable %s from %f to %f !\n",
441 SCIPvarGetName(vars[v]), SCIPvarGetUbLocal(vars[v]), -probingval + propdata->sdpsolvergaptol);
443 newbounds[nnewbounds] = -probingval;
444 newboundinds[nnewbounds] = v + 1;
447 #ifdef SCIP_MORE_DEBUG
450 SCIPdebugMsg(scip,
"Obbt-Sdp found upper bound of %f for variable %s, worse than old bound %f !\n",
451 -probingval, SCIPvarGetName(vars[v]), SCIPvarGetUbLocal(vars[v]));
455 #ifdef SCIP_MORE_DEBUG
458 SCIPdebugMsg(scip,
"Obbt-Sdp problem unbounded for variable %s!\n", SCIPvarGetName(vars[v]));
462 #ifdef SCIP_MORE_DEBUG
465 SCIPdebugMsg(scip,
"Skipping obbt for upper bound %f of variable %s, as current relaxation's solution is tight.\n",
466 SCIPvarGetUbLocal(vars[v]), SCIPvarGetName(vars[v]));
471 SCIP_CALL( SCIPchgVarObjProbing(scip, vars[v], 0.0) );
475 SCIP_CALL( SCIPendProbing(scip) );
476 SCIPdebugMsg(scip,
"end probing\n");
477 SCIP_CALL( SCIPsetBoolParam(scip,
"relaxing/SDP/objlimit", oldobjlimitparam) );
479 for (i = 0; i < nnewbounds; i++)
481 if ( newboundinds[i] < 0)
483 SCIP_CALL( SCIPchgVarLb(scip, vars[-1 * newboundinds[i] - 1], newbounds[i]) );
484 *result = SCIP_REDUCEDDOM;
491 if ( SCIPvarIsBinary(vars[newboundinds[i] - 1]) && SCIPisLT(scip, SCIPfeasFloor(scip, newbounds[i]),
492 SCIPvarGetLbLocal(vars[newboundinds[i] - 1]) ))
494 SCIPdebugMsg(scip,
"Probing sdp founded conflicting bounds for integer variable %s -> cutoff!\n",
495 SCIPvarGetName(vars[newboundinds[i] - 1]));
496 *result = SCIP_CUTOFF;
499 SCIP_CALL( SCIPchgVarUb(scip, vars[newboundinds[i] - 1], newbounds[i]) );
500 *result = SCIP_REDUCEDDOM;
504 SCIPfreeBufferArray(scip, &newboundinds);
505 SCIPfreeBufferArray(scip, &newbounds);
510 *result = SCIP_DIDNOTRUN;
527 SCIP_PROPDATA* propdata;
532 SCIP_CALL( SCIPallocMemory(scip, &propdata) );
533 propdata->lastnode = -1;
540 propExecSdpObbt, propdata) );
542 assert(prop != NULL);
545 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopySdpObbt) );
546 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeSdpObbt) );
547 SCIP_CALL( SCIPsetPropExit(scip, prop, propExitSdpObbt) );
548 SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolSdpObbt) );
551 SCIP_CALL( SCIPaddBoolParam(scip,
"propagating/" PROP_NAME "/propbin",
552 "Should optimization-based bound tightening be performed for binary variables?",
555 SCIP_CALL( SCIPaddBoolParam(scip,
"propagating/" PROP_NAME "/propcont",
556 "Should optimization-based bound tightening be performed for continuous variables?",
SCIP_RETCODE SCIPincludePropSdpObbt(SCIP *scip)
static SCIP_DECL_PROPEXIT(propExitSdpObbt)
static SCIP_DECL_PROPEXEC(propExecSdpObbt)
static SCIP_DECL_PROPCOPY(propCopySdpObbt)
optimization-based bound tightening propagator for semidefinite programs
SCIP_RETCODE SCIPrelaxSdpRelaxVal(SCIP_RELAX *relax, SCIP_Bool *success, SCIP_Real *objval)
static SCIP_DECL_PROPINITSOL(propInitsolSdpObbt)
static SCIP_DECL_PROPFREE(propFreeSdpObbt)
SCIP_Bool SCIPrelaxSdpSolvedProbing(SCIP_RELAX *relax)
SCIP_Bool SCIPrelaxSdpIsFeasible(SCIP_RELAX *relax)
SCIP_Bool SCIPrelaxSdpIsUnbounded(SCIP_RELAX *relax)