/** 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 */ }
/** output method of display column to output file stream 'file' */ static SCIP_DECL_DISPOUTPUT(SCIPdispOutputCutoffbound) { /*lint --e{715}*/ SCIP_Real cutoffbound; assert(disp != NULL); assert(strcmp(SCIPdispGetName(disp), DISP_NAME_CUTOFFBOUND) == 0); assert(scip != NULL); cutoffbound = SCIPgetCutoffbound(GCGpricerGetOrigprob(scip)); if( SCIPisInfinity(scip, REALABS(cutoffbound)) ) SCIPinfoMessage(scip, file, " -- "); else SCIPinfoMessage(scip, file, "%13.6e ", SCIPretransformObj(GCGpricerGetOrigprob(scip), cutoffbound)); return SCIP_OKAY; }
/** output method of display column to output file stream 'file' */ static SCIP_DECL_DISPOUTPUT(SCIPdispOutputPrimalbound) { /*lint --e{715}*/ SCIP_Real primalbound; assert(disp != NULL); assert(strcmp(SCIPdispGetName(disp), DISP_NAME_PRIMALBOUND) == 0); assert(scip != NULL); primalbound = SCIPgetPrimalbound(scip); if( SCIPisInfinity(scip, REALABS(primalbound)) ) SCIPinfoMessage(scip, file, " -- "); else SCIPinfoMessage(scip, file, "%13.6e%c", SCIPretransformObj(GCGpricerGetOrigprob(scip), primalbound), SCIPisPrimalboundSol(scip) ? ' ' : '*'); return SCIP_OKAY; }
/** outputs a new global upper bound to the visualization output file */ void SCIPvisualUpperbound( SCIP_VISUAL* visual, /**< visualization information */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_Real upperbound /**< new upper bound */ ) { assert( visual != NULL ); /* check, if VBC output should be created */ if( visual->vbcfile == NULL ) return; /* determine external upper bound */ if ( set->visual_objextern ) upperbound = SCIPretransformObj(set->scip, upperbound); printTime(visual, stat, TRUE); SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "U %f\n", upperbound); /* do nothing for BAK */ }
/** 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; }
/** 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; }
/** 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; }
/** changes the color of the node to the color of cutoff nodes */ void SCIPvisualCutoffNode( SCIP_VISUAL* visual, /**< visualization information */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node, /**< node, that was cut off */ SCIP_Bool infeasible /**< whether the node is infeasible (otherwise exceeded the cutoff bound) */ ) { 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_CUTOFF); } if ( visual->bakfile != NULL ) { size_t parentnodenum; char t = 'M'; /* determine branching type */ if ( branchvar != NULL ) t = (branchtype == SCIP_BOUNDTYPE_LOWER ? 'R' : 'L'); /* get nodenum of parent node from hash map */ parentnodenum = (node->parent != NULL ? (size_t)SCIPhashmapGetImage(visual->nodenum, node->parent) : 0); assert(node->parent == NULL || parentnodenum > 0); printTime(visual, stat, FALSE); if ( infeasible ) SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "infeasible %d %d %c\n", (int)nodenum, (int)parentnodenum, t); else SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "fathomed %d %d %c\n", (int)nodenum, (int)parentnodenum, t); } }
/** updates a node entry in the visualization output file */ SCIP_RETCODE SCIPvisualUpdateChild( SCIP_VISUAL* visual, /**< visualization information */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node /**< new node, that was created */ ) { 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 SCIP_OKAY; /* visualization is disabled on probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return SCIP_OKAY; /* 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\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar), branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", branchbound, lowerbound); } else { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), lowerbound); } } if ( visual->bakfile != NULL ) { size_t parentnodenum; SCIP_Real* lpcandsfrac; SCIP_Real sum = 0.0; int nlpcands = 0; char t = 'M'; const char* nodeinfo; int j; /* determine branching type */ if ( branchvar != NULL ) t = (branchtype == SCIP_BOUNDTYPE_LOWER ? 'R' : 'L'); /* get nodenum of parent node from hash map */ parentnodenum = (node->parent != NULL ? (size_t)SCIPhashmapGetImage(visual->nodenum, node->parent) : 0); assert(node->parent == NULL || parentnodenum > 0); /* update info depending on the node type */ switch( SCIPnodeGetType(node) ) { case SCIP_NODETYPE_CHILD: /* the child is a new candidate */ nodeinfo = "candidate"; break; case SCIP_NODETYPE_FOCUSNODE: /* the focus node is updated to a branch node */ nodeinfo = "branched"; /* calculate infeasibility information */ SCIP_CALL( SCIPgetLPBranchCands(set->scip, NULL, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) ); for (j = 0; j < nlpcands; ++j) sum += lpcandsfrac[j]; break; default: SCIPerrorMessage("Error: Unexpected node type <%d> in Update Child Method", SCIPnodeGetType(node)); return SCIP_INVALIDDATA; } /*lint !e788*/ /* append new status line with updated node information to the bakfile */ printTime(visual, stat, FALSE); SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "%s %d %d %c %f %f %d\n", nodeinfo, (int)nodenum, (int)parentnodenum, t, lowerbound, sum, nlpcands); } return SCIP_OKAY; }
/** creates a new node entry in the visualization output file */ SCIP_RETCODE SCIPvisualNewChild( SCIP_VISUAL* visual, /**< visualization information */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_NODE* node /**< new node, that was created */ ) { SCIP_VAR* branchvar; SCIP_BOUNDTYPE branchtype; SCIP_Real branchbound; SCIP_Real lowerbound; size_t parentnodenum; size_t nodenum; assert( visual != NULL ); assert( stat != NULL ); assert( node != NULL ); /* visualization is disabled on probing nodes */ if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE ) return SCIP_OKAY; /* check whether output should be created */ if ( visual->vbcfile == NULL && visual->bakfile == NULL ) 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 visualization file\n"); return SCIP_INVALIDDATA; } nodenum = (size_t)stat->ncreatednodesrun; assert(nodenum > 0); SCIP_CALL( SCIPhashmapInsert(visual->nodenum, node, (void*)nodenum) ); /* get nodenum of parent node from hash map */ parentnodenum = (node->parent != NULL ? (size_t)SCIPhashmapGetImage(visual->nodenum, node->parent) : 0); assert(node->parent == NULL || parentnodenum > 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); SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "N %d %d %d\n", (int)parentnodenum, (int)nodenum, SCIP_VBCCOLOR_UNSOLVED); 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\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar), branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", branchbound, lowerbound); } else { SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\n", (int)nodenum, (int)nodenum, node, SCIPnodeGetDepth(node), lowerbound); } } /* For BAK, not all available information is available here. Use SCIPvisualUpdateChild() instead */ return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecShifting) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_ROW** lprows; SCIP_Real* activities; SCIP_ROW** violrows; SCIP_Real* nincreases; SCIP_Real* ndecreases; int* violrowpos; int* nfracsinrow; SCIP_Real increaseweight; SCIP_Real obj; SCIP_Real bestshiftval; SCIP_Real minobj; int nlpcands; int nlprows; int nvars; int nfrac; int nviolrows; int nprevviolrows; int minnviolrows; int nnonimprovingshifts; int c; int r; SCIP_Longint nlps; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nnodes; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* 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; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* don't call heuristic, if we have already processed the current LP solution */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* don't call heuristic, if it was not successful enough in the past */ ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur); nnodes = SCIPgetNNodes(scip); if( nnodes % ((ncalls/100)/(nsolsfound+1)+1) != 0 ) return SCIP_OKAY; /* get fractional variables, that should be integral */ /* todo check if heuristic should include implicit integer variables for its calculations */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) ); nfrac = nlpcands; /* only call heuristic, if LP solution is fractional */ if( nfrac == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* get LP rows */ SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) ); SCIPdebugMessage("executing shifting heuristic: %d LP rows, %d fractionals\n", nlprows, nfrac); /* get memory for activities, violated rows, and row violation positions */ nvars = SCIPgetNVars(scip); SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &nfracsinrow, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &nincreases, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &ndecreases, nvars) ); BMSclearMemoryArray(nfracsinrow, nlprows); BMSclearMemoryArray(nincreases, nvars); BMSclearMemoryArray(ndecreases, nvars); /* get the activities for all globally valid rows; * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated */ nviolrows = 0; for( r = 0; r < nlprows; ++r ) { SCIP_ROW* row; row = lprows[r]; assert(SCIProwGetLPPos(row) == r); if( !SCIProwIsLocal(row) ) { activities[r] = SCIPgetRowActivity(scip, row); if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) ) { violrows[nviolrows] = row; violrowpos[r] = nviolrows; nviolrows++; } else violrowpos[r] = -1; } } /* calc the current number of fractional variables in rows */ for( c = 0; c < nlpcands; ++c ) addFracCounter(nfracsinrow, nlprows, lpcands[c], +1); /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* calculate the minimal objective value possible after rounding fractional variables */ minobj = SCIPgetSolTransObj(scip, sol); assert(minobj < SCIPgetCutoffbound(scip)); for( c = 0; c < nlpcands; ++c ) { obj = SCIPvarGetObj(lpcands[c]); bestshiftval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]); minobj += obj * (bestshiftval - lpcandssol[c]); } /* try to shift remaining variables in order to become/stay feasible */ nnonimprovingshifts = 0; minnviolrows = INT_MAX; increaseweight = 1.0; while( (nfrac > 0 || nviolrows > 0) && nnonimprovingshifts < MAXSHIFTINGS ) { SCIP_VAR* shiftvar; SCIP_Real oldsolval; SCIP_Real newsolval; SCIP_Bool oldsolvalisfrac; int probindex; SCIPdebugMessage("shifting heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g), cutoff=%g\n", nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj), SCIPretransformObj(scip, SCIPgetCutoffbound(scip))); nprevviolrows = nviolrows; /* choose next variable to process: * - if a violated row exists, shift a variable decreasing the violation, that has least impact on other rows * - otherwise, shift a variable, that has strongest devastating impact on rows in opposite direction */ shiftvar = NULL; oldsolval = 0.0; newsolval = 0.0; if( nviolrows > 0 && (nfrac == 0 || nnonimprovingshifts < MAXSHIFTINGS-1) ) { SCIP_ROW* row; int rowidx; int rowpos; int direction; rowidx = -1; rowpos = -1; row = NULL; if( nfrac > 0 ) { for( rowidx = nviolrows-1; rowidx >= 0; --rowidx ) { row = violrows[rowidx]; rowpos = SCIProwGetLPPos(row); assert(violrowpos[rowpos] == rowidx); if( nfracsinrow[rowpos] > 0 ) break; } } if( rowidx == -1 ) { rowidx = SCIPgetRandomInt(0, nviolrows-1, &heurdata->randseed); row = violrows[rowidx]; rowpos = SCIProwGetLPPos(row); assert(0 <= rowpos && rowpos < nlprows); assert(violrowpos[rowpos] == rowidx); assert(nfracsinrow[rowpos] == 0); } assert(violrowpos[rowpos] == rowidx); SCIPdebugMessage("shifting heuristic: try to fix violated row <%s>: %g <= %g <= %g\n", SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row)); SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) ); /* get direction in which activity must be shifted */ assert(SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row))); direction = SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) ? +1 : -1; /* search a variable that can shift the activity in the necessary direction */ SCIP_CALL( selectShifting(scip, sol, row, activities[rowpos], direction, nincreases, ndecreases, increaseweight, &shiftvar, &oldsolval, &newsolval) ); } if( shiftvar == NULL && nfrac > 0 ) { SCIPdebugMessage("shifting heuristic: search rounding variable and try to stay feasible\n"); SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &shiftvar, &oldsolval, &newsolval) ); } /* check, whether shifting was possible */ if( shiftvar == NULL || SCIPisEQ(scip, oldsolval, newsolval) ) { SCIPdebugMessage("shifting heuristic: -> didn't find a shifting variable\n"); break; } SCIPdebugMessage("shifting heuristic: -> shift var <%s>[%g,%g], type=%d, oldval=%g, newval=%g, obj=%g\n", SCIPvarGetName(shiftvar), SCIPvarGetLbGlobal(shiftvar), SCIPvarGetUbGlobal(shiftvar), SCIPvarGetType(shiftvar), oldsolval, newsolval, SCIPvarGetObj(shiftvar)); /* update row activities of globally valid rows */ SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows, shiftvar, oldsolval, newsolval) ); if( nviolrows >= nprevviolrows ) nnonimprovingshifts++; else if( nviolrows < minnviolrows ) { minnviolrows = nviolrows; nnonimprovingshifts = 0; } /* store new solution value and decrease fractionality counter */ SCIP_CALL( SCIPsetSolVal(scip, sol, shiftvar, newsolval) ); /* update fractionality counter and minimal objective value possible after shifting remaining variables */ oldsolvalisfrac = !SCIPisFeasIntegral(scip, oldsolval) && (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER); obj = SCIPvarGetObj(shiftvar); if( (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER) && oldsolvalisfrac ) { assert(SCIPisFeasIntegral(scip, newsolval)); nfrac--; nnonimprovingshifts = 0; minnviolrows = INT_MAX; addFracCounter(nfracsinrow, nlprows, shiftvar, -1); /* the rounding was already calculated into the minobj -> update only if rounding in "wrong" direction */ if( obj > 0.0 && newsolval > oldsolval ) minobj += obj; else if( obj < 0.0 && newsolval < oldsolval ) minobj -= obj; } else { /* update minimal possible objective value */ minobj += obj * (newsolval - oldsolval); } /* update increase/decrease arrays */ if( !oldsolvalisfrac ) { probindex = SCIPvarGetProbindex(shiftvar); assert(0 <= probindex && probindex < nvars); increaseweight *= WEIGHTFACTOR; if( newsolval < oldsolval ) ndecreases[probindex] += increaseweight; else nincreases[probindex] += increaseweight; if( increaseweight >= 1e+09 ) { int i; for( i = 0; i < nvars; ++i ) { nincreases[i] /= increaseweight; ndecreases[i] /= increaseweight; } increaseweight = 1.0; } } SCIPdebugMessage("shifting heuristic: -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n", nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj)); } /* check, if the new solution is feasible */ if( nfrac == 0 && nviolrows == 0 ) { SCIP_Bool stored; /* check solution for feasibility, and add it to solution store if possible * neither integrality nor feasibility of LP rows has to be checked, because this is already * done in the shifting heuristic itself; however, we better check feasibility of LP rows, * because of numerical problems with activity updating */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, &stored) ); if( stored ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } } /* free memory buffers */ SCIPfreeBufferArray(scip, &ndecreases); SCIPfreeBufferArray(scip, &nincreases); SCIPfreeBufferArray(scip, &nfracsinrow); SCIPfreeBufferArray(scip, &violrowpos); SCIPfreeBufferArray(scip, &violrows); SCIPfreeBufferArray(scip, &activities); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecRounding) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_ROW** lprows; SCIP_Real* activities; SCIP_ROW** violrows; int* violrowpos; SCIP_Real obj; SCIP_Real bestroundval; SCIP_Real minobj; int nlpcands; int nlprows; int nfrac; int nviolrows; int c; int r; SCIP_Longint nlps; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nnodes; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* 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; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* don't call heuristic, if we have already processed the current LP solution */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* don't call heuristic, if it was not successful enough in the past */ ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur); nnodes = SCIPgetNNodes(scip); if( nnodes % ((ncalls/heurdata->successfactor)/(nsolsfound+1)+1) != 0 ) return SCIP_OKAY; /* get fractional variables, that should be integral */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) ); nfrac = nlpcands; /* only call heuristic, if LP solution is fractional */ if( nfrac == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* get LP rows */ SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) ); SCIPdebugMessage("executing rounding heuristic: %d LP rows, %d fractionals\n", nlprows, nfrac); /* get memory for activities, violated rows, and row violation positions */ SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) ); /* get the activities for all globally valid rows; * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated */ nviolrows = 0; for( r = 0; r < nlprows; ++r ) { SCIP_ROW* row; row = lprows[r]; assert(SCIProwGetLPPos(row) == r); if( !SCIProwIsLocal(row) ) { activities[r] = SCIPgetRowActivity(scip, row); if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) ) { violrows[nviolrows] = row; violrowpos[r] = nviolrows; nviolrows++; } else violrowpos[r] = -1; } } /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* calculate the minimal objective value possible after rounding fractional variables */ minobj = SCIPgetSolTransObj(scip, sol); assert(minobj < SCIPgetCutoffbound(scip)); for( c = 0; c < nlpcands; ++c ) { obj = SCIPvarGetObj(lpcands[c]); bestroundval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]); minobj += obj * (bestroundval - lpcandssol[c]); } /* try to round remaining variables in order to become/stay feasible */ while( nfrac > 0 ) { SCIP_VAR* roundvar; SCIP_Real oldsolval; SCIP_Real newsolval; SCIPdebugMessage("rounding heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n", nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj)); /* minobj < SCIPgetCutoffbound(scip) should be true, otherwise the rounding variable selection * should have returned NULL. Due to possible cancellation we use SCIPisLE. */ assert( SCIPisLE(scip, minobj, SCIPgetCutoffbound(scip)) ); /* choose next variable to process: * - if a violated row exists, round a variable decreasing the violation, that has least impact on other rows * - otherwise, round a variable, that has strongest devastating impact on rows in opposite direction */ if( nviolrows > 0 ) { SCIP_ROW* row; int rowpos; row = violrows[nviolrows-1]; rowpos = SCIProwGetLPPos(row); assert(0 <= rowpos && rowpos < nlprows); assert(violrowpos[rowpos] == nviolrows-1); SCIPdebugMessage("rounding heuristic: try to fix violated row <%s>: %g <= %g <= %g\n", SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row)); if( SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) ) { /* lhs is violated: select a variable rounding, that increases the activity */ SCIP_CALL( selectIncreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) ); } else { assert(SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row))); /* rhs is violated: select a variable rounding, that decreases the activity */ SCIP_CALL( selectDecreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) ); } } else { SCIPdebugMessage("rounding heuristic: search rounding variable and try to stay feasible\n"); SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &roundvar, &oldsolval, &newsolval) ); } /* check, whether rounding was possible */ if( roundvar == NULL ) { SCIPdebugMessage("rounding heuristic: -> didn't find a rounding variable\n"); break; } SCIPdebugMessage("rounding heuristic: -> round var <%s>, oldval=%g, newval=%g, obj=%g\n", SCIPvarGetName(roundvar), oldsolval, newsolval, SCIPvarGetObj(roundvar)); /* update row activities of globally valid rows */ SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows, roundvar, oldsolval, newsolval) ); /* store new solution value and decrease fractionality counter */ SCIP_CALL( SCIPsetSolVal(scip, sol, roundvar, newsolval) ); nfrac--; /* update minimal objective value possible after rounding remaining variables */ obj = SCIPvarGetObj(roundvar); if( obj > 0.0 && newsolval > oldsolval ) minobj += obj; else if( obj < 0.0 && newsolval < oldsolval ) minobj -= obj; SCIPdebugMessage("rounding heuristic: -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n", nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj)); } /* check, if the new solution is feasible */ if( nfrac == 0 && nviolrows == 0 ) { SCIP_Bool stored; /* check solution for feasibility, and add it to solution store if possible * neither integrality nor feasibility of LP rows has to be checked, because this is already * done in the rounding heuristic itself; however, be better check feasibility of LP rows, * because of numerical problems with activity updating */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, 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; } } /* free memory buffers */ SCIPfreeBufferArray(scip, &violrowpos); SCIPfreeBufferArray(scip, &violrows); SCIPfreeBufferArray(scip, &activities); return SCIP_OKAY; }