/** adds coefficient to linear constraint (if it is not zero) */ JNIEXPORT void JNISCIPCONSLINEAR(addCoefLinear)( JNIEnv* env, /**< JNI environment variable */ jobject jobj, /**< JNI class pointer */ jlong jscip, /**< SCIP data structure */ jlong jcons, /**< constraint data */ jlong jvar, /**< variable of constraint entry */ jdouble val /**< coefficient of constraint entry */ ) { SCIP* scip; SCIP_CONS* cons; SCIP_VAR* var; /* convert JNI pointer into C pointer */ scip = (SCIP*) (size_t) jscip; assert(scip != NULL); /* convert JNI pointer into C pointer */ cons = (SCIP_CONS*) (size_t) jcons; assert( cons != NULL); /* convert JNI pointer into C pointer */ var = (SCIP_VAR*) (size_t) jvar; assert(var != NULL); JNISCIP_CALL( SCIPaddCoefLinear(scip, cons, var, (SCIP_Real) val) ); }
/** creates and captures a linear constraint * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the * method SCIPcreateConsLinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h * * @see SCIPcreateConsLinear() for information about the basic constraint flag configuration * * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() */ JNIEXPORT jlong JNISCIPCONSLINEAR(createConsBasicLinear)( JNIEnv* env, /**< JNI environment variable */ jobject jobj, /**< JNI class pointer */ jlong jscip, /**< SCIP data structure */ jstring jname, /**< name of constraint */ jint jnvars, /**< number of nonzeros in the constraint */ jlongArray jvars, /**< array with variables of constraint entries */ jdoubleArray jvals, /**< array with coefficients of constraint entries */ jdouble jlhs, /**< left hand side of constraint */ jdouble jrhs /**< right hand side of constraint */ ) { SCIP* scip; SCIP_CONS* cons; const char* name; int nvars; /* convert JNI pointer into C pointer */ scip = (SCIP*) (size_t) jscip; assert(scip != NULL); /* convert JNI string into C const char* */ name = (*env)->GetStringUTFChars(env, jname, NULL); if( name == NULL ) SCIPABORT(); /* create linear constraint with zero variables */ JNISCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 0, NULL, NULL, (SCIP_Real) jlhs, (SCIP_Real) jrhs) ); /* convert JNI integer into integer */ nvars = (int)jnvars; if( nvars > 0 ) { jlong* vars; jdouble* vals; int v; JNISCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); JNISCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) ); (*env)->GetLongArrayRegion(env, jvars, 0, nvars, vars); (*env)->GetDoubleArrayRegion(env, jvals, 0, nvars, vals); for( v = 0; v < nvars; ++v ) { JNISCIP_CALL( SCIPaddCoefLinear(scip, cons, (SCIP_VAR*)(size_t)vars[v], (SCIP_Real)vals[v])); } SCIPfreeBufferArray(scip, &vals); SCIPfreeBufferArray(scip, &vars); } /* relase string object */ (*env)->ReleaseStringUTFChars(env, jname, name); return (jlong)(size_t)cons; }
/** creates and captures a linear constraint * * @note the constraint gets captured, hence at one point you have to release it using the method {@link releaseCons()} */ JNIEXPORT jlong JNISCIPCONSLINEAR(createConsLinear)( JNIEnv* env, /**< JNI environment variable */ jobject jobj, /**< JNI class pointer */ jlong jscip, /**< SCIP data structure */ jstring jname, /**< name of constraint */ jint jnvars, /**< number of nonzeros in the constraint */ jlongArray jvars, /**< array with variables of constraint entries */ jdoubleArray jvals, /**< array with coefficients of constraint entries */ jdouble jlhs, /**< left hand side of constraint */ jdouble jrhs, /**< right hand side of constraint */ jboolean initial, /**< should the LP relaxation of constraint be in the initial LP? * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ jboolean separate, /**< should the constraint be separated during LP processing? * Usually set to TRUE. */ jboolean enforce, /**< should the constraint be enforced during node processing? * TRUE for model constraints, FALSE for additional, redundant constraints. */ jboolean check, /**< should the constraint be checked for feasibility? * TRUE for model constraints, FALSE for additional, redundant constraints. */ jboolean propagate, /**< should the constraint be propagated during node processing? * Usually set to TRUE. */ jboolean local, /**< is constraint only valid locally? * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ jboolean modifiable, /**< is constraint modifiable (subject to column generation)? * Usually set to FALSE. In column generation applications, set to TRUE if pricing * adds coefficients to this constraint. */ jboolean dynamic, /**< is constraint subject to aging? * Usually set to FALSE. Set to TRUE for own cuts which * are seperated as constraints. */ jboolean removable, /**< should the relaxation be removed from the LP due to aging or cleanup? * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ jboolean stickingatnode /**< should the constraint always be kept at the node where it was added, even * if it may be moved to a more global node? * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ ) { SCIP* scip; SCIP_CONS* cons; const char* name; int nvars; /* convert JNI pointer into C pointer */ scip = (SCIP*) (size_t) jscip; assert(scip != NULL); /* convert JNI string into C const char* */ name = (*env)->GetStringUTFChars(env, jname, NULL); if( name == NULL ) SCIPABORT(); /* create linear constraint with zero variables */ JNISCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 0, NULL, NULL, (SCIP_Real) jlhs, (SCIP_Real) jrhs, (SCIP_Bool) initial, (SCIP_Bool) separate, (SCIP_Bool) enforce, (SCIP_Bool) check, (SCIP_Bool) propagate, (SCIP_Bool) local, (SCIP_Bool) modifiable, (SCIP_Bool) dynamic, (SCIP_Bool) removable, (SCIP_Bool) stickingatnode) ); /* convert JNI integer into integer */ nvars = (int)jnvars; if( nvars > 0 ) { jlong* vars; jdouble* vals; int v; JNISCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); JNISCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) ); (*env)->GetLongArrayRegion(env, jvars, 0, nvars, vars); (*env)->GetDoubleArrayRegion(env, jvals, 0, nvars, vals); for( v = 0; v < nvars; ++v ) { JNISCIP_CALL( SCIPaddCoefLinear(scip, cons, (SCIP_VAR*)(size_t)vars[v], (SCIP_Real)vals[v])); } SCIPfreeBufferArray(scip, &vals); SCIPfreeBufferArray(scip, &vars); } /* relase string object */ (*env)->ReleaseStringUTFChars(env, jname, name); return (jlong)(size_t)cons; }
/** method for either Farkas or Redcost pricing */ static SCIP_RETCODE pricing( SCIP* scip, /**< SCIP data structure */ SCIP_PRICER* pricer, /**< pricer */ SCIP_Real* lowerbound, /**< lowerbound pointer */ SCIP_Bool farkas /**< TRUE: Farkas pricing; FALSE: Redcost pricing */ ) { SCIP_PRICERDATA* pricerdata; /* the data of the pricer */ SCIP_PROBDATA* probdata; GRAPH* graph; SCIP_VAR* var; PATH* path; SCIP_Real* edgecosts; /* edgecosts of the current subproblem */ char varname[SCIP_MAXSTRLEN]; SCIP_Real newlowerbound = -SCIPinfinity(scip); SCIP_Real redcost; /* reduced cost */ int tail; int e; int t; int i; assert(scip != NULL); assert(pricer != NULL); /* get pricer data */ pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); /* get problem data */ probdata = SCIPgetProbData(scip); assert(probdata != NULL); SCIPdebugMessage("solstat=%d\n", SCIPgetLPSolstat(scip)); if( !farkas && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) newlowerbound = SCIPgetSolTransObj(scip, NULL); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, NULL, NULL, FALSE) ) ); # if 0 if ( pricerdata->lowerbound <= 4 ) { char label[SCIP_MAXSTRLEN]; (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "X%g.gml", pricerdata->lowerbound); SCIP_CALL( SCIPprobdataPrintGraph(scip, label , NULL, TRUE) ); pricerdata->lowerbound++; } #endif /* get the graph*/ graph = SCIPprobdataGetGraph(probdata); /* get dual solutions and save them in mi and pi */ for( t = 0; t < pricerdata->realnterms; ++t ) { if( farkas ) { pricerdata->mi[t] = SCIPgetDualfarkasLinear(scip, pricerdata->pathcons[t]); } else { pricerdata->mi[t] = SCIPgetDualsolLinear(scip, pricerdata->pathcons[t]); assert(!SCIPisNegative(scip, pricerdata->mi[t])); } } for( e = 0; e < pricerdata->nedges; ++e ) { if( !pricerdata->bigt ) { for( t = 0; t < pricerdata->realnterms; ++t ) { if( farkas ) { pricerdata->pi[t * pricerdata->nedges + e] = SCIPgetDualfarkasLinear( scip, pricerdata->edgecons[t * pricerdata->nedges + e]); } else { pricerdata->pi[t * pricerdata->nedges + e] = SCIPgetDualsolLinear( scip, pricerdata->edgecons[t * pricerdata->nedges + e]); } } } else { if( farkas ) { pricerdata->pi[e] = SCIPgetDualfarkasLinear( scip, pricerdata->edgecons[e]); } else { pricerdata->pi[e] = SCIPgetDualsolLinear( scip, pricerdata->edgecons[e]); } } } SCIP_CALL( SCIPallocMemoryArray(scip, &path, graph->knots) ); SCIP_CALL( SCIPallocMemoryArray(scip, &edgecosts, pricerdata->nedges) ); if( pricerdata->bigt ) { for( e = 0; e < pricerdata->nedges; ++e ) { edgecosts[e] = (-pricerdata->pi[e]); } } /* find shortest r-t (r root, t terminal) paths and create corresponding variables iff reduced cost < 0 */ for( t = 0; t < pricerdata->realnterms; ++t ) { for( e = 0; e < pricerdata->nedges; ++e ) { if( !pricerdata->bigt ) { edgecosts[e] = (-pricerdata->pi[t * pricerdata->nedges + e]); } assert(!SCIPisNegative(scip, edgecosts[e])); } for( i = 0; i < graph->knots; i++ ) graph->mark[i] = 1; graph_path_exec(scip, graph, FSP_MODE, pricerdata->root, edgecosts, path); /* compute reduced cost of shortest path to terminal t */ redcost = 0.0; tail = pricerdata->realterms[t]; while( tail != pricerdata->root ) { redcost += edgecosts[path[tail].edge]; tail = graph->tail[path[tail].edge]; } redcost -= pricerdata->mi[t]; if( !farkas && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) { newlowerbound += redcost; } /* check if reduced cost < 0 */ if( SCIPisNegative(scip, redcost) ) { /* create variable to the shortest path (having reduced cost < 0) */ var = NULL; sprintf(varname, "PathVar%d_%d", t, pricerdata->ncreatedvars[t]); ++(pricerdata->ncreatedvars[t]); SCIP_CALL( SCIPcreateVarBasic(scip, &var, varname, 0.0, SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS) ); SCIP_CALL( SCIPaddPricedVar(scip, var, -redcost) ); tail = pricerdata->realterms[t]; while( tail != pricerdata->root ) { /* add variable to constraints */ if( !pricerdata->bigt ) { SCIP_CALL( SCIPaddCoefLinear(scip, pricerdata->edgecons[t * pricerdata->nedges + path[tail].edge], var, 1.0) ); } else { SCIP_CALL( SCIPaddCoefLinear(scip, pricerdata->edgecons[path[tail].edge], var, 1.0) ); } tail = graph->tail[path[tail].edge]; } SCIP_CALL( SCIPaddCoefLinear(scip, pricerdata->pathcons[t], var, 1.0) ); } } if( !farkas && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) *lowerbound = newlowerbound; SCIPfreeMemoryArray(scip, &edgecosts); SCIPfreeMemoryArray(scip, &path); return SCIP_OKAY; }
/** main procedure of the zeroobj heuristic, creates and solves a sub-SCIP */ SCIP_RETCODE SCIPapplyZeroobj( SCIP* scip, /**< original SCIP data structure */ SCIP_HEUR* heur, /**< heuristic data structure */ SCIP_RESULT* result, /**< result data structure */ SCIP_Real minimprove, /**< factor by which zeroobj should at least improve the incumbent */ SCIP_Longint nnodes /**< node limit for the subproblem */ ) { SCIP* subscip; /* the subproblem created by zeroobj */ 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_HEURDATA* heurdata; /* heuristic's private data structure */ SCIP_EVENTHDLR* eventhdlr; /* event handler for LP events */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real timelimit; /* time limit for zeroobj subproblem */ SCIP_Real memorylimit; /* memory limit for zeroobj subproblem */ SCIP_Real large; int nvars; /* number of original problem's variables */ int i; SCIP_Bool success; SCIP_Bool valid; SCIP_RETCODE retcode; SCIP_SOL** subsols; int nsubsols; assert(scip != NULL); assert(heur != NULL); assert(result != NULL); assert(nnodes >= 0); assert(0.0 <= minimprove && minimprove <= 1.0); *result = SCIP_DIDNOTRUN; /* only call heuristic once at the root */ if( SCIPgetDepth(scip) <= 0 && SCIPheurGetNCalls(heur) > 0 ) return SCIP_OKAY; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only call the heuristic if we do not have an incumbent */ if( SCIPgetNSolsFound(scip) > 0 && heurdata->onlywithoutsol ) 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; *result = SCIP_DIDNOTFIND; /* get variable data */ 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) ); /* different methods to create sub-problem: either copy LP relaxation or the CIP with all constraints */ valid = FALSE; /* copy complete SCIP instance */ SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "zeroobj", TRUE, FALSE, TRUE, &valid) ); SCIPdebugMessage("Copying the SCIP instance was %s complete.\n", valid ? "" : "not "); /* create event handler for LP events */ eventhdlr = NULL; SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecZeroobj, NULL) ); if( eventhdlr == NULL ) { SCIPerrorMessage("event handler for "HEUR_NAME" heuristic not found.\n"); return SCIP_PLUGINNOTFOUND; } /* determine large value to set variables to */ large = SCIPinfinity(scip); if( !SCIPisInfinity(scip, 0.1 / SCIPfeastol(scip)) ) large = 0.1 / SCIPfeastol(scip); /* get variable image and change to 0.0 in sub-SCIP */ for( i = 0; i < nvars; i++ ) { SCIP_Real adjustedbound; SCIP_Real lb; SCIP_Real ub; SCIP_Real inf; subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); SCIP_CALL( SCIPchgVarObj(subscip, subvars[i], 0.0) ); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); inf = SCIPinfinity(subscip); /* adjust infinite bounds in order to avoid that variables with non-zero objective * get fixed to infinite value in zeroobj subproblem */ if( SCIPisInfinity(subscip, ub ) ) { adjustedbound = MAX(large, lb+large); adjustedbound = MIN(adjustedbound, inf); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], adjustedbound) ); } if( SCIPisInfinity(subscip, -lb ) ) { adjustedbound = MIN(-large, ub-large); adjustedbound = MAX(adjustedbound, -inf); SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], adjustedbound) ); } } /* free hash map */ SCIPhashmapFree(&varmapfw); /* 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 limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/solutions", 1) ); /* forbid recursive call of heuristics and separators solving sub-SCIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable expensive techniques that merely work on the dual bound */ /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); if( !SCIPisParamFixed(subscip, "presolving/maxrounds") ) { SCIP_CALL( SCIPsetIntParam(subscip, "presolving/maxrounds", 50) ); } /* use best dfs node selection */ if( SCIPfindNodesel(subscip, "dfs") != NULL && !SCIPisParamFixed(subscip, "nodeselection/dfs/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/dfs/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/leastinf/priority", INT_MAX/4) ); } /* 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", 10) ); } /* disable feaspump and fracdiving */ if( !SCIPisParamFixed(subscip, "heuristics/feaspump/freq") ) { SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/feaspump/freq", -1) ); } if( !SCIPisParamFixed(subscip, "heuristics/fracdiving/freq") ) { SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/fracdiving/freq", -1) ); } /* restrict LP iterations */ SCIP_CALL( SCIPsetLongintParam(subscip, "lp/iterlim", 2*heurdata->maxlpiters / MAX(1,nnodes)) ); SCIP_CALL( SCIPsetLongintParam(subscip, "lp/rootiterlim", heurdata->maxlpiters) ); #ifdef SCIP_DEBUG /* for debugging zeroobj, enable MIP output */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) ); SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 100000000) ); #endif /* if there is already a solution, add an objective cutoff */ if( SCIPgetNSols(scip) > 0 ) { SCIP_Real upperbound; SCIP_CONS* origobjcons; #ifndef NDEBUG int nobjvars; nobjvars = 0; #endif cutoff = SCIPinfinity(scip); 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( SCIPcreateConsLinear(subscip, &origobjcons, "objbound_of_origscip", 0, NULL, NULL, -SCIPinfinity(subscip), cutoff, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); for( i = 0; i < nvars; ++i) { if( !SCIPisFeasZero(subscip, SCIPvarGetObj(vars[i])) ) { SCIP_CALL( SCIPaddCoefLinear(subscip, origobjcons, subvars[i], SCIPvarGetObj(vars[i])) ); #ifndef NDEBUG nobjvars++; #endif } } SCIP_CALL( SCIPaddCons(subscip, origobjcons) ); SCIP_CALL( SCIPreleaseCons(subscip, &origobjcons) ); assert(nobjvars == SCIPgetNObjVars(scip)); } /* catch LP events of sub-SCIP */ SCIP_CALL( SCIPtransformProb(subscip) ); SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_NODESOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) ); SCIPdebugMessage("solving subproblem: nnodes=%"SCIP_LONGINT_FORMAT"\n", nnodes); retcode = SCIPsolve(subscip); /* drop LP events of sub-SCIP */ SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_NODESOLVED, 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 zeroobj 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 || heurdata->addallsols); ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &success) ); if( success ) *result = SCIP_FOUNDSOL; } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif /* 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; }
/** 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; }
/** branching execution method for fractional LP solutions */ static SCIP_DECL_BRANCHEXECLP(branchExeclpStp) { /*lint --e{715}*/ SCIP_PROBDATA* probdata; SCIP_CONS* consin; SCIP_CONS* consout; SCIP_NODE* vertexin; SCIP_NODE* vertexout; SCIP_VAR** edgevars; SCIP_Real estimatein; SCIP_Real estimateout; GRAPH* g; int e; int branchvertex; assert(branchrule != NULL); assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); assert(scip != NULL); assert(result != NULL); SCIPdebugMessage("Execlp method of Stp branching\n "); estimatein = SCIPgetUpperbound(scip); estimateout = SCIPgetUpperbound(scip); *result = SCIP_DIDNOTRUN; /* get problem data */ probdata = SCIPgetProbData(scip); assert(probdata != NULL); /* get graph */ g = SCIPprobdataGetGraph(probdata); assert(g != NULL); /* get vertex to branch on */ SCIP_CALL( selectBranchingVertex(scip, &branchvertex) ); if( branchvertex == UNKNOWN ) { SCIPdebugMessage("Branching did not run \n"); return SCIP_OKAY; } edgevars = SCIPprobdataGetEdgeVars(scip); /* create constraints */ SCIP_CALL( SCIPcreateConsLinear(scip, &consin, "consin", 0, NULL, NULL, 1.0, 1.0, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) ); SCIP_CALL( SCIPcreateConsLinear(scip, &consout, "consout", 0, NULL, NULL, 0.0, 0.0, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) ); for( e = g->inpbeg[branchvertex]; e != EAT_LAST; e = g->ieat[e] ) { SCIP_CALL( SCIPaddCoefLinear(scip, consin, edgevars[e], 1.0) ); SCIP_CALL( SCIPaddCoefLinear(scip, consout, edgevars[e], 1.0) ); SCIP_CALL( SCIPaddCoefLinear(scip, consout, edgevars[flipedge(e)], 1.0) ); } /* create the child nodes */ SCIP_CALL( SCIPcreateChild(scip, &vertexin, 1.0, estimatein) ); SCIP_CALL( SCIPcreateChild(scip, &vertexout, 1.0, estimateout) ); assert(vertexin != NULL); assert(vertexout != NULL); SCIP_CALL( SCIPaddConsNode(scip, vertexin, consin, NULL) ); SCIP_CALL( SCIPaddConsNode(scip, vertexout, consout, NULL) ); /* relase constraints */ SCIP_CALL( SCIPreleaseCons(scip, &consin) ); SCIP_CALL( SCIPreleaseCons(scip, &consout) ); SCIPdebugMessage("Branched on stp vertex %d \n", branchvertex); *result = SCIP_BRANCHED; return SCIP_OKAY; }