/** adds given problem variable to pricing storage, if zero is not best bound w.r.t. objective function */ static SCIP_RETCODE addBoundViolated( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory buffers */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< dynamic problem statistics */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_VAR* var, /**< problem variable */ SCIP_Bool* added /**< pointer to store whether variable was added to pricing storage */ ) { assert(tree != NULL); assert(added != NULL); *added = FALSE; /* add variable, if zero is not feasible within the bounds */ if( SCIPsetIsPositive(set, SCIPvarGetLbLocal(var)) || SCIPsetIsNegative(set, SCIPvarGetUbLocal(var)) ) { SCIPdebugMessage(" -> zero violates bounds of <%s> [%g,%g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); SCIP_CALL( SCIPpricestoreAddBdviolvar(pricestore, blkmem, set, stat, lp, branchcand, eventqueue, var) ); *added = TRUE; } else { SCIP_Real bestbound; /* add variable, if zero is not best bound w.r.t. objective function */ bestbound = SCIPvarGetBestBoundLocal(var); if( !SCIPsetIsZero(set, bestbound) ) { SCIPdebugMessage(" -> best bound of <%s> [%g,%g] is not zero but %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestbound); SCIP_CALL( SCIPpricestoreAddVar(pricestore, blkmem, set, eventqueue, lp, var, -SCIPvarGetObj(var) * bestbound, (SCIPtreeGetCurrentDepth(tree) == 0)) ); *added = TRUE; } } return SCIP_OKAY; }
/** update the primal-dual integral statistic. method accepts + and - SCIPsetInfinity() as values for * upper and lower bound, respectively */ void SCIPstatUpdatePrimalDualIntegral( SCIP_STAT* stat, /**< problem statistics data */ SCIP_SET* set, /**< global SCIP settings */ SCIP_PROB* transprob, /**< transformed problem */ SCIP_PROB* origprob, /**< original problem */ SCIP_Real upperbound, /**< current upper bound in transformed problem, or infinity */ SCIP_Real lowerbound /**< current lower bound in transformed space, or -infinity */ ) { SCIP_Real currentgap; SCIP_Real solvingtime; SCIP_Real primalbound; SCIP_Real dualbound; assert(stat != NULL); assert(set != NULL); solvingtime = SCIPclockGetTime(stat->solvingtime); assert(solvingtime >= stat->previntegralevaltime); if( !SCIPsetIsInfinity(set, upperbound) ) /*lint !e777*/ { /* get value in original space for gap calculation */ primalbound = SCIPprobExternObjval(transprob, origprob, set, upperbound); if( SCIPsetIsZero(set, primalbound) ) primalbound = 0.0; } else { /* no new upper bound: use stored values from last update */ upperbound = stat->lastupperbound; primalbound = stat->lastprimalbound; assert(SCIPsetIsZero(set, primalbound) == (primalbound == 0.0)); /*lint !e777*/ } if( !SCIPsetIsInfinity(set, -lowerbound) ) /*lint !e777*/ { /* get value in original space for gap calculation */ dualbound = SCIPprobExternObjval(transprob, origprob, set, lowerbound); if( SCIPsetIsZero(set, dualbound) ) dualbound = 0.0; } else { /* no new lower bound: use stored values from last update */ lowerbound = stat->lastlowerbound; dualbound = stat->lastdualbound; assert(SCIPsetIsZero(set, dualbound) == (dualbound == 0.0)); /*lint !e777*/ } /* computation of the gap, special cases are handled first */ if( primalbound == SCIP_UNKNOWN || dualbound == SCIP_UNKNOWN ) /*lint !e777*/ currentgap = 100.0; /* the gap is 0.0 if bounds coincide */ else if( SCIPsetIsGE(set, lowerbound, upperbound) || SCIPsetIsEQ(set, primalbound, dualbound) ) currentgap = 0.0; /* the gap is 100.0 if bounds have different signs */ else if( primalbound * dualbound <= 0.0 ) /*lint !e777*/ currentgap = 100.0; else if( !SCIPsetIsInfinity(set, REALABS(primalbound)) && !SCIPsetIsInfinity(set, REALABS(dualbound)) ) { SCIP_Real absprim = REALABS(primalbound); SCIP_Real absdual = REALABS(dualbound); /* The gap in the definition of the primal-dual integral differs from the default SCIP gap function. * Here, the MAX(primalbound, dualbound) is taken for gap quotient in order to ensure a gap <= 100. */ currentgap = 100.0 * REALABS(primalbound - dualbound) / MAX(absprim, absdual); assert(SCIPsetIsLE(set, currentgap, 100.0)); } else currentgap = 100.0; /* if primal and dual bound have opposite signs, the gap always evaluates to 100.0% */ assert(currentgap == 0.0 || currentgap == 100.0 || SCIPsetIsGE(set, primalbound * dualbound, 0.0)); assert(SCIPsetIsGE(set, stat->previousgap, currentgap) || (set->stage == SCIP_STAGE_EXITPRESOLVE && SCIPsetIsFeasGE(set, stat->previousgap, currentgap))); /* update the integral based on previous information */ stat->primaldualintegral += (solvingtime - stat->previntegralevaltime) * stat->previousgap; /* update all relevant information for next evaluation */ stat->previousgap = currentgap; stat->previntegralevaltime = solvingtime; stat->lastprimalbound = primalbound; stat->lastdualbound = dualbound; stat->lastlowerbound = lowerbound; stat->lastupperbound = upperbound; }
/** applies a cut that is a bound change directly as bound change instead of adding it as row to the LP */ static SCIP_RETCODE sepastoreApplyBdchg( SCIP_SEPASTORE* sepastore, /**< separation storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_ROW* cut, /**< cut with a single variable */ SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */ ) { SCIP_COL** cols; SCIP_Real* vals; SCIP_VAR* var; SCIP_Real lhs; SCIP_Real rhs; assert(sepastore != NULL); assert(!SCIProwIsModifiable(cut)); assert(SCIProwGetNNonz(cut) == 1); assert(cutoff != NULL); *cutoff = FALSE; /* get the single variable and its coefficient of the cut */ cols = SCIProwGetCols(cut); assert(cols != NULL); var = SCIPcolGetVar(cols[0]); vals = SCIProwGetVals(cut); assert(vals != NULL); assert(!SCIPsetIsZero(set, vals[0])); /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */ if( SCIPsetIsFeasZero(set, vals[0]) ) return SCIP_OKAY; /* get the left hand side of the cut and convert it to a bound */ lhs = SCIProwGetLhs(cut); if( !SCIPsetIsInfinity(set, -lhs) ) { lhs -= SCIProwGetConstant(cut); if( vals[0] > 0.0 ) { /* coefficient is positive -> lhs corresponds to lower bound */ SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, lhs/vals[0], cutoff) ); } else { /* coefficient is negative -> lhs corresponds to upper bound */ SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, lhs/vals[0], cutoff) ); } } /* get the right hand side of the cut and convert it to a bound */ rhs = SCIProwGetRhs(cut); if( !SCIPsetIsInfinity(set, rhs) ) { rhs -= SCIProwGetConstant(cut); if( vals[0] > 0.0 ) { /* coefficient is positive -> rhs corresponds to upper bound */ SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, rhs/vals[0], cutoff) ); } else { /* coefficient is negative -> rhs corresponds to lower bound */ SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, rhs/vals[0], cutoff) ); } } /* count the bound change as applied cut */ if( !sepastore->initiallp ) sepastore->ncutsapplied++; return SCIP_OKAY; }