/** handle given linear constraint information */ static SCIP_RETCODE handleLinearCons( SCIP* scip, /**< SCIP data structure */ SCIP_VAR** vars, /**< array of variables */ SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */ int nvars, /**< number of variables */ SCIP_Bool transformed, /**< transformed constraint? */ SparseGraph* G /**< graph */ ) { int v; SCIP_VAR** activevars; SCIP_Real* activevals; int nactivevars; SCIP_Real activeconstant = 0.0; assert( scip != NULL ); assert( nvars > 0 ); /* duplicate variable and value array */ nactivevars = nvars; SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) ); if( vals != NULL ) SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) ); else { SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); for( v = 0; v < nactivevars; ++v ) activevals[v] = 1.0; } /* retransform given variables to active variables */ SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) ); /* print constraint */ SCIP_CALL( createEdgesFromRow(scip, activevars, activevals, nactivevars, G) ); /* free buffer arrays */ SCIPfreeBufferArray(scip, &activevars); SCIPfreeBufferArray(scip, &activevals); return SCIP_OKAY; }
/** parese job informations */ static SCIP_RETCODE getJobs( SCIP* scip, /**< SCIP data structure */ int lineno, /**< current line number of input file */ char* linestr, /**< current line */ STATE* state, /**< pointer to current reading state */ SCIP_RCPSPDATA* rcpspdata /**< pointer to resources constrained project scheduling data */ ) { char jobname[SCIP_MAXSTRLEN]; int value; int jobid; int r; assert(linestr != NULL); assert(state != NULL); /* skip lines which are not of interest */ if ( (!strncmp(linestr, "REQUESTS", 4) ) || ( !strncmp(linestr, "jobnr", 3) ) || ( !strncmp(linestr, "-", 1) ) ) { *state = JOBS; return SCIP_OKAY; } /* parse job id */ SCIPstrToIntValue(linestr, &value, &linestr); jobid = value - 1; /* construct job name */ (void)SCIPsnprintf(jobname, SCIP_MAXSTRLEN, "%d" , jobid) ; /* copy job name */ SCIP_CALL( SCIPduplicateBufferArray(scip, &rcpspdata->jobnames[jobid], jobname, strlen(jobname) + 1) ); /* skip next value */ SCIPstrToIntValue(linestr, &value, &linestr); /* parse duration */ SCIPstrToIntValue(linestr, &value, &linestr); rcpspdata->durations[jobid] = value; SCIP_CALL( SCIPallocBufferArray(scip, &rcpspdata->demands[jobid], rcpspdata->nresources) ); /* parse demands */ for( r = 0; r < rcpspdata->nresources; ++r ) { SCIPstrToIntValue(linestr, &value, &linestr); rcpspdata->demands[jobid][r] = value; } /* check if we paresed the last job */ if(jobid == rcpspdata->njobs - 1) *state = NEXT; return SCIP_OKAY; }
/** pares resource capacities */ static SCIP_RETCODE getResourcesNames( SCIP* scip, /**< SCIP data structure */ int lineno, /**< current line number of input file */ char* linestr, /**< current line */ STATE* state, /**< pointer to current reading state */ SCIP_RCPSPDATA* rcpspdata /**< pointer to resources constrained project scheduling data */ ) { char* name; char* endptr; int r; assert(linestr != NULL); assert(state != NULL); if( strncmp(linestr, "RESOURCEAVAILABILITIES", 10) == 0 ) return SCIP_OKAY; /* pares resource names */ name = SCIPstrtok(linestr, "R", &endptr); r = 0; do { while(isspace(*name)) name++; SCIP_CALL( SCIPduplicateBufferArray(scip, &rcpspdata->resourcenames[r], name, strlen(name) + 1) ); r++; } while( (name = SCIPstrtok(NULL, "R", &endptr)) != NULL ); *state = RESOURCECAPACITIES; return SCIP_OKAY; }
/** presolving execution method */ static SCIP_DECL_PRESOLEXEC(presolExecInttobinary) { /*lint --e{715}*/ SCIP_VAR** scipvars; SCIP_VAR** vars; int nbinvars; int nintvars; int v; assert(result != NULL); *result = SCIP_DIDNOTRUN; if( SCIPdoNotAggr(scip) ) return SCIP_OKAY; /* get the problem variables */ scipvars = SCIPgetVars(scip); nbinvars = SCIPgetNBinVars(scip); nintvars = SCIPgetNIntVars(scip); if( nintvars == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* copy the integer variables into an own array, since adding binary variables affects the left-most slots in the * array and thereby interferes with our search loop */ SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, &scipvars[nbinvars], nintvars) ); /* scan the integer variables for possible conversion into binaries; * we have to collect the variables first in an own */ for( v = 0; v < nintvars; ++v ) { SCIP_Real lb; SCIP_Real ub; assert(SCIPvarGetType(vars[v]) == SCIP_VARTYPE_INTEGER); /* get variable's bounds */ lb = SCIPvarGetLbGlobal(vars[v]); ub = SCIPvarGetUbGlobal(vars[v]); /* check if bounds are exactly one apart */ if( SCIPisEQ(scip, lb, ub - 1.0) ) { SCIP_VAR* binvar; char binvarname[SCIP_MAXSTRLEN]; SCIP_Bool infeasible; SCIP_Bool redundant; SCIP_Bool aggregated; SCIPdebugMessage("converting <%s>[%g,%g] into binary variable\n", SCIPvarGetName(vars[v]), lb, ub); /* create binary variable */ (void) SCIPsnprintf(binvarname, SCIP_MAXSTRLEN, "%s_bin", SCIPvarGetName(vars[v])); SCIP_CALL( SCIPcreateVar(scip, &binvar, binvarname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, SCIPvarIsInitial(vars[v]), SCIPvarIsRemovable(vars[v]), NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, binvar) ); /* aggregate integer and binary variable */ SCIP_CALL( SCIPaggregateVars(scip, vars[v], binvar, 1.0, -1.0, lb, &infeasible, &redundant, &aggregated) ); /* release binary variable */ SCIP_CALL( SCIPreleaseVar(scip, &binvar) ); /* it can be the case that this aggregation detects an infeasibility; for example, during the copy of the * variable bounds from the integer variable to the binary variable, infeasibility can be detected; this can * happen because an upper bound or a lower bound of such a variable bound variable was "just" changed and the * varbound constraint handler, who would detect that infeasibility (since it was creating it from a varbound * constraint), was called before that bound change was detected due to the presolving priorities; */ if( infeasible ) { *result = SCIP_CUTOFF; break; } assert(redundant); assert(aggregated); (*nchgvartypes)++; *result = SCIP_SUCCESS; } } /* free temporary memory */ SCIPfreeBufferArray(scip, &vars); 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; }
/** 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; }
/** constraint parsing method of constraint handler */ static SCIP_DECL_CONSPARSE(consParseConjunction) { /*lint --e{715}*/ SCIP_CONS** conss; int nconss; int sconss; char* token; char* saveptr; char* nexttokenstart; char* copystr; assert(scip != NULL); assert(conshdlr != NULL); assert(cons != NULL); assert(success != NULL); assert(str != NULL); assert(name != NULL); SCIPdebugMessage("parsing conjunction <%s>\n", name); *success = TRUE; /* allocate memory for constraint in conjunction, initial size is set to 10 */ nconss = 0; sconss = 10; SCIP_CALL( SCIPallocBufferArray(scip, &conss, sconss) ); SCIP_CALL( SCIPduplicateBufferArray(scip, ©str, str, (int)strlen(str)+1) ); /* find '(' at the beginning, string should start with 'conjunction(' */ saveptr = strpbrk(copystr, "("); /*lint !e158*/ if( saveptr == NULL ) { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } /* skip '(' */ ++saveptr; /* remember token start position */ nexttokenstart = saveptr; /* brackets '(' and ')' can exist co we check for them and the constraint delimeter */ saveptr = strpbrk(saveptr, "(,"); /* brackets '(' and ')' can exist in the rest of the string so we need to skip them to find the end of the first * sub-constraint marked by a ',' */ if( saveptr != NULL ) { do { int bracketcounter = 0; if( *saveptr == '(' ) { do { ++bracketcounter; ++saveptr; /* find last ending bracket */ while( bracketcounter > 0 ) { saveptr = strpbrk(saveptr, "()"); if( saveptr != NULL ) { if( *saveptr == '(' ) ++bracketcounter; else --bracketcounter; ++saveptr; } else { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } } saveptr = strpbrk(saveptr, "(,"); } while( saveptr != NULL && *saveptr == '(' ); } /* we found a ',' so the end of the first sub-constraint is determined */ if( saveptr != NULL ) { assert(*saveptr == ','); /* resize constraint array if necessary */ if( nconss == sconss ) { sconss = SCIPcalcMemGrowSize(scip, nconss+1); assert(nconss < sconss); SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) ); } assert(saveptr > nexttokenstart); /* extract token for parsing */ SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) ); token[saveptr - nexttokenstart] = '\0'; SCIPdebugMessage("conjunctive parsing token(constraint): %s\n", token); /* parsing a constraint, part of the conjunction */ SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, success) ); SCIPfreeBufferArray(scip, &token); if( *success ) ++nconss; else { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); goto TERMINATE; } /* skip ',' delimeter */ ++saveptr; /* remember token start position */ nexttokenstart = saveptr; saveptr = strpbrk(saveptr, "(,"); } } while( saveptr != NULL ); } /* find end of conjunction constraint */ saveptr = strrchr(nexttokenstart, ')'); if( saveptr == NULL ) { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } /* parse last sub-constraint */ else { /* resize constraint array if necessary */ if( nconss == sconss ) { ++sconss; SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) ); } assert(saveptr > nexttokenstart); /* extract token for parsing */ SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) ); token[saveptr - nexttokenstart] = '\0'; SCIPdebugMessage("conjunctive parsing token(constraint): %s\n", token); /* parsing a constraint, part of the conjunction */ SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, success) ); if( *success ) ++nconss; SCIPfreeBufferArray(scip, &token); } assert(nconss > 0 || !(*success)); /* if parsing sub-constraints was fine, create the conjunctive constraint */ if( *success ) { /* create conjunctive constraint */ SCIP_CALL( SCIPcreateConsConjunction(scip, cons, name, nconss, conss, enforce, check, local, modifiable, dynamic) ); } /* free parsed constraints */ for( --nconss; nconss >= 0; --nconss ) { SCIP_CALL( SCIPreleaseCons(scip, &conss[nconss]) ); } TERMINATE: /* free temporary memory */ SCIPfreeBufferArray(scip, ©str); SCIPfreeBufferArray(scip, &conss); return SCIP_OKAY; }
/** presolving execution method */ static SCIP_DECL_PRESOLEXEC(presolExecBoundshift) { /*lint --e{715}*/ SCIP_PRESOLDATA* presoldata; SCIP_VAR** scipvars; SCIP_VAR** vars; int nbinvars; int nvars; int v; assert(scip != NULL); assert(presol != NULL); assert(strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0); assert(result != NULL); *result = SCIP_DIDNOTRUN; /* get presolver data */ presoldata = SCIPpresolGetData(presol); assert(presoldata != NULL); /* get the problem variables */ scipvars = SCIPgetVars(scip); nbinvars = SCIPgetNBinVars(scip); nvars = SCIPgetNVars(scip) - nbinvars; if( nvars == 0 ) return SCIP_OKAY; if( SCIPdoNotAggr(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* copy the integer variables into an own array, since adding new integer variables affects the left-most slots in * the array and thereby interferes with our search loop */ SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, &scipvars[nbinvars], nvars) ); /* scan the integer, implicit, and continuous variables for possible conversion */ for( v = nvars - 1; v >= 0; --v ) { SCIP_VAR* var = vars[v]; SCIP_Real lb; SCIP_Real ub; assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY); /* get current variable's bounds */ lb = SCIPvarGetLbGlobal(var); ub = SCIPvarGetUbGlobal(var); assert( SCIPisLE(scip, lb, ub) ); if( SCIPisEQ(scip, lb, ub) ) continue; if( presoldata->integer && !SCIPisIntegral(scip, ub - lb) ) continue; /* check if bounds are shiftable */ if( !SCIPisEQ(scip, lb, 0.0) && /* lower bound != 0.0 */ SCIPisLT(scip, ub, SCIPinfinity(scip)) && /* upper bound != infinity */ SCIPisGT(scip, lb, -SCIPinfinity(scip)) && /* lower bound != -infinity */ #if 0 SCIPisLT(scip, ub - lb, SCIPinfinity(scip)) && /* interval length less than SCIPinfinity(scip) */ #endif SCIPisLT(scip, ub - lb, (SCIP_Real) presoldata->maxshift) ) /* less than max shifting */ { SCIP_VAR* newvar; char newvarname[SCIP_MAXSTRLEN]; SCIP_Bool infeasible; SCIP_Bool redundant; SCIP_Bool aggregated; SCIPdebugMessage("convert range <%s>[%g,%g] to [%g,%g]\n", SCIPvarGetName(var), lb, ub, 0.0, (ub - lb) ); /* create new variable */ (void) SCIPsnprintf(newvarname, SCIP_MAXSTRLEN, "%s_shift", SCIPvarGetName(var)); SCIP_CALL( SCIPcreateVar(scip, &newvar, newvarname, 0.0, (ub - lb), 0.0, SCIPvarGetType(var), SCIPvarIsInitial(var), SCIPvarIsRemovable(var), NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, newvar) ); /* aggregate old variable with new variable */ if( presoldata->flipping ) { if( REALABS(ub) < REALABS(lb) ) { SCIP_CALL( SCIPaggregateVars(scip, var, newvar, 1.0, 1.0, ub, &infeasible, &redundant, &aggregated) ); } else { SCIP_CALL( SCIPaggregateVars(scip, var, newvar, 1.0, -1.0, lb, &infeasible, &redundant, &aggregated) ); } } else { SCIP_CALL( SCIPaggregateVars(scip, var, newvar, 1.0, -1.0, lb, &infeasible, &redundant, &aggregated) ); } assert(!infeasible); assert(redundant); assert(aggregated); SCIPdebugMessage("var <%s> with bounds [%f,%f] has obj %f\n", SCIPvarGetName(newvar),SCIPvarGetLbGlobal(newvar),SCIPvarGetUbGlobal(newvar),SCIPvarGetObj(newvar)); /* release variable */ SCIP_CALL( SCIPreleaseVar(scip, &newvar) ); /* take care of statistic */ (*naggrvars)++; *result = SCIP_SUCCESS; } } /* free temporary memory */ SCIPfreeBufferArray(scip, &vars); 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; }
/** prints given linear constraint information in PPM format to file stream */ static SCIP_RETCODE printLinearCons( SCIP* scip, /**< SCIP data structure */ FILE* file, /**< output file (or NULL for standard output) */ SCIP_READERDATA* readerdata, /**< information for reader */ SCIP_VAR** vars, /**< array of variables */ SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */ int nvars, /**< number of variables */ int ncompletevars, /**< number of variables in whole problem */ SCIP_Bool transformed, /**< transformed constraint? */ SCIP_Real* maxcoef, /**< maximal coefficient */ SCIP_Bool printbool /**< print row or calculate maximum coefficient */ ) { int v; SCIP_VAR** activevars; SCIP_Real* activevals; int nactivevars; SCIP_Real activeconstant = 0.0; assert( scip != NULL ); assert( vars != NULL ); assert( nvars > 0 ); assert( readerdata != NULL ); /* duplicate variable and value array */ nactivevars = nvars; SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) ); if( vals != NULL ) { SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) ); } else { SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); for( v = 0; v < nactivevars; ++v ) activevals[v] = 1.0; } /* retransform given variables to active variables */ SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) ); if(!readerdata->rgb_relativ) { if(!printbool) for(v = 0; v < nactivevars; ++v) { if( REALABS(activevals[v]) > *maxcoef) *maxcoef = REALABS(activevals[v]); } else { assert (*maxcoef > 0); /* print constraint */ printRow(scip, file, readerdata, activevars, activevals, nactivevars, ncompletevars, *maxcoef); } } else { /* print constraint */ printRow(scip, file, readerdata, activevars, activevals, nactivevars, ncompletevars, *maxcoef); } /* free buffer arrays */ SCIPfreeBufferArray(scip, &activevars); SCIPfreeBufferArray(scip, &activevals); return SCIP_OKAY; }