/** check whether there is enough capacity for one additional edge in the given adjacency list */ static SCIP_RETCODE ensureEdgeCapacity( SCIP* scip, /**< SCIP data structure */ SparseGraph* G, /**< graph */ unsigned int node /**< list for node */ ) { if( G->deg[node] + 2 > G->size[node] ) { unsigned int newSize; newSize = G->size[node] * 2; SCIP_CALL( SCIPreallocBufferArray(scip, &(G->A[node]), (int) newSize) ); /*lint !e866 */ SCIP_CALL( SCIPreallocBufferArray(scip, &(G->W[node]), (int) newSize) ); /*lint !e866 */ G->size[node] = newSize; } return SCIP_OKAY; }
/** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */ static SCIP_RETCODE getActiveVariables( SCIP* scip, /**< SCIP data structure */ SCIP_VAR** vars, /**< vars array to get active variables for */ SCIP_Real* scalars, /**< scalars a_1, ..., a_n inrc/scip/reader_ppm.c linear sum a_1*x_1 + ... + a_n*x_n + c */ int* nvars, /**< pointer to number of variables and values in vars and vals array */ SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ SCIP_Bool transformed /**< transformed constraint? */ ) { int requiredsize; int v; assert( scip != NULL ); assert( vars != NULL ); assert( scalars != NULL ); assert( nvars != NULL ); assert( constant != NULL ); if( transformed ) { SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) ); SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); assert( requiredsize <= *nvars ); } } else { for( v = 0; v < *nvars; ++v ) { SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &scalars[v], constant) ); } } 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; }
/** 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; }
/** Execute the branching of nodes with additional constraints. */ static SCIP_RETCODE Exec( SCIP* scip, /**< SCIP data structure */ SCIP_RESULT* result /**< pointer to store the result */ ) { SCIP_REOPTNODE* reoptnode; SCIP_NODE* curnode; SCIP_REOPTTYPE reopttype; SCIP_Bool localrestart; unsigned int* childids; unsigned int curid; int naddedconss; int nchilds; int childnodessize; int ncreatednodes; int c; assert(scip != NULL ); assert(SCIPisReoptEnabled(scip)); curnode = SCIPgetCurrentNode(scip); assert(curnode != NULL); curid = SCIPnodeGetReoptID(curnode); assert(curid >= 1 || SCIPgetRootNode(scip) == curnode); /* calculate local similarity and delete the induced subtree if the similarity is to low */ localrestart = FALSE; SCIP_CALL( SCIPcheckReoptRestart(scip, curnode, &localrestart) ); ncreatednodes = 0; if( localrestart ) { *result = SCIP_DIDNOTRUN; goto TERMINATE; } SCIPdebugMessage("current node is %lld, ID %u:\n", SCIPnodeGetNumber(curnode), curid); /* get the corresponding node of the reoptimization tree */ reoptnode = SCIPgetReoptnode(scip, curid); assert(reoptnode != NULL); reopttype = (SCIP_REOPTTYPE)SCIPreoptnodeGetType(reoptnode); /* The current node is equal to the root and dual reductions were performed. Since the root has a special role * within the reoptimiziation we have to split the root node into several nodes and move all stored child nodes to * the one representing the root node including all dual reductions as before. * * @note If the type is infsubtree, there cannot exist a child node and the method SCIPapplyReopt adds a global valid * constraint only. */ if( curid == 0 ) { if( reopttype == SCIP_REOPTTYPE_STRBRANCHED || reopttype == SCIP_REOPTTYPE_INFSUBTREE ) { int ncreatedchilds; /* apply the reoptimization at the root node */ SCIP_CALL( SCIPsplitReoptRoot(scip, &ncreatedchilds, &naddedconss) ); if( reopttype == SCIP_REOPTTYPE_INFSUBTREE ) { assert(ncreatedchilds == 0); assert(naddedconss == 1); /* there is nothing to do */ *result = SCIP_DIDNOTRUN; goto TERMINATE; } assert(reopttype == SCIP_REOPTTYPE_STRBRANCHED); assert(ncreatedchilds >= 2); ncreatednodes += ncreatedchilds; /* We decrease the counter by one because after splitting the root node and moving all children to the node * representing the original root with all fixings (caused by dual reductions), we continue reactivating the * original children nodes of the root. Thus, the node containing all the fixings can be replaced by the children * nodes */ --ncreatednodes; } goto REVIVE; } /* if we reach this part of the code the current has to be different to the root node */ assert(curid >= 1); REVIVE: /* get the IDs of all child nodes */ childnodessize = SCIPreoptnodeGetNChildren(reoptnode); SCIP_CALL( SCIPallocBufferArray(scip, &childids, childnodessize) ); SCIP_CALL( SCIPgetReoptChildIDs(scip, curnode, childids, childnodessize, &nchilds) ); if( childnodessize < nchilds ) { childnodessize = SCIPreoptnodeGetNChildren(reoptnode); SCIP_CALL( SCIPreallocBufferArray(scip, &childids, childnodessize) ); SCIP_CALL( SCIPgetReoptChildIDs(scip, curnode, childids, childnodessize, &nchilds) ); } assert(nchilds <= childnodessize); naddedconss = 0; for(c = 0; c < nchilds; c++) { SCIP_NODE** childnodes; SCIP_Bool success; unsigned int childid; int ncreatedchilds; childid = childids[c]; assert(childid >= 1); SCIPdebugMessage("process child at ID %u\n", childid); reoptnode = SCIPgetReoptnode(scip, childid); assert(reoptnode != NULL); reopttype = (SCIP_REOPTTYPE)SCIPreoptnodeGetType(reoptnode); ncreatedchilds = 0; /* check whether node need to be split */ if( reopttype == SCIP_REOPTTYPE_STRBRANCHED || reopttype == SCIP_REOPTTYPE_INFSUBTREE ) { /* by default we assume the node get split into two node (because using a constraint to split the node is * the default case */ childnodessize = 2; } else { /* we only need to reconstruct the node */ childnodessize = 1; } /* allocate buffer */ SCIP_CALL( SCIPallocBufferArray(scip, &childnodes, childnodessize) ); /* apply the reoptimization */ SCIP_CALL( SCIPapplyReopt(scip, reoptnode, childid, SCIPnodeGetEstimate(curnode), childnodes, &ncreatedchilds, &naddedconss, childnodessize, &success) ); if( !success ) { assert(ncreatedchilds > childnodessize); /* reallocate buffer memory */ childnodessize = ncreatedchilds+1; SCIP_CALL( SCIPreallocBufferArray(scip, &childnodes, childnodessize) ); /* apply the reoptimization */ SCIP_CALL( SCIPapplyReopt(scip, reoptnode, childid, SCIPnodeGetEstimate(curnode), childnodes, &ncreatedchilds, &naddedconss, childnodessize, &success) ); } assert(success); /* free buffer memory */ SCIPfreeBufferArray(scip, &childnodes); ncreatednodes += ncreatedchilds; } if( ncreatednodes == 0 ) *result = SCIP_DIDNOTRUN; else *result = SCIP_BRANCHED; /* free the buffer memory */ SCIPfreeBufferArray(scip, &childids); TERMINATE: SCIPdebugMessage("**** finish reoptimizing %d child nodes of node %lld ****\n", ncreatednodes, SCIPnodeGetNumber(curnode)); return SCIP_OKAY; }
/** get next input line; this are all characters until the next semicolon */ static SCIP_RETCODE getInputString( SCIP* scip, /**< SCIP data structure */ CIPINPUT* cipinput /**< CIP parsing data */ ) { char* endline; char* endcharacter; char* windowsendlinechar; assert(cipinput != NULL); /* read next line */ cipinput->endfile = (SCIPfgets(cipinput->strbuf, cipinput->len, cipinput->file) == NULL); if( cipinput->endfile ) { /* clear the line for safety reason */ BMSclearMemoryArray(cipinput->strbuf, cipinput->len); return SCIP_OKAY; } cipinput->linenumber++; endline = strchr(cipinput->strbuf, '\n'); endcharacter = strchr(cipinput->strbuf, ';'); while( endline == NULL || (endcharacter == NULL && cipinput->section == CIP_CONSTRAINTS && strncmp(cipinput->strbuf, "END", 3) != 0 ) ) { int pos; /* we refill the buffer from the '\n' character */ if( endline == NULL ) pos = cipinput->len - 1; else pos = (int) (endline - cipinput->strbuf); /* don't erase the '\n' from all buffers for constraints */ if( endline != NULL && cipinput->section == CIP_CONSTRAINTS ) pos++; /* if necessary reallocate memory */ if( pos + cipinput->readingsize >= cipinput->len ) { cipinput->len = SCIPcalcMemGrowSize(scip, pos + cipinput->readingsize); SCIP_CALL( SCIPreallocBufferArray(scip, &(cipinput->strbuf), cipinput->len) ); } /* read next line */ cipinput->endfile = (SCIPfgets(&(cipinput->strbuf[pos]), cipinput->len - pos, cipinput->file) == NULL); if( cipinput->endfile ) { /* clear the line for safety reason */ BMSclearMemoryArray(cipinput->strbuf, cipinput->len); return SCIP_OKAY; } cipinput->linenumber++; endline = strrchr(cipinput->strbuf, '\n'); endcharacter = strchr(cipinput->strbuf, ';'); } assert(endline != NULL); /*SCIPdebugMessage("read line: %s\n", cipinput->strbuf);*/ /* check for windows "carriage return" endline character */ windowsendlinechar = strrchr(cipinput->strbuf, '\r'); if( windowsendlinechar != NULL && windowsendlinechar + 1 == endline ) --endline; else /* if the assert should not hold we found a windows "carriage return" which was not at the end of the line */ assert(windowsendlinechar == NULL); if( cipinput->section == CIP_CONSTRAINTS && endcharacter != NULL && endline - endcharacter != 1 ) { SCIPerrorMessage("Constraint line has to end with ';\\n' (line: %d).\n", cipinput->linenumber); cipinput->haserror = TRUE; return SCIP_OKAY; /* return error at hightest level */ } *endline = '\0'; return SCIP_OKAY; }
/** read fixed variable */ static SCIP_RETCODE getFixedVariable( SCIP* scip, /**< SCIP data structure */ CIPINPUT* cipinput /**< CIP parsing data */ ) { SCIP_Bool success; SCIP_VAR* var; char* buf; char* endptr; char name[SCIP_MAXSTRLEN]; buf = cipinput->strbuf; if( strncmp(buf, "CONSTRAINTS", 11) == 0 ) cipinput->section = CIP_CONSTRAINTS; else if( strncmp(buf, "END", 3) == 0 ) cipinput->section = CIP_END; if( cipinput->section != CIP_FIXEDVARS ) return SCIP_OKAY; SCIPdebugMessage("parse fixed variable\n"); /* parse the variable */ SCIP_CALL( SCIPparseVar(scip, &var, buf, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL, &endptr, &success) ); if( !success ) { SCIPerrorMessage("syntax error in variable information (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } /* skip intermediate stuff */ buf = endptr; while ( *buf != '\0' && (*buf == ' ' || *buf == ',') ) ++buf; /* check whether variable is fixed */ if ( strncmp(buf, "fixed:", 6) == 0 ) { SCIP_CALL( SCIPaddVar(scip, var) ); SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) ); } else if ( strncmp(buf, "negated:", 8) == 0 ) { SCIP_CONS* lincons; SCIP_VAR* negvar; SCIP_Real vals[2]; SCIP_VAR* vars[2]; buf += 8; /* we can just parse the next variable (ignoring all other information in between) */ SCIP_CALL( SCIPparseVarName(scip, buf, &negvar, &endptr) ); if ( negvar == NULL ) { SCIPerrorMessage("could not parse negated variable (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } assert(SCIPvarIsBinary(var)); assert(SCIPvarIsBinary(negvar)); SCIP_CALL( SCIPaddVar(scip, var) ); SCIPdebugMessage("creating negated variable <%s> (of <%s>) ...\n", SCIPvarGetName(var), SCIPvarGetName(negvar) ); SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) ); /* add linear constraint for negation */ (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "neg_%s", SCIPvarGetName(var) ); vars[0] = var; vars[1] = negvar; vals[0] = 1.0; vals[1] = 1.0; SCIPdebugMessage("coupling constraint:\n"); SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, 2, vars, vals, 1.0, 1.0, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) ); SCIPdebugPrintCons(scip, lincons, NULL); SCIP_CALL( SCIPaddCons(scip, lincons) ); SCIP_CALL( SCIPreleaseCons(scip, &lincons) ); } else if ( strncmp(buf, "aggregated:", 11) == 0 ) { /* handle (multi-)aggregated variables */ SCIP_CONS* lincons; SCIP_Real* vals; SCIP_VAR** vars; SCIP_Real rhs = 0.0; const char* str; int nvarssize = 20; int requsize; int nvars; buf += 11; SCIPdebugMessage("parsing aggregated variable <%s> ...\n", SCIPvarGetName(var)); /* first parse constant */ if ( ! SCIPstrToRealValue(buf, &rhs, &endptr) ) { SCIPerrorMessage("expected constant when aggregated variable information (line: %d):\n%s\n", cipinput->linenumber, buf); cipinput->haserror = TRUE; return SCIP_OKAY; } /* check whether constant is 0.0 */ str = endptr; while ( *str != '\0' && isspace(*str) ) ++str; /* if next char is '<' we found a variable -> constant is 0 */ if ( *str != '<' ) { SCIPdebugMessage("constant: %f\n", rhs); buf = endptr; } else { /* otherwise keep buf */ rhs = 0.0; } /* initialize buffers for storing the variables and values */ SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvarssize) ); SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvarssize) ); vars[0] = var; vals[0] = -1.0; --nvarssize; /* parse linear sum to get variables and coefficients */ SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) ); if ( success && requsize > nvarssize ) { /* realloc buffers and try again */ nvarssize = requsize; SCIP_CALL( SCIPreallocBufferArray(scip, &vars, nvarssize + 1) ); SCIP_CALL( SCIPreallocBufferArray(scip, &vals, nvarssize + 1) ); SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) ); assert( ! success || requsize <= nvarssize); /* if successful, then should have had enough space now */ } if( success ) { /* add aggregated variable */ SCIP_CALL( SCIPaddVar(scip, var) ); /* special handling of variables that seem to be slack variables of indicator constraints */ str = SCIPvarGetName(var); if ( strncmp(str, "indslack", 8) == 0 ) { (void) strcpy(name, "indlin"); (void) strncat(name, str+8, SCIP_MAXSTRLEN-7); } else if ( strncmp(str, "t_indslack", 10) == 0 ) { (void) strcpy(name, "indlin"); (void) strncat(name, str+10, SCIP_MAXSTRLEN-7); } else (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var) ); /* add linear constraint for (multi-)aggregation */ SCIPdebugMessage("coupling constraint:\n"); SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars + 1, vars, vals, -rhs, -rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) ); SCIPdebugPrintCons(scip, lincons, NULL); SCIP_CALL( SCIPaddCons(scip, lincons) ); SCIP_CALL( SCIPreleaseCons(scip, &lincons) ); } else { SCIPwarningMessage(scip, "Could not read (multi-)aggregated variable <%s>: dependent variables unkown - consider changing the order (line: %d):\n%s\n", SCIPvarGetName(var), cipinput->linenumber, buf); } SCIPfreeBufferArray(scip, &vals); SCIPfreeBufferArray(scip, &vars); } else { SCIPerrorMessage("unknown section when parsing variables (line: %d):\n%s\n", cipinput->linenumber, buf); cipinput->haserror = TRUE; return SCIP_OKAY; } SCIP_CALL( SCIPreleaseVar(scip, &var) ); return SCIP_OKAY; }
/** ensure that maxindex + 1 rows can be represented in data arrays; memory gets reallocated with 10% extra space * to save some time for future allocations */ static SCIP_RETCODE heurdataEnsureArraySize( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int maxindex /**< row index at hand (size must be at least this large) */ ) { int newsize; int r; /* maxindex fits in current array -> nothing to do */ if( maxindex < heurdata->memsize ) return SCIP_OKAY; /* new memory size is the max index + 1 plus 10% additional space */ newsize = (int)SCIPfeasCeil(scip, (maxindex + 1) * 1.1); assert(newsize > heurdata->memsize); assert(heurdata->memsize >= 0); /* alloc memory arrays for row information */ if( heurdata->memsize == 0 ) { SCIP_VAR** vars; int v; int nvars; SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowinfinitiesdown, newsize) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowinfinitiesup, newsize) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowmeans, newsize) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowvariances, newsize) ); assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING); vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); assert(nvars > 0); /* allocate variable update event processing array storage */ SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->varfilterposs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->varposs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->updatedvars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->currentubs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->currentlbs, nvars) ); heurdata->varpossmemsize = nvars; heurdata->nupdatedvars = 0; /* init variable event processing data */ for( v = 0; v < nvars; ++v ) { assert(SCIPvarIsActive(vars[v])); assert(SCIPvarGetProbindex(vars[v]) == v); /* set up variable events to catch bound changes */ SCIP_CALL( SCIPcatchVarEvent(scip, vars[v], EVENT_DISTRIBUTION, heurdata->eventhdlr, NULL, &(heurdata->varfilterposs[v])) ); assert(heurdata->varfilterposs[v] >= 0); heurdata->varposs[v] = -1; heurdata->updatedvars[v] = NULL; heurdata->currentlbs[v] = SCIP_INVALID; heurdata->currentubs[v] = SCIP_INVALID; } } else { SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowinfinitiesdown, newsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowinfinitiesup, newsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowmeans, newsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowvariances, newsize) ); } /* loop over extended arrays and invalidate data to trigger initialization of this row when necessary */ for( r = heurdata->memsize; r < newsize; ++r ) { heurdata->rowmeans[r] = SCIP_INVALID; heurdata->rowvariances[r] = SCIP_INVALID; heurdata->rowinfinitiesdown[r] = 0; heurdata->rowinfinitiesup[r] = 0; } /* adjust memsize */ heurdata->memsize = newsize; return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecReoptsols) {/*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL** sols; SCIP_Real objsimsol; SCIP_Bool sepabestsol; int allocmem; int nchecksols; int nsolsadded; #ifdef SCIP_MORE_DEBUG int nsolsaddedrun; #endif int run; int max_run; assert(heur != NULL); assert(scip != NULL); *result = SCIP_DIDNOTRUN; if( !SCIPisReoptEnabled(scip) ) return SCIP_OKAY; heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); max_run = heurdata->maxruns == -1 ? 0 : MAX(0, SCIPgetNReoptRuns(scip)-1-heurdata->maxruns); /*lint !e666*/ nchecksols = heurdata->maxsols == -1 ? INT_MAX : heurdata->maxsols; SCIP_CALL( SCIPgetRealParam(scip, "reoptimization/objsimsol", &objsimsol) ); SCIP_CALL( SCIPgetBoolParam(scip, "reoptimization/sepabestsol", &sepabestsol) ); /* allocate a buffer array to store the solutions */ allocmem = 20; SCIP_CALL( SCIPallocBufferArray(scip, &sols, allocmem) ); nsolsadded = 0; for( run = SCIPgetNReoptRuns(scip); run > max_run && nchecksols > 0; run-- ) { SCIP_Real sim; int nsols; #ifdef SCIP_MORE_DEBUG nsolsaddedrun = 0; #endif nsols = 0; if( objsimsol == -1 ) sim = 1; else sim = SCIPgetReoptSimilarity(scip, run, SCIPgetNReoptRuns(scip)-1); if( sim >= objsimsol ) { int s; /* get solutions of a specific run */ SCIP_CALL( SCIPgetReopSolsRun(scip, run, sols, allocmem, &nsols) ); /* check memory and reallocate */ if( nsols > allocmem ) { allocmem = nsols; SCIP_CALL( SCIPreallocBufferArray(scip, &sols, allocmem) ); SCIP_CALL( SCIPgetReopSolsRun(scip, run, sols, allocmem, &nsols) ); } assert(nsols <= allocmem); /* update the solutions * stop, if the maximal number of solutions to be checked is reached */ for( s = 0; s < nsols && nchecksols > 0; s++ ) { SCIP_SOL* sol; SCIP_Real objsol; sol = sols[s]; SCIP_CALL( SCIPrecomputeSolObj(scip, sol) ); objsol = SCIPgetSolTransObj(scip, sol); /* we do not want to add solutions with objective value +infinity. * moreover, the solution should improve the current primal bound */ if( !SCIPisInfinity(scip, objsol) && !SCIPisInfinity(scip, -objsol) && SCIPisFeasLT(scip, objsol, SCIPgetCutoffbound(scip)) ) { SCIP_Bool stored; SCIP_Bool feasible; if( sepabestsol ) { SCIP_CALL( SCIPcheckSolOrig(scip, sol, &feasible, FALSE, TRUE) ); } else feasible = TRUE; if( feasible) { /* create a new solution */ SCIP_CALL( createNewSol(scip, heur, sol, &stored) ); if( stored ) { nsolsadded++; #ifdef SCIP_MORE_DEBUG nsolsaddedrun++; #endif heurdata->nimprovingsols++; } } } nchecksols--; heurdata->ncheckedsols++; } } #ifdef SCIP_MORE_DEBUG printf(">> heuristic <%s> found %d of %d improving solutions from run %d.\n", HEUR_NAME, nsolsaddedrun, nsols, run); #endif } SCIPdebugMessage(">> heuristic <%s> found %d improving solutions.\n", HEUR_NAME, nsolsadded); if( nsolsadded > 0 ) *result = SCIP_FOUNDSOL; else *result = SCIP_DIDNOTFIND; /* reset the marks of the checked solutions */ SCIPresetReoptSolMarks(scip); /* free the buffer array */ SCIPfreeBufferArray(scip, &sols); return SCIP_OKAY; }