/** applies an upper bound change */ static SCIP_RETCODE sepastoreApplyUb( 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_VAR* var, /**< problem variable */ SCIP_Real bound, /**< new upper bound of variable */ SCIP_Bool* cutoff /**< pointer to store TRUE, if an infeasibility has been detected */ ) { assert(sepastore != NULL); assert(cutoff != NULL); if( SCIPsetIsLT(set, bound, SCIPvarGetUbLocal(var)) ) { SCIPdebugMessage(" -> applying bound change: <%s>: [%g,%g] -> [%g,%g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var), bound); if( SCIPsetIsFeasGE(set, bound, SCIPvarGetLbLocal(var)) ) { SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, tree, lp, branchcand, eventqueue, var, bound, SCIP_BOUNDTYPE_UPPER, FALSE) ); } else *cutoff = TRUE; if( !sepastore->initiallp ) sepastore->ncutsapplied++; } 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; }
/** returns whether the solution is contained in node's subproblem */ static SCIP_RETCODE isSolutionInNode( BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_NODE* node, /**< local node where this bound change was applied */ SCIP_Bool* solcontained /**< pointer to store whether the solution is contained in node's subproblem */ ) { SCIP_Bool* boolptr; assert(set != NULL); assert(blkmem != NULL); assert(node != NULL); assert(solcontained != NULL); /* check if we are in the original problem and not in a sub MIP */ if( !isSolutionInMip(set) ) { *solcontained = FALSE; return SCIP_OKAY; } /* generate the hashmap */ if( solinnode == NULL ) { SCIP_CALL( SCIPhashmapCreate(&solinnode, blkmem, SCIPcalcHashtableSize(SCIP_HASHSIZE_DEBUG)) ); } /* check, whether we know already whether the solution is contained in the given node */ boolptr = (SCIP_Bool*)SCIPhashmapGetImage(solinnode, (void*)node); if( boolptr != NULL ) { if( boolptr != &falseptr && boolptr != &trueptr ) { SCIPerrorMessage("wrong value in node hashmap\n"); SCIPABORT(); } *solcontained = *boolptr; return SCIP_OKAY; } /* if the solution is not contained in the parent of the node, it cannot be contained in the current node */ *solcontained = TRUE; if( node->parent != NULL ) { SCIP_CALL( isSolutionInNode(blkmem, set, node->parent, solcontained) ); } if( *solcontained ) { /* check whether the bound changes at the current node remove the debugging solution from the subproblem */ if( node->domchg != NULL ) { SCIP_DOMCHGBOUND* domchgbound; SCIP_BOUNDCHG* boundchgs; int i; domchgbound = &node->domchg->domchgbound; boundchgs = domchgbound->boundchgs; for( i = 0; i < (int)domchgbound->nboundchgs && *solcontained; ++i ) { SCIP_Real varsol; if( SCIPboundchgIsRedundant(&boundchgs[i]) ) continue; /* get solution value of variable */ SCIP_CALL( getSolutionValue(set, boundchgs[i].var, &varsol) ); if( varsol != SCIP_UNKNOWN ) /*lint !e777*/ { /* compare the bound change with the solution value */ if( SCIPboundchgGetBoundtype(&boundchgs[i]) == SCIP_BOUNDTYPE_LOWER ) *solcontained = SCIPsetIsFeasGE(set, varsol, boundchgs[i].newbound); else *solcontained = SCIPsetIsFeasLE(set, varsol, boundchgs[i].newbound); if( !(*solcontained) && SCIPboundchgGetBoundchgtype(&boundchgs[i]) != SCIP_BOUNDCHGTYPE_BRANCHING ) { SCIPerrorMessage("debugging solution was cut off in local node %p at depth %d by inference <%s>[%.15g] %s %.15g\n", node, SCIPnodeGetDepth(node), SCIPvarGetName(boundchgs[i].var), varsol, SCIPboundchgGetBoundtype(&boundchgs[i]) == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", boundchgs[i].newbound); SCIPABORT(); } } else if( SCIPboundchgGetBoundchgtype(&boundchgs[i]) == SCIP_BOUNDCHGTYPE_BRANCHING ) { /* we branched on a variable were we don't know the solution: no debugging can be applied in this subtree */ *solcontained = FALSE; } } } } /* remember the status of the current node */ SCIP_CALL( SCIPhashmapSetImage(solinnode, (void*)node, *solcontained ? (void*)(&trueptr) : (void*)(&falseptr)) ); return SCIP_OKAY; }