/** adds variable where zero violates the bounds to pricing storage, capture it */ SCIP_RETCODE SCIPpricestoreAddBdviolvar( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_VAR* var /**< variable, where zero violates the bounds */ ) { assert(pricestore != NULL); assert(set != NULL); assert(var != NULL); assert(SCIPsetIsPositive(set, SCIPvarGetLbLocal(var)) || SCIPsetIsNegative(set, SCIPvarGetUbLocal(var))); assert(pricestore->naddedbdviolvars <= pricestore->nbdviolvars); SCIPdebugMessage("zero violates bounds of <%s> (lb=%g, ub=%g)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); if( !pricestore->initiallp ) pricestore->nvarsfound++; /* get enough memory to store additional variable */ SCIP_CALL( pricestoreEnsureBdviolvarsMem(pricestore, set, pricestore->nbdviolvars+1) ); assert(pricestore->nbdviolvars <= pricestore->bdviolvarssize); /* capture variable */ SCIPvarCapture(var); /* insert variable in bdviolvars arrays */ pricestore->bdviolvars[pricestore->nbdviolvars] = var; pricestore->bdviolvarslb[pricestore->nbdviolvars] = SCIPvarGetLbLocal(var); pricestore->bdviolvarsub[pricestore->nbdviolvars] = SCIPvarGetUbLocal(var); pricestore->nbdviolvars++; /* Temporarily set bounds, such that zero is feasible, because we don't want to destroy * dual feasibility (by adding columns) and primal feasibility (by introducing violated bounds) * at the same time. * The correct bounds must be reset with a call to SCIPpricestoreResetBounds(). * The inference information is unimportant for this temporary bound change. */ if( SCIPsetIsPositive(set, SCIPvarGetLbLocal(var)) ) { SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, 0.0) ); } else { SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, 0.0) ); } return SCIP_OKAY; }
/** creates a new node entry in the VBC output file */ SCIP_RETCODE SCIPvbcNewChild( SCIP_VBC* vbc, /**< VBC information */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node /**< new node, that was created */ ) { SCIP_VAR* branchvar; SCIP_BOUNDTYPE branchtype; SCIP_Real branchbound; size_t parentnodenum; size_t nodenum; assert(vbc != NULL); assert(stat != NULL); assert(node != NULL); /* check, if VBC output should be created */ if( vbc->file == NULL ) return SCIP_OKAY; /* vbc is disabled on probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return SCIP_OKAY; /* insert mapping node -> nodenum into hash map */ if( stat->ncreatednodesrun >= (SCIP_Longint)INT_MAX ) { SCIPerrorMessage("too many nodes to store in the VBC file\n"); return SCIP_INVALIDDATA; } nodenum = (size_t)stat->ncreatednodesrun; assert(nodenum > 0); SCIP_CALL( SCIPhashmapInsert(vbc->nodenum, node, (void*)nodenum) ); /* get nodenum of parent node from hash map */ parentnodenum = (node->parent != NULL ? (size_t)SCIPhashmapGetImage(vbc->nodenum, node->parent) : 0); assert(node->parent == NULL || parentnodenum > 0); /* get branching information */ getBranchInfo(node, &branchvar, &branchtype, &branchbound); printTime(vbc, stat); SCIPmessageFPrintInfo(vbc->messagehdlr, vbc->file, "N %d %d %d\n", (int)parentnodenum, (int)nodenum, SCIP_VBCCOLOR_UNSOLVED); printTime(vbc, stat); if( branchvar != NULL ) { SCIPmessageFPrintInfo(vbc->messagehdlr, vbc->file, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar), branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", branchbound, SCIPnodeGetLowerbound(node)); } else { SCIPmessageFPrintInfo(vbc->messagehdlr, vbc->file, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPnodeGetLowerbound(node)); } return SCIP_OKAY; }
void scip_branch_around_val(SCIP* scip, SCIP_VAR* v, llint x) { #ifdef DEBUG cout << "[SU] branching around " << x << " for " << var_id(v) << endl; #endif fflush(stdout); SCIP_NODE* left; SCIP_NODE* middle; SCIP_NODE* right; assert(SCIPvarGetLbLocal(v) <= x); assert(x <= SCIPvarGetUbLocal(v)); sa(SCIPbranchVarVal(scip, v, x, &left, &middle, &right)); #ifdef DEBUG cout << "created children " << left << " < " << middle << " < " << right << endl; #endif }
/** marks node as solved in visualization output file */ void SCIPvisualSolvedNode( SCIP_VISUAL* visual, /**< visualization information */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node /**< node, that was solved */ ) { SCIP_VAR* branchvar; SCIP_BOUNDTYPE branchtype; SCIP_Real branchbound; SCIP_Real lowerbound; size_t nodenum; assert( visual != NULL ); assert( stat != NULL ); assert( node != NULL ); /* check whether output should be created */ if ( visual->vbcfile == NULL && visual->bakfile == NULL ) return; /* visualization is disabled on probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return; /* get node num from hash map */ nodenum = (size_t)SCIPhashmapGetImage(visual->nodenum, node); assert(nodenum > 0); /* get branching information */ getBranchInfo(node, &branchvar, &branchtype, &branchbound); /* determine lower bound */ if ( set->visual_objextern ) lowerbound = SCIPretransformObj(set->scip, SCIPnodeGetLowerbound(node)); else lowerbound = SCIPnodeGetLowerbound(node); if ( visual->vbcfile != NULL ) { printTime(visual, stat, TRUE); if( branchvar != NULL ) { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\\nnr:\\t%" SCIP_LONGINT_FORMAT "\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar), branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", branchbound, lowerbound, stat->nnodes); } else { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\\nnr:\\t%" SCIP_LONGINT_FORMAT "\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), lowerbound, stat->nnodes); } vbcSetColor(visual, stat, node, SCIP_VBCCOLOR_SOLVED); } /* do nothing for BAK */ }
/** 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; }
static SCIP_Bool consdataCheck( SCIP* scip, /**< SCIP data structure */ SCIP_PROBDATA* probdata, /**< problem data */ SCIP_CONSDATA* consdata /**< constraint data */ ) { SCIP_VAR** vars; int nvars; SCIP_VARDATA* vardata; SCIP_VAR* var; int* consids; int nconsids; SCIP_Bool existid1; SCIP_Bool existid2; CONSTYPE type; int pos; int v; vars = SCIPprobdataGetVars(probdata); nvars = SCIPprobdataGetNVars(probdata); for( v = 0; v < nvars; ++v ) { var = vars[v]; /* if variables is locally fixed to zero continue */ if( SCIPvarGetLbLocal(var) < 0.5 ) continue; /* check if the packing which corresponds to the variable is feasible for this constraint */ vardata = SCIPvarGetData(var); nconsids = SCIPvardataGetNConsids(vardata); consids = SCIPvardataGetConsids(vardata); existid1 = SCIPsortedvecFindInt(consids, consdata->itemid1, nconsids, &pos); existid2 = SCIPsortedvecFindInt(consids, consdata->itemid2, nconsids, &pos); type = consdata->type; if( (type == SAME && existid1 != existid2) || (type == DIFFER && existid1 && existid2) ) { SCIPdebug( SCIPvardataPrint(scip, vardata, NULL) ); SCIPdebug( consdataPrint(scip, consdata, NULL) ); SCIPdebug( SCIPprintVar(scip, var, NULL) ); return FALSE; } } return TRUE; }
/** return an aggregated score for the given variable using the conflict score and cutoff score */ static SCIP_Real getValueScore( SCIP* scip, /**< SCIP data structure */ SCIP_VAR* var, /**< problem variable */ SCIP_Real conflictweight, /**< weight in score calculations for conflict score */ SCIP_Real cutoffweight, /**< weight in score calculations for cutoff score */ SCIP_Real reliablescore, /**< score which is seen to be reliable for a branching decision */ SCIP_Real* branchpoint, /**< pointer to store the branching point */ SCIP_BRANCHDIR* branchdir /**< pointer to store the branching direction relative to the branching point */ ) { SCIP_VALUEHISTORY* valuehistory; SCIP_Real bestscore; (*branchpoint) = SCIP_UNKNOWN; (*branchdir) = SCIP_BRANCHDIR_UPWARDS; valuehistory = SCIPvarGetValuehistory(var); bestscore = 0.0; if( valuehistory != NULL ) { SCIP_HISTORY** histories; SCIP_Real* values; int nvalues; int v; histories = SCIPvaluehistoryGetHistories(valuehistory); values = SCIPvaluehistoryGetValues(valuehistory); nvalues = SCIPvaluehistoryGetNValues(valuehistory); for( v = 0; v < nvalues; ++v ) { SCIP_Real value; value = values[v]; /* skip all domain values which are smaller or equal to the lower bound */ if( value <= SCIPvarGetLbLocal(var) ) continue; /* skip all domain values which are larger or equal to the upper bound */ if( value >= SCIPvarGetUbLocal(var) ) break; /* check var <= value */ checkValueScore(value, histories[v], SCIP_BRANCHDIR_DOWNWARDS, conflictweight, cutoffweight, reliablescore, &bestscore, branchpoint, branchdir); /* check var >= value */ checkValueScore(value, histories[v], SCIP_BRANCHDIR_UPWARDS, conflictweight, cutoffweight, reliablescore, &bestscore, branchpoint, branchdir); } } return bestscore; }
/** 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; }
/** changes the color of the node to the color of solved nodes */ void SCIPvbcSolvedNode( SCIP_VBC* vbc, /**< VBC information */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node /**< node, that was solved */ ) { SCIP_VAR* branchvar; SCIP_BOUNDTYPE branchtype; SCIP_Real branchbound; size_t nodenum; assert(vbc != NULL); assert(stat != NULL); assert(node != NULL); /* check, if VBC output should be created */ if( vbc->file == NULL ) return; /* vbc is disabled on probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return; /* get node num from hash map */ nodenum = (size_t)SCIPhashmapGetImage(vbc->nodenum, node); assert(nodenum > 0); /* get branching information */ getBranchInfo(node, &branchvar, &branchtype, &branchbound); printTime(vbc, stat); if( branchvar != NULL ) { SCIPmessageFPrintInfo(vbc->messagehdlr, vbc->file, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\\nnr:\\t%"SCIP_LONGINT_FORMAT"\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar), branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", branchbound, SCIPnodeGetLowerbound(node), stat->nnodes); } else { SCIPmessageFPrintInfo(vbc->messagehdlr, vbc->file, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\\nnr:\\t%"SCIP_LONGINT_FORMAT"\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPnodeGetLowerbound(node), stat->nnodes); } vbcSetColor(vbc, stat, node, SCIP_VBCCOLOR_SOLVED); }
/** reset variables' bounds violated by zero to its original value */ SCIP_RETCODE SCIPpricestoreResetBounds( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue /**< event queue */ ) { SCIP_VAR* var; int v; assert(pricestore != NULL); assert(set != NULL); assert(lp != NULL); assert(pricestore->nvars == 0); assert(pricestore->naddedbdviolvars == pricestore->nbdviolvars); /* reset variables' bounds, release them, and clear the boundviolation storage; * the inference information is unimportant in these removals of temporary bound changes */ for( v = 0; v < pricestore->nbdviolvars; ++v ) { var = pricestore->bdviolvars[v]; assert(var != NULL); SCIPdebugMessage("resetting bounds of <%s> from [%g,%g] to [%g,%g]\n", var->name, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), pricestore->bdviolvarslb[v], pricestore->bdviolvarsub[v]); SCIP_CALL( SCIPvarChgLbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, pricestore->bdviolvarslb[v]) ); SCIP_CALL( SCIPvarChgUbLocal(var, blkmem, set, stat, lp, branchcand, eventqueue, pricestore->bdviolvarsub[v]) ); SCIP_CALL( SCIPvarRelease(&pricestore->bdviolvars[v], blkmem, set, eventqueue, lp) ); } pricestore->naddedbdviolvars = 0; pricestore->nbdviolvars = 0; return SCIP_OKAY; }
bool scip_fix_variable (SCIP* scip, SCIP_VAR* v, llint x, bool* infeasible) { SCIP_Bool lb_infeasible, lb_tightened, ub_infeasible, ub_tightened; if (SCIPisEQ(scip, x, SCIPvarGetLbLocal(v)) && SCIPisEQ(scip, x, SCIPvarGetUbLocal(v))) { *infeasible = false; return false; } sa(SCIPinferVarUbCons(scip, v, x, NULL, 0, TRUE, &lb_infeasible, &lb_tightened)); sa(SCIPinferVarLbCons(scip, v, x, NULL, 0, TRUE, &ub_infeasible, &ub_tightened)); *infeasible = *infeasible || lb_infeasible || ub_infeasible; return (lb_tightened || ub_tightened); }
/** update the variables current lower and upper bound */ static void heurdataUpdateCurrentBounds( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ SCIP_VAR* var /**< the variable to update current bounds */ ) { int varindex; SCIP_Real lblocal; SCIP_Real ublocal; assert(var != NULL); varindex = SCIPvarGetProbindex(var); assert(0 <= varindex && varindex < heurdata->varpossmemsize); lblocal = SCIPvarGetLbLocal(var); ublocal = SCIPvarGetUbLocal(var); assert(SCIPisFeasLE(scip, lblocal, ublocal)); heurdata->currentlbs[varindex] = lblocal; heurdata->currentubs[varindex] = ublocal; }
/** branching execution method for external candidates */ static SCIP_DECL_BRANCHEXECEXT(branchExecextRandom) { /*lint --e{715}*/ SCIP_BRANCHRULEDATA* branchruledata; SCIP_VAR** externcands; SCIP_Real* externcandssol; int nprioexterncands; SCIP_VAR* bestcand; SCIP_Real bestcandsol; SCIP_Real brpoint; SCIP_NODE* downchild; SCIP_NODE* eqchild; SCIP_NODE* upchild; assert(branchrule != NULL); assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); assert(scip != NULL); assert(result != NULL); SCIPdebugMessage("Execrel method of random branching\n"); branchruledata = SCIPbranchruleGetData(branchrule); assert(branchruledata != NULL); bestcand = NULL; bestcandsol = 0.0; /* get branching candidates */ SCIP_CALL( SCIPgetExternBranchCands(scip, &externcands, &externcandssol, NULL, NULL, &nprioexterncands, NULL, NULL, NULL) ); assert(nprioexterncands > 0); /* get random branching candidate * * since variables can occur several times in the list of candidates, variables that have been added more often have * a higher probability to be chosen for branching */ getRandomVariable(scip, externcands, externcandssol, nprioexterncands, &bestcand, &bestcandsol, &branchruledata->seed); if( bestcand == NULL ) { SCIPerrorMessage("branchExecrelRandom failed to select a branching variable from %d candidates\n", nprioexterncands); *result = SCIP_DIDNOTRUN; return SCIP_OKAY; } brpoint = SCIPgetBranchingPoint(scip, bestcand, bestcandsol); SCIPdebugMessage(" -> %d candidates, selected variable <%s> with solution value %g, branching point=%g\n", nprioexterncands, SCIPvarGetName(bestcand), bestcandsol, brpoint); SCIP_CALL( SCIPbranchVarVal(scip, bestcand, brpoint, &downchild, &eqchild, &upchild) ); if( downchild != NULL || eqchild != NULL || upchild != NULL ) { *result = SCIP_BRANCHED; } else { /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */ assert(SCIPisEQ(scip, SCIPvarGetLbLocal(bestcand), SCIPvarGetUbLocal(bestcand))); *result = SCIP_REDUCEDDOM; } return SCIP_OKAY; }
/** adds variable to pricing storage and capture it */ SCIP_RETCODE SCIPpricestoreAddVar( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_LP* lp, /**< LP data */ SCIP_VAR* var, /**< priced variable */ SCIP_Real score, /**< pricing score of variable (the larger, the better the variable) */ SCIP_Bool root /**< are we at the root node? */ ) { int maxpricevars; int v; assert(pricestore != NULL); assert(set != NULL); assert(var != NULL); #ifndef NDEBUG /* check if we add this variables to the same scip, where we created it */ if( var->scip != set->scip ) { SCIPerrorMessage("try to add a variable of another scip instance\n"); return SCIP_INVALIDDATA; } #endif SCIPdebugMessage("adding variable <%s> (lb=%g, ub=%g) to pricing storage (initiallp=%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), pricestore->initiallp); if( pricestore->initiallp ) maxpricevars = INT_MAX; else { pricestore->nvarsfound++; maxpricevars = SCIPsetGetPriceMaxvars(set, root); } assert(maxpricevars >= 1); assert(pricestore->nvars <= maxpricevars); /* check, if variable belongs to the best "maxpricevars" pricing variables */ if( pricestore->nvars < maxpricevars || score > pricestore->scores[maxpricevars-1] ) { /* capture variable */ SCIPvarCapture(var); /* if the array consists of "maxpricevars" variables, release the worst variables */ if( pricestore->nvars == maxpricevars ) { SCIP_CALL( SCIPvarRelease(&pricestore->vars[pricestore->nvars-1], blkmem, set, eventqueue, lp) ); pricestore->nvars--; } assert(pricestore->nvars < maxpricevars); /* get enough memory to store additional variable */ SCIP_CALL( pricestoreEnsureVarsMem(pricestore, set, pricestore->nvars+1) ); assert(pricestore->nvars <= pricestore->varssize); /* insert the variable at the correct position in sorted arrays */ for( v = pricestore->nvars; v > 0 && score > pricestore->scores[v-1]; --v ) { pricestore->vars[v] = pricestore->vars[v-1]; pricestore->scores[v] = pricestore->scores[v-1]; } pricestore->vars[v] = var; pricestore->scores[v] = score; pricestore->nvars++; } return SCIP_OKAY; }
/** selects a random active variable from a given list of variables */ static void getRandomVariable( SCIP* scip, /**< SCIP data structure */ SCIP_VAR** cands, /**< array of branching candidates */ SCIP_Real* candssol, /**< relaxation solution values of branching candidates, or NULL */ int ncands, /**< number of branching candidates */ SCIP_VAR** bestcand, /**< buffer to store pointer to best candidate */ SCIP_Real* bestcandsol, /**< buffer to store solution value of best candidate */ unsigned int* seed /**< seed for random number generator */ ) { int idx; int firstidx; assert(scip != NULL); assert(cands != NULL); assert(ncands > 0); assert(bestcand != NULL); assert(bestcandsol != NULL); assert(seed != NULL); idx = SCIPgetRandomInt(0, ncands-1, seed); assert(idx >= 0); /* handle case where cands[idx] is fixed by selecting next idx with unfixed var * this may happen if we are inside a multi-aggregation */ firstidx = idx; while( SCIPisEQ(scip, SCIPvarGetLbLocal(cands[idx]), SCIPvarGetUbLocal(cands[idx])) ) { ++idx; if( idx == ncands ) idx = 0; if( idx == firstidx ) { /* odd: all variables seem to be fixed */ SCIPdebugMessage("Warning: all branching candidates seem to be fixed\n"); return; } } /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */ assert(SCIPvarIsActive(SCIPvarGetProbvar(cands[idx])) || SCIPvarGetStatus(SCIPvarGetProbvar(cands[idx])) == SCIP_VARSTATUS_MULTAGGR); if( SCIPvarGetStatus(SCIPvarGetProbvar(cands[idx])) == SCIP_VARSTATUS_MULTAGGR ) { /* for a multi-aggregated variable, we call the getRandomVariable function recursively with all variables in the multi-aggregation */ SCIP_VAR* cand; cand = SCIPvarGetProbvar(cands[idx]); getRandomVariable(scip, SCIPvarGetMultaggrVars(cand), NULL, SCIPvarGetMultaggrNVars(cand), bestcand, bestcandsol, seed); return; } assert(idx >= 0 && idx < ncands); *bestcand = cands[idx]; assert(*bestcand != NULL); if( candssol != NULL ) *bestcandsol = candssol[idx]; }
/** fixes a variable to zero if the corresponding packings are not valid for this constraint/node (due to branching) */ static SCIP_RETCODE checkVariable( SCIP* scip, /**< SCIP data structure */ SCIP_CONSDATA* consdata, /**< constraint data */ SCIP_VAR* var, /**< variables to check */ int* nfixedvars, /**< pointer to store the number of fixed variables */ SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */ ) { SCIP_VARDATA* vardata; int* consids; int nconsids; SCIP_Bool existid1; SCIP_Bool existid2; CONSTYPE type; SCIP_Bool fixed; SCIP_Bool infeasible; int pos; assert(scip != NULL); assert(consdata != NULL); assert(var != NULL); assert(nfixedvars != NULL); assert(cutoff != NULL); /* if variables is locally fixed to zero continue */ if( SCIPvarGetUbLocal(var) < 0.5 ) return SCIP_OKAY; /* check if the packing which corresponds to the variable feasible for this constraint */ vardata = SCIPvarGetData(var); nconsids = SCIPvardataGetNConsids(vardata); consids = SCIPvardataGetConsids(vardata); existid1 = SCIPsortedvecFindInt(consids, consdata->itemid1, nconsids, &pos); existid2 = SCIPsortedvecFindInt(consids, consdata->itemid2, nconsids, &pos); type = consdata->type; if( (type == SAME && existid1 != existid2) || (type == DIFFER && existid1 && existid2) ) { SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) ); if( infeasible ) { assert( SCIPvarGetLbLocal(var) > 0.5 ); SCIPdebugMessage("-> cutoff\n"); (*cutoff) = TRUE; } else { assert(fixed); (*nfixedvars)++; } } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecActconsdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_VAR* var; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_Real* lpcandsfrac; SCIP_Real searchubbound; SCIP_Real searchavgbound; SCIP_Real searchbound; SCIP_Real objval; SCIP_Real oldobjval; SCIP_Real frac; SCIP_Real bestfrac; SCIP_Bool bestcandmayrounddown; SCIP_Bool bestcandmayroundup; SCIP_Bool bestcandroundup; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Bool roundup; SCIP_Bool lperror; SCIP_Bool cutoff; SCIP_Bool backtracked; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int nlpcands; int startnlpcands; int depth; int maxdepth; int maxdivedepth; int divedepth; SCIP_Real actscore; SCIP_Real downscore; SCIP_Real upscore; SCIP_Real bestactscore; int bestcand; int c; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* do not call heuristic of node was already detected to be infeasible */ if( nodeinfeasible ) return SCIP_OKAY; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call heuristic, if the LP objective value is smaller than the cutoff bound */ if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) ) return SCIP_OKAY; /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* don't dive two times at the same node */ if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */ depth = SCIPgetDepth(scip); maxdepth = SCIPgetMaxDepth(scip); maxdepth = MAX(maxdepth, 30); if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth ) return SCIP_OKAY; /* calculate the maximal number of LP iterations until heuristic is aborted */ nlpiterations = SCIPgetNNodeLPIterations(scip); ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess; maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations); maxnlpiterations += heurdata->maxlpiterofs; /* don't try to dive, if we took too many LP iterations during diving */ if( heurdata->nlpiterations >= maxnlpiterations ) return SCIP_OKAY; /* allow at least a certain number of LP iterations in this dive */ maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER); /* get fractional variables that should be integral */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); /* don't try to dive, if there are no fractional variables */ if( nlpcands == 0 ) return SCIP_OKAY; /* calculate the objective search bound */ if( SCIPgetNSolsFound(scip) == 0 ) { if( heurdata->maxdiveubquotnosol > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquotnosol > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } else { if( heurdata->maxdiveubquot > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquot > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } searchbound = MIN(searchubbound, searchavgbound); if( SCIPisObjIntegral(scip) ) searchbound = SCIPceil(scip, searchbound); /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */ maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); maxdivedepth = MIN(maxdivedepth, maxdepth); maxdivedepth *= 10; *result = SCIP_DIDNOTFIND; /* start diving */ SCIP_CALL( SCIPstartProbing(scip) ); /* enables collection of variable statistics during probing */ SCIPenableVarHistory(scip); /* get LP objective value */ lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; objval = SCIPgetLPObjval(scip); SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing actconsdiving heuristic: depth=%d, %d fractionals, dualbound=%g, avgbound=%g, cutoffbound=%g, searchbound=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPgetAvgDualbound(scip), SCIPretransformObj(scip, SCIPgetCutoffbound(scip)), SCIPretransformObj(scip, searchbound)); /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but * - if possible, we dive at least with the depth 10 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving */ lperror = FALSE; cutoff = FALSE; divedepth = 0; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; startnlpcands = nlpcands; while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && (divedepth < 10 || nlpcands <= startnlpcands - divedepth/2 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound)) && !SCIPisStopped(scip) ) { divedepth++; SCIP_CALL( SCIPnewProbingNode(scip) ); /* choose variable fixing: * - prefer variables that may not be rounded without destroying LP feasibility: * - of these variables, round variable with least number of locks in corresponding direction * - if all remaining fractional variables may be rounded without destroying LP feasibility: * - round variable with least number of locks in opposite of its feasible rounding direction */ bestcand = -1; bestactscore = -1.0; bestfrac = SCIP_INVALID; bestcandmayrounddown = TRUE; bestcandmayroundup = TRUE; bestcandroundup = FALSE; for( c = 0; c < nlpcands; ++c ) { var = lpcands[c]; mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); frac = lpcandsfrac[c]; if( mayrounddown || mayroundup ) { /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */ if( bestcandmayrounddown || bestcandmayroundup ) { /* choose rounding direction: * - if variable may be rounded in both directions, round corresponding to the fractionality * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution */ if( mayrounddown && mayroundup ) roundup = (frac > 0.5); else roundup = mayrounddown; if( roundup ) frac = 1.0 - frac; actscore = getNActiveConsScore(scip, var, &downscore, &upscore); /* penalize too small fractions */ if( frac < 0.01 ) actscore *= 0.01; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) actscore *= 0.01; /* check, if candidate is new best candidate */ assert(0.0 < frac && frac < 1.0); if( SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) ) { bestcand = c; bestactscore = actscore; bestfrac = frac; bestcandmayrounddown = mayrounddown; bestcandmayroundup = mayroundup; bestcandroundup = roundup; } } } else { /* the candidate may not be rounded */ actscore = getNActiveConsScore(scip, var, &downscore, &upscore); roundup = (downscore < upscore); if( roundup ) frac = 1.0 - frac; /* penalize too small fractions */ if( frac < 0.01 ) actscore *= 0.01; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) actscore *= 0.01; /* check, if candidate is new best candidate: prefer unroundable candidates in any case */ assert(0.0 < frac && frac < 1.0); if( bestcandmayrounddown || bestcandmayroundup || SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) ) { bestcand = c; bestactscore = actscore; bestfrac = frac; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; bestcandroundup = roundup; } assert(bestfrac < SCIP_INVALID); } } assert(bestcand != -1); /* if all candidates are roundable, try to round the solution */ if( bestcandmayrounddown || bestcandmayroundup ) { SCIP_Bool success; /* create solution from diving LP and try to round it */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) ); if( success ) { SCIPdebugMessage("actconsdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } } assert(bestcand != -1); var = lpcands[bestcand]; backtracked = FALSE; do { /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have * occured or variable was fixed by propagation while backtracking => Abort diving! */ if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 ) { SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]); cutoff = TRUE; break; } if( SCIPisFeasLT(scip, lpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, lpcandssol[bestcand], SCIPvarGetUbLocal(var)) ) { SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]); assert(backtracked); break; } /* apply rounding of best candidate */ if( bestcandroundup == !backtracked ) { /* round variable up */ SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPfeasCeil(scip, lpcandssol[bestcand]), SCIPvarGetUbLocal(var)); SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) ); } else { /* round variable down */ SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand])); SCIP_CALL( SCIPchgVarUbProbing(scip, lpcands[bestcand], SCIPfeasFloor(scip, lpcandssol[bestcand])) ); } /* apply domain propagation */ SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) ); if( !cutoff ) { /* resolve the diving LP */ /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic. * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ #ifdef NDEBUG SCIP_RETCODE retstat; nlpiterations = SCIPgetNLPIterations(scip); retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff); if( retstat != SCIP_OKAY ) { SCIPwarningMessage(scip, "Error while solving LP in Actconsdiving heuristic; LP solve terminated with code <%d>\n",retstat); } #else nlpiterations = SCIPgetNLPIterations(scip); SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) ); #endif if( lperror ) break; /* update iteration count */ heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations; /* get LP solution status, objective value, and fractional variables, that should be integral */ lpsolstat = SCIPgetLPSolstat(scip); assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE && (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip))))); } /* perform backtracking if a cutoff was detected */ if( cutoff && !backtracked && heurdata->backtrack ) { SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip)); SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) ); SCIP_CALL( SCIPnewProbingNode(scip) ); backtracked = TRUE; } else backtracked = FALSE; } while( backtracked ); if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { /* get new objective value */ oldobjval = objval; objval = SCIPgetLPObjval(scip); /* update pseudo cost values */ if( SCIPisGT(scip, objval, oldobjval) ) { if( bestcandroundup ) { SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 1.0-lpcandsfrac[bestcand], objval - oldobjval, 1.0) ); } else { SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 0.0-lpcandsfrac[bestcand], objval - oldobjval, 1.0) ); } } /* get new fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); } SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g, nfrac=%d\n", lpsolstat, objval, searchbound, nlpcands); } /* check if a solution has been found */ if( nlpcands == 0 && !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* create solution from diving LP */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIPdebugMessage("actconsdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } /* end diving */ SCIP_CALL( SCIPendProbing(scip) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") finished actconsdiving heuristic: %d fractionals, dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT", objval=%g/%g, lpsolstat=%d, cutoff=%u\n", SCIPgetNNodes(scip), nlpcands, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPretransformObj(scip, objval), SCIPretransformObj(scip, searchbound), lpsolstat, cutoff); return SCIP_OKAY; }
/** perform randomized rounding of the given solution. Domain propagation is optionally applied after every rounding * step */ static SCIP_RETCODE performRandRounding( SCIP* scip, /**< SCIP main data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ SCIP_SOL* sol, /**< solution to round */ SCIP_VAR** cands, /**< candidate variables */ int ncands, /**< number of candidates */ SCIP_Bool propagate, /**< should the rounding be propagated? */ SCIP_RESULT* result /**< pointer to store the result of the heuristic call */ ) { int c; SCIP_Bool stored; SCIP_VAR** permutedcands; SCIP_Bool cutoff; assert(heurdata != NULL); /* start probing tree before rounding begins */ if( propagate ) { SCIP_CALL( SCIPstartProbing(scip) ); SCIPenableVarHistory(scip); } /* copy and permute the candidate array */ SCIP_CALL( SCIPduplicateBufferArray(scip, &permutedcands, cands, ncands) ); assert(permutedcands != NULL); SCIPpermuteArray((void **)permutedcands, 0, ncands, &heurdata->randseed); cutoff = FALSE; /* loop over candidates and perform randomized rounding and optionally probing. */ for (c = 0; c < ncands && !cutoff; ++c) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real newsolval; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Longint ndomreds; SCIP_Real lb; SCIP_Real ub; SCIP_Real ceilval; SCIP_Real floorval; /* get next variable from permuted candidate array */ var = permutedcands[c]; oldsolval = SCIPgetSolVal(scip, sol, var); lb = SCIPvarGetLbLocal(var); ub = SCIPvarGetUbLocal(var); assert( ! SCIPisFeasIntegral(scip, oldsolval) ); assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ); mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); ceilval = SCIPfeasCeil(scip, oldsolval); floorval = SCIPfeasFloor(scip, oldsolval); SCIPdebugMessage("rand rounding heuristic: var <%s>, val=%g, rounddown=%u, roundup=%u\n", SCIPvarGetName(var), oldsolval, mayrounddown, mayroundup); /* abort if rounded ceil and floor value lie outside the variable domain. Otherwise, check if * bounds allow only one rounding direction, anyway */ if( lb > ceilval + 0.5 || ub < floorval - 0.5 ) { cutoff = TRUE; break; } else if( SCIPisFeasEQ(scip, lb, ceilval) ) { /* only rounding up possible */ assert(SCIPisFeasGE(scip, ub, ceilval)); newsolval = ceilval; } else if( SCIPisFeasEQ(scip, ub, floorval) ) { /* only rounding down possible */ assert(SCIPisFeasLE(scip,lb, floorval)); newsolval = floorval; } else if( !heurdata->usesimplerounding || !(mayroundup || mayrounddown) ) { /* the standard randomized rounding */ SCIP_Real randnumber; randnumber = SCIPgetRandomReal(0.0, 1.0, &heurdata->randseed); if( randnumber <= oldsolval - floorval ) newsolval = ceilval; else newsolval = floorval; } /* choose rounding direction, if possible, or use the only direction guaranteed to be feasible */ else if( mayrounddown && mayroundup ) { /* we can round in both directions: round in objective function direction */ if ( SCIPvarGetObj(var) >= 0.0 ) newsolval = floorval; else newsolval = ceilval; } else if( mayrounddown ) newsolval = floorval; else { assert(mayroundup); newsolval = ceilval; } assert(SCIPisFeasLE(scip, lb, newsolval)); assert(SCIPisFeasGE(scip, ub, newsolval)); /* if propagation is enabled, fix the candidate variable to its rounded value and propagate the solution */ if( propagate ) { SCIP_Bool lbadjust; SCIP_Bool ubadjust; lbadjust = SCIPisGT(scip, newsolval, lb); ubadjust = SCIPisLT(scip, newsolval, ub); assert( lbadjust || ubadjust || SCIPisFeasEQ(scip, lb, ub)); /* enter a new probing node if the variable was not already fixed before */ if( lbadjust || ubadjust ) { SCIP_RETCODE retcode; if( SCIPisStopped(scip) ) break; retcode = SCIPnewProbingNode(scip); if( retcode == SCIP_MAXDEPTHLEVEL ) break; SCIP_CALL( retcode ); /* tighten the bounds to fix the variable for the probing node */ if( lbadjust ) { SCIP_CALL( SCIPchgVarLbProbing(scip, var, newsolval) ); } if( ubadjust ) { SCIP_CALL( SCIPchgVarUbProbing(scip, var, newsolval) ); } /* call propagation routines for the reduced problem */ SCIP_CALL( SCIPpropagateProbing(scip, heurdata->maxproprounds, &cutoff, &ndomreds) ); } } /* store new solution value */ SCIP_CALL( SCIPsetSolVal(scip, sol, var, newsolval) ); } /* if no cutoff was detected, the solution is a candidate to be checked for feasibility */ if( !cutoff && ! SCIPisStopped(scip) ) { if( SCIPallColsInLP(scip) ) { /* check solution for feasibility, and add it to solution store if possible * neither integrality nor feasibility of LP rows has to be checked, because all fractional * variables were already moved in feasible direction to the next integer */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, &stored) ); } else { /* if there are variables which are not present in the LP, e.g., for * column generation, we need to check their bounds */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, TRUE, FALSE, TRUE, &stored) ); } if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif *result = SCIP_FOUNDSOL; } } assert( !propagate || SCIPinProbing(scip) ); /* exit probing mode and free locally allocated memory */ if( propagate ) { SCIP_CALL( SCIPendProbing(scip) ); } SCIPfreeBufferArray(scip, &permutedcands); return SCIP_OKAY; }
/** perform dual presolving */ static SCIP_RETCODE performDualfix( SCIP* scip, /**< SCIP data structure */ int* nfixedvars, /**< pointer to store number of fixed variables */ SCIP_Bool* unbounded, /**< pointer to store if an unboundness was detected */ SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */ ) { SCIP_VAR** vars; int nvars; int v; /* get active problem variables */ vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); /* look for fixable variables * loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array */ for( v = nvars - 1; v >= 0; --v ) { SCIP_VAR* var; SCIP_Real bound; SCIP_Real obj; SCIP_Bool infeasible; SCIP_Bool fixed; var = vars[v]; assert(var != NULL); /* don't perform dual presolving operations on deleted variables */ if( SCIPvarIsDeleted(var) ) continue; /* ignore already fixed variables (use feasibility tolerance since this is used in SCIPfixVar() */ if( SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ) continue; obj = SCIPvarGetObj(var); /* if the objective coefficient of the variable is 0 and it may be rounded both * up and down, then fix it to the closest feasible value to 0 */ if( SCIPisZero(scip, obj) && SCIPvarMayRoundDown(var) && SCIPvarMayRoundUp(var) ) { SCIP_Real roundbound; bound = SCIPvarGetLbGlobal(var); if( SCIPisLT(scip, bound, 0.0) ) { if( SCIPisLE(scip, 0.0, SCIPvarGetUbGlobal(var)) ) bound = 0.0; else { /* try to take an integer value, only for polishing */ roundbound = SCIPfloor(scip, SCIPvarGetUbGlobal(var)); if( roundbound < bound ) bound = SCIPvarGetUbGlobal(var); else bound = roundbound; } } else { /* try to take an integer value, only for polishing */ roundbound = SCIPceil(scip, bound); if( roundbound < SCIPvarGetUbGlobal(var) ) bound = roundbound; } SCIPdebugMessage("fixing variable <%s> with objective 0 to %g\n", SCIPvarGetName(var), bound); } else { /* if it is always possible to round variable in direction of objective value, fix it to its proper bound */ if( SCIPvarMayRoundDown(var) && !SCIPisNegative(scip, obj) ) { bound = SCIPvarGetLbGlobal(var); if ( SCIPisInfinity(scip, -bound) ) { /* variable can be fixed to -infinity */ if ( SCIPgetStage(scip) > SCIP_STAGE_PRESOLVING ) { /* Fixing variables to infinity is not allowed after presolving, since LP-solvers cannot handle this * consistently. We thus have to ignore this (should better be handled in presolving). */ continue; } if ( SCIPisZero(scip, obj) && SCIPvarGetNLocksUp(var) == 1 ) { /* Variable is only contained in one constraint: we hope that the corresponding constraint handler is * clever enough to set/aggregate the variable to something more useful than -infinity and do nothing * here. */ continue; } } SCIPdebugMessage("fixing variable <%s> with objective %g and %d uplocks to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetObj(var), SCIPvarGetNLocksUp(var), bound); } else if( SCIPvarMayRoundUp(var) && !SCIPisPositive(scip, obj) ) { bound = SCIPvarGetUbGlobal(var); if ( SCIPisInfinity(scip, bound) ) { /* variable can be fixed to infinity */ if ( SCIPgetStage(scip) > SCIP_STAGE_PRESOLVING ) { /* Fixing variables to infinity is not allowed after presolving, since LP-solvers cannot handle this * consistently. We thus have to ignore this (should better be handled in presolving). */ continue; } if ( SCIPisZero(scip, obj) && SCIPvarGetNLocksDown(var) == 1 ) { /* Variable is only contained in one constraint: we hope that the corresponding constraint handler is * clever enough to set/aggregate the variable to something more useful than +infinity and do nothing * here */ continue; } } SCIPdebugMessage("fixing variable <%s> with objective %g and %d downlocks to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetObj(var), SCIPvarGetNLocksDown(var), bound); } else continue; } if( SCIPisInfinity(scip, REALABS(bound)) && !SCIPisZero(scip, obj) ) { SCIPdebugMessage(" -> unbounded fixing\n"); SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible or unbounded: variable <%s> with objective %.15g can be made infinitely %s\n", SCIPvarGetName(var), SCIPvarGetObj(var), bound < 0.0 ? "small" : "large"); *unbounded = TRUE; return SCIP_OKAY; } /* apply the fixing */ SCIPdebugMessage("apply fixing of variable %s to %g\n", SCIPvarGetName(var), bound); SCIP_CALL( SCIPfixVar(scip, var, bound, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *cutoff = TRUE; return SCIP_OKAY; } assert(fixed || (SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisFeasEQ(scip, bound, SCIPvarGetLbLocal(var)) && SCIPisFeasEQ(scip, bound, SCIPvarGetUbLocal(var)))); (*nfixedvars)++; } return SCIP_OKAY; }
/** checks if a given branching candidate is better than a previous one and updates the best branching candidate accordingly */ static SCIP_RETCODE updateBestCandidate( SCIP* scip, /**< SCIP data structure */ SCIP_BRANCHRULEDATA* branchruledata, /**< branching rule data */ SCIP_VAR** bestvar, /**< best branching candidate */ SCIP_Real* bestbrpoint, /**< branching point for best branching candidate */ SCIP_Real* bestscore, /**< score of best branching candidate */ SCIP_VAR* cand, /**< branching candidate to consider */ SCIP_Real candscoremin, /**< minimal score of branching candidate */ SCIP_Real candscoremax, /**< maximal score of branching candidate */ SCIP_Real candscoresum, /**< sum of scores of branching candidate */ SCIP_Real candsol /**< proposed branching point of branching candidate */ ) { SCIP_Real candbrpoint; SCIP_Real branchscore; SCIP_Real deltaminus; SCIP_Real deltaplus; SCIP_Real pscostdown; SCIP_Real pscostup; char strategy; assert(scip != NULL); assert(branchruledata != NULL); assert(bestvar != NULL); assert(bestbrpoint != NULL); assert(bestscore != NULL); assert(cand != NULL); /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */ assert(SCIPvarIsActive(SCIPvarGetProbvar(cand)) || SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR); if( SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR ) { /* for a multi-aggregated variable, we call updateBestCandidate function recursively with all variables in the multi-aggregation */ SCIP_VAR** multvars; int nmultvars; int i; SCIP_Bool success; SCIP_Real multvarlb; SCIP_Real multvarub; cand = SCIPvarGetProbvar(cand); multvars = SCIPvarGetMultaggrVars(cand); nmultvars = SCIPvarGetMultaggrNVars(cand); /* if we have a candidate branching point, then first register only aggregation variables * for which we can compute a corresponding branching point too (see also comments below) * if this fails, then register all (unfixed) aggregation variables, thereby forgetting about candsol */ success = FALSE; if( candsol != SCIP_INVALID ) /*lint !e777*/ { SCIP_Real* multscalars; SCIP_Real minact; SCIP_Real maxact; SCIP_Real aggrvarsol; SCIP_Real aggrvarsol1; SCIP_Real aggrvarsol2; multscalars = SCIPvarGetMultaggrScalars(cand); /* for computing the branching point, we need the current bounds of the multi-aggregated variable */ minact = SCIPcomputeVarLbLocal(scip, cand); maxact = SCIPcomputeVarUbLocal(scip, cand); for( i = 0; i < nmultvars; ++i ) { /* skip fixed variables */ multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]); multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]); if( SCIPisEQ(scip, multvarlb, multvarub) ) continue; assert(multscalars != NULL); assert(multscalars[i] != 0.0); /* we cannot ensure that both the upper bound in the left node and the lower bound in the right node * will be candsol by a clever choice for the branching point of multvars[i], * but we can try to ensure that at least one of them will be at candsol */ if( multscalars[i] > 0.0 ) { /* cand >= candsol * if multvars[i] >= (candsol - (maxact - multscalars[i] * ub(multvars[i]))) / multscalars[i] * = (candsol - maxact) / multscalars[i] + ub(multvars[i]) */ aggrvarsol1 = (candsol - maxact) / multscalars[i] + multvarub; /* cand <= candsol * if multvars[i] <= (candsol - (minact - multscalar[i] * lb(multvars[i]))) / multscalars[i] * = (candsol - minact) / multscalars[i] + lb(multvars[i]) */ aggrvarsol2 = (candsol - minact) / multscalars[i] + multvarlb; } else { /* cand >= candsol * if multvars[i] <= (candsol - (maxact - multscalars[i] * lb(multvars[i]))) / multscalars[i] * = (candsol - maxact) / multscalars[i] + lb(multvars[i]) */ aggrvarsol2 = (candsol - maxact) / multscalars[i] + multvarlb; /* cand <= candsol * if multvars[i] >= (candsol - (minact - multscalar[i] * ub(multvars[i]))) / multscalars[i] * = (candsol - minact) / multscalars[i] + ub(multvars[i]) */ aggrvarsol1 = (candsol - minact) / multscalars[i] + multvarub; } /* by the above choice, aggrvarsol1 <= ub(multvars[i]) and aggrvarsol2 >= lb(multvars[i]) * if aggrvarsol1 <= lb(multvars[i]) or aggrvarsol2 >= ub(multvars[i]), then choose the other one * if both are out of bounds, then give up * if both are inside bounds, then choose the one closer to 0.0 (someone has better idea???) */ if( SCIPisFeasLE(scip, aggrvarsol1, multvarlb) ) { if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) ) continue; else aggrvarsol = aggrvarsol2; } else { if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) ) aggrvarsol = aggrvarsol1; else aggrvarsol = REALABS(aggrvarsol1) < REALABS(aggrvarsol2) ? aggrvarsol1 : aggrvarsol2; } success = TRUE; SCIP_CALL( updateBestCandidate(scip, branchruledata, bestvar, bestbrpoint, bestscore, multvars[i], candscoremin, candscoremax, candscoresum, aggrvarsol) ); } } if( !success ) for( i = 0; i < nmultvars; ++i ) { /* skip fixed variables */ multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]); multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]); if( SCIPisEQ(scip, multvarlb, multvarub) ) continue; SCIP_CALL( updateBestCandidate(scip, branchruledata, bestvar, bestbrpoint, bestscore, multvars[i], candscoremin, candscoremax, candscoresum, SCIP_INVALID) ); } assert(*bestvar != NULL); /* if all variables were fixed, something is strange */ return SCIP_OKAY; } /* select branching point for this variable */ candbrpoint = SCIPgetBranchingPoint(scip, cand, candsol); assert(candbrpoint >= SCIPvarGetLbLocal(cand)); assert(candbrpoint <= SCIPvarGetUbLocal(cand)); /* we cannot branch on a huge value for a discrete variable, because we simply cannot enumerate such huge integer values in floating point * arithmetics */ if( SCIPvarGetType(cand) != SCIP_VARTYPE_CONTINUOUS && (SCIPisHugeValue(scip, candbrpoint) || SCIPisHugeValue(scip, -candbrpoint)) ) return SCIP_OKAY; assert(SCIPvarGetType(cand) == SCIP_VARTYPE_CONTINUOUS || !SCIPisIntegral(scip, candbrpoint)); if( SCIPvarGetType(cand) == SCIP_VARTYPE_CONTINUOUS ) strategy = (branchruledata->strategy == 'u' ? branchruledata->updatestrategy : branchruledata->strategy); else strategy = (branchruledata->strategy == 'u' ? 'l' : branchruledata->strategy); switch( strategy ) { case 'l': if( SCIPisInfinity(scip, SCIPgetSolVal(scip, NULL, cand)) || SCIPgetSolVal(scip, NULL, cand) <= SCIPadjustedVarUb(scip, cand, candbrpoint) ) deltaminus = 0.0; else deltaminus = SCIPgetSolVal(scip, NULL, cand) - SCIPadjustedVarUb(scip, cand, candbrpoint); if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, NULL, cand)) || SCIPgetSolVal(scip, NULL, cand) >= SCIPadjustedVarLb(scip, cand, candbrpoint) ) deltaplus = 0.0; else deltaplus = SCIPadjustedVarLb(scip, cand, candbrpoint) - SCIPgetSolVal(scip, NULL, cand); break; case 'd': if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) ) deltaminus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaminus = SCIPadjustedVarUb(scip, cand, candbrpoint) - SCIPvarGetLbLocal(cand); if( SCIPisInfinity(scip, SCIPvarGetUbLocal(cand)) ) deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaplus = SCIPvarGetUbLocal(cand) - SCIPadjustedVarLb(scip, cand, candbrpoint); break; case 's': if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) ) deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaplus = SCIPadjustedVarUb(scip, cand, candbrpoint) - SCIPvarGetLbLocal(cand); if( SCIPisInfinity(scip, SCIPvarGetUbLocal(cand)) ) deltaminus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); else deltaminus = SCIPvarGetUbLocal(cand) - SCIPadjustedVarLb(scip, cand, candbrpoint); break; case 'v': deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum); deltaminus = deltaplus; break; default : SCIPerrorMessage("branching strategy %c unknown\n", strategy); SCIPABORT(); return SCIP_INVALIDDATA; /*lint !e527*/ } if( SCIPisInfinity(scip, deltaminus) || SCIPisInfinity(scip, deltaplus) ) { branchscore = SCIPinfinity(scip); } else { pscostdown = SCIPgetVarPseudocostVal(scip, cand, -deltaminus); pscostup = SCIPgetVarPseudocostVal(scip, cand, deltaplus); branchscore = SCIPgetBranchScore(scip, cand, pscostdown, pscostup); assert(!SCIPisNegative(scip, branchscore)); } SCIPdebugMessage("branching score variable <%s>[%g,%g] = %g; wscore = %g; type=%d bestbrscore=%g\n", SCIPvarGetName(cand), SCIPvarGetLbLocal(cand), SCIPvarGetUbLocal(cand), branchscore, WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum), SCIPvarGetType(cand), *bestscore); if( SCIPisInfinity(scip, branchscore) ) branchscore = 0.9*SCIPinfinity(scip); if( SCIPisSumGT(scip, branchscore, *bestscore) ) { (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } else if( SCIPisSumEQ(scip, branchscore, *bestscore) && !(SCIPisInfinity(scip, -SCIPvarGetLbLocal(*bestvar)) && SCIPisInfinity(scip, SCIPvarGetUbLocal(*bestvar))) ) { /* if best candidate so far is not unbounded to both sides, maybe take new candidate */ if( (SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(cand))) && (SCIPisInfinity(scip, -SCIPvarGetLbLocal(*bestvar)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(*bestvar))) ) { /* if both variables are unbounded but one of them is bounded on one side, take the one with the larger bound on this side (hope that this avoids branching on always the same variable) */ if( SCIPvarGetUbLocal(cand) > SCIPvarGetUbLocal(*bestvar) || SCIPvarGetLbLocal(cand) < SCIPvarGetLbLocal(*bestvar) ) { (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } } else if( SCIPvarGetType(*bestvar) == SCIPvarGetType(cand) ) { /* if both have the same type, take the one with larger diameter */ if( SCIPvarGetUbLocal(*bestvar) - SCIPvarGetLbLocal(*bestvar) < SCIPvarGetUbLocal(cand) - SCIPvarGetLbLocal(cand) ) { (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } } else if( SCIPvarGetType(*bestvar) > SCIPvarGetType(cand) ) { /* take the one with better type ("more discrete") */ (*bestscore) = branchscore; (*bestvar) = cand; (*bestbrpoint) = candbrpoint; } } return SCIP_OKAY; }
/** searches and adds integral objective cuts that separate the given primal solution */ static SCIP_RETCODE separateCuts( SCIP* scip, /**< SCIP data structure */ SCIP_SEPA* sepa, /**< the intobj separator */ SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */ SCIP_RESULT* result /**< pointer to store the result */ ) { SCIP_SEPADATA* sepadata; SCIP_Real objval; SCIP_Real intbound; SCIP_Bool infeasible; SCIP_Bool tightened; assert(result != NULL); assert(*result == SCIP_DIDNOTRUN); /* if the objective value may be fractional, we cannot do anything */ if( !SCIPisObjIntegral(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* if the current objective value is integral, there is no integral objective value cut */ if( sol == NULL ) objval = SCIPretransformObj(scip, SCIPgetLPObjval(scip)); else objval = SCIPgetSolOrigObj(scip, sol); if( SCIPisFeasIntegral(scip, objval) ) return SCIP_OKAY; sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); /* the objective value is fractional: create the objective value inequality, if not yet existing */ SCIP_CALL( createObjRow(scip, sepa, sepadata) ); /* adjust the bounds of the objective value variable */ if( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ) { intbound = SCIPceil(scip, objval) - sepadata->setoff; SCIP_CALL( SCIPtightenVarLb(scip, sepadata->objvar, intbound, FALSE, &infeasible, &tightened) ); SCIPdebugMessage("new objective variable lower bound: <%s>[%g,%g]\n", SCIPvarGetName(sepadata->objvar), SCIPvarGetLbLocal(sepadata->objvar), SCIPvarGetUbLocal(sepadata->objvar)); } else { intbound = SCIPfloor(scip, objval) - sepadata->setoff; SCIP_CALL( SCIPtightenVarUb(scip, sepadata->objvar, intbound, FALSE, &infeasible, &tightened) ); SCIPdebugMessage("new objective variable upper bound: <%s>[%g,%g]\n", SCIPvarGetName(sepadata->objvar), SCIPvarGetLbLocal(sepadata->objvar), SCIPvarGetUbLocal(sepadata->objvar)); } /* add the objective value inequality as a cut to the LP */ if( infeasible ) *result = SCIP_CUTOFF; else { if( !SCIProwIsInLP(sepadata->objrow) ) { SCIP_CALL( SCIPaddCut(scip, sol, sepadata->objrow, FALSE, &infeasible) ); } if ( infeasible ) *result = SCIP_CUTOFF; else if ( tightened ) *result = SCIP_REDUCEDDOM; else *result = SCIP_SEPARATED; } return SCIP_OKAY; }
/** selects the branching variable from given candidate array */ static SCIP_RETCODE selectBranchVar( SCIP* scip, /**< SCIP data structure */ SCIP_BRANCHRULE* branchrule, /**< branching rule */ SCIP_VAR** cands, /**< array of branching candidates */ SCIP_Real* candssol, /**< array of candidate solution values */ SCIP_Real* candsscore, /**< array of candidate scores */ int ncands, /**< the number of candidates */ SCIP_VAR** brvar, /**< pointer to store the selected branching candidate or NULL if none */ SCIP_Real* brpoint /**< pointer to store branching point of selected branching variable */ ) { /*lint --e{850}*/ SCIP_BRANCHRULEDATA* branchruledata; SCIP_VAR* cand; SCIP_Real candsol; SCIP_Real bestbranchscore; SCIP_Real scoremin; SCIP_Real scoresum; SCIP_Real scoremax; SCIP_VAR** candssorted; int* candsorigidx; int i; int j; assert(brvar != NULL); assert(brpoint != NULL); (*brvar) = NULL; (*brpoint) = SCIP_INVALID; if( ncands == 0 ) return SCIP_OKAY; branchruledata = SCIPbranchruleGetData(branchrule); assert(branchruledata != NULL); /* sort branching candidates (in a copy), such that same variables are on consecutive positions */ SCIP_CALL( SCIPduplicateBufferArray(scip, &candssorted, cands, ncands) ); SCIP_CALL( SCIPallocBufferArray(scip, &candsorigidx, ncands) ); for( i = 0; i < ncands; ++i ) candsorigidx[i] = i; SCIPsortPtrInt((void**)candssorted, candsorigidx, SCIPvarComp, ncands); bestbranchscore = -1.0; for( i = 0; i < ncands; ++i ) { cand = candssorted[i]; /* there should be no fixed branching candidates */ assert(!SCIPisEQ(scip, SCIPvarGetLbLocal(cand), SCIPvarGetUbLocal(cand))); /* compute min, sum, and max of all registered scores for this variables * set candsol to a valid value, if someone registered one */ scoremin = candsscore[candsorigidx[i]]; scoresum = scoremin; scoremax = scoremin; candsol = candssol[candsorigidx[i]]; for( j = i+1 ; j < ncands && SCIPvarCompare(candssorted[j], cand) == 0; ++j ) { assert(candsscore[candsorigidx[j]] >= 0.0); scoresum += candsscore[candsorigidx[j]]; if( candsscore[candsorigidx[j]] < scoremin ) scoremin = candsscore[candsorigidx[j]]; else if( candsscore[candsorigidx[j]] > scoremax ) scoremax = candsscore[candsorigidx[j]]; /* @todo if there are two valid externcandssol available for the same variable, should we take the one closer to the middle of the domain? */ if( SCIPisInfinity(scip, REALABS(candsol)) ) candsol = candssol[candsorigidx[j]]; } /* set i to last occurrence of cand in candssorted (instead of first one as before), so in next round we look at another variable */ i = j-1; assert(candssorted[i] == cand); /* check if new candidate is better than previous candidate (if any) */ SCIP_CALL( updateBestCandidate(scip, branchruledata, brvar, brpoint, &bestbranchscore, cand, scoremin, scoremax, scoresum, candsol) ); } /* there were candidates, but no variable was selected; this can only happen if the branching points are huge values * for all variables on which we cannot branch * @todo delay the node? */ if( (*brvar) == NULL ) { SCIPerrorMessage("no branching could be created: all external candidates have huge bounds\n"); SCIPABORT(); return SCIP_BRANCHERROR; /*lint !e527*/ } /* free buffer arrays */ SCIPfreeBufferArray(scip, &candssorted); SCIPfreeBufferArray(scip, &candsorigidx); return SCIP_OKAY; }
/** branching execution method for external candidates */ static SCIP_DECL_BRANCHEXECEXT(branchExecextPscost) { /*lint --e{715}*/ SCIP_BRANCHRULEDATA* branchruledata; SCIP_VAR** externcands; SCIP_Real* externcandssol; SCIP_Real* externcandsscore; int nprioexterncands; SCIP_VAR* brvar; SCIP_Real brpoint; int nchildren; assert(branchrule != NULL); assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); assert(scip != NULL); assert(result != NULL); branchruledata = SCIPbranchruleGetData(branchrule); assert(branchruledata != NULL); SCIPdebugMessage("Execext method of pscost branching\n"); /* get branching candidates */ SCIP_CALL( SCIPgetExternBranchCands(scip, &externcands, &externcandssol, &externcandsscore, NULL, &nprioexterncands, NULL, NULL, NULL) ); assert(nprioexterncands > 0); /* get current update strategy for pseudo costs, if our multiplier rule is 'u' */ if( branchruledata->strategy == 'u' ) { SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &branchruledata->updatestrategy) ); } /* select branching variable */ SCIP_CALL( selectBranchVar(scip, branchrule, externcands, externcandssol, externcandsscore, nprioexterncands, &brvar, &brpoint) ); if( brvar == NULL ) { SCIPerrorMessage("branchExecextPscost failed to select a branching variable from %d candidates\n", nprioexterncands); *result = SCIP_DIDNOTRUN; return SCIP_OKAY; } assert(SCIPvarIsActive(SCIPvarGetProbvar(brvar))); SCIPdebugMessage("branching on variable <%s>: new intervals: [%g, %g] and [%g, %g]\n", SCIPvarGetName(brvar), SCIPvarGetLbLocal(brvar), SCIPadjustedVarUb(scip, brvar, brpoint), SCIPadjustedVarLb(scip, brvar, brpoint), SCIPvarGetUbLocal(brvar)); if( branchruledata->nchildren > 2 && SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) <= branchruledata->narymaxdepth ) { /* do n-ary branching */ SCIP_Real minwidth; minwidth = 0.0; if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(brvar)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(brvar)) ) minwidth = branchruledata->naryminwidth * (SCIPvarGetUbGlobal(brvar) - SCIPvarGetLbGlobal(brvar)); SCIP_CALL( SCIPbranchVarValNary(scip, brvar, brpoint, branchruledata->nchildren, minwidth, branchruledata->narywidthfactor, &nchildren) ); } else { /* do binary branching */ SCIP_CALL( SCIPbranchVarValNary(scip, brvar, brpoint, 2, 0.0, 1.0, &nchildren) ); } if( nchildren > 1 ) { *result = SCIP_BRANCHED; } else { /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */ assert(SCIPisEQ(scip, SCIPvarGetLbLocal(brvar), SCIPvarGetUbLocal(brvar))); *result = SCIP_REDUCEDDOM; } return SCIP_OKAY; }
/** propagate the given binary variable/column using the root reduced cost stored in the SCIP internal data structers * and check if the implictions can be useful. Deppending on that implictions are used or not used during the search to * strength the reduced costs. */ static SCIP_RETCODE propagateRootRedcostBinvar( SCIP* scip, /**< SCIP data structure */ SCIP_PROPDATA* propdata, /**< propagator data structure */ SCIP_VAR* var, /**< variable to use for propagation */ SCIP_COL* col, /**< LP column of the variable */ SCIP_Real cutoffbound, /**< the current cutoff bound */ int* nchgbds /**< pointer to count the number of bound changes */ ) { SCIP_Real rootredcost; SCIP_Real rootsol; SCIP_Real rootlpobjval; assert(SCIPgetDepth(scip) == 0); /* skip binary variable if it is locally fixed */ if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 ) return SCIP_OKAY; rootredcost = SCIPvarGetBestRootRedcost(var); rootsol = SCIPvarGetBestRootSol(var); rootlpobjval = SCIPvarGetBestRootLPObjval(var); if( SCIPisFeasZero(scip, rootredcost) ) return SCIP_OKAY; assert(rootlpobjval != SCIP_INVALID); /*lint !e777*/ if( rootsol > 0.5 ) { assert(!SCIPisFeasPositive(scip, rootredcost)); /* update maximum reduced cost of a single binary variable */ propdata->maxredcost = MAX(propdata->maxredcost, -rootredcost); if( rootlpobjval - rootredcost > cutoffbound ) { SCIPdebugMessage("globally fix binary variable <%s> to 1.0\n", SCIPvarGetName(var)); SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) ); (*nchgbds)++; return SCIP_OKAY; } } else { assert(!SCIPisFeasNegative(scip, rootredcost)); /* update maximum reduced cost of a single binary variable */ propdata->maxredcost = MAX(propdata->maxredcost, rootredcost); if( rootlpobjval + rootredcost > cutoffbound ) { SCIPdebugMessage("globally fix binary variable <%s> to 0.0\n", SCIPvarGetName(var)); SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) ); (*nchgbds)++; return SCIP_OKAY; } } /* evaluate if the implications are useful; the implications are seen to be useful if they provide an increase for * the root reduced costs */ if( !propdata->usefullimplics ) { SCIP_Real lbredcost; SCIP_Real ubredcost; lbredcost = SCIPgetVarImplRedcost(scip, var, FALSE); assert(!SCIPisFeasPositive(scip, lbredcost)); ubredcost = SCIPgetVarImplRedcost(scip, var, TRUE); assert(!SCIPisFeasNegative(scip, ubredcost)); switch( SCIPcolGetBasisStatus(col) ) { case SCIP_BASESTAT_LOWER: ubredcost -= SCIPgetVarRedcost(scip, var); assert(!SCIPisFeasNegative(scip, ubredcost)); break; case SCIP_BASESTAT_UPPER: lbredcost -= SCIPgetVarRedcost(scip, var); assert(!SCIPisFeasPositive(scip, lbredcost)); break; case SCIP_BASESTAT_BASIC: case SCIP_BASESTAT_ZERO: default: break; } propdata->usefullimplics = (lbredcost < 0.0) || (ubredcost > 0.0); } return SCIP_OKAY; }
/** branching execution method for external candidates */ static SCIP_DECL_BRANCHEXECEXT(branchExecextLeastinf) { /*lint --e{715}*/ SCIP_VAR** externcands; SCIP_Real* externcandssol; SCIP_Real* externcandsscore; int nexterncands; SCIP_VAR* bestcand; SCIP_Real bestscore; SCIP_Real bestobj; SCIP_Real bestsol; SCIP_Real brpoint; int i; SCIP_NODE* downchild; SCIP_NODE* eqchild; SCIP_NODE* upchild; assert(branchrule != NULL); assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); assert(scip != NULL); assert(result != NULL); SCIPdebugMessage("Execext method of leastinf branching\n"); /* get branching candidates */ SCIP_CALL( SCIPgetExternBranchCands(scip, &externcands, &externcandssol, &externcandsscore, NULL, &nexterncands, NULL, NULL, NULL) ); assert(nexterncands > 0); /* search the least infeasible candidate */ bestscore = SCIPinfinity(scip); bestobj = 0.0; bestcand = NULL; bestsol = SCIP_INVALID; for( i = 0; i < nexterncands; ++i ) { updateBestCandidate(scip, &bestcand, &bestscore, &bestobj, &bestsol, externcands[i], externcandsscore[i], externcandssol[i]); } if( bestcand == NULL ) { SCIPerrorMessage("branchExecextLeastinf failed to select a branching variable from %d candidates\n", nexterncands); *result = SCIP_DIDNOTRUN; return SCIP_OKAY; } brpoint = SCIPgetBranchingPoint(scip, bestcand, bestsol); SCIPdebugMessage(" -> %d candidates, selected variable <%s> (infeas=%g, obj=%g, factor=%g, score=%g), branching point=%g\n", nexterncands, SCIPvarGetName(bestcand), bestsol, bestobj, SCIPvarGetBranchFactor(bestcand), bestscore, brpoint); /* perform the branching */ SCIP_CALL( SCIPbranchVarVal(scip, bestcand, brpoint, &downchild, &eqchild, &upchild) ); if( downchild != NULL || eqchild != NULL || upchild != NULL ) { *result = SCIP_BRANCHED; } else { /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */ assert(SCIPisEQ(scip, SCIPvarGetLbLocal(bestcand), SCIPvarGetUbLocal(bestcand))); *result = SCIP_REDUCEDDOM; } return SCIP_OKAY; }
/** propagate the given binary variable/column using the reduced cost */ static SCIP_RETCODE propagateRedcostBinvar( SCIP* scip, /**< SCIP data structure */ SCIP_PROPDATA* propdata, /**< propagator data structure */ SCIP_VAR* var, /**< variable to use for propagation */ SCIP_COL* col, /**< LP column of the variable */ SCIP_Real requiredredcost, /**< required reduset cost to be able to fix a binary variable */ int* nchgbds, /**< pointer to count the number of bound changes */ SCIP_Bool* cutoff /**< pointer to store if an cutoff was detected */ ) { SCIP_Real lbredcost; SCIP_Real ubredcost; SCIP_Real redcost; /* skip binary variable if it is locally fixed */ if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 ) return SCIP_OKAY; /* first use the redcost cost to fix the binary variable */ switch( SCIPcolGetBasisStatus(col) ) { case SCIP_BASESTAT_LOWER: redcost = SCIPgetVarRedcost(scip, var); assert(!SCIPisFeasNegative(scip, redcost)); if( redcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 0.0 (requiredredcost <%g>, redcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost); SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) ); (*nchgbds)++; return SCIP_OKAY; } break; case SCIP_BASESTAT_UPPER: redcost = SCIPgetVarRedcost(scip, var); assert(!SCIPisFeasPositive(scip, redcost)); if( -redcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 1.0 (requiredredcost <%g>, redcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost); SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) ); (*nchgbds)++; return SCIP_OKAY; } break; case SCIP_BASESTAT_BASIC: return SCIP_OKAY; case SCIP_BASESTAT_ZERO: assert(SCIPisFeasZero(scip, SCIPgetColRedcost(scip, col))); return SCIP_OKAY; default: SCIPerrorMessage("invalid basis state\n"); return SCIP_INVALIDDATA; } /* second, if the implications should be used and if the implications are seen to be promising used the implied * reduced costs to fix the binary variable */ if( propdata->useimplics && propdata->usefullimplics ) { /* collect implied reduced costs if the variable would be fixed to its lower bound */ lbredcost = SCIPgetVarImplRedcost(scip, var, FALSE); assert(!SCIPisFeasPositive(scip, lbredcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); /* collect implied reduced costs if the variable would be fixed to its upper bound */ ubredcost = SCIPgetVarImplRedcost(scip, var, TRUE); assert(!SCIPisFeasNegative(scip, ubredcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); if( -lbredcost > requiredredcost && ubredcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: cutoff (requiredredcost <%g>, lbredcost <%g>, ubredcost <%g>)\n", SCIPvarGetName(var), requiredredcost, lbredcost, ubredcost); (*cutoff) = TRUE; } else if( -lbredcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 1.0 (requiredredcost <%g>, redcost <%g>, lbredcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost, lbredcost); SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) ); (*nchgbds)++; } else if( ubredcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 0.0 (requiredredcost <%g>, redcost <%g>, ubredcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost, ubredcost); SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) ); (*nchgbds)++; } /* update maximum reduced cost of a single binary variable */ propdata->maxredcost = MAX3(propdata->maxredcost, -lbredcost, ubredcost); } return SCIP_OKAY; }
/** adds problem variables with negative reduced costs to pricing storage */ SCIP_RETCODE SCIPpricestoreAddProbVars( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory buffers */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< dynamic problem statistics */ SCIP_PROB* prob, /**< transformed problem after presolve */ 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; SCIP_COL* col; SCIP_Bool root; SCIP_Bool added; int v; int abortpricevars; int maxpricevars; int nfoundvars; assert(pricestore != NULL); assert(set != NULL); assert(stat != NULL); assert(prob != NULL); assert(lp != NULL); assert(lp->solved); assert(tree != NULL); assert(SCIPtreeHasCurrentNodeLP(tree)); assert(prob->nvars >= SCIPlpGetNCols(lp)); /* if all problem variables of status COLUMN are already in the LP, nothing has to be done */ if( prob->ncolvars == SCIPlpGetNCols(lp) ) return SCIP_OKAY; root = (SCIPtreeGetCurrentDepth(tree) == 0); maxpricevars = SCIPsetGetPriceMaxvars(set, root); assert(maxpricevars >= 1); abortpricevars = (int)(set->price_abortfac * maxpricevars); assert(abortpricevars >= maxpricevars); /**@todo test pricing: is abortpricevars a good idea? -> like strong branching, lookahead, ... */ pricestore->nprobpricings++; /* start timing */ SCIPclockStart(pricestore->probpricingtime, set); /* price already existing problem variables */ nfoundvars = 0; for( v = 0; v < prob->nvars && nfoundvars < abortpricevars; ++v ) { var = prob->vars[v]; if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ) { col = SCIPvarGetCol(var); assert(col != NULL); assert(col->var == var); assert(col->len >= 0); assert(col->lppos >= -1); assert(col->lpipos >= -1); assert(SCIPcolIsInLP(col) == (col->lpipos >= 0)); if( !SCIPcolIsInLP(col) ) { SCIPdebugMessage("price column variable <%s> in bounds [%g,%g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); /* add variable to pricing storage, if zero is not best bound w.r.t. objective function */ SCIP_CALL( addBoundViolated(pricestore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, &added) ); if( added ) { pricestore->nprobvarsfound++; nfoundvars++; } else if( SCIPcolGetNNonz(col) > 0 ) { SCIP_Real feasibility; /* a column not in LP that doesn't have zero in its bounds was added by bound checking above */ assert(!SCIPsetIsPositive(set, SCIPvarGetLbLocal(col->var))); assert(!SCIPsetIsNegative(set, SCIPvarGetUbLocal(col->var))); if( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_INFEASIBLE ) { /* The LP was proven infeasible, so we have an infeasibility proof by the dual Farkas multipliers y. * The valid inequality y^T A x >= y^T b is violated by all x, especially by the (for this * inequality most feasible solution) x' defined by * x'_i = ub_i, if y^T A_i > 0 * x'_i = lb_i, if y^T A_i <= 0. * Pricing in this case means to add variables i with positive Farkas value, i.e. y^T A_i x'_i > 0 */ feasibility = -SCIPcolGetFarkasValue(col, stat, lp); SCIPdebugMessage(" <%s> Farkas feasibility: %e\n", SCIPvarGetName(col->var), feasibility); } else { /* The dual LP is feasible, and we have a feasible dual solution. Pricing in this case means to * add variables with negative feasibility, that is * - positive reduced costs for variables with negative lower bound * - negative reduced costs for variables with positive upper bound */ feasibility = SCIPcolGetFeasibility(col, set, stat, lp); SCIPdebugMessage(" <%s> reduced cost feasibility: %e\n", SCIPvarGetName(col->var), feasibility); } /* the score is -feasibility / (#nonzeros in column + 1) to prefer short columns * we must add variables with negative feasibility, but in order to not get a too large lower bound * due to missing columns, we better also add variables, that have a very small feasibility */ if( !SCIPsetIsPositive(set, feasibility) ) { SCIP_CALL( SCIPpricestoreAddVar(pricestore, blkmem, set, eventqueue, lp, var, -feasibility / (col->len+1), root) ); pricestore->nprobvarsfound++; nfoundvars++; } } } } } /* stop timing */ SCIPclockStop(pricestore->probpricingtime, set); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecIntdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_VAR** pseudocands; SCIP_VAR** fixcands; SCIP_Real* fixcandscores; SCIP_Real searchubbound; SCIP_Real searchavgbound; SCIP_Real searchbound; SCIP_Real objval; SCIP_Bool lperror; SCIP_Bool cutoff; SCIP_Bool backtracked; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int nfixcands; int nbinfixcands; int depth; int maxdepth; int maxdivedepth; int divedepth; int nextcand; int c; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* do not call heuristic of node was already detected to be infeasible */ if( nodeinfeasible ) return SCIP_OKAY; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call heuristic, if the LP objective value is smaller than the cutoff bound */ if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) ) return SCIP_OKAY; /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* don't dive two times at the same node */ if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */ depth = SCIPgetDepth(scip); maxdepth = SCIPgetMaxDepth(scip); maxdepth = MAX(maxdepth, 100); if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth ) return SCIP_OKAY; /* calculate the maximal number of LP iterations until heuristic is aborted */ nlpiterations = SCIPgetNNodeLPIterations(scip); ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess; maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations); maxnlpiterations += heurdata->maxlpiterofs; /* don't try to dive, if we took too many LP iterations during diving */ if( heurdata->nlpiterations >= maxnlpiterations ) return SCIP_OKAY; /* allow at least a certain number of LP iterations in this dive */ maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER); /* get unfixed integer variables */ SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &nfixcands, NULL) ); /* don't try to dive, if there are no fractional variables */ if( nfixcands == 0 ) return SCIP_OKAY; /* calculate the objective search bound */ if( SCIPgetNSolsFound(scip) == 0 ) { if( heurdata->maxdiveubquotnosol > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquotnosol > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } else { if( heurdata->maxdiveubquot > 0.0 ) searchubbound = SCIPgetLowerbound(scip) + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip)); else searchubbound = SCIPinfinity(scip); if( heurdata->maxdiveavgquot > 0.0 ) searchavgbound = SCIPgetLowerbound(scip) + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip)); else searchavgbound = SCIPinfinity(scip); } searchbound = MIN(searchubbound, searchavgbound); if( SCIPisObjIntegral(scip) ) searchbound = SCIPceil(scip, searchbound); /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */ maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); maxdivedepth = MIN(maxdivedepth, maxdepth); maxdivedepth *= 10; *result = SCIP_DIDNOTFIND; /* start diving */ SCIP_CALL( SCIPstartProbing(scip) ); /* enables collection of variable statistics during probing */ SCIPenableVarHistory(scip); SCIPdebugMessage("(node %" SCIP_LONGINT_FORMAT ") executing intdiving heuristic: depth=%d, %d non-fixed, dualbound=%g, searchbound=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nfixcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound)); /* copy the pseudo candidates into own array, because we want to reorder them */ SCIP_CALL( SCIPduplicateBufferArray(scip, &fixcands, pseudocands, nfixcands) ); /* sort non-fixed variables by non-increasing inference score, but prefer binaries over integers in any case */ SCIP_CALL( SCIPallocBufferArray(scip, &fixcandscores, nfixcands) ); nbinfixcands = 0; for( c = 0; c < nfixcands; ++c ) { SCIP_VAR* var; SCIP_Real score; int colveclen; int left; int right; int i; assert(c >= nbinfixcands); var = fixcands[c]; assert(SCIPvarIsIntegral(var)); colveclen = (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ? SCIPcolGetNNonz(SCIPvarGetCol(var)) : 0); if( SCIPvarIsBinary(var) ) { score = 500.0 * SCIPvarGetNCliques(var, TRUE) + 100.0 * SCIPvarGetNImpls(var, TRUE) + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/100.0; /* shift the non-binary variables one slot to the right */ for( i = c; i > nbinfixcands; --i ) { fixcands[i] = fixcands[i-1]; fixcandscores[i] = fixcandscores[i-1]; } /* put the new candidate into the first nbinfixcands slot */ left = 0; right = nbinfixcands; nbinfixcands++; } else { score = 5.0 * (SCIPvarGetNCliques(var, FALSE) + SCIPvarGetNCliques(var, TRUE)) + SCIPvarGetNImpls(var, FALSE) + SCIPvarGetNImpls(var, TRUE) + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/10000.0; /* put the new candidate in the slots after the binary candidates */ left = nbinfixcands; right = c; } for( i = right; i > left && score > fixcandscores[i-1]; --i ) { fixcands[i] = fixcands[i-1]; fixcandscores[i] = fixcandscores[i-1]; } fixcands[i] = var; fixcandscores[i] = score; SCIPdebugMessage(" <%s>: ncliques=%d/%d, nimpls=%d/%d, inferencescore=%g, colveclen=%d -> score=%g\n", SCIPvarGetName(var), SCIPvarGetNCliques(var, FALSE), SCIPvarGetNCliques(var, TRUE), SCIPvarGetNImpls(var, FALSE), SCIPvarGetNImpls(var, TRUE), SCIPgetVarAvgInferenceScore(scip, var), colveclen, score); } SCIPfreeBufferArray(scip, &fixcandscores); /* get LP objective value */ lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; objval = SCIPgetLPObjval(scip); /* dive as long we are in the given objective, depth and iteration limits, but if possible, we dive at least with * the depth 10 */ lperror = FALSE; cutoff = FALSE; divedepth = 0; nextcand = 0; while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && (divedepth < 10 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound)) && !SCIPisStopped(scip) ) { SCIP_VAR* var; SCIP_Real bestsolval; SCIP_Real bestfixval; int bestcand; SCIP_Longint nnewlpiterations; SCIP_Longint nnewdomreds; /* open a new probing node if this will not exceed the maximal tree depth, otherwise stop here */ if( SCIPgetDepth(scip) < SCIPgetDepthLimit(scip) ) { SCIP_CALL( SCIPnewProbingNode(scip) ); divedepth++; } else break; nnewlpiterations = 0; nnewdomreds = 0; /* fix binary variable that is closest to 1 in the LP solution to 1; * if all binary variables are fixed, fix integer variable with least fractionality in LP solution */ bestcand = -1; bestsolval = -1.0; bestfixval = 1.0; /* look in the binary variables for fixing candidates */ for( c = nextcand; c < nbinfixcands; ++c ) { SCIP_Real solval; var = fixcands[c]; /* ignore already fixed variables */ if( var == NULL ) continue; if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 ) { fixcands[c] = NULL; continue; } /* get the LP solution value */ solval = SCIPvarGetLPSol(var); if( solval > bestsolval ) { bestcand = c; bestfixval = 1.0; bestsolval = solval; if( SCIPisGE(scip, bestsolval, 1.0) ) { /* we found an unfixed binary variable with LP solution value of 1.0 - there cannot be a better candidate */ break; } else if( SCIPisLE(scip, bestsolval, 0.0) ) { /* the variable is currently at 0.0 - this is the only situation where we want to fix it to 0.0 */ bestfixval = 0.0; } } } /* if all binary variables are fixed, look in the integer variables for a fixing candidate */ if( bestcand == -1 ) { SCIP_Real bestfrac; bestfrac = SCIP_INVALID; for( c = MAX(nextcand, nbinfixcands); c < nfixcands; ++c ) { SCIP_Real solval; SCIP_Real frac; var = fixcands[c]; /* ignore already fixed variables */ if( var == NULL ) continue; if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 ) { fixcands[c] = NULL; continue; } /* get the LP solution value */ solval = SCIPvarGetLPSol(var); frac = SCIPfrac(scip, solval); /* ignore integer variables that are currently integral */ if( SCIPisFeasFracIntegral(scip, frac) ) continue; if( frac < bestfrac ) { bestcand = c; bestsolval = solval; bestfrac = frac; bestfixval = SCIPfloor(scip, bestsolval + 0.5); if( SCIPisZero(scip, bestfrac) ) { /* we found an unfixed integer variable with integral LP solution value */ break; } } } } assert(-1 <= bestcand && bestcand < nfixcands); /* if there is no unfixed candidate left, we are done */ if( bestcand == -1 ) break; var = fixcands[bestcand]; assert(var != NULL); assert(SCIPvarIsIntegral(var)); assert(SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) > 0.5); assert(SCIPisGE(scip, bestfixval, SCIPvarGetLbLocal(var))); assert(SCIPisLE(scip, bestfixval, SCIPvarGetUbLocal(var))); backtracked = FALSE; do { /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have * occured or variable was fixed by propagation while backtracking => Abort diving! */ if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 ) { SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g], diving aborted \n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); cutoff = TRUE; break; } if( SCIPisFeasLT(scip, bestfixval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestfixval, SCIPvarGetUbLocal(var)) ) { SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval); assert(backtracked); break; } /* apply fixing of best candidate */ SCIPdebugMessage(" dive %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", %d unfixed: var <%s>, sol=%g, oldbounds=[%g,%g], fixed to %g\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPgetNPseudoBranchCands(scip), SCIPvarGetName(var), bestsolval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval); SCIP_CALL( SCIPfixVarProbing(scip, var, bestfixval) ); /* apply domain propagation */ SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &nnewdomreds) ); if( !cutoff ) { /* if the best candidate was just fixed to its LP value and no domain reduction was found, the LP solution * stays valid, and the LP does not need to be resolved */ if( nnewdomreds > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) ) { /* resolve the diving LP */ /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic. * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ #ifdef NDEBUG SCIP_RETCODE retstat; nlpiterations = SCIPgetNLPIterations(scip); retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff); if( retstat != SCIP_OKAY ) { SCIPwarningMessage(scip, "Error while solving LP in Intdiving heuristic; LP solve terminated with code <%d>\n",retstat); } #else nlpiterations = SCIPgetNLPIterations(scip); SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) ); #endif if( lperror ) break; /* update iteration count */ nnewlpiterations = SCIPgetNLPIterations(scip) - nlpiterations; heurdata->nlpiterations += nnewlpiterations; /* get LP solution status */ lpsolstat = SCIPgetLPSolstat(scip); assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE && (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip))))); } } /* perform backtracking if a cutoff was detected */ if( cutoff && !backtracked && heurdata->backtrack ) { SCIPdebugMessage(" *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip)); SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) ); /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */ assert(SCIPgetDepthLimit(scip) > SCIPgetDepth(scip)); SCIP_CALL( SCIPnewProbingNode(scip) ); bestfixval = SCIPvarIsBinary(var) ? 1.0 - bestfixval : (SCIPisGT(scip, bestsolval, bestfixval) && SCIPisFeasLE(scip, bestfixval + 1, SCIPvarGetUbLocal(var)) ? bestfixval + 1 : bestfixval - 1); backtracked = TRUE; } else backtracked = FALSE; } while( backtracked ); if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* get new objective value */ objval = SCIPgetLPObjval(scip); if( nnewlpiterations > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) ) { /* we must start again with the first candidate, since the LP solution changed */ nextcand = 0; /* create solution from diving LP and try to round it */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) ); if( success ) { SCIPdebugMessage("intdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } } else nextcand = bestcand+1; /* continue with the next candidate in the following loop */ } SCIPdebugMessage(" -> lpsolstat=%d, objval=%g/%g\n", lpsolstat, objval, searchbound); } /* free temporary memory */ SCIPfreeBufferArray(scip, &fixcands); /* end diving */ SCIP_CALL( SCIPendProbing(scip) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; SCIPdebugMessage("intdiving heuristic finished\n"); return SCIP_OKAY; }
/** propagate the given none binary variable/column using the reduced cost */ static SCIP_RETCODE propagateRedcostVar( SCIP* scip, /**< SCIP data structure */ SCIP_VAR* var, /**< variable to use for propagation */ SCIP_COL* col, /**< LP column of the variable */ SCIP_Real lpobjval, /**< objective value of the current LP */ SCIP_Real cutoffbound, /**< the current cutoff bound */ int* nchgbds /**< pointer to count the number of bound changes */ ) { SCIP_Real redcost; switch( SCIPcolGetBasisStatus(col) ) { case SCIP_BASESTAT_LOWER: redcost = SCIPgetColRedcost(scip, col); assert(!SCIPisFeasNegative(scip, redcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); if( SCIPisFeasPositive(scip, redcost) ) { SCIP_Real oldlb; SCIP_Real oldub; oldlb = SCIPvarGetLbLocal(var); oldub = SCIPvarGetUbLocal(var); assert(SCIPisEQ(scip, oldlb, SCIPcolGetLb(col))); assert(SCIPisEQ(scip, oldub, SCIPcolGetUb(col))); if( SCIPisFeasLT(scip, oldlb, oldub) ) { SCIP_Real newub; SCIP_Bool strengthen; /* calculate reduced cost based bound */ newub = (cutoffbound - lpobjval) / redcost + oldlb; /* check, if new bound is good enough: * - integer variables: take all possible strengthenings * - continuous variables: strengthening must cut part of the variable's dynamic range, and * at least 20% of the current domain */ if( SCIPvarIsIntegral(var) ) { newub = SCIPadjustedVarUb(scip, var, newub); strengthen = (newub < oldub - 0.5); } else strengthen = (newub < SCIPcolGetMaxPrimsol(col) && newub <= 0.2 * oldlb + 0.8 * oldub); if( strengthen ) { /* strengthen upper bound */ SCIPdebugMessage("redcost strengthening upper bound: <%s> [%g,%g] -> [%g,%g] (ub=%g, lb=%g, redcost=%g)\n", SCIPvarGetName(var), oldlb, oldub, oldlb, newub, cutoffbound, lpobjval, redcost); SCIP_CALL( SCIPchgVarUb(scip, var, newub) ); (*nchgbds)++; } } } break; case SCIP_BASESTAT_BASIC: break; case SCIP_BASESTAT_UPPER: redcost = SCIPgetColRedcost(scip, col); assert(!SCIPisFeasPositive(scip, redcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); if( SCIPisFeasNegative(scip, redcost) ) { SCIP_Real oldlb; SCIP_Real oldub; oldlb = SCIPvarGetLbLocal(var); oldub = SCIPvarGetUbLocal(var); assert(SCIPisEQ(scip, oldlb, SCIPcolGetLb(col))); assert(SCIPisEQ(scip, oldub, SCIPcolGetUb(col))); if( SCIPisFeasLT(scip, oldlb, oldub) ) { SCIP_Real newlb; SCIP_Bool strengthen; /* calculate reduced cost based bound */ newlb = (cutoffbound - lpobjval) / redcost + oldub; /* check, if new bound is good enough: * - integer variables: take all possible strengthenings * - continuous variables: strengthening must cut part of the variable's dynamic range, and * at least 20% of the current domain */ if( SCIPvarIsIntegral(var) ) { newlb = SCIPadjustedVarLb(scip, var, newlb); strengthen = (newlb > oldlb + 0.5); } else strengthen = (newlb > SCIPcolGetMinPrimsol(col) && newlb >= 0.8 * oldlb + 0.2 * oldub); /* check, if new bound is good enough: at least 20% strengthening for continuous variables */ if( strengthen ) { /* strengthen lower bound */ SCIPdebugMessage("redcost strengthening lower bound: <%s> [%g,%g] -> [%g,%g] (ub=%g, lb=%g, redcost=%g)\n", SCIPvarGetName(var), oldlb, oldub, newlb, oldub, cutoffbound, lpobjval, redcost); SCIP_CALL( SCIPchgVarLb(scip, var, newlb) ); (*nchgbds)++; } } } break; case SCIP_BASESTAT_ZERO: assert(SCIPisFeasZero(scip, SCIPgetColRedcost(scip, col))); break; default: SCIPerrorMessage("invalid basis state\n"); return SCIP_INVALIDDATA; } return SCIP_OKAY; }
/** transforms given solution of the master problem into solution of the original problem * @todo think about types of epsilons used in this method */ SCIP_RETCODE GCGrelaxTransformMastersolToOrigsol( SCIP* scip, /**< SCIP data structure */ SCIP_SOL* mastersol, /**< solution of the master problem, or NULL for current LP solution */ SCIP_SOL** origsol /**< pointer to store the new created original problem's solution */ ) { SCIP* masterprob; int npricingprobs; int* blocknrs; SCIP_Real* blockvalue; SCIP_Real increaseval; SCIP_VAR** mastervars; SCIP_Real* mastervals; int nmastervars; SCIP_VAR** vars; int nvars; SCIP_Real feastol; int i; int j; assert(scip != NULL); assert(origsol != NULL); masterprob = GCGrelaxGetMasterprob(scip); npricingprobs = GCGrelaxGetNPricingprobs(scip); assert( !SCIPisInfinity(scip, SCIPgetSolOrigObj(masterprob, mastersol)) ); SCIP_CALL( SCIPcreateSol(scip, origsol, GCGrelaxGetProbingheur(scip)) ); SCIP_CALL( SCIPallocBufferArray(scip, &blockvalue, npricingprobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &blocknrs, npricingprobs) ); /* get variables of the master problem and their solution values */ SCIP_CALL( SCIPgetVarsData(masterprob, &mastervars, &nmastervars, NULL, NULL, NULL, NULL) ); assert(mastervars != NULL); assert(nmastervars >= 0); SCIP_CALL( SCIPallocBufferArray(scip, &mastervals, nmastervars) ); SCIP_CALL( SCIPgetSolVals(masterprob, mastersol, nmastervars, mastervars, mastervals) ); /* initialize the block values for the pricing problems */ for( i = 0; i < npricingprobs; i++ ) { blockvalue[i] = 0.0; blocknrs[i] = 0; } /* loop over all given master variables */ for( i = 0; i < nmastervars; i++ ) { SCIP_VAR** origvars; int norigvars; SCIP_Real* origvals; SCIP_Bool isray; int blocknr; origvars = GCGmasterVarGetOrigvars(mastervars[i]); norigvars = GCGmasterVarGetNOrigvars(mastervars[i]); origvals = GCGmasterVarGetOrigvals(mastervars[i]); blocknr = GCGvarGetBlock(mastervars[i]); isray = GCGmasterVarIsRay(mastervars[i]); assert(GCGvarIsMaster(mastervars[i])); assert(!SCIPisFeasNegative(scip, mastervals[i])); /** @todo handle infinite master solution values */ assert(!SCIPisInfinity(scip, mastervals[i])); /* first of all, handle variables representing rays */ if( isray ) { assert(blocknr >= 0); /* we also want to take into account variables representing rays, that have a small value (between normal and feas eps), * so we do no feas comparison here */ if( SCIPisPositive(scip, mastervals[i]) ) { /* loop over all original variables contained in the current master variable */ for( j = 0; j < norigvars; j++ ) { if( SCIPisZero(scip, origvals[j]) ) break; assert(!SCIPisZero(scip, origvals[j])); /* the original variable is a linking variable: just transfer the solution value of the direct copy (this is done later) */ if( GCGvarIsLinking(origvars[j]) ) continue; SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origvars[j]), origvals[j] * mastervals[i], SCIPvarGetName(mastervars[i])); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origvars[j], origvals[j] * mastervals[i]) ); } } mastervals[i] = 0.0; continue; } /* handle the variables with value >= 1 to get integral values in original solution */ while( SCIPisFeasGE(scip, mastervals[i], 1.0) ) { /* variable was directly transferred to the master problem (only in linking conss or linking variable) */ /** @todo this may be the wrong place for this case, handle it before the while loop * and remove the similar case in the next while loop */ if( blocknr == -1 ) { assert(norigvars == 1); assert(origvals[0] == 1.0); /* increase the corresponding value */ SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origvars[0]), origvals[0] * mastervals[i], SCIPvarGetName(mastervars[i])); SCIP_CALL( SCIPincSolVal(scip, *origsol, origvars[0], origvals[0] * mastervals[i]) ); mastervals[i] = 0.0; } else { assert(blocknr >= 0); /* loop over all original variables contained in the current master variable */ for( j = 0; j < norigvars; j++ ) { SCIP_VAR* pricingvar; int norigpricingvars; SCIP_VAR** origpricingvars; if( SCIPisZero(scip, origvals[j]) ) break; assert(!SCIPisZero(scip, origvals[j])); /* the original variable is a linking variable: just transfer the solution value of the direct copy (this is done above) */ if( GCGvarIsLinking(origvars[j]) ) continue; pricingvar = GCGoriginalVarGetPricingVar(origvars[j]); assert(GCGvarIsPricing(pricingvar)); norigpricingvars = GCGpricingVarGetNOrigvars(pricingvar); origpricingvars = GCGpricingVarGetOrigvars(pricingvar); /* just in case a variable has a value higher than the number of blocks, it represents */ if( norigpricingvars <= blocknrs[blocknr] ) { SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[norigpricingvars-1]), mastervals[i] * origvals[j], SCIPvarGetName(mastervars[i])); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[norigpricingvars-1], mastervals[i] * origvals[j]) ); mastervals[i] = 1.0; } /* this should be default */ else { SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[blocknrs[blocknr]]), origvals[j], SCIPvarGetName(mastervars[i]) ); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[blocknrs[blocknr]], origvals[j]) ); } } mastervals[i] = mastervals[i] - 1.0; blocknrs[blocknr]++; } } } /* loop over all given master variables */ for( i = 0; i < nmastervars; i++ ) { SCIP_VAR** origvars; int norigvars; SCIP_Real* origvals; int blocknr; origvars = GCGmasterVarGetOrigvars(mastervars[i]); norigvars = GCGmasterVarGetNOrigvars(mastervars[i]); origvals = GCGmasterVarGetOrigvals(mastervars[i]); blocknr = GCGvarGetBlock(mastervars[i]); if( SCIPisFeasZero(scip, mastervals[i]) ) { continue; } assert(SCIPisFeasGE(scip, mastervals[i], 0.0) && SCIPisFeasLT(scip, mastervals[i], 1.0)); while( SCIPisFeasPositive(scip, mastervals[i]) ) { assert(GCGvarIsMaster(mastervars[i])); assert(!GCGmasterVarIsRay(mastervars[i])); if( blocknr == -1 ) { assert(norigvars == 1); assert(origvals[0] == 1.0); SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origvars[0]), origvals[0] * mastervals[i], SCIPvarGetName(mastervars[i]) ); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origvars[0], origvals[0] * mastervals[i]) ); mastervals[i] = 0.0; } else { increaseval = MIN(mastervals[i], 1.0 - blockvalue[blocknr]); /* loop over all original variables contained in the current master variable */ for( j = 0; j < norigvars; j++ ) { SCIP_VAR* pricingvar; int norigpricingvars; SCIP_VAR** origpricingvars; if( SCIPisZero(scip, origvals[j]) ) continue; /* the original variable is a linking variable: just transfer the solution value of the direct copy (this is done above) */ if( GCGvarIsLinking(origvars[j]) ) continue; pricingvar = GCGoriginalVarGetPricingVar(origvars[j]); assert(GCGvarIsPricing(pricingvar)); norigpricingvars = GCGpricingVarGetNOrigvars(pricingvar); origpricingvars = GCGpricingVarGetOrigvars(pricingvar); if( norigpricingvars <= blocknrs[blocknr] ) { increaseval = mastervals[i]; SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[norigpricingvars-1]), origvals[j] * increaseval, SCIPvarGetName(mastervars[i]) ); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[norigpricingvars-1], origvals[j] * increaseval) ); } else { /* increase the corresponding value */ SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[blocknrs[blocknr]]), origvals[j] * increaseval, SCIPvarGetName(mastervars[i]) ); SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[blocknrs[blocknr]], origvals[j] * increaseval) ); } } mastervals[i] = mastervals[i] - increaseval; if( SCIPisFeasZero(scip, mastervals[i]) ) { mastervals[i] = 0.0; } blockvalue[blocknr] += increaseval; /* if the value assigned to the block is equal to 1, this block is full and we take the next block */ if( SCIPisFeasGE(scip, blockvalue[blocknr], 1.0) ) { blockvalue[blocknr] = 0.0; blocknrs[blocknr]++; } } } } SCIPfreeBufferArray(scip, &mastervals); SCIPfreeBufferArray(scip, &blocknrs); SCIPfreeBufferArray(scip, &blockvalue); /* if the solution violates one of its bounds by more than feastol * and less than 10*feastol, round it and print a warning */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPgetRealParam(scip, "numerics/feastol", &feastol) ); for( i = 0; i < nvars; ++i ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, *origsol, vars[i]); lb = SCIPvarGetLbLocal(vars[i]); ub = SCIPvarGetUbLocal(vars[i]); if( SCIPisFeasGT(scip, solval, ub) && EPSEQ(solval, ub, 10 * feastol) ) { SCIP_CALL( SCIPsetSolVal(scip, *origsol, vars[i], ub) ); SCIPwarningMessage(scip, "Variable %s rounded from %g to %g in relaxation solution\n", SCIPvarGetName(vars[i]), solval, ub); } else if( SCIPisFeasLT(scip, solval, lb) && EPSEQ(solval, lb, 10 * feastol) ) { SCIP_CALL( SCIPsetSolVal(scip, *origsol, vars[i], lb) ); SCIPwarningMessage(scip, "Variable %s rounded from %g to %g in relaxation solution\n", SCIPvarGetName(vars[i]), solval, lb); } } return SCIP_OKAY; }