/** output method of display column to output file stream 'file' */ static SCIP_DECL_DISPOUTPUT(SCIPdispOutputSolfound) { /*lint --e{715}*/ SCIP* origprob; SCIP_SOL* sol; SCIP_DISPDATA* dispdata; /* get original problem */ origprob = GCGpricerGetOrigprob(scip); assert(origprob != NULL); assert(disp != NULL); assert(strcmp(SCIPdispGetName(disp), DISP_NAME_SOLFOUND) == 0); assert(scip != NULL); sol = SCIPgetBestSol(scip); if( sol == NULL ) SCIPdispSetData(disp, NULL); dispdata = SCIPdispGetData(disp); if( sol != (SCIP_SOL*)dispdata ) { SCIPinfoMessage(scip, file, "%c%c", GCGrelaxGetProbingheur(origprob) == NULL ? '*' : SCIPheurGetDispchar(GCGrelaxGetProbingheur(origprob)), SCIPgetSolHeur(scip, sol) == NULL ? '*' : SCIPheurGetDispchar(SCIPgetSolHeur(scip, sol))); SCIPdispSetData(disp, (SCIP_DISPDATA*)sol); } else SCIPinfoMessage(scip, file, " "); return SCIP_OKAY; }
/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the * score */ static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreGuideddiving) { SCIP_SOL* bestsol; SCIP_Real bestsolval; SCIP_Real obj; SCIP_Real objnorm; SCIP_Real objgain; bestsol = SCIPgetBestSol(scip); assert(bestsol != NULL); assert(!SCIPsolIsOriginal(bestsol)); bestsolval = SCIPgetSolVal(scip, bestsol, cand); /* variable should be rounded (guided) into the direction of its incumbent solution value */ if( candsol < bestsolval ) *roundup = TRUE; else *roundup = FALSE; obj = SCIPvarGetObj(cand); objnorm = SCIPgetObjNorm(scip); /* divide by objective norm to normalize obj into [-1,1] */ if( SCIPisPositive(scip, objnorm) ) obj /= objnorm; /* calculate objective gain and fractionality for the selected rounding direction */ if( *roundup ) { candsfrac = 1.0 - candsfrac; objgain = obj * candsfrac; } else objgain = -obj * candsfrac; assert(objgain >= -1.0 && objgain <= 1.0); /* penalize too small fractions */ if( candsfrac < 0.01 ) candsfrac *= 0.1; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(cand) ) candsfrac *= 0.1; /* prefer variables which cannot be rounded by scoring their fractionality */ if( !(SCIPvarMayRoundDown(cand) || SCIPvarMayRoundUp(cand)) ) *score = -candsfrac; else *score = -2.0 - objgain; return SCIP_OKAY; }
std::vector<double> ILPSolverSCIP::get_solution() const { std::vector<double> res; if (get_status() != SolutionStatus::SUBOPTIMAL && get_status() != SolutionStatus::PROVEN_OPTIMAL) return res; res.reserve(d_cols.size()); // Obtain the best solution value for each variable in the current best solution. auto sol = SCIPgetBestSol(d_scip); for (auto& s : d_cols) res.push_back(SCIPgetSolVal(d_scip, sol, s)); return res; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecGuideddiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_DIVESET* diveset; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* don't dive, if no feasible solutions exist */ if( SCIPgetNSols(scip) == 0 ) return SCIP_OKAY; /* get best solution that should guide the search; if this solution lives in the original variable space, * we cannot use it since it might violate the global bounds of the current problem */ if( SCIPsolIsOriginal(SCIPgetBestSol(scip)) ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* if there are no integer variables (note that, e.g., SOS1 variables may be present) */ if ( SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 ) return SCIP_OKAY; assert(SCIPheurGetNDivesets(heur) > 0); assert(SCIPheurGetDivesets(heur) != NULL); diveset = SCIPheurGetDivesets(heur)[0]; assert(diveset != NULL); /* call generic diving algorithm */ SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, diveset, heurdata->sol, heur, result, nodeinfeasible) ); return SCIP_OKAY; }
/** returns whether the debug solution is worse as the best known solution or if the debug solution was found */ static SCIP_Bool debugSolIsAchieved( SCIP_SET* set /**< global SCIP settings */ ) { SCIP_SOL* bestsol; SCIP* scip; if( solisachieved ) return TRUE; assert(set != NULL); scip = set->scip; assert(scip != NULL); bestsol = SCIPgetBestSol(scip); if( bestsol != NULL ) { SCIP_Real solvalue; /* don't check solution while in problem creation stage */ if( SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM ) return TRUE; solvalue = SCIPgetSolOrigObj(scip, bestsol); /* make sure a debug solution has been read, so we do not compare against the initial debugsolval == 0 */ SCIP_CALL( readSolution(set) ); if( (SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE && SCIPsetIsLE(set, solvalue, debugsolval)) || (SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE && SCIPsetIsGE(set, solvalue, debugsolval)) ) solisachieved = TRUE; } return solisachieved; }
/** execution method of event handler */ static SCIP_DECL_EVENTEXEC(eventExecBestsol) { /*lint --e{715}*/ SCIP_SOL* bestsol; SCIP_Real solvalue; assert(eventhdlr != NULL); assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); assert(event != NULL); assert(scip != NULL); assert(SCIPeventGetType(event) == SCIP_EVENTTYPE_BESTSOLFOUND); SCIPdebugMessage("exec method of event handler for best solution found\n"); bestsol = SCIPgetBestSol(scip); assert(bestsol != NULL); solvalue = SCIPgetSolOrigObj(scip, bestsol); /* print best solution value */ SCIPinfoMessage(scip, NULL, "found new best solution with solution value <%g> in SCIP <%s>\n", solvalue, SCIPgetProbName(scip) ); return SCIP_OKAY; }
double SCIPSolver::get_value(void *ptr){ return SCIPgetSolVal(_scip, SCIPgetBestSol(_scip), (SCIP_VAR*) ptr); }
/* standard "main" method for mex interface */ void mexFunction( int nlhs, /* number of expected outputs */ mxArray* plhs[], /* array of pointers to output arguments */ int nrhs, /* number of inputs */ const mxArray* prhs[] /* array of pointers to input arguments */ ) { SCIP* scip; SCIP_VAR** vars; SCIP_Real* objs; SCIP_Real* lhss; SCIP_Real* rhss; SCIP_Real* lbs; SCIP_Real* ubs; SCIP_Real* matrix; SCIP_Real* bestsol; SCIP_Real* objval; char* vartypes; char objsense[SCIP_MAXSTRLEN]; int nvars; int nconss; int stringsize; int i; if( SCIPmajorVersion() < 2 ) { mexErrMsgTxt("SCIP versions less than 2.0 are not supported\n"); return; } /* initialize SCIP */ SCIP_CALL_ABORT( SCIPcreate(&scip) ); /* output SCIP information */ SCIPprintVersion(scip, NULL); /* include default SCIP plugins */ SCIP_CALL_ABORT( SCIPincludeDefaultPlugins(scip) ); if( nlhs != 2 || nrhs != 8 ) mexErrMsgTxt("invalid number of parameters. Call as [bestsol, objval] = matscip(matrix, lhs, rhs, obj, lb, ub, vartype, objsense)\n"); if( mxIsSparse(prhs[0]) ) mexErrMsgTxt("sparse matrices are not supported yet"); /* ???????? of course this has to change */ /* get linear constraint coefficient matrix */ matrix = mxGetPr(prhs[0]); if( matrix == NULL ) mexErrMsgTxt("matrix must not be NULL"); if( mxGetNumberOfDimensions(prhs[0]) != 2 ) mexErrMsgTxt("matrix must have exactly two dimensions"); /* get dimensions of matrix */ nconss = mxGetM(prhs[0]); nvars = mxGetN(prhs[0]); assert(nconss > 0); assert(nvars > 0); /* get left hand sides of linear constraints */ lhss = mxGetPr(prhs[1]); if( mxGetM(prhs[1]) != nconss ) mexErrMsgTxt("dimension of left hand side vector does not match matrix dimension"); assert(lhss != NULL); /* get right hand sides of linear constraints */ rhss = mxGetPr(prhs[2]); if( mxGetM(prhs[2]) != nconss ) mexErrMsgTxt("dimension of right hand side vector does not match matrix dimension"); assert(rhss != NULL); /* get objective coefficients */ objs = mxGetPr(prhs[3]); if( mxGetM(prhs[3]) != nvars ) mexErrMsgTxt("dimension of objective coefficient vector does not match matrix dimension"); /* get lower bounds of variables */ lbs = mxGetPr(prhs[4]); if( mxGetM(prhs[4]) != nvars ) mexErrMsgTxt("dimension of lower bound vector does not match matrix dimension"); /* get upper bounds of variables */ ubs = mxGetPr(prhs[5]); if( mxGetM(prhs[5]) != nvars ) mexErrMsgTxt("dimension of upper bound vector does not match matrix dimension"); /* allocate memory for variable type characters */ SCIP_CALL_ABORT( SCIPallocMemoryArray(scip, &vartypes, nvars+1) ); /* get variable types */ if( mxGetString(prhs[6], vartypes, nvars+1) != 0 ) mexErrMsgTxt("Error when parsing variable types, maybe a wrong vector dimension?"); /* get objective sense */ stringsize = mxGetNumberOfElements(prhs[7]); if( stringsize != 3 ) mexErrMsgTxt("objective sense must be a three character word: \"max\" or \"min\""); if( mxGetString(prhs[7], objsense, stringsize+1) != 0) mexErrMsgTxt("Error when parsing objective sense string"); if( strcmp(objsense,"max") != 0 && strcmp(objsense,"min") != 0 ) mexErrMsgTxt("objective sense must be either \"max\" or \"min\""); /* get output parameters */ plhs[0] = mxCreateDoubleMatrix(nvars, 1, mxREAL); bestsol = mxGetPr(plhs[0]); plhs[1] = mxCreateDoubleScalar(mxREAL); objval = mxGetPr(plhs[1]); /* create SCIP problem */ SCIP_CALL_ABORT( SCIPcreateProb(scip, "mex_prob", NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* allocate memory for variable array */ SCIP_CALL_ABORT( SCIPallocMemoryArray(scip, &vars, nvars) ); /* create variables */ for( i = 0; i < nvars; ++i) { SCIP_VARTYPE vartype; char varname[SCIP_MAXSTRLEN]; /* convert vartype character to SCIP vartype */ if( vartypes[i] == 'i' ) vartype = SCIP_VARTYPE_INTEGER; else if( vartypes[i] == 'b' ) vartype = SCIP_VARTYPE_BINARY; else if( vartypes[i] == 'c' ) vartype = SCIP_VARTYPE_CONTINUOUS; else mexErrMsgTxt("unkown variable type"); /* variables get canonic names x_i */ (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "x_%d", i); /* create variable object and add it to SCIP */ SCIP_CALL_ABORT( SCIPcreateVar(scip, &vars[i], varname, lbs[i], ubs[i], objs[i], vartype, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); assert(vars[i] != NULL); SCIP_CALL_ABORT( SCIPaddVar(scip, vars[i]) ); } /* create linear constraints */ for( i = 0; i < nconss; ++i ) { SCIP_CONS* cons; char consname[SCIP_MAXSTRLEN]; int j; /* constraints get canonic names cons_i */ (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cons_%d", i); /* create empty linear constraint */ SCIP_CALL_ABORT( SCIPcreateConsLinear(scip, &cons, consname, 0, NULL, NULL, lhss[i], rhss[i], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); /* add non-zero coefficients to linear constraint */ for( j = 0; j < nvars; ++j ) { if( !SCIPisFeasZero(scip, matrix[i+j*nconss]) ) { SCIP_CALL_ABORT( SCIPaddCoefLinear(scip, cons, vars[j], matrix[i+j*nconss]) ); } } /* add constraint to SCIP and release it */ SCIP_CALL_ABORT( SCIPaddCons(scip, cons) ); SCIP_CALL_ABORT( SCIPreleaseCons(scip, &cons) ); } /* set objective sense in SCIP */ if( strcmp(objsense,"max") == 0) { SCIP_CALL_ABORT( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); } else if( strcmp(objsense,"min") == 0) { SCIP_CALL_ABORT( SCIPsetObjsense(scip, SCIP_OBJSENSE_MINIMIZE) ); } else /* this should have been caught earlier when parsing objsense */ mexErrMsgTxt("unkown objective sense"); /* solve SCIP problem */ SCIP_CALL_ABORT( SCIPsolve(scip) ); /* if SCIP found a solution, pass it back into MATLAB output parameters */ if( SCIPgetNSols > 0 ) { SCIP_SOL* scipbestsol; /* get incumbent solution vector */ scipbestsol = SCIPgetBestSol(scip); assert(scipbestsol != NULL); /* get objective value of incumbent solution */ *objval = SCIPgetSolOrigObj(scip, scipbestsol); assert(!SCIPisInfinity(scip, REALABS(*objval))); /* copy solution values into output vector */ for( i = 0; i < nvars; ++i ) bestsol[i] = SCIPgetSolVal(scip,scipbestsol,vars[i]); } /* release variables */ for( i = 0; i < nvars; ++i ) { SCIP_CALL_ABORT( SCIPreleaseVar(scip, &vars[i]) ); } /* free memory for variable arrays */ SCIPfreeMemoryArray(scip, &vartypes); SCIPfreeMemoryArray(scip, &vars); /* deinitialize SCIP */ SCIP_CALL_ABORT( SCIPfree(&scip) ); /* check for memory leaks */ BMScheckEmptyMemory(); return; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecGuideddiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_SOL* bestsol; 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 obj; SCIP_Real objgain; SCIP_Real bestobjgain; SCIP_Real frac; SCIP_Real bestfrac; SCIP_Real solval; SCIP_Real bestsolval; 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; 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; /* don't dive, if no feasible solutions exist */ if( SCIPgetNSols(scip) == 0 ) return SCIP_OKAY; /* 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( 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; /* get best solution that should guide the search; if this solution lives in the original variable space, * we cannot use it since it might violate the global bounds of the current problem */ if( SCIPsolIsOriginal(SCIPgetBestSol(scip)) ) return SCIP_OKAY; /* store a copy of the best solution */ SCIP_CALL( SCIPcreateSolCopy(scip, &bestsol, SCIPgetBestSol(scip)) ); *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 guideddiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(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) ) { SCIP_CALL( SCIPnewProbingNode(scip) ); divedepth++; /* choose variable fixing: * - prefer variables that may not be rounded without destroying LP feasibility: * - of these variables, round a variable to its value in direction of incumbent solution, and choose the * variable that is closest to its rounded value * - if all remaining fractional variables may be rounded without destroying LP feasibility: * - round variable in direction that destroys LP feasibility (other direction is checked by SCIProundSol()) * - round variable with least increasing objective value */ bestcand = -1; bestobjgain = SCIPinfinity(scip); bestfrac = SCIP_INVALID; bestcandmayrounddown = TRUE; bestcandmayroundup = TRUE; bestcandroundup = FALSE; for( c = 0; c < nlpcands; ++c ) { var = lpcands[c]; mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); solval = lpcandssol[c]; frac = lpcandsfrac[c]; obj = SCIPvarGetObj(var); bestsolval = SCIPgetSolVal(scip, bestsol, var); /* select default rounding direction */ roundup = (solval < bestsolval); 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 its value in incumbent solution * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution with SCIProundSol() */ if( !mayrounddown || !mayroundup ) roundup = mayrounddown; if( roundup ) { frac = 1.0 - frac; objgain = frac*obj; } else objgain = -frac*obj; /* penalize too small fractions */ if( frac < 0.01 ) objgain *= 1000.0; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) objgain *= 1000.0; /* check, if candidate is new best candidate */ if( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) ) { bestcand = c; bestobjgain = objgain; bestfrac = frac; bestcandmayrounddown = mayrounddown; bestcandmayroundup = mayroundup; bestcandroundup = roundup; } } } else { /* the candidate may not be rounded */ if( roundup ) frac = 1.0 - frac; /* penalize too small fractions */ if( frac < 0.01 ) frac += 10.0; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(var) ) frac *= 1000.0; /* check, if candidate is new best candidate: prefer unroundable candidates in any case */ if( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac ) { bestcand = c; bestfrac = frac; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; bestcandroundup = roundup; } } } 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("guideddiving 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; } } } 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, bestsol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetSolVal(scip, bestsol, var), 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, bestsol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetSolVal(scip, bestsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand])); SCIP_CALL( SCIPchgVarUbProbing(scip, var, 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 Guideddiving 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, nfrac=%d\n", lpsolstat, objval, 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("guideddiving 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) ); /* free copied best solution */ SCIP_CALL( SCIPfreeSol(scip, &bestsol) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; SCIPdebugMessage("guideddiving heuristic finished\n"); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecOneopt) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* bestsol; /* incumbent solution */ SCIP_SOL* worksol; /* heuristic's working solution */ SCIP_VAR** vars; /* SCIP variables */ SCIP_VAR** shiftcands; /* shiftable variables */ SCIP_ROW** lprows; /* SCIP LP rows */ SCIP_Real* activities; /* row activities for working solution */ SCIP_Real* shiftvals; SCIP_Real lb; SCIP_Real ub; SCIP_Bool localrows; SCIP_Bool valid; int nchgbound; int nbinvars; int nintvars; int nvars; int nlprows; int i; int nshiftcands; int shiftcandssize; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); *result = SCIP_DELAYED; /* we only want to process each solution once */ bestsol = SCIPgetBestSol(scip); if( bestsol == NULL || heurdata->lastsolindex == SCIPsolGetIndex(bestsol) ) return SCIP_OKAY; /* reset the timing mask to its default value (at the root node it could be different) */ if( SCIPgetNNodes(scip) > 1 ) SCIPheurSetTimingmask(heur, HEUR_TIMING); /* get problem variables */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); nintvars += nbinvars; /* do not run if there are no discrete variables */ if( nintvars == 0 ) { *result = SCIP_DIDNOTRUN; return SCIP_OKAY; } if( heurtiming == SCIP_HEURTIMING_BEFOREPRESOL ) { SCIP* subscip; /* the subproblem created by zeroobj */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_Real* subsolvals; /* solution values of the subproblem */ SCIP_Real timelimit; /* time limit for zeroobj subproblem */ SCIP_Real memorylimit; /* memory limit for zeroobj subproblem */ SCIP_SOL* startsol; SCIP_SOL** subsols; int nsubsols; if( !heurdata->beforepresol ) return SCIP_OKAY; /* check whether there is enough time and memory left */ timelimit = 0.0; memorylimit = 0.0; SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) return SCIP_OKAY; /* initialize the subproblem */ SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); /* copy complete SCIP instance */ valid = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "oneopt", TRUE, FALSE, TRUE, &valid) ); SCIP_CALL( SCIPtransformProb(subscip) ); /* get variable image */ for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* copy the solution */ SCIP_CALL( SCIPallocBufferArray(scip, &subsolvals, nvars) ); SCIP_CALL( SCIPgetSolVals(scip, bestsol, nvars, vars, subsolvals) ); /* create start solution for the subproblem */ SCIP_CALL( SCIPcreateOrigSol(subscip, &startsol, NULL) ); SCIP_CALL( SCIPsetSolVals(subscip, startsol, nvars, subvars, subsolvals) ); /* try to add new solution to sub-SCIP and free it immediately */ valid = FALSE; SCIP_CALL( SCIPtrySolFree(subscip, &startsol, FALSE, FALSE, FALSE, FALSE, &valid) ); SCIPfreeBufferArray(scip, &subsolvals); SCIPhashmapFree(&varmapfw); /* disable statistic timing inside sub SCIP */ SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) ); /* deactivate basically everything except oneopt in the sub-SCIP */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetHeuristics(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", 1LL) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* if necessary, some of the parameters have to be unfixed first */ if( SCIPisParamFixed(subscip, "lp/solvefreq") ) { SCIPwarningMessage(scip, "unfixing parameter lp/solvefreq in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "lp/solvefreq") ); } SCIP_CALL( SCIPsetIntParam(subscip, "lp/solvefreq", -1) ); if( SCIPisParamFixed(subscip, "heuristics/oneopt/freq") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/freq in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/freq") ); } SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/oneopt/freq", 1) ); if( SCIPisParamFixed(subscip, "heuristics/oneopt/forcelpconstruction") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/forcelpconstruction in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/forcelpconstruction") ); } SCIP_CALL( SCIPsetBoolParam(subscip, "heuristics/oneopt/forcelpconstruction", TRUE) ); /* avoid recursive call, which would lead to an endless loop */ if( SCIPisParamFixed(subscip, "heuristics/oneopt/beforepresol") ) { SCIPwarningMessage(scip, "unfixing parameter heuristics/oneopt/beforepresol in subscip of oneopt heuristic\n"); SCIP_CALL( SCIPunfixParam(subscip, "heuristics/oneopt/beforepresol") ); } SCIP_CALL( SCIPsetBoolParam(subscip, "heuristics/oneopt/beforepresol", FALSE) ); if( valid ) { retcode = SCIPsolve(subscip); /* errors in solving the subproblem should not kill the overall solving process; * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in zeroobj heuristic; sub-SCIP terminated with code <%d>\n",retcode); } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif } /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); valid = FALSE; for( i = 0; i < nsubsols && !valid; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &valid) ); if( valid ) *result = SCIP_FOUNDSOL; } /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; } /* we can only work on solutions valid in the transformed space */ if( SCIPsolIsOriginal(bestsol) ) return SCIP_OKAY; if( heurtiming == SCIP_HEURTIMING_BEFORENODE && (SCIPhasCurrentNodeLP(scip) || heurdata->forcelpconstruction) ) { SCIP_Bool cutoff; cutoff = FALSE; SCIP_CALL( SCIPconstructLP(scip, &cutoff) ); SCIP_CALL( SCIPflushLP(scip) ); /* get problem variables again, SCIPconstructLP() might have added new variables */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); nintvars += nbinvars; } /* we need an LP */ if( SCIPgetNLPRows(scip) == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; nchgbound = 0; /* initialize data */ nshiftcands = 0; shiftcandssize = 8; heurdata->lastsolindex = SCIPsolGetIndex(bestsol); SCIP_CALL( SCIPcreateSolCopy(scip, &worksol, bestsol) ); SCIPsolSetHeur(worksol,heur); SCIPdebugMessage("Starting bound adjustment in 1-opt heuristic\n"); /* maybe change solution values due to global bound changes first */ for( i = nvars - 1; i >= 0; --i ) { SCIP_VAR* var; SCIP_Real solval; var = vars[i]; lb = SCIPvarGetLbGlobal(var); ub = SCIPvarGetUbGlobal(var); solval = SCIPgetSolVal(scip, bestsol,var); /* old solution value is smaller than the actual lower bound */ if( SCIPisFeasLT(scip, solval, lb) ) { /* set the solution value to the global lower bound */ SCIP_CALL( SCIPsetSolVal(scip, worksol, var, lb) ); ++nchgbound; SCIPdebugMessage("var <%s> type %d, old solval %g now fixed to lb %g\n", SCIPvarGetName(var), SCIPvarGetType(var), solval, lb); } /* old solution value is greater than the actual upper bound */ else if( SCIPisFeasGT(scip, solval, SCIPvarGetUbGlobal(var)) ) { /* set the solution value to the global upper bound */ SCIP_CALL( SCIPsetSolVal(scip, worksol, var, ub) ); ++nchgbound; SCIPdebugMessage("var <%s> type %d, old solval %g now fixed to ub %g\n", SCIPvarGetName(var), SCIPvarGetType(var), solval, ub); } } SCIPdebugMessage("number of bound changes (due to global bounds) = %d\n", nchgbound); SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) ); localrows = FALSE; valid = TRUE; /* initialize activities */ for( i = 0; i < nlprows; ++i ) { SCIP_ROW* row; row = lprows[i]; assert(SCIProwGetLPPos(row) == i); if( !SCIProwIsLocal(row) ) { activities[i] = SCIPgetRowSolActivity(scip, row, worksol); SCIPdebugMessage("Row <%s> has activity %g\n", SCIProwGetName(row), activities[i]); if( SCIPisFeasLT(scip, activities[i], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[i], SCIProwGetRhs(row)) ) { valid = FALSE; SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) ); SCIPdebugMessage("row <%s> activity %g violates bounds, lhs = %g, rhs = %g\n", SCIProwGetName(row), activities[i], SCIProwGetLhs(row), SCIProwGetRhs(row)); break; } } else localrows = TRUE; } if( !valid ) { /** @todo try to correct lp rows */ SCIPdebugMessage("Some global bound changes were not valid in lp rows.\n"); goto TERMINATE; } SCIP_CALL( SCIPallocBufferArray(scip, &shiftcands, shiftcandssize) ); SCIP_CALL( SCIPallocBufferArray(scip, &shiftvals, shiftcandssize) ); SCIPdebugMessage("Starting 1-opt heuristic\n"); /* enumerate all integer variables and find out which of them are shiftable */ for( i = 0; i < nintvars; i++ ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { SCIP_Real shiftval; SCIP_Real solval; /* find out whether the variable can be shifted */ solval = SCIPgetSolVal(scip, worksol, vars[i]); shiftval = calcShiftVal(scip, vars[i], solval, activities); /* insert the variable into the list of shifting candidates */ if( !SCIPisFeasZero(scip, shiftval) ) { SCIPdebugMessage(" -> Variable <%s> can be shifted by <%1.1f> \n", SCIPvarGetName(vars[i]), shiftval); if( nshiftcands == shiftcandssize) { shiftcandssize *= 8; SCIP_CALL( SCIPreallocBufferArray(scip, &shiftcands, shiftcandssize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &shiftvals, shiftcandssize) ); } shiftcands[nshiftcands] = vars[i]; shiftvals[nshiftcands] = shiftval; nshiftcands++; } } } /* if at least one variable can be shifted, shift variables sorted by their objective */ if( nshiftcands > 0 ) { SCIP_Real shiftval; SCIP_Real solval; SCIP_VAR* var; /* the case that exactly one variable can be shifted is slightly easier */ if( nshiftcands == 1 ) { var = shiftcands[0]; assert(var != NULL); solval = SCIPgetSolVal(scip, worksol, var); shiftval = shiftvals[0]; assert(!SCIPisFeasZero(scip,shiftval)); SCIPdebugMessage(" Only one shiftcand found, var <%s>, which is now shifted by<%1.1f> \n", SCIPvarGetName(var), shiftval); SCIP_CALL( SCIPsetSolVal(scip, worksol, var, solval+shiftval) ); } else { SCIP_Real* objcoeffs; SCIP_CALL( SCIPallocBufferArray(scip, &objcoeffs, nshiftcands) ); SCIPdebugMessage(" %d shiftcands found \n", nshiftcands); /* sort the variables by their objective, optionally weighted with the shiftval */ if( heurdata->weightedobj ) { for( i = 0; i < nshiftcands; ++i ) objcoeffs[i] = SCIPvarGetObj(shiftcands[i])*shiftvals[i]; } else { for( i = 0; i < nshiftcands; ++i ) objcoeffs[i] = SCIPvarGetObj(shiftcands[i]); } /* sort arrays with respect to the first one */ SCIPsortRealPtr(objcoeffs, (void**)shiftcands, nshiftcands); /* try to shift each variable -> Activities have to be updated */ for( i = 0; i < nshiftcands; ++i ) { var = shiftcands[i]; assert(var != NULL); solval = SCIPgetSolVal(scip, worksol, var); shiftval = calcShiftVal(scip, var, solval, activities); SCIPdebugMessage(" -> Variable <%s> is now shifted by <%1.1f> \n", SCIPvarGetName(vars[i]), shiftval); assert(i > 0 || !SCIPisFeasZero(scip, shiftval)); assert(SCIPisFeasGE(scip, solval+shiftval, SCIPvarGetLbGlobal(var)) && SCIPisFeasLE(scip, solval+shiftval, SCIPvarGetUbGlobal(var))); SCIP_CALL( SCIPsetSolVal(scip, worksol, var, solval+shiftval) ); SCIP_CALL( updateRowActivities(scip, activities, var, shiftval) ); } SCIPfreeBufferArray(scip, &objcoeffs); } /* if the problem is a pure IP, try to install the solution, if it is a MIP, solve LP again to set the continuous * variables to the best possible value */ if( nvars == nintvars || !SCIPhasCurrentNodeLP(scip) || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* since we ignore local rows, we cannot guarantee their feasibility and have to set the checklprows flag to * TRUE if local rows are present */ SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, localrows, &success) ); if( success ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) ); heurdata->lastsolindex = SCIPsolGetIndex(bestsol); *result = SCIP_FOUNDSOL; } } else { SCIP_Bool lperror; #ifdef NDEBUG SCIP_RETCODE retstat; #endif SCIPdebugMessage("shifted solution should be feasible -> solve LP to fix continuous variables to best values\n"); /* start diving to calculate the LP relaxation */ SCIP_CALL( SCIPstartDive(scip) ); /* set the bounds of the variables: fixed for integers, global bounds for continuous */ for( i = 0; i < nvars; ++i ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], SCIPvarGetLbGlobal(vars[i])) ); SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], SCIPvarGetUbGlobal(vars[i])) ); } } /* apply this after global bounds to not cause an error with intermediate empty domains */ for( i = 0; i < nintvars; ++i ) { if( SCIPvarGetStatus(vars[i]) == SCIP_VARSTATUS_COLUMN ) { solval = SCIPgetSolVal(scip, worksol, vars[i]); SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], solval) ); SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], solval) ); } } /* solve LP */ SCIPdebugMessage(" -> old LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip)); /**@todo in case of an MINLP, if SCIPisNLPConstructed() is TRUE, say, rather solve the NLP instead of the 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 retstat = SCIPsolveDiveLP(scip, -1, &lperror, NULL); if( retstat != SCIP_OKAY ) { SCIPwarningMessage(scip, "Error while solving LP in Oneopt heuristic; LP solve terminated with code <%d>\n",retstat); } #else SCIP_CALL( SCIPsolveDiveLP(scip, -1, &lperror, NULL) ); #endif SCIPdebugMessage(" -> new LP iterations: %" SCIP_LONGINT_FORMAT "\n", SCIPgetNLPIterations(scip)); SCIPdebugMessage(" -> error=%u, status=%d\n", lperror, SCIPgetLPSolstat(scip)); /* check if this is a feasible solution */ if( !lperror && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, worksol) ); SCIP_CALL( SCIPtrySol(scip, worksol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check solution for feasibility */ if( success ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, worksol, NULL, FALSE) ) ); heurdata->lastsolindex = SCIPsolGetIndex(bestsol); *result = SCIP_FOUNDSOL; } } /* terminate the diving */ SCIP_CALL( SCIPendDive(scip) ); } } SCIPdebugMessage("Finished 1-opt heuristic\n"); SCIPfreeBufferArray(scip, &shiftvals); SCIPfreeBufferArray(scip, &shiftcands); TERMINATE: SCIPfreeBufferArray(scip, &activities); SCIP_CALL( SCIPfreeSol(scip, &worksol) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecIndicator) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; int nfoundsols = 0; assert( heur != NULL ); assert( scip != NULL ); assert( result != NULL ); *result = SCIP_DIDNOTRUN; if ( SCIPgetSubscipDepth(scip) > 0 ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* call heuristic, if solution candidate is available */ if ( heurdata->solcand != NULL ) { assert( heurdata->nindconss > 0 ); assert( heurdata->indconss != NULL ); /* The heuristic will only be successful if there are no integral variables and no binary variables except the * indicator variables. */ if ( SCIPgetNIntVars(scip) > 0 || heurdata->nindconss < SCIPgetNBinVars(scip) ) return SCIP_OKAY; SCIP_CALL( trySolCandidate(scip, heur, heurdata, heurdata->nindconss, heurdata->indconss, heurdata->solcand, &nfoundsols) ); if ( nfoundsols > 0 ) *result = SCIP_FOUNDSOL; else *result = SCIP_DIDNOTFIND; /* free memory */ SCIPfreeBlockMemoryArray(scip, &(heurdata->solcand), heurdata->nindconss); SCIPfreeBlockMemoryArray(scip, &(heurdata->indconss), heurdata->nindconss); } else { SCIP_CONS** indconss; SCIP_Bool* solcand; SCIP_SOL* bestsol; int nindconss; int i; if ( heurdata->indicatorconshdlr == NULL ) return SCIP_OKAY; /* check whether a new best solution has been found */ bestsol = SCIPgetBestSol(scip); if ( bestsol == heurdata->lastsol ) return SCIP_OKAY; heurdata->lastsol = bestsol; /* avoid solutions produced by this heuristic */ if ( SCIPsolGetHeur(bestsol) == heur ) return SCIP_OKAY; /* The heuristic will only be successful if there are no integral variables and no binary variables except the * indicator variables. */ if ( SCIPgetNIntVars(scip) > 0 || SCIPconshdlrGetNConss(heurdata->indicatorconshdlr) < SCIPgetNBinVars(scip) ) return SCIP_OKAY; nindconss = SCIPconshdlrGetNConss(heurdata->indicatorconshdlr); if ( nindconss == 0 ) return SCIP_OKAY; indconss = SCIPconshdlrGetConss(heurdata->indicatorconshdlr); assert( indconss != NULL ); /* fill solutin candidate */ SCIP_CALL( SCIPallocBufferArray(scip, &solcand, nindconss) ); for (i = 0; i < nindconss; ++i) { SCIP_VAR* binvar; SCIP_Real val; solcand[i] = FALSE; if ( SCIPconsIsActive(indconss[i]) ) { binvar = SCIPgetBinaryVarIndicator(indconss[i]); assert( binvar != NULL ); val = SCIPgetSolVal(scip, bestsol, binvar); assert( SCIPisFeasIntegral(scip, val) ); if ( val > 0.5 ) solcand[i] = TRUE; } } SCIPdebugMessage("Trying to improve best solution of value %f.\n", SCIPgetSolOrigObj(scip, bestsol) ); /* try one-opt heuristic */ SCIP_CALL( tryOneOpt(scip, heur, heurdata, nindconss, indconss, solcand, &nfoundsols) ); if ( nfoundsols > 0 ) *result = SCIP_FOUNDSOL; else *result = SCIP_DIDNOTFIND; SCIPfreeBufferArray(scip, &solcand); } return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpClosecuts) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; SCIP_Longint currentnodenumber; SCIP_Bool isroot; assert( sepa != NULL ); assert( strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0 ); assert( result != NULL ); *result = SCIP_DIDNOTRUN; /* only call separator, if there are fractional variables */ if ( SCIPgetNLPBranchCands(scip) == 0 ) return SCIP_OKAY; sepadata = SCIPsepaGetData(sepa); assert( sepadata != NULL ); currentnodenumber = SCIPnodeGetNumber(SCIPgetCurrentNode(scip)); if ( sepadata->discardnode == currentnodenumber ) return SCIP_OKAY; isroot = FALSE; if (SCIPgetNNodes(scip) == 0) isroot = TRUE; /* only separate close cuts in the root if required */ if ( sepadata->separootonly || isroot ) { SCIP_SOL* point = NULL; SCIPdebugMessage("Separation method of closecuts separator.\n"); *result = SCIP_DIDNOTFIND; /* check whether we have to compute a relative interior point */ if ( sepadata->separelint ) { /* check if previous relative interior point should be forgotten, * otherwise it is computed only once and the same point is used for all nodes */ if ( sepadata->recomputerelint && sepadata->sepasol != NULL ) { SCIP_CALL( SCIPfreeSol(scip, &sepadata->sepasol) ); } if ( sepadata->sepasol == NULL ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, 0, "Computing relative interior point (norm type: %c) ...\n", sepadata->relintnormtype); assert(sepadata->relintnormtype == 'o' || sepadata->relintnormtype == 's'); SCIP_CALL( SCIPcomputeLPRelIntPoint(scip, TRUE, sepadata->inclobjcutoff, sepadata->relintnormtype, &sepadata->sepasol) ); } } else { /* get best solution (NULL if not present) */ sepadata->sepasol = SCIPgetBestSol(scip); } /* separate close cuts */ if ( sepadata->sepasol != NULL ) { SCIPdebugMessage("Generating close cuts ... (combination value: %f)\n", sepadata->sepacombvalue); /* generate point to be separated */ SCIP_CALL( generateCloseCutPoint(scip, sepadata, &point) ); /* apply a separation round to generated point */ if ( point != NULL ) { int noldcuts; SCIP_Bool delayed; SCIP_Bool cutoff; noldcuts = SCIPgetNCuts(scip); SCIP_CALL( SCIPseparateSol(scip, point, isroot, FALSE, &delayed, &cutoff) ); SCIP_CALL( SCIPfreeSol(scip, &point) ); assert( point == NULL ); /* the cuts can be not violated by the current LP if the computed point is strange */ SCIP_CALL( SCIPremoveInefficaciousCuts(scip) ); if ( cutoff ) *result = SCIP_CUTOFF; else { if ( SCIPgetNCuts(scip) - noldcuts > sepadata->sepathreshold ) { sepadata->nunsuccessful = 0; *result = SCIP_NEWROUND; } else { if ( SCIPgetNCuts(scip) > noldcuts ) { sepadata->nunsuccessful = 0; *result = SCIP_SEPARATED; } else ++sepadata->nunsuccessful; } } SCIPdebugMessage("Separated close cuts: %d (enoughcuts: %d, unsuccessful: %d).\n", SCIPgetNCuts(scip) - noldcuts, SCIPgetNCuts(scip) - noldcuts > sepadata->sepathreshold, sepadata->nunsuccessful); if ( sepadata->maxunsuccessful >= 0 && sepadata->nunsuccessful > sepadata->maxunsuccessful ) { SCIPdebugMessage("Turn off close cut separation, because of %d unsuccessful calls.\n", sepadata->nunsuccessful); sepadata->discardnode = currentnodenumber; } } } } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecLocalbranching) { /*lint --e{715}*/ SCIP_Longint maxnnodes; /* maximum number of subnodes */ SCIP_Longint nsubnodes; /* nodelimit for subscip */ SCIP_HEURDATA* heurdata; SCIP* subscip; /* the subproblem created by localbranching */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_SOL* bestsol; /* best solution so far */ SCIP_EVENTHDLR* eventhdlr; /* event handler for LP events */ SCIP_Real timelimit; /* timelimit for subscip (equals remaining time of scip) */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real upperbound; SCIP_Real memorylimit; SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; int nvars; int i; SCIP_Bool success; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* there should be enough binary variables that a local branching constraint makes sense */ if( SCIPgetNBinVars(scip) < 2*heurdata->neighborhoodsize ) return SCIP_OKAY; *result = SCIP_DELAYED; /* only call heuristic, if an IP solution is at hand */ if( SCIPgetNSols(scip) <= 0 ) return SCIP_OKAY; bestsol = SCIPgetBestSol(scip); assert(bestsol != NULL); /* only call heuristic, if the best solution comes from transformed problem */ if( SCIPsolIsOriginal(bestsol) ) return SCIP_OKAY; /* only call heuristic, if enough nodes were processed since last incumbent */ if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip, bestsol) < heurdata->nwaitingnodes) return SCIP_OKAY; /* only call heuristic, if the best solution does not come from trivial heuristic */ if( SCIPsolGetHeur(bestsol) != NULL && strcmp(SCIPheurGetName(SCIPsolGetHeur(bestsol)), "trivial") == 0 ) return SCIP_OKAY; /* reset neighborhood and minnodes, if new solution was found */ if( heurdata->lastsol != bestsol ) { heurdata->curneighborhoodsize = heurdata->neighborhoodsize; heurdata->curminnodes = heurdata->minnodes; heurdata->emptyneighborhoodsize = 0; heurdata->callstatus = EXECUTE; heurdata->lastsol = bestsol; } /* if no new solution was found and local branching also seems to fail, just keep on waiting */ if( heurdata->callstatus == WAITFORNEWSOL ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* calculate the maximal number of branching nodes until heuristic is aborted */ maxnnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip)); /* reward local branching if it succeeded often */ maxnnodes = (SCIP_Longint)(maxnnodes * (1.0 + 2.0*(SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0))); maxnnodes -= 100 * SCIPheurGetNCalls(heur); /* count the setup costs for the sub-MIP as 100 nodes */ maxnnodes += heurdata->nodesofs; /* determine the node limit for the current process */ nsubnodes = maxnnodes - heurdata->usednodes; nsubnodes = MIN(nsubnodes, heurdata->maxnodes); /* check whether we have enough nodes left to call sub problem solving */ if( nsubnodes < heurdata->curminnodes ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIPdebugMessage("running localbranching heuristic ...\n"); /* get the data of the variables and the best solution */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* initializing the subproblem */ SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); success = FALSE; eventhdlr = NULL; if( heurdata->uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_localbranchsub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_localbranchsub", SCIPgetProbName(scip)); /* create the subproblem */ SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* copy all variables */ SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) ); } else { SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "localbranchsub", TRUE, FALSE, TRUE, &success) ); if( heurdata->copycuts ) { /* copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) ); } /* create event handler for LP events */ SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecLocalbranching, NULL) ); if( eventhdlr == NULL ) { SCIPerrorMessage("event handler for "HEUR_NAME" heuristic not found.\n"); return SCIP_PLUGINNOTFOUND; } } SCIPdebugMessage("Copying the plugins was %ssuccessful.\n", success ? "" : "not "); for (i = 0; i < nvars; ++i) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); /* if the subproblem could not be created, free memory and return */ if( !success ) { *result = SCIP_DIDNOTRUN; goto TERMINATE; } /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); #ifndef SCIP_DEBUG /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); #endif /* check whether there is enough time and memory left */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) goto TERMINATE; /* set limits for the subproblem */ heurdata->nodelimit = nsubnodes; SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nsubnodes) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", MAX(10, nsubnodes/10)) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", 3) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving subMIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* use best estimate node selection */ if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ if( !SCIPisParamFixed(subscip, "conflict/useprop") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useinflp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useboundlp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usesb") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usepseudo") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); } /* employ a limit on the number of enforcement rounds in the quadratic constraint handler; this fixes the issue that * sometimes the quadratic constraint handler needs hundreds or thousands of enforcement rounds to determine the * feasibility status of a single node without fractional branching candidates by separation (namely for uflquad * instances); however, the solution status of the sub-SCIP might get corrupted by this; hence no deductions shall be * made for the original SCIP */ if( SCIPfindConshdlr(subscip, "quadratic") != NULL && !SCIPisParamFixed(subscip, "constraints/quadratic/enfolplimit") ) { SCIP_CALL( SCIPsetIntParam(subscip, "constraints/quadratic/enfolplimit", 500) ); } /* copy the original problem and add the local branching constraint */ if( heurdata->uselprows ) { SCIP_CALL( createSubproblem(scip, subscip, subvars) ); } SCIP_CALL( addLocalBranchingConstraint(scip, subscip, subvars, heurdata) ); /* add an objective cutoff */ cutoff = SCIPinfinity(scip); assert( !SCIPisInfinity(scip,SCIPgetUpperbound(scip)) ); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) ) { cutoff = (1-heurdata->minimprove)*SCIPgetUpperbound(scip) + heurdata->minimprove*SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound ( scip ) >= 0 ) cutoff = ( 1 - heurdata->minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + heurdata->minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff ); SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) ); /* catch LP events of sub-SCIP */ if( !heurdata->uselprows ) { assert(eventhdlr != NULL); SCIP_CALL( SCIPtransformProb(subscip) ); SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) ); } /* solve the subproblem */ SCIPdebugMessage("solving local branching subproblem with neighborhoodsize %d and maxnodes %"SCIP_LONGINT_FORMAT"\n", heurdata->curneighborhoodsize, nsubnodes); retcode = SCIPsolve(subscip); /* drop LP events of sub-SCIP */ if( !heurdata->uselprows ) { assert(eventhdlr != NULL); SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) ); } /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in local branching heuristic; sub-SCIP terminated with code <%d>\n",retcode); } /* print solving statistics of subproblem if we are in SCIP's debug mode */ SCIPdebug( SCIP_CALL( SCIPprintStatistics(subscip, NULL) ) ); heurdata->usednodes += SCIPgetNNodes(subscip); SCIPdebugMessage("local branching used %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT" nodes\n", SCIPgetNNodes(subscip), nsubnodes); /* check, whether a solution was found */ if( SCIPgetNSols(subscip) > 0 ) { SCIP_SOL** subsols; int nsubsols; /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; for( i = 0; i < nsubsols && !success; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &success) ); } if( success ) { SCIPdebugMessage("-> accepted solution of value %g\n", SCIPgetSolOrigObj(subscip, subsols[i])); *result = SCIP_FOUNDSOL; } } /* check the status of the sub-MIP */ switch( SCIPgetStatus(subscip) ) { case SCIP_STATUS_OPTIMAL: case SCIP_STATUS_BESTSOLLIMIT: heurdata->callstatus = WAITFORNEWSOL; /* new solution will immediately be installed at next call */ SCIPdebugMessage(" -> found new solution\n"); break; case SCIP_STATUS_NODELIMIT: case SCIP_STATUS_STALLNODELIMIT: case SCIP_STATUS_TOTALNODELIMIT: heurdata->callstatus = EXECUTE; heurdata->curneighborhoodsize = (heurdata->emptyneighborhoodsize + heurdata->curneighborhoodsize)/2; heurdata->curminnodes *= 2; SCIPdebugMessage(" -> node limit reached: reduced neighborhood to %d, increased minnodes to %d\n", heurdata->curneighborhoodsize, heurdata->curminnodes); if( heurdata->curneighborhoodsize <= heurdata->emptyneighborhoodsize ) { heurdata->callstatus = WAITFORNEWSOL; SCIPdebugMessage(" -> new neighborhood was already proven to be empty: wait for new solution\n"); } break; case SCIP_STATUS_INFEASIBLE: case SCIP_STATUS_INFORUNBD: heurdata->emptyneighborhoodsize = heurdata->curneighborhoodsize; heurdata->curneighborhoodsize += heurdata->curneighborhoodsize/2; heurdata->curneighborhoodsize = MAX(heurdata->curneighborhoodsize, heurdata->emptyneighborhoodsize + 2); heurdata->callstatus = EXECUTE; SCIPdebugMessage(" -> neighborhood is empty: increased neighborhood to %d\n", heurdata->curneighborhoodsize); break; case SCIP_STATUS_UNKNOWN: case SCIP_STATUS_USERINTERRUPT: case SCIP_STATUS_TIMELIMIT: case SCIP_STATUS_MEMLIMIT: case SCIP_STATUS_GAPLIMIT: case SCIP_STATUS_SOLLIMIT: case SCIP_STATUS_UNBOUNDED: default: heurdata->callstatus = WAITFORNEWSOL; SCIPdebugMessage(" -> unexpected sub-MIP status <%d>: waiting for new solution\n", SCIPgetStatus(subscip)); break; } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** create the extra constraint of local branching and add it to subscip */ static SCIP_RETCODE addLocalBranchingConstraint( SCIP* scip, /**< SCIP data structure of the original problem */ SCIP* subscip, /**< SCIP data structure of the subproblem */ SCIP_VAR** subvars, /**< variables of the subproblem */ SCIP_HEURDATA* heurdata /**< heuristic's data structure */ ) { SCIP_CONS* cons; /* local branching constraint to create */ SCIP_VAR** consvars; SCIP_VAR** vars; SCIP_SOL* bestsol; int nbinvars; int i; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* consvals; char consname[SCIP_MAXSTRLEN]; (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_localbranchcons", SCIPgetProbName(scip)); /* get the data of the variables and the best solution */ SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, NULL, NULL, NULL) ); bestsol = SCIPgetBestSol(scip); assert( bestsol != NULL ); /* memory allocation */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) ); /* set initial left and right hand sides of local branching constraint */ lhs = (SCIP_Real)heurdata->emptyneighborhoodsize + 1.0; rhs = (SCIP_Real)heurdata->curneighborhoodsize; /* create the distance (to incumbent) function of the binary variables */ for( i = 0; i < nbinvars; i++ ) { SCIP_Real solval; solval = SCIPgetSolVal(scip, bestsol, vars[i]); assert( SCIPisFeasIntegral(scip,solval) ); /* is variable i part of the binary support of bestsol? */ if( SCIPisFeasEQ(scip,solval,1.0) ) { consvals[i] = -1.0; rhs -= 1.0; lhs -= 1.0; } else consvals[i] = 1.0; consvars[i] = subvars[i]; assert( SCIPvarGetType(consvars[i]) == SCIP_VARTYPE_BINARY ); } /* creates localbranching constraint and adds it to subscip */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, consname, nbinvars, consvars, consvals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free local memory */ SCIPfreeBufferArray(scip, &consvals); SCIPfreeBufferArray(scip, &consvars); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecCrossover) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; /* primal heuristic data */ SCIP* subscip; /* the subproblem created by crossover */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; /* original problem's variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_SOL** sols; SCIP_Real memorylimit; /* memory limit for the subproblem */ SCIP_Real timelimit; /* time limit for the subproblem */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real upperbound; SCIP_Bool success; SCIP_Longint nstallnodes; /* node limit for the subproblem */ int* selection; /* pool of solutions crossover uses */ int nvars; /* number of original problem's variables */ int nbinvars; int nintvars; int nusedsols; int i; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); nusedsols = heurdata->nusedsols; *result = SCIP_DELAYED; /* only call heuristic, if enough solutions are at hand */ if( SCIPgetNSols(scip) < nusedsols ) return SCIP_OKAY; sols = SCIPgetSols(scip); assert(sols != NULL); /* if one good solution was found, heuristic should not be delayed any longer */ if( sols[nusedsols-1] != heurdata->prevlastsol ) { heurdata->nextnodenumber = SCIPgetNNodes(scip); if( sols[0] != heurdata->prevbestsol ) heurdata->nfailures = 0; } /* in nonrandomized mode: only recall heuristic, if at least one new good solution was found in the meantime */ else if( !heurdata->randomization ) return SCIP_OKAY; /* if heuristic should be delayed, wait until certain number of nodes is reached */ if( SCIPgetNNodes(scip) < heurdata->nextnodenumber ) return SCIP_OKAY; /* only call heuristic, if enough nodes were processed since last incumbent */ if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip,SCIPgetBestSol(scip)) < heurdata->nwaitingnodes && (SCIPgetDepth(scip) > 0 || !heurdata->dontwaitatroot) ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* calculate the maximal number of branching nodes until heuristic is aborted */ nstallnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip)); /* reward Crossover if it succeeded often */ nstallnodes = (SCIP_Longint) (nstallnodes * (1.0 + 2.0*(SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0))); /* count the setup costs for the sub-MIP as 100 nodes */ nstallnodes -= 100 * SCIPheurGetNCalls(heur); nstallnodes += heurdata->nodesofs; /* determine the node limit for the current process */ nstallnodes -= heurdata->usednodes; nstallnodes = MIN(nstallnodes, heurdata->maxnodes); /* check whether we have enough nodes left to call subproblem solving */ if( nstallnodes < heurdata->minnodes ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); assert(nvars > 0); /* check whether discrete variables are available */ if( nbinvars == 0 && nintvars == 0 ) return SCIP_OKAY; /* initializing the subproblem */ SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); success = FALSE; if( heurdata->uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_crossoversub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_crossoversub", SCIPgetProbName(scip)); /* create the subproblem */ SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* copy all variables */ SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) ); } else { SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "crossover", TRUE, FALSE, TRUE, &success) ); if( heurdata->copycuts ) { /** copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) ); } } SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &selection, nusedsols) ); for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) (size_t) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); success = FALSE; /* create a new problem, which fixes variables with same value in a certain set of solutions */ SCIP_CALL( setupSubproblem(scip, subscip, subvars, selection, heurdata, &success) ); heurdata->prevbestsol = SCIPgetBestSol(scip); heurdata->prevlastsol = sols[heurdata->nusedsols-1]; /* if creation of sub-SCIP was aborted (e.g. due to number of fixings), free sub-SCIP and abort */ if( !success ) { *result = SCIP_DIDNOTRUN; /* this run will be counted as a failure since no new solution tuple could be generated or the neighborhood of the * solution was not fruitful in the sense that it was too big */ updateFailureStatistic(scip, heurdata); goto TERMINATE; } /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* check whether there is enough time and memory left */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) goto TERMINATE; /* set limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nstallnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving subMIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* use best estimate node selection */ if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ if( !SCIPisParamFixed(subscip, "conflict/useprop") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useinflp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useboundlp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usesb") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usepseudo") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); } /* add an objective cutoff */ cutoff = SCIPinfinity(scip); assert(!SCIPisInfinity(scip, SCIPgetUpperbound(scip))); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) ) { cutoff = (1-heurdata->minimprove)*SCIPgetUpperbound(scip) + heurdata->minimprove*SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound ( scip ) >= 0 ) cutoff = ( 1 - heurdata->minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + heurdata->minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff ); SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) ); /* permute the subproblem to increase diversification */ if( heurdata->permute ) { SCIP_CALL( SCIPpermuteProb(subscip, (unsigned int) SCIPheurGetNCalls(heur), TRUE, TRUE, TRUE, TRUE, TRUE) ); } /* solve the subproblem */ SCIPdebugMessage("Solve Crossover subMIP\n"); retcode = SCIPsolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process. * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in Crossover heuristic; sub-SCIP terminated with code <%d>\n", retcode); } heurdata->usednodes += SCIPgetNNodes(subscip); /* check, whether a solution was found */ if( SCIPgetNSols(subscip) > 0 ) { SCIP_SOL** subsols; int nsubsols; int solindex; /* index of the solution created by crossover */ /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; solindex = -1; for( i = 0; i < nsubsols && !success; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &solindex, &success) ); } if( success ) { int tmp; assert(solindex != -1); *result = SCIP_FOUNDSOL; /* insert all crossings of the new solution and (nusedsols-1) of its parents into the hashtable * in order to avoid incest ;) */ for( i = 0; i < nusedsols; i++ ) { SOLTUPLE* elem; tmp = selection[i]; selection[i] = solindex; SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) ); SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) ); selection[i] = tmp; } /* if solution was among the best ones, crossover should not be called until another good solution was found */ if( !heurdata->randomization ) { heurdata->prevbestsol = SCIPgetBestSol(scip); heurdata->prevlastsol = SCIPgetSols(scip)[heurdata->nusedsols-1]; } } /* if solution is not better then incumbent or could not be added to problem => run is counted as a failure */ if( !success || solindex != SCIPsolGetIndex(SCIPgetBestSol(scip)) ) updateFailureStatistic(scip, heurdata); } else { /* if no new solution was found, run was a failure */ updateFailureStatistic(scip, heurdata); } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &selection); SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecMutation) { /*lint --e{715}*/ SCIP_Longint maxnnodes; SCIP_Longint nsubnodes; /* node limit for the subproblem */ SCIP_HEURDATA* heurdata; /* heuristic's data */ SCIP* subscip; /* the subproblem created by mutation */ SCIP_VAR** vars; /* original problem's variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real maxnnodesr; SCIP_Real memorylimit; SCIP_Real timelimit; /* timelimit for the subproblem */ SCIP_Real upperbound; int nvars; /* number of original problem's variables */ int i; SCIP_Bool success; SCIP_RETCODE retcode; assert( heur != NULL ); assert( scip != NULL ); assert( result != NULL ); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); *result = SCIP_DELAYED; /* only call heuristic, if feasible solution is available */ if( SCIPgetNSols(scip) <= 0 ) return SCIP_OKAY; /* only call heuristic, if the best solution comes from transformed problem */ assert( SCIPgetBestSol(scip) != NULL ); if( SCIPsolIsOriginal(SCIPgetBestSol(scip)) ) return SCIP_OKAY; /* only call heuristic, if enough nodes were processed since last incumbent */ if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip,SCIPgetBestSol(scip)) < heurdata->nwaitingnodes) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* only call heuristic, if discrete variables are present */ if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 ) return SCIP_OKAY; /* calculate the maximal number of branching nodes until heuristic is aborted */ maxnnodesr = heurdata->nodesquot * SCIPgetNNodes(scip); /* reward mutation if it succeeded often, count the setup costs for the sub-MIP as 100 nodes */ maxnnodesr *= 1.0 + 2.0 * (SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur) + 1.0); maxnnodes = (SCIP_Longint) maxnnodesr - 100 * SCIPheurGetNCalls(heur); maxnnodes += heurdata->nodesofs; /* determine the node limit for the current process */ nsubnodes = maxnnodes - heurdata->usednodes; nsubnodes = MIN(nsubnodes, heurdata->maxnodes); /* check whether we have enough nodes left to call subproblem solving */ if( nsubnodes < heurdata->minnodes ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* initializing the subproblem */ SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); if( heurdata->uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_mutationsub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_mutationsub", SCIPgetProbName(scip)); /* create the subproblem */ SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* copy all variables */ SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) ); } else { SCIP_Bool valid; valid = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "rens", TRUE, FALSE, TRUE, &valid) ); if( heurdata->copycuts ) { /* copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) ); } SCIPdebugMessage("Copying the SCIP instance was %s complete.\n", valid ? "" : "not "); } for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); /* create a new problem, which fixes variables with same value in bestsol and LP relaxation */ SCIP_CALL( createSubproblem(scip, subscip, subvars, heurdata->minfixingrate, &heurdata->randseed, heurdata->uselprows) ); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* check whether there is enough time and memory left */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) goto TERMINATE; /* set limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nsubnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving subMIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* use best estimate node selection */ if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ if( !SCIPisParamFixed(subscip, "conflict/useprop") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useinflp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useboundlp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usesb") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usepseudo") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); } /* employ a limit on the number of enforcement rounds in the quadratic constraint handlers; this fixes the issue that * sometimes the quadratic constraint handler needs hundreds or thousands of enforcement rounds to determine the * feasibility status of a single node without fractional branching candidates by separation (namely for uflquad * instances); however, the solution status of the sub-SCIP might get corrupted by this; hence no decutions shall be * made for the original SCIP */ if( SCIPfindConshdlr(subscip, "quadratic") != NULL && !SCIPisParamFixed(subscip, "constraints/quadratic/enfolplimit") ) { SCIP_CALL( SCIPsetIntParam(subscip, "constraints/quadratic/enfolplimit", 10) ); } /* add an objective cutoff */ cutoff = SCIPinfinity(scip); assert( !SCIPisInfinity(scip, SCIPgetUpperbound(scip)) ); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip, -1.0 * SCIPgetLowerbound(scip)) ) { cutoff = (1-heurdata->minimprove) * SCIPgetUpperbound(scip) + heurdata->minimprove * SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound ( scip ) >= 0 ) cutoff = ( 1 - heurdata->minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + heurdata->minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff ); SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) ); /* solve the subproblem */ SCIPdebugMessage("Solve Mutation subMIP\n"); retcode = SCIPsolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in Mutation heuristic; sub-SCIP terminated with code <%d>\n",retcode); } heurdata->usednodes += SCIPgetNNodes(subscip); /* check, whether a solution was found */ if( SCIPgetNSols(subscip) > 0 ) { SCIP_SOL** subsols; int nsubsols; /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; for( i = 0; i < nsubsols && !success; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &success) ); } if( success ) *result = SCIP_FOUNDSOL; } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ unsigned int* randseed, /**< a seed value for the random number generator */ SCIP_Bool uselprows /**< should subproblem be created out of the rows in the LP rows? */ ) { SCIP_VAR** vars; /* original scip variables */ SCIP_SOL* sol; /* pool of solutions */ SCIP_Bool* marked; /* array of markers, which variables to fixed */ SCIP_Bool fixingmarker; /* which flag should label a fixed variable? */ int nvars; int nbinvars; int nintvars; int i; int j; int nmarkers; /* get required data of the original problem */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); sol = SCIPgetBestSol(scip); assert(sol != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &marked, nbinvars+nintvars) ); if( minfixingrate > 0.5 ) { nmarkers = nbinvars + nintvars - (int) SCIPfloor(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = FALSE; } else { nmarkers = (int) SCIPceil(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = TRUE; } assert( 0 <= nmarkers && nmarkers <= SCIPceil(scip,(nbinvars+nintvars)/2.0 ) ); j = 0; BMSclearMemoryArray(marked, nbinvars+nintvars); while( j < nmarkers ) { do { i = SCIPgetRandomInt(0, nbinvars+nintvars-1, randseed); } while( marked[i] ); marked[i] = TRUE; j++; } assert( j == nmarkers ); /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { /* fix all randomly marked variables */ if( marked[i] == fixingmarker ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, sol, vars[i]); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); assert(SCIPisLE(scip, lb, ub)); /* due to dual reductions, it may happen that the solution value is not in the variable's domain anymore */ if( SCIPisLT(scip, solval, lb) ) solval = lb; else if( SCIPisGT(scip, solval, ub) ) solval = ub; /* perform the bound change */ if( !SCIPisInfinity(scip, solval) && !SCIPisInfinity(scip, -solval) ) { SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], solval) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], solval) ); } } } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } } SCIPfreeBufferArray(scip, &marked); return SCIP_OKAY; }
/** evalutate solution */ SCIP_RETCODE LOPevalSolution( SCIP* scip /**< SCIP data structure */ ) { SCIP_PROBDATA* probdata; SCIP_VAR*** vars; SCIP_SOL* sol; int* outDegree; int* indices; int i; int j; int n; /* get problem data */ probdata = SCIPgetProbData(scip); assert( probdata != NULL ); assert( probdata->vars != NULL ); n = probdata->n; vars = probdata->vars; sol = SCIPgetBestSol(scip); if ( sol == NULL ) printf("\nNo solution found.\n"); else { SCIP_CALL( SCIPallocBufferArray(scip, &outDegree, n) ); SCIP_CALL( SCIPallocBufferArray(scip, &indices, n) ); /* compute out-degree */ for (i = 0; i < n; ++i) { int deg = 0; for (j = 0; j < n; ++j) { SCIP_Real val; if (j == i) continue; val = SCIPgetSolVal(scip, sol, vars[i][j]); assert( SCIPisIntegral(scip, val) ); if ( val < 0.5 ) ++deg; } outDegree[i] = deg; indices[i] = i; } /* sort such that degrees are non-decreasing */ SCIPsortIntInt(outDegree, indices, n); /* output */ printf("\nFinal order:\n"); for (i = 0; i < n; ++i) printf("%d ", indices[i]); printf("\n"); SCIPfreeBufferArray(scip, &indices); SCIPfreeBufferArray(scip, &outDegree); } return SCIP_OKAY; }