/** problem reading method of reader */ static SCIP_DECL_READERREAD(readerReadCnf) { /*lint --e{715}*/ SCIP_FILE* f; SCIP_RETCODE retcode; assert(reader != NULL); assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); assert(filename != NULL); assert(result != NULL); /* open file */ f = SCIPfopen(filename, "r"); if( f == NULL ) { SCIPerrorMessage("cannot open file <%s> for reading\n", filename); SCIPprintSysError(filename); return SCIP_NOFILE; } /* create problem */ SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* read cnf file */ retcode = readCnf(scip, f); /* close file */ SCIPfclose(f); *result = SCIP_SUCCESS; return retcode; }
/** create linear ordering problem instance */ SCIP_RETCODE LOPcreateProb( SCIP* scip, /**< SCIP data structure */ const char* filename /**< name of file to read */ ) { SCIP_PROBDATA* probdata = NULL; char probname[SCIP_MAXSTRLEN]; /* allocate memory */ SCIP_CALL( SCIPallocMemory(scip, &probdata) ); /* take filename as problem name */ SCIP_CALL( getProblemName(filename, probname, SCIP_MAXSTRLEN) ); SCIPinfoMessage(scip, NULL, "File name:\t\t%s\n", filename); SCIPinfoMessage(scip, NULL, "Problem name:\t\t%s\n", probname); /* read file */ SCIP_CALL( LOPreadFile(scip, filename, probdata) ); probdata->vars = NULL; SCIP_CALL( SCIPcreateProb(scip, probname, probdelorigLOP, NULL, NULL, NULL, NULL, probcopyLOP, probdata) ); return SCIP_OKAY; }
SCIPSolver::SCIPSolver(){ DBG("create a scip solver\n%s", ""); var_counter = 0; _verbosity = 0; has_been_added = false; // Load up SCIP SCIP_CALL_EXC( SCIPcreate(& _scip) ); // load default plugins linke separators, heuristics, etc. SCIP_CALL_EXC( SCIPincludeDefaultPlugins(_scip) ); // create an empty problem SCIP_CALL_EXC( SCIPcreateProb(_scip, "Numberjack Model", NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); // set the objective sense to maximize, default is minimize SCIP_CALL_EXC( SCIPsetObjsense(_scip, SCIP_OBJSENSE_MAXIMIZE) ); }
/** 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; }
/* 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; }
/** problem reading method of reader */ static SCIP_DECL_READERREAD(readerReadCip) { /*lint --e{715}*/ CIPINPUT cipinput; SCIP_Real objscale; SCIP_Real objoffset; SCIP_Bool initialconss; SCIP_Bool dynamicconss; SCIP_Bool dynamiccols; SCIP_Bool dynamicrows; SCIP_Bool initialvar; SCIP_Bool removablevar; SCIP_RETCODE retcode; if( NULL == (cipinput.file = SCIPfopen(filename, "r")) ) { SCIPerrorMessage("cannot open file <%s> for reading\n", filename); SCIPprintSysError(filename); return SCIP_NOFILE; } cipinput.len = 131071; SCIP_CALL( SCIPallocBufferArray(scip, &(cipinput.strbuf), cipinput.len) ); cipinput.linenumber = 0; cipinput.section = CIP_START; cipinput.haserror = FALSE; cipinput.endfile = FALSE; cipinput.readingsize = 65535; SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &initialconss) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &dynamiccols) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &dynamicconss) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &dynamicrows) ); initialvar = !dynamiccols; removablevar = dynamiccols; objscale = 1.0; objoffset = 0.0; while( cipinput.section != CIP_END && !cipinput.haserror ) { /* get next input string */ SCIP_CALL( getInputString(scip, &cipinput) ); if( cipinput.endfile ) break; switch( cipinput.section ) { case CIP_START: getStart(scip, &cipinput); break; case CIP_STATISTIC: SCIP_CALL( getStatistics(scip, &cipinput) ); break; case CIP_OBJECTIVE: SCIP_CALL( getObjective(scip, &cipinput, &objscale, &objoffset) ); break; case CIP_VARS: retcode = getVariable(scip, &cipinput, initialvar, removablevar, objscale); if( retcode == SCIP_READERROR ) { cipinput.haserror = TRUE; goto TERMINATE; } SCIP_CALL(retcode); break; case CIP_FIXEDVARS: retcode = getFixedVariable(scip, &cipinput); if( retcode == SCIP_READERROR ) { cipinput.haserror = TRUE; goto TERMINATE; } SCIP_CALL(retcode); break; case CIP_CONSTRAINTS: retcode = getConstraint(scip, &cipinput, initialconss, dynamicconss, dynamicrows); if( retcode == SCIP_READERROR ) { cipinput.haserror = TRUE; goto TERMINATE; } SCIP_CALL(retcode); break; default: SCIPerrorMessage("invalid CIP state\n"); SCIPABORT(); return SCIP_INVALIDDATA; /*lint !e527*/ } /*lint !e788*/ } if( !SCIPisZero(scip, objoffset) && !cipinput.haserror ) { SCIP_VAR* objoffsetvar; objoffset *= objscale; SCIP_CALL( SCIPcreateVar(scip, &objoffsetvar, "objoffset", objoffset, objoffset, 1.0, SCIP_VARTYPE_CONTINUOUS, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, objoffsetvar) ); SCIP_CALL( SCIPreleaseVar(scip, &objoffsetvar) ); SCIPdebugMessage("added variables <objoffset> for objective offset of <%g>\n", objoffset); } if( cipinput.section != CIP_END && !cipinput.haserror ) { SCIPerrorMessage("unexpected EOF\n"); } TERMINATE: /* close file stream */ SCIPfclose(cipinput.file); SCIPfreeBufferArray(scip, &cipinput.strbuf); if( cipinput.haserror ) return SCIP_READERROR; /* successfully parsed cip format */ *result = SCIP_SUCCESS; return SCIP_OKAY; }
/** main procedure of the RENS heuristic, creates and solves a subMIP */ SCIP_RETCODE SCIPapplyGcgrens( SCIP* scip, /**< original SCIP data structure */ SCIP_HEUR* heur, /**< heuristic data structure */ SCIP_RESULT* result, /**< result data structure */ SCIP_Real minfixingrate, /**< minimum percentage of integer variables that have to be fixed */ SCIP_Real minimprove, /**< factor by which RENS should at least improve the incumbent */ SCIP_Longint maxnodes, /**< maximum number of nodes for the subproblem */ SCIP_Longint nstallnodes, /**< number of stalling nodes for the subproblem */ SCIP_Bool binarybounds, /**< should general integers get binary bounds [floor(.),ceil(.)]? */ SCIP_Bool uselprows /**< should subproblem be created out of the rows in the LP rows? */ ) { SCIP* subscip; /* the subproblem created by RENS */ 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_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real timelimit; SCIP_Real memorylimit; int nvars; int i; SCIP_Bool success; SCIP_RETCODE retcode; assert(scip != NULL); assert(heur != NULL); assert(result != NULL); assert(maxnodes >= 0); assert(nstallnodes >= 0); assert(0.0 <= minfixingrate && minfixingrate <= 1.0); assert(0.0 <= minimprove && minimprove <= 1.0); SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* 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) ); if( uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_gcgrenssub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_gcgrenssub", 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; SCIP_HEURDATA* heurdata; valid = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "gcgrens", TRUE, FALSE, TRUE, &valid) ); /** @todo check for thread safeness */ /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); 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, minfixingrate, binarybounds, uselprows, &success) ); SCIPdebugMessage("RENS subproblem: %d vars, %d cons, success=%u\n", SCIPgetNVars(subscip), SCIPgetNConss(subscip), success); /* 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 */ 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) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; if( timelimit <= 0.0 || memorylimit <= 0.0 ) goto TERMINATE; /* set limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", nstallnodes) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving sub-SCIPs */ 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(scip, "estimate") != NULL ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(scip, "inference") != NULL ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); #ifdef SCIP_DEBUG /* for debugging RENS, enable MIP output */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) ); SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 100000000) ); #endif /* if the subproblem could not be created, free memory and return */ if( !success ) { *result = SCIP_DIDNOTRUN; SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; } /* if there is already a solution, add an objective cutoff */ if( SCIPgetNSols(scip) > 0 ) { SCIP_Real upperbound; assert( !SCIPisInfinity(scip,SCIPgetUpperbound(scip)) ); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) ) { cutoff = (1-minimprove)*SCIPgetUpperbound(scip) + minimprove*SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound ( scip ) >= 0 ) cutoff = ( 1 - minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff); SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) ); } /* presolve the subproblem */ retcode = SCIPpresolve(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 presolving subproblem in GCG RENS heuristic; sub-SCIP terminated with code <%d>\n",retcode); } SCIPdebugMessage("GCG RENS presolved subproblem: %d vars, %d cons, success=%u\n", SCIPgetNVars(subscip), SCIPgetNConss(subscip), success); /* after presolving, we should have at least reached a certain fixing rate over ALL variables (including continuous) * to ensure that not only the MIP but also the LP relaxation is easy enough */ if( ( nvars - SCIPgetNVars(subscip) ) / (SCIP_Real)nvars >= minfixingrate / 2.0 ) { SCIP_SOL** subsols; int nsubsols; /* solve the subproblem */ SCIPdebugMessage("solving subproblem: nstallnodes=%"SCIP_LONGINT_FORMAT", maxnodes=%"SCIP_LONGINT_FORMAT"\n", nstallnodes, maxnodes); 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 GCG RENS heuristic; sub-SCIP terminated with code <%d>\n",retcode); } /* 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; }
/** reduced cost pricing method of variable pricer for feasible LPs */ static SCIP_DECL_PRICERREDCOST(pricerRedcostBinpacking) { /*lint --e{715}*/ SCIP* subscip; SCIP_PRICERDATA* pricerdata; SCIP_CONS** conss; SCIP_VAR** vars; int* ids; SCIP_Bool addvar; SCIP_SOL** sols; int nsols; int s; int nitems; SCIP_Longint* values; SCIP_Longint* weights; SCIP_Longint* capacities; int nbins; int b; SCIP_Real timelimit; SCIP_Real memorylimit; SCIP_Real dualHallBound; assert(scip != NULL); assert(pricer != NULL); (*result) = SCIP_DIDNOTRUN; /* get the pricer data */ pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); capacities = pricerdata->capacities; conss = pricerdata->conss; ids = pricerdata->ids; values = pricerdata->values; weights = pricerdata->weights; nitems = pricerdata->nitems; nbins = pricerdata->nbins; dualHallBound = 0.0; // run pricing problem for each bin for (b = 0; b < nbins; ++b) { // assert(SCIPgetDualsolLinear(scip, conss[nitems+b])<= 0); // TODO edit if correct objsense dualHallBound -= SCIPgetDualsolLinear(scip, conss[nitems+b]); if (b < nbins-1 && capacities[b+1] == capacities[b]) continue; /* get the remaining time and memory limit */ SCIP_CALL(SCIPgetRealParam(scip, "limits/time", &timelimit)); if (!SCIPisInfinity(scip, timelimit)) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL(SCIPgetRealParam(scip, "limits/memory", &memorylimit)); if (!SCIPisInfinity(scip, memorylimit)) memorylimit -= SCIPgetMemUsed(scip) / 1048576.0; /* initialize SCIP */ SCIP_CALL(SCIPcreate(&subscip)); SCIP_CALL(SCIPincludeDefaultPlugins(subscip)); /* free sub SCIP */ SCIP_CALL(SCIPcreateProb(subscip, "pricing", NULL, NULL, NULL, NULL, NULL, NULL, NULL)); SCIP_CALL(SCIPsetObjsense(subscip, SCIP_OBJSENSE_MAXIMIZE)); /* 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)); /* set time and memory limit */ SCIP_CALL(SCIPsetRealParam(subscip, "limits/time", timelimit)); SCIP_CALL(SCIPsetRealParam(subscip, "limits/memory", memorylimit)); SCIP_CALL(SCIPallocMemoryArray(subscip, &vars, nitems)); /* initialization local pricing problem */ SCIP_CALL(initPricing(scip, pricerdata, subscip, vars, b)); SCIPdebugMessage("solve pricer problem\n"); /* solve sub SCIP */ SCIP_CALL(SCIPsolve(subscip)); sols = SCIPgetSols(subscip); nsols = SCIPgetNSols(subscip); addvar = FALSE; /* loop over all solutions and create the corresponding column to master if the reduced cost are negative for master, * that is the objective value i greater than 1.0 */ for (s = 0; s < nsols; ++s) { SCIP_Bool feasible; SCIP_SOL* sol; /* the soultion should be sorted w.r.t. the objective function value */ assert(s == 0 || SCIPisFeasGE(subscip, SCIPgetSolOrigObj(subscip, sols[s - 1]), SCIPgetSolOrigObj(subscip, sols[s]))); sol = sols[s]; assert(sol != NULL); /* check if solution is feasible in original sub SCIP */ SCIP_CALL(SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE)); if (!feasible) { SCIPwarningMessage("solution in pricing problem (capacity <%d>) is infeasible\n", capacities[b]); continue; } /* check if the solution has a value greater than 1.0 */ // First subscip? if (SCIPisFeasGT(scip, SCIPgetSolOrigObj(subscip, sol), dualHallBound)) { SCIP_VAR* var; SCIP_VARDATA* vardata; int* consids; char strtmp[SCIP_MAXSTRLEN]; char name[SCIP_MAXSTRLEN]; int nconss; int o; int v; SCIP_Longint totalvalue; SCIP_Longint totalweight; SCIPdebug(SCIP_CALL(SCIPprintSol(subscip, sol, NULL, FALSE))); nconss = 0; totalvalue = 0.0; totalweight = 0.0; (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "items"); SCIP_CALL(SCIPallocBufferArray(scip, &consids, nitems)); /* check which variables are fixed -> which item belongs to this packing */ for (o = 0, v = 0; o < nitems; ++o) { if (!SCIPconsIsEnabled(conss[o])) continue; assert(SCIPgetNFixedonesSetppc(scip, conss[o]) == 0); if (SCIPgetSolVal(subscip, sol, vars[v]) > 0.5) { (void) SCIPsnprintf(strtmp, SCIP_MAXSTRLEN, "_%d", ids[o]); strcat(name, strtmp); consids[nconss] = o; totalvalue+= values[o]; totalweight += weights[o]; nconss++; } else assert(SCIPisFeasEQ(subscip, SCIPgetSolVal(subscip, sol, vars[v]), 0.0)); v++; } SCIP_CALL(SCIPvardataCreateBinpacking(scip, &vardata, consids, nconss)); /* create variable for a new column with objective function coefficient 0.0 */ SCIP_CALL(SCIPcreateVarBinpacking(scip, &var, name, -totalvalue, FALSE, TRUE, vardata)); /* add the new variable to the pricer store */ SCIP_CALL(SCIPaddPricedVar(scip, var, 1.0)); addvar = TRUE; /* change the upper bound of the binary variable to lazy since the upper bound is already enforced due to * the objective function the set covering constraint; The reason for doing is that, is to avoid the bound * of x <= 1 in the LP relaxation since this bound constraint would produce a dual variable which might have * a positive reduced cost */ SCIP_CALL(SCIPchgVarUbLazy(scip, var, 1.0)); /* check which variable are fixed -> which orders belong to this packing */ for (v = 0; v < nconss; v++) { assert(SCIPconsIsEnabled(conss[consids[v]])); SCIP_CALL(SCIPaddCoefSetppc(scip, conss[consids[v]], var)); } /* add variable to hall constraints */ for (v = 0; v <= b; v++) { SCIP_CALL(SCIPaddCoefLinear(scip, conss[nitems+v], var, 1.0)); if (totalweight <= capacities[v] && v < b && capacities[b] != capacities[b+1]) break; } SCIPdebug(SCIPprintVar(scip, var, NULL)); SCIP_CALL(SCIPreleaseVar(scip, &var)); SCIPfreeBufferArray(scip, &consids); } else break; } /* free pricer MIP */ SCIPfreeMemoryArray(subscip, &vars); if (addvar || SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL) (*result) = SCIP_SUCCESS; /* free sub SCIP */ SCIP_CALL(SCIPfree(&subscip)); } 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; }
/** 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; }
/** sets up the problem data */ SCIP_RETCODE SCIPcreateProbColoring( SCIP* scip, /**< SCIP data structure */ const char* name, /**< problem name */ int nnodes, /**< number of nodes */ int nedges, /**< number of edges */ int** edges /**< array with start- and endpoints of the edges */ ) { int i; SCIP_PROBDATA* probdata = NULL; assert(nnodes > 0); /* at least one node */ assert(nedges >= 0); /* no negative number of edges */ printf("Creating problem: %s \n", name); /* allocate memory */ SCIP_CALL( SCIPallocMemory(scip, &probdata) ); /* create graph */ if( !tcliqueCreate(&((probdata)->oldgraph)) ) { SCIPerrorMessage("could not create the clique graph\n"); return SCIP_ERROR; } /* add all nodes from 0 to nnodes-1 */ if( !tcliqueAddNode((probdata)->oldgraph, nnodes-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } /* add all edges, first into cache, then flush to add all of them to the graph */ for ( i = 0; i < nedges; i++ ) { assert((edges[i][0] > 0) && (edges[i][0] <= nnodes)); assert((edges[i][1] > 0) && (edges[i][1] <= nnodes)); if( !tcliqueAddEdge((probdata)->oldgraph, edges[i][0]-1, edges[i][1]-1) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } } if( !tcliqueFlush((probdata)->oldgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } /* create constraints */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->constraints), nnodes) ); /* at the beginning memory for 2 sets */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->stablesets), 2) ); SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->stablesetlengths), 2) ); SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->stablesetvars), 2) ); probdata->maxstablesets = 2; probdata->nstablesets = 0; /* include variable deleted event handler into SCIP */ SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecProbdatavardeleted, NULL) ); /* create problem in SCIP */ SCIP_CALL( SCIPcreateProb(scip, name, probdelorigColoring, probtransColoring, probdeltransColoring, NULL, NULL, NULL, probdata) ); SCIP_CALL( preprocessGraph(scip) ); return SCIP_OKAY; }
/** creates a cumulative scheduling problem */ SCIP_RETCODE SCIPcreateSchedulingProblem( SCIP* scip, /**< SCIP data structure */ const char* problemname, /**< problem name */ const char** jobnames, /**< job names, or NULL */ const char** resourcenames, /**< resource names, or NULL */ int** demands, /**< demand matrix resource job demand */ SCIP_DIGRAPH* precedencegraph, /**< direct graph to store the precedence conditions */ int* durations, /**< array to store the processing for each job */ int* capacities, /**< array to store the different capacities */ int njobs, /**< number of jobs to be parsed */ int nresources /**< number of capacities to be parsed */ ) { SCIP_VAR** jobs; SCIP_VAR** vars; SCIP_VAR* var; SCIP_CONS* cons; char name[SCIP_MAXSTRLEN]; int* consdurations; int* consdemands; int nvars; int ubmakespan; int i; int j; int r; assert( scip != NULL ); assert( njobs >= 0 ); SCIPdebugMessage( "start method SCIPcreateSchedulingSMProblem\n"); /* create SCIP data structure */ SCIP_CALL( SCIPcreateProb(scip, problemname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* compute a feasible upper bound on the makespan */ ubmakespan = computeUbmakespan(durations, njobs); ubmakespan *= 100; /* allocate buffer for jobs and precedence constraints */ SCIP_CALL( SCIPallocBufferArray(scip, &jobs, njobs) ); /* create an activity constraint for each activity */ for( j = 0; j < njobs - 1; ++j ) /* but not for last job which is the makespan (-1) */ { /* construct variable name */ if( jobnames != NULL ) (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "start_%s", jobnames[j]); else (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "start_%d", j); /* create integer starting variable */ SCIP_CALL( SCIPcreateVar(scip, &var, name, 0.0, (SCIP_Real)ubmakespan, 0.0, SCIP_VARTYPE_INTEGER, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, var) ); SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) ); jobs[j] = var; SCIP_CALL( SCIPreleaseVar(scip, &var) ); } /* create makespan variable */ SCIP_CALL( SCIPcreateVar(scip, &var, "makespan", 0.0, (SCIP_Real)ubmakespan, 1.0, SCIP_VARTYPE_INTEGER, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, var) ); SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) ); jobs[njobs-1] = var; SCIP_CALL( SCIPreleaseVar(scip, &var) ); /* precedence constraints */ for( j = 0; j < njobs - 1; ++j ) { SCIP_VAR* predvar; int nsuccessors; nsuccessors = SCIPdigraphGetNSuccessors(precedencegraph, j); predvar = jobs[j]; assert(predvar != NULL); if( nsuccessors > 0 ) { int* successors; void** distances; successors = SCIPdigraphGetSuccessors(precedencegraph, j); distances = SCIPdigraphGetSuccessorsDatas(precedencegraph, j); for( i = 0; i < nsuccessors; ++i ) { SCIP_VAR* succvar; int distance; succvar = jobs[successors[i]]; assert(succvar != NULL); (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "precedences_(%d,%d)", j, successors[i]); distance = (int)(size_t)distances[i]; if( distance == INT_MAX ) distance = durations[j]; SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, predvar, succvar, -1.0, -SCIPinfinity(scip), -distance, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } else { /* add precedence constraints for those jobs without successor */ (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "precedences_(%d,%d)", j, njobs); SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, predvar, jobs[njobs-1], -1.0, -SCIPinfinity(scip), -durations[j], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } SCIP_CALL( SCIPallocBufferArray(scip, &vars, njobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &consdemands, njobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &consdurations, njobs) ); /* create resource constraints */ for( r = 0; r < nresources; ++r ) { nvars = 0; for( j = 0; j < njobs; ++j ) /* also makespan constraint! */ { if( demands[j][r] > 0 ) { vars[nvars] = jobs[j]; consdemands[nvars] = demands[j][r]; consdurations[nvars] = durations[j]; nvars++; } } if( nvars > 0 ) { /* construct constraint name */ if( resourcenames != NULL ) (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "R%s", resourcenames[r]); else (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "R%d", r); SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, consdurations, consdemands, capacities[r], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } /* initialize the problem specific heuristic */ SCIP_CALL( SCIPinitializeHeurListScheduling(scip, precedencegraph, jobs, durations, demands, capacities, njobs, nresources) ); /* free buffer array */ SCIPfreeBufferArray(scip, &consdurations); SCIPfreeBufferArray(scip, &consdemands); SCIPfreeBufferArray(scip, &vars); SCIPfreeBufferArray(scip, &jobs); return SCIP_OKAY; }