/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */ static SCIP_DECL_CONSFREE(consFreeOrigbranch) { /*lint --e{715}*/ SCIP_CONSHDLRDATA* conshdlrData; assert(scip != NULL); assert(conshdlr != NULL); assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); conshdlrData = SCIPconshdlrGetData(conshdlr); assert(conshdlrData != NULL); SCIPdebugMessage("freeing branch orig constraint handler\n"); /* free constraint handler storage */ assert(conshdlrData->stack == NULL); if( conshdlrData->rootcons != NULL ) { SCIP_CALL( SCIPreleaseCons(scip, &conshdlrData->rootcons) ); } SCIPfreeMemory(scip, &conshdlrData); return SCIP_OKAY; }
/** frees the memory of the given problem data */ static SCIP_RETCODE probdataFree( SCIP* scip, /**< SCIP data structure */ SCIP_PROBDATA** probdata /**< pointer to problem data */ ) { int i; assert(scip != NULL); assert(probdata != NULL); /* release all variables */ for( i = 0; i < (*probdata)->nvars; ++i ) { SCIP_CALL( SCIPreleaseVar(scip, &(*probdata)->vars[i]) ); } /* release all constraints */ for( i = 0; i < (*probdata)->nitems; ++i ) { SCIP_CALL( SCIPreleaseCons(scip, &(*probdata)->conss[i]) ); } /* free memory of arrays */ SCIPfreeMemoryArray(scip, &(*probdata)->vars); SCIPfreeMemoryArray(scip, &(*probdata)->conss); SCIPfreeMemoryArray(scip, &(*probdata)->weights); SCIPfreeMemoryArray(scip, &(*probdata)->ids); /* free probdata */ SCIPfreeMemory(scip, probdata); return SCIP_OKAY; }
/** initialization method of variable pricer (called after problem was transformed) */ static SCIP_DECL_PRICERINIT(pricerInitBinpacking) { /*lint --e{715}*/ SCIP_PRICERDATA* pricerdata; SCIP_CONS* cons; int c; assert(scip != NULL); assert(pricer != NULL); pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); /* get transformed constraints */ for( c = 0; c < pricerdata->nitems; ++c ) { cons = pricerdata->conss[c]; /* release original constraint */ SCIP_CALL( SCIPreleaseCons(scip, &pricerdata->conss[c]) ); /* get transformed constraint */ SCIP_CALL( SCIPgetTransformedCons(scip, cons, &pricerdata->conss[c]) ); /* capture transformed constraint */ SCIP_CALL( SCIPcaptureCons(scip, pricerdata->conss[c]) ); } return SCIP_OKAY; }
/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */ static SCIP_DECL_CONSINITSOL(consInitsolOrigbranch) { /*lint --e{715}*/ SCIP_CONSHDLRDATA* conshdlrData; assert(scip != NULL); assert(conshdlr != NULL); assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); conshdlrData = SCIPconshdlrGetData(conshdlr); assert(conshdlrData != NULL); /* prepare stack */ SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrData->stack, conshdlrData->maxstacksize) ); assert( conshdlrData->nstack >= 0 ); /* check consistency */ if( conshdlrData->rootcons != NULL ) { SCIP_CALL( SCIPreleaseCons(scip, &conshdlrData->rootcons) ); conshdlrData->rootcons = NULL; --(conshdlrData->nstack); } GCGconsOrigbranchCheckConsistency(scip); return SCIP_OKAY; }
/** deletes the transformed problem */ static SCIP_DECL_PROBDELTRANS(probdeltransColoring) { int i; assert(scip != NULL); assert(probdata != NULL); /* relese constraints and free array for constraints */ for ( i = 0; i < tcliqueGetNNodes((*probdata)->graph); i++) { SCIP_CALL( SCIPreleaseCons(scip, &((*probdata)->constraints[i])) ); } SCIPfreeMemoryArray(scip, &((*probdata)->constraints)); /* free the arrays for the stable sets and relese the related variables */ for ( i = (*probdata)->nstablesets-1; i >= 0; i-- ) { SCIPfreeBlockMemoryArray(scip, &((*probdata)->stablesets[i]), (*probdata)->stablesetlengths[i]); /*lint !e866*/ SCIP_CALL( SCIPreleaseVar(scip, &((*probdata)->stablesetvars[i])) ); } SCIPfreeMemoryArray(scip, &((*probdata)->new2oldnode)); SCIPfreeMemoryArray(scip, &((*probdata)->deletednodes)); SCIPfreeMemoryArray(scip, &((*probdata)->stablesetvars)); SCIPfreeMemoryArray(scip, &((*probdata)->stablesetlengths)); SCIPfreeMemoryArray(scip, &((*probdata)->stablesets)); tcliqueFree(&(*probdata)->graph); SCIPfreeMemory(scip, probdata); return SCIP_OKAY; }
/** creates the rows of the subproblem */ static SCIP_RETCODE createRows( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars /**< the variables of the subproblem */ ) { SCIP_ROW** rows; /* original scip rows */ SCIP_CONS* cons; /* new constraint */ SCIP_VAR** consvars; /* new constraint's variables */ SCIP_COL** cols; /* original row's columns */ SCIP_Real constant; /* constant added to the row */ SCIP_Real lhs; /* left hand side of the row */ SCIP_Real rhs; /* left right side of the row */ SCIP_Real* vals; /* variables' coefficient values of the row */ int nrows; int nnonz; int i; int j; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert(lhs <= rhs); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } return SCIP_OKAY; }
/** presolving method of constraint handler */ static SCIP_DECL_CONSPRESOL(consPresolConjunction) { /*lint --e{715}*/ SCIP_CONSDATA* consdata; int c; int i; assert(result != NULL); *result = SCIP_DIDNOTFIND; /* all constraints in a conjunction constraint of the global problem can be added directly to the problem and * removed from the conjunction constraint; * an unmodifiable conjunction constraint can be deleted */ for( c = 0; c < nconss; ++c ) { consdata = SCIPconsGetData(conss[c]); assert(consdata != NULL); /* add all inactive constraints to the global problem */ for( i = 0; i < consdata->nconss; ++i ) { /* update check flag for sub constraints when upgrade takes place */ if( SCIPconsIsChecked(conss[c]) ) { /* make sure, the constraint is checked for feasibility */ SCIP_CALL( SCIPsetConsChecked(scip, consdata->conss[i], TRUE) ); } /* add constraint, if it is not active yet */ if( !SCIPconsIsActive(consdata->conss[i]) ) { SCIPdebugMessage("adding constraint <%s> from add conjunction <%s>\n", SCIPconsGetName(consdata->conss[i]), SCIPconsGetName(conss[c])); SCIP_CALL( SCIPaddCons(scip, consdata->conss[i]) ); *result = SCIP_SUCCESS; } /* release constraint because it will be removed from the conjunction constraint */ SCIP_CALL( SCIPreleaseCons(scip, &(consdata->conss[i])) ); } /* all constraints where removed, so we need to clear the array */ consdata->nconss = 0; /* delete conjunction constraint, if it is unmodifiable */ if( !SCIPconsIsModifiable(conss[c]) ) { SCIP_CALL( SCIPdelCons(scip, conss[c]) ); } } return SCIP_OKAY; }
/** exit method of constraint handler (called before problem is free transformed) */ static SCIP_DECL_CONSEXIT(consExitOrigbranch) { /*lint --e{715}*/ SCIP_CONSHDLRDATA* conshdlrdata; assert(conshdlr != NULL); assert(scip != NULL); conshdlrdata = SCIPconshdlrGetData(conshdlr); assert(conshdlrdata != NULL); SCIPdebugMessage("exiting transformed branch orig constraint handler\n"); if( conshdlrdata->rootcons != NULL ) { SCIP_CALL( SCIPreleaseCons(scip, &conshdlrdata->rootcons) ); conshdlrdata->rootcons = NULL; } return SCIP_OKAY; }
/** presolving method of constraint handler */ static SCIP_DECL_CONSPRESOL(consPresolDisjunction) { /*lint --e{715}*/ SCIP_CONSDATA* consdata; int oldndelconss; int c; assert(result != NULL); *result = SCIP_DIDNOTFIND; oldndelconss = *ndelconss; /* all disjunction constraints with one constraint can be replaced with that corresponding constraint */ for( c = 0; c < nconss; ++c ) { consdata = SCIPconsGetData(conss[c]); assert(consdata != NULL); if( !SCIPconsIsModifiable(conss[c]) && consdata->nconss == 1 ) { /* add constraint to the problem */ if( !SCIPconsIsActive(consdata->conss[0]) ) { SCIP_CALL( SCIPaddCons(scip, consdata->conss[0]) ); /* release constraint from the disjunction constraint */ SCIP_CALL( SCIPreleaseCons(scip, &consdata->conss[0]) ); } /* remove disjunction constraint */ SCIP_CALL( SCIPdelCons(scip, conss[0]) ); *result = SCIP_SUCCESS; } /* propagate constraint */ SCIP_CALL( propagateCons(scip, conss[c], ndelconss) ); } if( *ndelconss > oldndelconss ) *result = SCIP_SUCCESS; return SCIP_OKAY; }
/** solving process deinitialization method of variable pricer (called before branch and bound process data is freed) */ static SCIP_DECL_PRICEREXITSOL(pricerExitsolBinpacking) { SCIP_PRICERDATA* pricerdata; int c; assert(scip != NULL); assert(pricer != NULL); pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); /* get release constraints */ for (c = 0; c < pricerdata->nitems + pricerdata->nbins; ++c) { /* release constraint */ SCIP_CALL(SCIPreleaseCons(scip, &(pricerdata->conss[c]))); } return SCIP_OKAY; }
/** create linear ordering problem model */ SCIP_RETCODE LOPgenerateModel( SCIP* scip /**< SCIP data structure */ ) { SCIP_PROBDATA* probdata; SCIP_CONS* cons; int i, j; /* get problem data */ probdata = SCIPgetProbData(scip); assert( probdata != NULL ); /* generate variables */ SCIP_CALL( SCIPallocMemoryArray(scip, &probdata->vars, probdata->n) ); for (i = 0; i < probdata->n; ++i) { SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->vars[i]), probdata->n) ); /*lint !e866*/ for (j = 0; j < probdata->n; ++j) { if (j != i) { char s[SCIP_MAXSTRLEN]; (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "x#%d#%d", i, j); SCIP_CALL( SCIPcreateVar(scip, &(probdata->vars[i][j]), s, 0.0, 1.0, probdata->W[i][j], SCIP_VARTYPE_BINARY, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL)); SCIP_CALL( SCIPaddVar(scip, probdata->vars[i][j]) ); } else probdata->vars[i][j] = NULL; } } /* generate linear ordering constraint */ SCIP_CALL( SCIPcreateConsLinearOrdering(scip, &cons, "LOP", probdata->n, probdata->vars, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE)); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); /* set maximization */ SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); return SCIP_OKAY; }
/** frees constraint data and releases all constraints in conjunction */ static SCIP_RETCODE consdataFree( SCIP* scip, /**< SCIP data structure */ SCIP_CONSDATA** consdata /**< pointer to constraint data */ ) { int c; assert(consdata != NULL); assert(*consdata != NULL); /* release constraints */ for( c = 0; c < (*consdata)->nconss; ++c ) { SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->conss[c]) ); } /* free memory */ SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->conss, (*consdata)->consssize); SCIPfreeBlockMemory(scip, consdata); return SCIP_OKAY; }
static SCIP_DECL_PROBDELORIG(probdelorigColoring) { int i; assert(probdata != NULL); assert(*probdata != NULL); SCIPfreeMemoryArray(scip, &((*probdata)->new2oldnode)); SCIPfreeMemoryArray(scip, &((*probdata)->deletednodes)); for ( i = (*probdata)->nstablesets-1; i >= 0; i-- ) { SCIPfreeBlockMemoryArray(scip, &((*probdata)->stablesets[i]), (*probdata)->stablesetlengths[i]); /*lint !e866*/ SCIP_CALL( SCIPreleaseVar(scip, &((*probdata)->stablesetvars[i])) ); } SCIPfreeMemoryArray(scip, &((*probdata)->stablesetvars)); SCIPfreeMemoryArray(scip, &((*probdata)->stablesetlengths)); SCIPfreeMemoryArray(scip, &((*probdata)->stablesets)); /* release Constraints */ for ( i = 0; i < tcliqueGetNNodes((*probdata)->graph); i++ ) { SCIP_CALL( SCIPreleaseCons(scip, &((*probdata)->constraints[i])) ); } SCIPfreeMemoryArray(scip, &((*probdata)->constraints)); /* free memory used for graph */ tcliqueFree(&((*probdata)->graph)); tcliqueFree(&((*probdata)->oldgraph)); /* free probdata */ SCIPfreeMemory(scip, probdata); return SCIP_OKAY; }
/** read constraint */ static SCIP_RETCODE getConstraint( SCIP* scip, /**< SCIP data structure */ CIPINPUT* cipinput, /**< CIP parsing data */ SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ SCIP_Bool dynamic, /**< Is constraint subject to aging? * Usually set to FALSE. Set to TRUE for own cuts which * are separated as constraints. */ SCIP_Bool 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'. */ ) { SCIP_CONS* cons; char* buf; char* copybuf; SCIP_RETCODE retcode; SCIP_Bool separate; SCIP_Bool enforce; SCIP_Bool check; SCIP_Bool propagate; SCIP_Bool local; SCIP_Bool modifiable; SCIP_Bool success; int len; buf = cipinput->strbuf; if( strncmp(buf, "END", 3) == 0 ) { cipinput->section = CIP_END; return SCIP_OKAY; } SCIPdebugMessage("parse constraints in line %d\n", cipinput->linenumber); separate = TRUE; enforce = TRUE; check = TRUE; propagate = TRUE; local = FALSE; modifiable = FALSE; /* get length of line and check for correct ending of constraint line */ len = (int)strlen(buf); if( len < 1 ) { SCIPerrorMessage("syntax error: expected constraint in line %d.\n", cipinput->linenumber); cipinput->haserror = TRUE; return SCIP_OKAY; } if ( buf[len - 1] != ';' ) { SCIPerrorMessage("syntax error: line has to end with ';' (line: %d)\n", cipinput->linenumber); cipinput->haserror = TRUE; return SCIP_OKAY; } /* copy buffer for working purpose */ SCIP_CALL( SCIPduplicateMemoryArray(scip, ©buf, buf, len) ); copybuf[len - 1] = '\0'; /* parse the constraint */ retcode = SCIPparseCons(scip, &cons, copybuf, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, FALSE, &success); /* free temporary buffer */ SCIPfreeMemoryArray(scip, ©buf); SCIP_CALL( retcode ); if( !success ) { SCIPerrorMessage("syntax error when reading constraint (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } SCIP_CALL( SCIPaddCons(scip, cons) ); SCIPdebugPrintCons(scip, cons, NULL); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); return SCIP_OKAY; }
/** read fixed variable */ static SCIP_RETCODE getFixedVariable( SCIP* scip, /**< SCIP data structure */ CIPINPUT* cipinput /**< CIP parsing data */ ) { SCIP_Bool success; SCIP_VAR* var; char* buf; char* endptr; char name[SCIP_MAXSTRLEN]; buf = cipinput->strbuf; if( strncmp(buf, "CONSTRAINTS", 11) == 0 ) cipinput->section = CIP_CONSTRAINTS; else if( strncmp(buf, "END", 3) == 0 ) cipinput->section = CIP_END; if( cipinput->section != CIP_FIXEDVARS ) return SCIP_OKAY; SCIPdebugMessage("parse fixed variable\n"); /* parse the variable */ SCIP_CALL( SCIPparseVar(scip, &var, buf, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL, &endptr, &success) ); if( !success ) { SCIPerrorMessage("syntax error in variable information (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } /* skip intermediate stuff */ buf = endptr; while ( *buf != '\0' && (*buf == ' ' || *buf == ',') ) ++buf; /* check whether variable is fixed */ if ( strncmp(buf, "fixed:", 6) == 0 ) { SCIP_CALL( SCIPaddVar(scip, var) ); SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) ); } else if ( strncmp(buf, "negated:", 8) == 0 ) { SCIP_CONS* lincons; SCIP_VAR* negvar; SCIP_Real vals[2]; SCIP_VAR* vars[2]; buf += 8; /* we can just parse the next variable (ignoring all other information in between) */ SCIP_CALL( SCIPparseVarName(scip, buf, &negvar, &endptr) ); if ( negvar == NULL ) { SCIPerrorMessage("could not parse negated variable (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } assert(SCIPvarIsBinary(var)); assert(SCIPvarIsBinary(negvar)); SCIP_CALL( SCIPaddVar(scip, var) ); SCIPdebugMessage("creating negated variable <%s> (of <%s>) ...\n", SCIPvarGetName(var), SCIPvarGetName(negvar) ); SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) ); /* add linear constraint for negation */ (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "neg_%s", SCIPvarGetName(var) ); vars[0] = var; vars[1] = negvar; vals[0] = 1.0; vals[1] = 1.0; SCIPdebugMessage("coupling constraint:\n"); SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, 2, vars, vals, 1.0, 1.0, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) ); SCIPdebugPrintCons(scip, lincons, NULL); SCIP_CALL( SCIPaddCons(scip, lincons) ); SCIP_CALL( SCIPreleaseCons(scip, &lincons) ); } else if ( strncmp(buf, "aggregated:", 11) == 0 ) { /* handle (multi-)aggregated variables */ SCIP_CONS* lincons; SCIP_Real* vals; SCIP_VAR** vars; SCIP_Real rhs = 0.0; const char* str; int nvarssize = 20; int requsize; int nvars; buf += 11; SCIPdebugMessage("parsing aggregated variable <%s> ...\n", SCIPvarGetName(var)); /* first parse constant */ if ( ! SCIPstrToRealValue(buf, &rhs, &endptr) ) { SCIPerrorMessage("expected constant when aggregated variable information (line: %d):\n%s\n", cipinput->linenumber, buf); cipinput->haserror = TRUE; return SCIP_OKAY; } /* check whether constant is 0.0 */ str = endptr; while ( *str != '\0' && isspace(*str) ) ++str; /* if next char is '<' we found a variable -> constant is 0 */ if ( *str != '<' ) { SCIPdebugMessage("constant: %f\n", rhs); buf = endptr; } else { /* otherwise keep buf */ rhs = 0.0; } /* initialize buffers for storing the variables and values */ SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvarssize) ); SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvarssize) ); vars[0] = var; vals[0] = -1.0; --nvarssize; /* parse linear sum to get variables and coefficients */ SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) ); if ( success && requsize > nvarssize ) { /* realloc buffers and try again */ nvarssize = requsize; SCIP_CALL( SCIPreallocBufferArray(scip, &vars, nvarssize + 1) ); SCIP_CALL( SCIPreallocBufferArray(scip, &vals, nvarssize + 1) ); SCIP_CALL( SCIPparseVarsLinearsum(scip, buf, &(vars[1]), &(vals[1]), &nvars, nvarssize, &requsize, &endptr, &success) ); assert( ! success || requsize <= nvarssize); /* if successful, then should have had enough space now */ } if( success ) { /* add aggregated variable */ SCIP_CALL( SCIPaddVar(scip, var) ); /* special handling of variables that seem to be slack variables of indicator constraints */ str = SCIPvarGetName(var); if ( strncmp(str, "indslack", 8) == 0 ) { (void) strcpy(name, "indlin"); (void) strncat(name, str+8, SCIP_MAXSTRLEN-7); } else if ( strncmp(str, "t_indslack", 10) == 0 ) { (void) strcpy(name, "indlin"); (void) strncat(name, str+10, SCIP_MAXSTRLEN-7); } else (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var) ); /* add linear constraint for (multi-)aggregation */ SCIPdebugMessage("coupling constraint:\n"); SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars + 1, vars, vals, -rhs, -rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) ); SCIPdebugPrintCons(scip, lincons, NULL); SCIP_CALL( SCIPaddCons(scip, lincons) ); SCIP_CALL( SCIPreleaseCons(scip, &lincons) ); } else { SCIPwarningMessage(scip, "Could not read (multi-)aggregated variable <%s>: dependent variables unkown - consider changing the order (line: %d):\n%s\n", SCIPvarGetName(var), cipinput->linenumber, buf); } SCIPfreeBufferArray(scip, &vals); SCIPfreeBufferArray(scip, &vars); } else { SCIPerrorMessage("unknown section when parsing variables (line: %d):\n%s\n", cipinput->linenumber, buf); cipinput->haserror = TRUE; return SCIP_OKAY; } SCIP_CALL( SCIPreleaseVar(scip, &var) ); return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpRapidlearning) {/*lint --e{715}*/ SCIP* subscip; /* the subproblem created by rapid learning */ SCIP_SEPADATA* sepadata; /* separator's private data */ 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_HASHMAP* varmapbw; /* mapping of sub-SCIP variables to SCIP variables */ SCIP_CONSHDLR** conshdlrs; /* array of constraint handler's that might that might obtain conflicts */ int* oldnconss; /* number of constraints without rapid learning conflicts */ SCIP_Longint nodelimit; /* node limit for the subproblem */ SCIP_Real timelimit; /* time limit for the subproblem */ SCIP_Real memorylimit; /* memory limit for the subproblem */ int nconshdlrs; /* size of conshdlr and oldnconss array */ int nfixedvars; /* number of variables that could be fixed by rapid learning */ int nvars; /* number of variables */ int restartnum; /* maximal number of conflicts that should be created */ int i; /* counter */ SCIP_Bool success; /* was problem creation / copying constraint successful? */ SCIP_RETCODE retcode; /* used for catching sub-SCIP errors in debug mode */ int nconflicts; /* statistic: number of conflicts applied */ int nbdchgs; /* statistic: number of bound changes applied */ int n1startinfers; /* statistic: number of one side infer values */ int n2startinfers; /* statistic: number of both side infer values */ SCIP_Bool soladded; /* statistic: was a new incumbent found? */ SCIP_Bool dualboundchg; /* statistic: was a new dual bound found? */ SCIP_Bool disabledualreductions; /* TRUE, if dual reductions in sub-SCIP are not valid for original SCIP, * e.g., because a constraint could not be copied or a primal solution * could not be copied back */ int ndiscvars; soladded = FALSE; assert(sepa != NULL); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; ndiscvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip)+SCIPgetNImplVars(scip); /* only run when still not fixed binary variables exists */ if( ndiscvars == 0 ) return SCIP_OKAY; /* get separator's data */ sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); /* only run for integer programs */ if( !sepadata->contvars && ndiscvars != SCIPgetNVars(scip) ) return SCIP_OKAY; /* only run if there are few enough continuous variables */ if( sepadata->contvars && SCIPgetNContVars(scip) > sepadata->contvarsquot * SCIPgetNVars(scip) ) return SCIP_OKAY; /* do not run if pricers are present */ if( SCIPgetNActivePricers(scip) > 0 ) return SCIP_OKAY; /* if the separator should be exclusive to the root node, this prevents multiple calls due to restarts */ if( SCIPsepaGetFreq(sepa) == 0 && SCIPsepaGetNCalls(sepa) > 0) return SCIP_OKAY; /* call separator at most once per node */ if( SCIPsepaGetNCallsAtNode(sepa) > 0 ) return SCIP_OKAY; /* do not call rapid learning, if the problem is too big */ if( SCIPgetNVars(scip) > sepadata->maxnvars || SCIPgetNConss(scip) > sepadata->maxnconss ) 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) ); SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); success = FALSE; /* copy the subproblem */ SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "rapid", FALSE, FALSE, &success) ); if( sepadata->copycuts ) { /** copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, FALSE) ); } for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) (size_t) SCIPhashmapGetImage(varmapfw, vars[i]); SCIPhashmapFree(&varmapfw); /* this avoids dual presolving */ if( !success ) { for( i = 0; i < nvars; i++ ) { SCIP_CALL( SCIPaddVarLocks(subscip, subvars[i], 1, 1 ) ); } } SCIPdebugMessage("Copying SCIP was%s successful.\n", success ? "" : " not"); /* mimic an FD solver: DFS, no LP solving, 1-FUIP instead of all-FUIP */ SCIP_CALL( SCIPsetIntParam(subscip, "lp/solvefreq", -1) ); SCIP_CALL( SCIPsetIntParam(subscip, "conflict/fuiplevels", 1) ); SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/dfs/stdpriority", INT_MAX/4) ); SCIP_CALL( SCIPsetBoolParam(subscip, "constraints/disableenfops", TRUE) ); SCIP_CALL( SCIPsetIntParam(subscip, "propagating/pseudoobj/freq", -1) ); /* use inference branching */ SCIP_CALL( SCIPsetBoolParam(subscip, "branching/inference/useweightedsum", FALSE) ); /* only create short conflicts */ SCIP_CALL( SCIPsetRealParam(subscip, "conflict/maxvarsfac", 0.05) ); /* set limits for the subproblem */ nodelimit = SCIPgetNLPIterations(scip); nodelimit = MAX(sepadata->minnodes, nodelimit); nodelimit = MIN(sepadata->maxnodes, nodelimit); restartnum = 1000; /* 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) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; if( timelimit <= 0.0 || memorylimit <= 0.0 ) goto TERMINATE; SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit/5) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/restarts", 0) ); SCIP_CALL( SCIPsetIntParam(subscip, "conflict/restartnum", restartnum) ); /* 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) ); /* 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 /* add an objective cutoff */ SCIP_CALL( SCIPsetObjlimit(subscip, SCIPgetUpperbound(scip)) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapbw, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nvars)) ); /* store reversing mapping of variables */ SCIP_CALL( SCIPtransformProb(subscip) ); for( i = 0; i < nvars; ++i) { SCIP_CALL( SCIPhashmapInsert(varmapbw, SCIPvarGetTransVar(subvars[i]), vars[i]) ); } /** allocate memory for constraints storage. Each constraint that will be created from now on will be a conflict. * Therefore, we need to remember oldnconss to get the conflicts from the FD search. */ nconshdlrs = 4; SCIP_CALL( SCIPallocBufferArray(scip, &conshdlrs, nconshdlrs) ); SCIP_CALL( SCIPallocBufferArray(scip, &oldnconss, nconshdlrs) ); /* store number of constraints before rapid learning search */ conshdlrs[0] = SCIPfindConshdlr(subscip, "bounddisjunction"); conshdlrs[1] = SCIPfindConshdlr(subscip, "setppc"); conshdlrs[2] = SCIPfindConshdlr(subscip, "linear"); conshdlrs[3] = SCIPfindConshdlr(subscip, "logicor"); /* redundant constraints might be eliminated in presolving */ SCIP_CALL( SCIPpresolve(subscip)); for( i = 0; i < nconshdlrs; ++i) { if( conshdlrs[i] != NULL ) oldnconss[i] = SCIPconshdlrGetNConss(conshdlrs[i]); } nfixedvars = SCIPgetNFixedVars(scip); /* solve the subproblem */ 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("Error while solving subproblem in rapid learning separator; sub-SCIP terminated with code <%d>\n",retcode); } /* abort solving, if limit of applied conflicts is reached */ if( SCIPgetNConflictConssApplied(subscip) >= restartnum ) { SCIPdebugMessage("finish after %lld successful conflict calls.\n", SCIPgetNConflictConssApplied(subscip)); } /* if the first 20% of the solution process were successful, proceed */ else if( (sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 && SCIPisFeasLT(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) ) || (sepadata->applybdchgs && SCIPgetNFixedVars(subscip) > nfixedvars) || (sepadata->applyconflicts && SCIPgetNConflictConssApplied(subscip) > 0) ) { SCIPdebugMessage("proceed solving after the first 20%% of the solution process, since:\n"); if( SCIPgetNSols(subscip) > 0 && SCIPisFeasLE(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) ) { SCIPdebugMessage(" - there was a better solution (%f < %f)\n",SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip)); } if( SCIPgetNFixedVars(subscip) > nfixedvars ) { SCIPdebugMessage(" - there were %d variables fixed\n", SCIPgetNFixedVars(scip)-nfixedvars ); } if( SCIPgetNConflictConssFound(subscip) > 0 ) { SCIPdebugMessage(" - there were %lld conflict constraints created\n", SCIPgetNConflictConssApplied(subscip)); } /* set node limit to 100% */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit) ); /* solve the subproblem */ 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("Error while solving subproblem in rapid learning separator; sub-SCIP terminated with code <%d>\n",retcode); } } else { SCIPdebugMessage("do not proceed solving after the first 20%% of the solution process.\n"); } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif disabledualreductions = FALSE; /* check, whether a solution was found */ if( sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 && SCIPfindHeur(scip, "trysol") != NULL ) { SCIP_HEUR* heurtrysol; 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 was declared to be feasible */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); soladded = FALSE; heurtrysol = SCIPfindHeur(scip, "trysol"); /* sequentially add solutions to trysol heuristic */ for( i = 0; i < nsubsols && !soladded; ++i ) { SCIPdebugMessage("Try to create new solution by copying subscip solution.\n"); SCIP_CALL( createNewSol(scip, subscip, subvars, heurtrysol, subsols[i], &soladded) ); } if( !soladded || !SCIPisEQ(scip, SCIPgetSolOrigObj(subscip, subsols[i-1]), SCIPgetSolOrigObj(subscip, subsols[0])) ) disabledualreductions = TRUE; } /* if the sub problem was solved completely, we update the dual bound */ dualboundchg = FALSE; if( sepadata->applysolved && !disabledualreductions && (SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL || SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE) ) { /* we need to multiply the dualbound with the scaling factor and add the offset, * because this information has been disregarded in the sub-SCIP */ SCIPdebugMessage("Update old dualbound %g to new dualbound %g.\n", SCIPgetDualbound(scip), SCIPgetTransObjscale(scip) * SCIPgetDualbound(subscip) + SCIPgetTransObjoffset(scip)); SCIP_CALL( SCIPupdateLocalDualbound(scip, SCIPgetDualbound(subscip) * SCIPgetTransObjscale(scip) + SCIPgetTransObjoffset(scip)) ); dualboundchg = TRUE; } /* check, whether conflicts were created */ nconflicts = 0; if( sepadata->applyconflicts && !disabledualreductions && SCIPgetNConflictConssApplied(subscip) > 0 ) { SCIP_HASHMAP* consmap; int hashtablesize; assert(SCIPgetNConflictConssApplied(subscip) < (SCIP_Longint) INT_MAX); hashtablesize = (int) SCIPgetNConflictConssApplied(subscip); assert(hashtablesize < INT_MAX/5); hashtablesize *= 5; /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), SCIPcalcHashtableSize(hashtablesize)) ); /* loop over all constraint handlers that might contain conflict constraints */ for( i = 0; i < nconshdlrs; ++i) { /* copy constraints that have been created in FD run */ if( conshdlrs[i] != NULL && SCIPconshdlrGetNConss(conshdlrs[i]) > oldnconss[i] ) { SCIP_CONS** conss; int c; int nconss; nconss = SCIPconshdlrGetNConss(conshdlrs[i]); conss = SCIPconshdlrGetConss(conshdlrs[i]); /* loop over all constraints that have been added in sub-SCIP run, these are the conflicts */ for( c = oldnconss[i]; c < nconss; ++c) { SCIP_CONS* cons; SCIP_CONS* conscopy; cons = conss[c]; assert(cons != NULL); success = FALSE; SCIP_CALL( SCIPgetConsCopy(subscip, scip, cons, &conscopy, conshdlrs[i], varmapbw, consmap, NULL, SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), TRUE, FALSE, SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), FALSE, TRUE, &success) ); if( success ) { nconflicts++; SCIP_CALL( SCIPaddCons(scip, conscopy) ); SCIP_CALL( SCIPreleaseCons(scip, &conscopy) ); } else { SCIPdebugMessage("failed to copy conflict constraint %s back to original SCIP\n", SCIPconsGetName(cons)); } } } } SCIPhashmapFree(&consmap); } /* check, whether tighter global bounds were detected */ nbdchgs = 0; if( sepadata->applybdchgs && !disabledualreductions ) for( i = 0; i < nvars; ++i ) { SCIP_Bool infeasible; SCIP_Bool tightened; assert(SCIPisLE(scip, SCIPvarGetLbGlobal(vars[i]), SCIPvarGetLbGlobal(subvars[i]))); assert(SCIPisLE(scip, SCIPvarGetLbGlobal(subvars[i]), SCIPvarGetUbGlobal(subvars[i]))); assert(SCIPisLE(scip, SCIPvarGetUbGlobal(subvars[i]), SCIPvarGetUbGlobal(vars[i]))); /* update the bounds of the original SCIP, if a better bound was proven in the sub-SCIP */ SCIP_CALL( SCIPtightenVarUb(scip, vars[i], SCIPvarGetUbGlobal(subvars[i]), FALSE, &infeasible, &tightened) ); if( tightened ) nbdchgs++; SCIP_CALL( SCIPtightenVarLb(scip, vars[i], SCIPvarGetLbGlobal(subvars[i]), FALSE, &infeasible, &tightened) ); if( tightened ) nbdchgs++; } n1startinfers = 0; n2startinfers = 0; /* install start values for inference branching */ if( sepadata->applyinfervals && (!sepadata->reducedinfer || soladded || nbdchgs+nconflicts > 0) ) { for( i = 0; i < nvars; ++i ) { SCIP_Real downinfer; SCIP_Real upinfer; SCIP_Real downvsids; SCIP_Real upvsids; SCIP_Real downconflen; SCIP_Real upconflen; /* copy downwards branching statistics */ downvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); downconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); downinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); /* copy upwards branching statistics */ upvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); upconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); upinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); /* memorize statistics */ if( downinfer+downconflen+downvsids > 0.0 || upinfer+upconflen+upvsids != 0 ) n1startinfers++; if( downinfer+downconflen+downvsids > 0.0 && upinfer+upconflen+upvsids != 0 ) n2startinfers++; SCIP_CALL( SCIPinitVarBranchStats(scip, vars[i], 0.0, 0.0, downvsids, upvsids, downconflen, upconflen, downinfer, upinfer, 0.0, 0.0) ); } } SCIPdebugPrintf("XXX Rapidlearning added %d conflicts, changed %d bounds, %s primal solution, %s dual bound improvement.\n", nconflicts, nbdchgs, soladded ? "found" : "no", dualboundchg ? "found" : "no"); SCIPdebugPrintf("YYY Infervalues initialized on one side: %5.2f %% of variables, %5.2f %% on both sides\n", 100.0 * n1startinfers/(SCIP_Real)nvars, 100.0 * n2startinfers/(SCIP_Real)nvars); /* change result pointer */ if( nconflicts > 0 || dualboundchg ) *result = SCIP_CONSADDED; else if( nbdchgs > 0 ) *result = SCIP_REDUCEDDOM; /* free local data */ SCIPfreeBufferArray(scip, &oldnconss); SCIPfreeBufferArray(scip, &conshdlrs); SCIPhashmapFree(&varmapbw); TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** initializes the pricing problem for the given capacity */ static SCIP_RETCODE initPricing( SCIP* scip, /**< SCIP data structure */ SCIP_PRICERDATA* pricerdata, /**< pricer data */ SCIP* subscip, /**< pricing SCIP data structure */ SCIP_VAR** vars /**< variable array for the items */ ) { SCIP_CONS** conss; SCIP_Longint* vals; SCIP_CONS* cons; SCIP_VAR* var; SCIP_Longint* weights; SCIP_Longint capacity; SCIP_Real dual; int nitems; int nvars; int c; assert( SCIPgetStage(subscip) == SCIP_STAGE_PROBLEM ); assert(pricerdata != NULL); nitems = pricerdata->nitems; conss = pricerdata->conss; weights = pricerdata->weights; capacity = pricerdata->capacity; nvars = 0; SCIP_CALL( SCIPallocBufferArray(subscip, &vals, nitems) ); /* create for each order, which is not assigned yet, a variable with objective coefficient */ for( c = 0; c < nitems; ++c ) { cons = conss[c]; /* check if each constraint is setppc constraint */ assert( !strncmp( SCIPconshdlrGetName( SCIPconsGetHdlr(cons) ), "setppc", 6) ); /* constraints which are (locally) disabled/redundant are not of * interest since the corresponding job is assigned to a packing */ if( !SCIPconsIsEnabled(cons) ) continue; if( SCIPgetNFixedonesSetppc(scip, cons) == 1 ) { /* disable constraint locally */ SCIP_CALL( SCIPdelConsLocal(scip, cons) ); continue; } /* dual value in original SCIP */ dual = SCIPgetDualsolSetppc(scip, cons); SCIP_CALL( SCIPcreateVarBasic(subscip, &var, SCIPconsGetName(cons), 0.0, 1.0, dual, SCIP_VARTYPE_BINARY) ); SCIP_CALL( SCIPaddVar(subscip, var) ); vals[nvars] = weights[c]; vars[nvars] = var; nvars++; /* release variable */ SCIP_CALL( SCIPreleaseVar(subscip, &var) ); } /* create capacity constraint */ SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, "capacity", nvars, vars, vals, capacity) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* add constraint of the branching decisions */ SCIP_CALL( addBranchingDecisionConss(scip, subscip, vars, pricerdata->conshdlr) ); /* avoid to generate columns which are fixed to zero */ SCIP_CALL( addFixedVarsConss(scip, subscip, vars, conss, nitems) ); SCIPfreeBufferArray(subscip, &vals); return SCIP_OKAY; }
/** avoid to generate columns which are fixed to zero; therefore add for each variable which is fixed to zero a * corresponding logicor constraint to forbid this column * * @note variable which are fixed locally to zero should not be generated again by the pricing MIP */ static SCIP_RETCODE addFixedVarsConss( SCIP* scip, /**< SCIP data structure */ SCIP* subscip, /**< pricing SCIP data structure */ SCIP_VAR** vars, /**< variable array of the subscuip */ SCIP_CONS** conss, /**< array of setppc constraint for each item one */ int nitems /**< number of items */ ) { SCIP_VAR** origvars; int norigvars; SCIP_CONS* cons; int* consids; int nconsids; int consid; int nvars; SCIP_VAR** logicorvars; SCIP_VAR* var; SCIP_VARDATA* vardata; SCIP_Bool needed; int nlogicorvars; int v; int c; int o; /* collect all variable which are currently existing */ origvars = SCIPgetVars(scip); norigvars = SCIPgetNVars(scip); /* loop over all these variables and check if they are fixed to zero */ for( v = 0; v < norigvars; ++v ) { assert(SCIPvarGetType(origvars[v]) == SCIP_VARTYPE_BINARY); /* if the upper bound is smaller than 0.5 if follows due to the integrality that the binary variable is fixed to zero */ if( SCIPvarGetUbLocal(origvars[v]) < 0.5 ) { SCIPdebugMessage("variable <%s> glb=[%.15g,%.15g] loc=[%.15g,%.15g] is fixed to zero\n", SCIPvarGetName(origvars[v]), SCIPvarGetLbGlobal(origvars[v]), SCIPvarGetUbGlobal(origvars[v]), SCIPvarGetLbLocal(origvars[v]), SCIPvarGetUbLocal(origvars[v]) ); /* coolect the constraints/items the variable belongs to */ vardata = SCIPvarGetData(origvars[v]); nconsids = SCIPvardataGetNConsids(vardata); consids = SCIPvardataGetConsids(vardata); needed = TRUE; SCIP_CALL( SCIPallocBufferArray(subscip, &logicorvars, nitems) ); nlogicorvars = 0; consid = consids[0]; nvars = 0; /* loop over these items and create a linear (logicor) constraint which forbids this item combination in the * pricing problem; thereby check if this item combination is already forbidden */ for( c = 0, o = 0; o < nitems && needed; ++o ) { assert(o <= consid); cons = conss[o]; if( SCIPconsIsEnabled(cons) ) { assert( SCIPgetNFixedonesSetppc(scip, cons) == 0 ); var = vars[nvars]; nvars++; assert(var != NULL); if( o == consid ) { SCIP_CALL( SCIPgetNegatedVar(subscip, var, &var) ); } logicorvars[nlogicorvars] = var; nlogicorvars++; } else if( o == consid ) needed = FALSE; if( o == consid ) { c++; if ( c == nconsids ) consid = nitems + 100; else { assert(consid < consids[c]); consid = consids[c]; } } } if( needed ) { SCIP_CALL( SCIPcreateConsBasicLogicor(subscip, &cons, SCIPvarGetName(origvars[v]), nlogicorvars, logicorvars) ); SCIP_CALL( SCIPsetConsInitial(subscip, cons, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); } SCIPfreeBufferArray(subscip, &logicorvars); } } 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; }
/** create the extra constraint of local branching and add it to subscip */ static SCIP_RETCODE addLocalBranchingConstraint( SCIP* scip, /**< SCIP data structure of the original problem */ SCIP* subscip, /**< SCIP data structure of the subproblem */ SCIP_VAR** subvars, /**< variables of the subproblem */ SCIP_HEURDATA* heurdata /**< heuristic's data structure */ ) { SCIP_CONS* cons; /* local branching constraint to create */ SCIP_VAR** consvars; SCIP_VAR** vars; SCIP_SOL* bestsol; int nbinvars; int i; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* consvals; char consname[SCIP_MAXSTRLEN]; (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_localbranchcons", SCIPgetProbName(scip)); /* get the data of the variables and the best solution */ SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, NULL, NULL, NULL) ); bestsol = SCIPgetBestSol(scip); assert( bestsol != NULL ); /* memory allocation */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) ); /* set initial left and right hand sides of local branching constraint */ lhs = (SCIP_Real)heurdata->emptyneighborhoodsize + 1.0; rhs = (SCIP_Real)heurdata->curneighborhoodsize; /* create the distance (to incumbent) function of the binary variables */ for( i = 0; i < nbinvars; i++ ) { SCIP_Real solval; solval = SCIPgetSolVal(scip, bestsol, vars[i]); assert( SCIPisFeasIntegral(scip,solval) ); /* is variable i part of the binary support of bestsol? */ if( SCIPisFeasEQ(scip,solval,1.0) ) { consvals[i] = -1.0; rhs -= 1.0; lhs -= 1.0; } else consvals[i] = 1.0; consvars[i] = subvars[i]; assert( SCIPvarGetType(consvars[i]) == SCIP_VARTYPE_BINARY ); } /* creates localbranching constraint and adds it to subscip */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, consname, nbinvars, consvars, consvals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free local memory */ SCIPfreeBufferArray(scip, &consvals); SCIPfreeBufferArray(scip, &consvars); return SCIP_OKAY; }
/* 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; }
/** 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; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ unsigned int* randseed, /**< a seed value for the random number generator */ SCIP_Bool uselprows /**< should subproblem be created out of the rows in the LP rows? */ ) { SCIP_VAR** vars; /* original scip variables */ SCIP_SOL* sol; /* pool of solutions */ SCIP_Bool* marked; /* array of markers, which variables to fixed */ SCIP_Bool fixingmarker; /* which flag should label a fixed variable? */ int nvars; int nbinvars; int nintvars; int i; int j; int nmarkers; /* get required data of the original problem */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); sol = SCIPgetBestSol(scip); assert(sol != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &marked, nbinvars+nintvars) ); if( minfixingrate > 0.5 ) { nmarkers = nbinvars + nintvars - (int) SCIPfloor(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = FALSE; } else { nmarkers = (int) SCIPceil(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = TRUE; } assert( 0 <= nmarkers && nmarkers <= SCIPceil(scip,(nbinvars+nintvars)/2.0 ) ); j = 0; BMSclearMemoryArray(marked, nbinvars+nintvars); while( j < nmarkers ) { do { i = SCIPgetRandomInt(0, nbinvars+nintvars-1, randseed); } while( marked[i] ); marked[i] = TRUE; j++; } assert( j == nmarkers ); /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { /* fix all randomly marked variables */ if( marked[i] == fixingmarker ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, sol, vars[i]); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); assert(SCIPisLE(scip, lb, ub)); /* due to dual reductions, it may happen that the solution value is not in the variable's domain anymore */ if( SCIPisLT(scip, solval, lb) ) solval = lb; else if( SCIPisGT(scip, solval, ub) ) solval = ub; /* perform the bound change */ if( !SCIPisInfinity(scip, solval) && !SCIPisInfinity(scip, -solval) ) { SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], solval) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], solval) ); } } } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } } SCIPfreeBufferArray(scip, &marked); return SCIP_OKAY; }
/** constraint parsing method of constraint handler */ static SCIP_DECL_CONSPARSE(consParseConjunction) { /*lint --e{715}*/ SCIP_CONS** conss; int nconss; int sconss; char* token; char* saveptr; char* nexttokenstart; char* copystr; assert(scip != NULL); assert(conshdlr != NULL); assert(cons != NULL); assert(success != NULL); assert(str != NULL); assert(name != NULL); SCIPdebugMessage("parsing conjunction <%s>\n", name); *success = TRUE; /* allocate memory for constraint in conjunction, initial size is set to 10 */ nconss = 0; sconss = 10; SCIP_CALL( SCIPallocBufferArray(scip, &conss, sconss) ); SCIP_CALL( SCIPduplicateBufferArray(scip, ©str, str, (int)strlen(str)+1) ); /* find '(' at the beginning, string should start with 'conjunction(' */ saveptr = strpbrk(copystr, "("); /*lint !e158*/ if( saveptr == NULL ) { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } /* skip '(' */ ++saveptr; /* remember token start position */ nexttokenstart = saveptr; /* brackets '(' and ')' can exist co we check for them and the constraint delimeter */ saveptr = strpbrk(saveptr, "(,"); /* brackets '(' and ')' can exist in the rest of the string so we need to skip them to find the end of the first * sub-constraint marked by a ',' */ if( saveptr != NULL ) { do { int bracketcounter = 0; if( *saveptr == '(' ) { do { ++bracketcounter; ++saveptr; /* find last ending bracket */ while( bracketcounter > 0 ) { saveptr = strpbrk(saveptr, "()"); if( saveptr != NULL ) { if( *saveptr == '(' ) ++bracketcounter; else --bracketcounter; ++saveptr; } else { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } } saveptr = strpbrk(saveptr, "(,"); } while( saveptr != NULL && *saveptr == '(' ); } /* we found a ',' so the end of the first sub-constraint is determined */ if( saveptr != NULL ) { assert(*saveptr == ','); /* resize constraint array if necessary */ if( nconss == sconss ) { sconss = SCIPcalcMemGrowSize(scip, nconss+1); assert(nconss < sconss); SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) ); } assert(saveptr > nexttokenstart); /* extract token for parsing */ SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) ); token[saveptr - nexttokenstart] = '\0'; SCIPdebugMessage("conjunctive parsing token(constraint): %s\n", token); /* parsing a constraint, part of the conjunction */ SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, success) ); SCIPfreeBufferArray(scip, &token); if( *success ) ++nconss; else { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); goto TERMINATE; } /* skip ',' delimeter */ ++saveptr; /* remember token start position */ nexttokenstart = saveptr; saveptr = strpbrk(saveptr, "(,"); } } while( saveptr != NULL ); } /* find end of conjunction constraint */ saveptr = strrchr(nexttokenstart, ')'); if( saveptr == NULL ) { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } /* parse last sub-constraint */ else { /* resize constraint array if necessary */ if( nconss == sconss ) { ++sconss; SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) ); } assert(saveptr > nexttokenstart); /* extract token for parsing */ SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) ); token[saveptr - nexttokenstart] = '\0'; SCIPdebugMessage("conjunctive parsing token(constraint): %s\n", token); /* parsing a constraint, part of the conjunction */ SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, success) ); if( *success ) ++nconss; SCIPfreeBufferArray(scip, &token); } assert(nconss > 0 || !(*success)); /* if parsing sub-constraints was fine, create the conjunctive constraint */ if( *success ) { /* create conjunctive constraint */ SCIP_CALL( SCIPcreateConsConjunction(scip, cons, name, nconss, conss, enforce, check, local, modifiable, dynamic) ); } /* free parsed constraints */ for( --nconss; nconss >= 0; --nconss ) { SCIP_CALL( SCIPreleaseCons(scip, &conss[nconss]) ); } TERMINATE: /* free temporary memory */ SCIPfreeBufferArray(scip, ©str); SCIPfreeBufferArray(scip, &conss); return SCIP_OKAY; }
/** constraint copying method of constraint handler */ static SCIP_DECL_CONSCOPY(consCopyConjunction) { /*lint --e{715}*/ SCIP_CONSDATA* sourcedata; SCIP_CONS** sourceconss; SCIP_CONS** conss; int nconss; int c; *valid = TRUE; sourcedata = SCIPconsGetData(sourcecons); assert(sourcedata != NULL); sourceconss = sourcedata->conss; nconss = sourcedata->nconss; if( nconss > 0 ) { assert(sourceconss != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &conss, nconss) ); /* copy each constraint one by one */ for( c = 0; c < nconss && (*valid); ++c ) { SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourceconss[c], &conss[c], SCIPconsGetHdlr(sourceconss[c]), varmap, consmap, SCIPconsGetName(sourceconss[c]), SCIPconsIsInitial(sourceconss[c]), SCIPconsIsSeparated(sourceconss[c]), SCIPconsIsEnforced(sourceconss[c]), SCIPconsIsChecked(sourceconss[c]), SCIPconsIsPropagated(sourceconss[c]), SCIPconsIsLocal(sourceconss[c]), SCIPconsIsModifiable(sourceconss[c]), SCIPconsIsDynamic(sourceconss[c]), SCIPconsIsRemovable(sourceconss[c]), SCIPconsIsStickingAtNode(sourceconss[c]), global, valid) ); assert(!(*valid) || conss[c] != NULL); } if( *valid ) { if( name == NULL ) { SCIP_CALL( SCIPcreateConsConjunction(scip, cons, SCIPconsGetName(sourcecons), nconss, conss, enforce, check, local, modifiable, dynamic) ); } else { SCIP_CALL( SCIPcreateConsConjunction(scip, cons, name, nconss, conss, enforce, check, local, modifiable, dynamic) ); } } /* release the copied constraints */ for( c = (*valid ? c - 1 : c - 2); c >= 0; --c ) { assert(conss[c] != NULL); SCIP_CALL( SCIPreleaseCons(scip, &conss[c]) ); } SCIPfreeBufferArray(scip, &conss); } return SCIP_OKAY; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ 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_Bool* success /**< pointer to store whether the problem was created successfully */ ) { SCIP_VAR** vars; /* original SCIP variables */ SCIP_Real fixingrate; int nvars; int nbinvars; int nintvars; int i; int fixingcounter; assert(scip != NULL); assert(subscip != NULL); assert(subvars != NULL); assert(0.0 <= minfixingrate && minfixingrate <= 1.0); /* get required variable data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); fixingcounter = 0; /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { SCIP_Real lpsolval; SCIP_Real lb; SCIP_Real ub; /* get the current LP solution for each variable */ lpsolval = SCIPgetRelaxSolVal(scip, vars[i]); if( SCIPisFeasIntegral(scip, lpsolval) ) { /* fix variables to current LP solution if it is integral, * use exact integral value, if the variable is only integral within numerical tolerances */ lb = SCIPfloor(scip, lpsolval+0.5); ub = lb; fixingcounter++; } else if( binarybounds ) { /* if the sub problem should be a binary problem, change the bounds to nearest integers */ lb = SCIPfeasFloor(scip,lpsolval); ub = SCIPfeasCeil(scip,lpsolval); } else { /* otherwise just copy bounds */ lb = SCIPvarGetLbGlobal(vars[i]); ub = SCIPvarGetUbGlobal(vars[i]); } /* perform the bound change */ SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], lb) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], ub) ); } /* abort, if all integer variables were fixed (which should not happen for MIP) */ if( fixingcounter == nbinvars + nintvars ) { *success = FALSE; return SCIP_OKAY; } else fixingrate = fixingcounter / (SCIP_Real)(MAX(nbinvars + nintvars, 1)); SCIPdebugMessage("fixing rate: %g = %d of %d\n", fixingrate, fixingcounter, nbinvars + nintvars); /* abort, if the amount of fixed variables is insufficient */ if( fixingrate < minfixingrate ) { *success = FALSE; return SCIP_OKAY; } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; int j; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(subscip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(subscip, &consvars); } } *success = TRUE; return SCIP_OKAY; }
/** add branching decisions constraints to the sub SCIP */ static SCIP_RETCODE addBranchingDecisionConss( SCIP* scip, /**< SCIP data structure */ SCIP* subscip, /**< pricing SCIP data structure */ SCIP_VAR** vars, /**< variable array of the subscuip oder variables */ SCIP_CONSHDLR* conshdlr /**< constraint handler for branching data */ ) { SCIP_CONS** conss; SCIP_CONS* cons; int nconss; int id1; int id2; CONSTYPE type; SCIP_Real vbdcoef; SCIP_Real lhs; SCIP_Real rhs; int c; assert( scip != NULL ); assert( subscip != NULL ); assert( conshdlr != NULL ); /* collect all branching decision constraints */ conss = SCIPconshdlrGetConss(conshdlr); nconss = SCIPconshdlrGetNConss(conshdlr); /* loop over all branching decision constraints and apply the branching decision if the corresponding constraint is * active */ for( c = 0; c < nconss; ++c ) { cons = conss[c]; /* ignore constraints which are not active since these are not laying on the current active path of the search * tree */ if( !SCIPconsIsActive(cons) ) continue; /* collect the two item ids and the branching type (SAME or DIFFER) on which the constraint branched */ id1 = SCIPgetItemid1Samediff(scip, cons); id2 = SCIPgetItemid2Samediff(scip, cons); type = SCIPgetTypeSamediff(scip, cons); SCIPdebugMessage("create varbound for %s(%d,%d)\n", type == SAME ? "same" : "diff", SCIPprobdataGetIds(SCIPgetProbData(scip))[id1], SCIPprobdataGetIds(SCIPgetProbData(scip))[id2]); /* depending on the branching type select the correct left and right hand side for the linear constraint which * enforces this branching decision in the pricing problem MIP */ if( type == SAME ) { lhs = 0.0; rhs = 0.0; vbdcoef = -1.0; } else if( type == DIFFER ) { lhs = -SCIPinfinity(scip); rhs = 1.0; vbdcoef = 1.0; } else { SCIPerrorMessage("unknow constraint type <%d>\n, type"); return SCIP_INVALIDDATA; } /* add linear (in that case a variable bound) constraint to pricing MIP depending on the branching type: * * - branching type SAME: x1 = x2 <=> x1 - x2 = 0 <=> 0 <= x1 - x2 <= 0 * * - branching type DIFFER: x1 - x2 <= 1 <=> -inf <= x1 - x2 <= 1 * */ SCIP_CALL( SCIPcreateConsBasicVarbound(subscip, &cons, SCIPconsGetName(conss[c]), vars[id1], vars[id2], vbdcoef, lhs, rhs) ); SCIPdebug( SCIPprintCons(subscip, cons, NULL) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); } return SCIP_OKAY; }
/* Read SAT formula in "CNF File Format". * * The specification is taken from the * * Satisfiability Suggested Format * * Online available at http://www.intellektik.informatik.tu-darmstadt.de/SATLIB/Benchmarks/SAT/satformat.ps * * The method reads all files of CNF format. Other formats (SAT, SATX, SATE) are not supported. */ static SCIP_RETCODE readCnf( SCIP* scip, /**< SCIP data structure */ SCIP_FILE* file /**< input file */ ) { SCIP_RETCODE retcode; SCIP_VAR** vars; SCIP_VAR** clausevars; SCIP_CONS* cons; int* varsign; char* tok; char* nexttok; char line[MAXLINELEN]; char format[SCIP_MAXSTRLEN]; char varname[SCIP_MAXSTRLEN]; char s[SCIP_MAXSTRLEN]; SCIP_Bool dynamicconss; SCIP_Bool dynamiccols; SCIP_Bool dynamicrows; SCIP_Bool useobj; int linecount; int clauselen; int clausenum; int nvars; int nclauses; int varnum; int v; assert(scip != NULL); assert(file != NULL); retcode = SCIP_OKAY; linecount = 0; /* read header */ SCIP_CALL( readCnfLine(scip, file, line, (int) sizeof(line), &linecount) ); if( *line != 'p' ) { readError(scip, linecount, "problem declaration line expected"); return SCIP_READERROR; } if( sscanf(line, "p %8s %d %d", format, &nvars, &nclauses) != 3 ) { readError(scip, linecount, "invalid problem declaration (must be 'p cnf <nvars> <nclauses>')"); return SCIP_READERROR; } if( strcmp(format, "cnf") != 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid format tag <%s> (must be 'cnf')", format); readError(scip, linecount, s); return SCIP_READERROR; } if( nvars <= 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid number of variables <%d> (must be positive)", nvars); readError(scip, linecount, s); return SCIP_READERROR; } if( nclauses <= 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid number of clauses <%d> (must be positive)", nclauses); readError(scip, linecount, s); return SCIP_READERROR; } /* get parameter values */ SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/dynamicconss", &dynamicconss) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/dynamiccols", &dynamiccols) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/dynamicrows", &dynamicrows) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/useobj", &useobj) ); /* get temporary memory */ SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &clausevars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) ); /* create the variables */ for( v = 0; v < nvars; ++v ) { (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "x%d", v+1); SCIP_CALL( SCIPcreateVar(scip, &vars[v], varname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, vars[v]) ); varsign[v] = 0; } /* read clauses */ clausenum = 0; clauselen = 0; do { retcode = readCnfLine(scip, file, line, (int) sizeof(line), &linecount); if( retcode != SCIP_OKAY ) goto TERMINATE; if( *line != '\0' && *line != '%' ) { tok = SCIPstrtok(line, " \f\n\r\t", &nexttok); while( tok != NULL ) { /* parse literal and check for errors */ if( sscanf(tok, "%d", &v) != 1 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid literal <%s>", tok); readError(scip, linecount, s); retcode = SCIP_READERROR; goto TERMINATE; } /* interpret literal number: v == 0: end of clause, v < 0: negated literal, v > 0: positive literal */ if( v == 0 ) { /* end of clause: construct clause and add it to SCIP */ if( clauselen == 0 ) readWarning(scip, linecount, "empty clause detected in line -- problem infeasible"); clausenum++; (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "c%d", clausenum); if( SCIPfindConshdlr(scip, "logicor") != NULL ) { /* if the constraint handler logicor exit create a logicor constraint */ SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, s, clauselen, clausevars, !dynamicrows, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); } else if( SCIPfindConshdlr(scip, "setppc") != NULL ) { /* if the constraint handler logicor does not exit but constraint * handler setppc create a setppc constraint */ SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, s, clauselen, clausevars, !dynamicrows, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); } else { /* if none of the previous constraint handler exits create a linear * constraint */ SCIP_Real* vals; int i; SCIP_CALL( SCIPallocBufferArray(scip, &vals, clauselen) ); for( i = 0; i < clauselen; ++i ) vals[i] = 1.0; SCIP_CALL( SCIPcreateConsLinear(scip, &cons, s, clauselen, clausevars, vals, 1.0, SCIPinfinity(scip), !dynamicrows, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); SCIPfreeBufferArray(scip, &vals); } SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); clauselen = 0; } else if( v >= -nvars && v <= nvars ) { if( clauselen >= nvars ) { readError(scip, linecount, "too many literals in clause"); retcode = SCIP_READERROR; goto TERMINATE; } /* add literal to clause */ varnum = ABS(v)-1; if( v < 0 ) { SCIP_CALL( SCIPgetNegatedVar(scip, vars[varnum], &clausevars[clauselen]) ); varsign[varnum]--; } else { clausevars[clauselen] = vars[varnum]; varsign[varnum]++; } clauselen++; } else { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid variable number <%d>", ABS(v)); readError(scip, linecount, s); retcode = SCIP_READERROR; goto TERMINATE; } /* get next token */ tok = SCIPstrtok(NULL, " \f\n\r\t", &nexttok); } } } while( *line != '\0' && *line != '%' ); /* check for additional literals */ if( clauselen > 0 ) { SCIPwarningMessage(scip, "found %d additional literals after last clause\n", clauselen); } /* check number of clauses */ if( clausenum != nclauses ) { SCIPwarningMessage(scip, "expected %d clauses, but found %d\n", nclauses, clausenum); } TERMINATE: /* change objective values and release variables */ SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); if( useobj ) { for( v = 0; v < nvars; ++v ) { SCIP_CALL( SCIPchgVarObj(scip, vars[v], (SCIP_Real)varsign[v]) ); SCIP_CALL( SCIPreleaseVar(scip, &vars[v]) ); } } /* free temporary memory */ SCIPfreeBufferArray(scip, &varsign); SCIPfreeBufferArray(scip, &clausevars); SCIPfreeBufferArray(scip, &vars); return retcode; }
/** 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; }