All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
prop_genvbounds.c
Go to the documentation of this file.
23 /**@todo should we only discard events catched from nodes that are not the current node's ancestors? */
27 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 #define PROP_PRESOL_PRIORITY -2000000 /**< priority of the presolving method (>= 0: before, < 0: after
46 #define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates
49 #define DEFAULT_PROPAGATE_IN_ROOT_NODE TRUE /**< apply genvbounds in root node if no new incumbent was found? */
72 SCIP_BOUNDTYPE boundtype; /**< type of bound provided by the genvbound, SCIP_BOUNDTYPE_LOWER/UPPER
112 int* gstartcomponents; /**< components corresponding to indices stored in gstartindices array */
147 /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
148 * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective is
149 * subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
150 * contribution of the cutoff bound in the generalized variable bound to the original problem as described in
266 /** calculates the minactivity of a linear combination of variables stored in the current conflict set */
273 SCIP_BDCHGIDX* bdchgidx /**< bound change at which minactivity should be computed; if NULL use local bounds */
300 /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
312 /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
341 boundval = getGenVBoundsMinActivity(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, global);
344 return (genvbound->boundtype == SCIP_BOUNDTYPE_LOWER) ? -SCIPinfinity(scip) : SCIPinfinity(scip);
387 /* the genvbound must be valid for all cutoff bounds greater equal the objective value of the debug solution */
390 (SCIPgetSolTransObj(scip, debugsol) + SCIPgetTransObjoffset(scip)) * SCIPgetTransObjscale(scip);
441 SCIP_CALL( SCIPhashmapCreate(&(propdata->startmap), SCIPblkmem(scip), SCIPcalcHashtableSize(propdata->ncomponents)) );
606 /** resolves propagation of lower bound on +/- left-hand side variable of a generalized variable bound */
611 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
640 /* if only the primal bound participates in the propagation, it is globally valid and should not be analyzed */
643 /* when resolving a propagation, bdchgidx is not NULL and boundval should be the bound change performed for the
647 SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, SCIPvarGetLbAtIndex(lhsvar, bdchgidx, TRUE)));
649 SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, -SCIPvarGetUbAtIndex(lhsvar, bdchgidx, TRUE)));
651 /* when creating an initial conflict, bdchgidx is NULL and +/-boundval must exceed the upper/lower bound of the
669 /* compute minimal activity; if bdchgidx is NULL, we create the initial conflict and use local bounds */
670 minactivity = getGenVBoundsMinActivityConflict(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, bdchgidx);
674 /* a genvbound might have been replaced since the propagation took place, hence we have to check that the current
675 * genvbound can explain the propagation at the given bound change index; note that by now, with smaller cutoff
684 /* if bdchgidx is NULL, i.e., we create the initial conflict, we should be able to explain the bound change */
696 assert(SCIPisEQ(scip, SCIPvarGetLbAtIndex(vars[i], bdchgidx, TRUE), SCIPvarGetLbAtIndex(vars[i], bdchgidx, FALSE)));
697 assert(SCIPisEQ(scip, SCIPvarGetUbAtIndex(vars[i], bdchgidx, TRUE), SCIPvarGetUbAtIndex(vars[i], bdchgidx, FALSE)));
712 SCIPdebugMessage("lower bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
715 /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
720 SCIPdebugMessage("skipping lower bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
734 /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictLbRelaxed(),
762 SCIPdebugMessage("upper bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
765 /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
770 SCIPdebugMessage("skipping upper bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
784 /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictUbRelaxed(),
809 /* boundval should not have been decreased; if this happened nevertheless, maybe due to numerical errors, we quit
814 SCIPdebugMessage("boundval was reduced from %.15g to %.15g; propagation not resolved\n", *boundval, tmpboundval);
850 /* get minimal right-hand side bound that leads to infeasibility; first try with a factor of 2 for robustness */
855 /* add right-hand side variables that force the lower bound of the left-hand side variable above its upper bound
876 /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
886 SCIPdebugMessage("skipping upper bound of left-hand side variable <%s> already enforced in conflict set\n",
891 SCIPdebugMessage("adding upper bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
902 /* get minimal right-hand side bound that leads to infeasibility; try with a factor of 2 first for robustness */
907 /* add right-hand side variables that force the upper bound of the left-hand side variable below its lower bound
928 /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
938 SCIPdebugMessage("skipping lower bound of left-hand side variable <%s> already enforced in conflict set\n",
943 SCIPdebugMessage("adding lower bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
955 /** apply propagation for one generalized variable bound; also if the left-hand side variable is locally fixed, we
1007 SCIP_CALL( SCIPtightenVarLbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1011 SCIP_CALL( SCIPtightenVarUbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1014 /* tighten bound locally and start conflict analysis in case of infeasibility; as inferinfo we pass the index of the
1021 SCIP_CALL( SCIPinferVarLbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1034 SCIP_CALL( SCIPinferVarUbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1081 SCIPdebugPrintf("(component %d, index %d) ", eventdata->startcomponents[i], eventdata->startindices[i]);
1182 SCIP_CALL( SCIPdropVarEvent(scip, propdata->lbevents[i]->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr,
1189 SCIP_CALL( SCIPdropVarEvent(scip, propdata->ubevents[i]->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr,
1205 /** returns the corresponding event data entry in the corresponding array, if there is one; if not: allocates a new
1231 SCIP_CALL( SCIPallocMemoryArray(scip, &((*eventdata)->startcomponents), propdata->ncomponents) );
1256 /** adds an event to the event array lbevents (if boundtype == SCIP_BOUNDTYPE_LOWER) or ubevents (if boundtype ==
1281 if( eventdata->nstarts > 0 && eventdata->startcomponents[eventdata->nstarts - 1] == startcomponent )
1283 /* if there is already a starting index for startcomponent stored at the last entry of eventdata->startindices,
1284 * it should be smaller; this relies on the implementation of setUpEvents(), calling addEventData() in
1326 SCIP_CALL( SCIPhashmapCreate(&(propdata->lbeventsmap), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1327 SCIP_CALL( SCIPhashmapCreate(&(propdata->ubeventsmap), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1385 SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr, eventdata,
1404 SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr, eventdata,
1421 * there is an arc from genvbound1 to genvbound2 iff c1 = +1 and x_i1 appears with positive coefficient in RHS2 or
1422 * c1 = -1 and x_i1 appears with negative coefficient in RHS2; in this case, a bound change of x_i1 deduced from
1460 int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->lbgenvbounds, genvbound->vars[j]))->index;
1466 int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->ubgenvbounds, genvbound->vars[j]))->index;
1479 SCIP_CALL( SCIPallocMemoryArray(scip, &(propdata->componentsstart), propdata->ncomponents + 1) );
1569 /* if the genvbounds are not sorted, i.e. if root node processing has not been finished, yet, we just propagate in
1603 SCIPdebugMessage("starting in component %d at index %d\n", startingcomponents[i], startingindices[i]);
1615 SCIPdebugMessage("applying genvbound with index %d, component %d\n", j, startingcomponents[i]);
1653 SCIP_CALL( SCIPhashmapCreate(&(propdata->lbgenvbounds), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1654 SCIP_CALL( SCIPhashmapCreate(&(propdata->ubgenvbounds), SCIPblkmem(scip), SCIPcalcHashtableSize(nprobvars)) );
1674 hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
1676 /* e.g., during presolving after a restart, new variables might have been created; in this case, we need to extend
1677 * the genvboundstore; the new size may even exceed 2*SCIPgetNVars() if we have genvbounds with nonactive left-hand
1684 SCIP_CALL( SCIPreallocMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize) );
1713 /* we only sort after the root node is finished; this avoids having to sort again after adding more genvbounds; if
1745 if( propdata->global && SCIPgetDepth(scip) > 0 && SCIPisFeasLT(scip, SCIPgetCutoffbound(scip), propdata->lastcutoff) )
1753 /* within the tree, the objective function should not change anymore, hence the cutoff bound should be a stable
1765 /* if genvbounds are already sorted, check if bound change events were caught; otherwise apply all genvbounds */
1766 if( !propdata->issorted || ( SCIPgetCurrentNode(scip) == propdata->lastnodecaught && propdata->nindices > 0 ) )
1782 /** adds a generalized variable bound to the genvbounds propagator; if there is already a genvbound for the bound
1825 /* check if there already is a genvbound corresponding to this bound, freeing its data and overwriting it */
1878 /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
1879 * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective
1880 * is subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
1881 * contribution of the cutoff bound in the generalized variable bound to the original problem as follows:
1887 * +/- var >= ... + (z / SCIPgetTransObjscale()) * origcutoffbound + (constant - z * SCIPgetTransObjoffset())
1889 * with SCIPgetCutoffbound() = origcutoffbound / SCIPgetTransObjscale() - SCIPgetTransObjoffset(); in the
1890 * propagation later, we will use (SCIPgetCutoffbound() + SCIPgetTransObjoffset()) * SCIPgetTransObjscale(), see
2003 /** presolving deinitialization method of propagator (called after presolving has been finished) */
2014 SCIPdebugMessage("propexitpre in problem <%s>: removing fixed, aggregated, negated, and multi-aggregated variables from right-hand side\n",
2034 SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, genvbound->ncoefs, &genvbound->constant, &requiredsize, TRUE) );
2043 SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, requiredsize, &genvbound->constant, &requiredsize, TRUE) );
2052 hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
2091 SCIPdebugMessage("propexec in problem <%s> at depth %d%s\n", SCIPgetProbName(scip), SCIPgetDepth(scip),
2097 /**@todo is it really no performance issue to be called each time when there are no genvbounds, e.g., for MIPs? */
2105 /* when called in presolving stage the result is set to SCIP_SUCCESS instead of SCIP_REDUCEDDOM, this is corrected
2131 /* as inferinfo we passed the index of the genvbound that was used for propagation; the genvbound might have been
2132 * replaced, but also the new genvbound at this position has the same variable on the left-hand side
2142 SCIPerrorMessage("generalized variable bounds propagator received inferinfo out of range; propagation not resolved, safe to continue\n");
2154 SCIPerrorMessage("generalized variable bounds propagator received incorrect inferinfo; propagation not resolved, but it's safe to continue\n");
2163 /* if left-hand side variable is integral, it suffices to explain a bound change greater than boundval - 1 */
2183 /** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
2300 componentidx = (int)(size_t) SCIPhashmapGetImage(propdata->startmap, (void*)(size_t) (component + 1)) - 1;
2344 SCIP_CALL( SCIPincludePropBasic(scip, &prop, PROP_NAME, PROP_DESC, PROP_PRIORITY, PROP_FREQ, PROP_DELAY, PROP_TIMING,
2369 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecGenvbounds, NULL) );
|