/** creates and captures a variable bound constraint: lhs <= x + c*y <= rhs * * @note the constraint gets captured, hence at one point you have to release it using the method {@link releaseCons()} */ JNIEXPORT jlong JNISCIPCONSVARBOUND(createConsVarbound)( JNIEnv* env, /**< JNI environment variable */ jobject jobj, /**< JNI class pointer */ jlong jscip, /**< SCIP data structure */ jstring jname, /**< name of constraint */ jlong jvar, /**< variable x that has variable bound */ jlong jvbdvar, /**< binary, integer or implicit integer bounding variable y */ jdouble jvbdcoef, /**< coefficient c of bounding variable y */ jdouble jlhs, /**< left hand side of variable bound inequality */ jdouble jrhs, /**< right hand side of variable bound inequality */ jboolean jinitial, /**< should the LP relaxation of constraint be in the initial LP? * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ jboolean jseparate, /**< should the constraint be separated during LP processing? * Usually set to TRUE. */ jboolean jenforce, /**< should the constraint be enforced during node processing? * TRUE for model constraints, FALSE for additional, redundant constraints. */ jboolean jcheck, /**< should the constraint be checked for feasibility? * TRUE for model constraints, FALSE for additional, redundant constraints. */ jboolean jpropagate, /**< should the constraint be propagated during node processing? * Usually set to TRUE. */ jboolean jlocal, /**< is constraint only valid locally? * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ jboolean jmodifiable, /**< 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 jdynamic, /**< is constraint subject to aging? * Usually set to FALSE. Set to TRUE for own cuts which * are seperated as constraints. */ jboolean jremovable, /**< 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 jstickingatnode /**< 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; SCIP_VAR* var; SCIP_VAR* vbdvar; jboolean iscopy; /* 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, &iscopy); if( name == NULL ) SCIPABORT(); assert(iscopy); /* convert JNI pointer into C pointer */ var = (SCIP_VAR*) (size_t) jvar; assert(var != NULL); /* convert JNI pointer into C pointer */ vbdvar = (SCIP_VAR*) (size_t) jvbdvar; assert(vbdvar != NULL); JNISCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, (SCIP_Real)jvbdcoef, (SCIP_Real)jlhs, (SCIP_Real)jrhs, (SCIP_Bool) jinitial, (SCIP_Bool) jseparate, (SCIP_Bool) jenforce, (SCIP_Bool) jcheck, (SCIP_Bool) jpropagate, (SCIP_Bool) jlocal, (SCIP_Bool) jmodifiable, (SCIP_Bool) jdynamic, (SCIP_Bool) jremovable, (SCIP_Bool) jstickingatnode) ); (*env)->ReleaseStringUTFChars(env, jname, name); return (jlong)(size_t)cons; }
/** 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(SCIPcreateConsVarbound(subscip, &cons, SCIPconsGetName(conss[c]), vars[id1], vars[id2], vbdcoef, lhs, rhs, // TODO: Alert! id1 and id2 might not be the correct indices of the vars (if some constraints are skipped) TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE)); SCIPdebug(SCIPprintCons(subscip, cons, NULL)); SCIP_CALL(SCIPaddCons(subscip, cons)); SCIP_CALL(SCIPreleaseCons(subscip, &cons)); } return SCIP_OKAY; }
/** creates a cumulative scheduling problem */ SCIP_RETCODE SCIPcreateSchedulingProblem( SCIP* scip, /**< SCIP data structure */ const char* problemname, /**< problem name */ const char** jobnames, /**< job names, or NULL */ const char** resourcenames, /**< resource names, or NULL */ int** demands, /**< demand matrix resource job demand */ SCIP_DIGRAPH* precedencegraph, /**< direct graph to store the precedence conditions */ int* durations, /**< array to store the processing for each job */ int* capacities, /**< array to store the different capacities */ int njobs, /**< number of jobs to be parsed */ int nresources /**< number of capacities to be parsed */ ) { SCIP_VAR** jobs; SCIP_VAR** vars; SCIP_VAR* var; SCIP_CONS* cons; char name[SCIP_MAXSTRLEN]; int* consdurations; int* consdemands; int nvars; int ubmakespan; int i; int j; int r; assert( scip != NULL ); assert( njobs >= 0 ); SCIPdebugMessage( "start method SCIPcreateSchedulingSMProblem\n"); /* create SCIP data structure */ SCIP_CALL( SCIPcreateProb(scip, problemname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* compute a feasible upper bound on the makespan */ ubmakespan = computeUbmakespan(durations, njobs); ubmakespan *= 100; /* allocate buffer for jobs and precedence constraints */ SCIP_CALL( SCIPallocBufferArray(scip, &jobs, njobs) ); /* create an activity constraint for each activity */ for( j = 0; j < njobs - 1; ++j ) /* but not for last job which is the makespan (-1) */ { /* construct variable name */ if( jobnames != NULL ) (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "start_%s", jobnames[j]); else (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "start_%d", j); /* create integer starting variable */ SCIP_CALL( SCIPcreateVar(scip, &var, name, 0.0, (SCIP_Real)ubmakespan, 0.0, SCIP_VARTYPE_INTEGER, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, var) ); SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) ); jobs[j] = var; SCIP_CALL( SCIPreleaseVar(scip, &var) ); } /* create makespan variable */ SCIP_CALL( SCIPcreateVar(scip, &var, "makespan", 0.0, (SCIP_Real)ubmakespan, 1.0, SCIP_VARTYPE_INTEGER, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, var) ); SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) ); jobs[njobs-1] = var; SCIP_CALL( SCIPreleaseVar(scip, &var) ); /* precedence constraints */ for( j = 0; j < njobs - 1; ++j ) { SCIP_VAR* predvar; int nsuccessors; nsuccessors = SCIPdigraphGetNSuccessors(precedencegraph, j); predvar = jobs[j]; assert(predvar != NULL); if( nsuccessors > 0 ) { int* successors; void** distances; successors = SCIPdigraphGetSuccessors(precedencegraph, j); distances = SCIPdigraphGetSuccessorsDatas(precedencegraph, j); for( i = 0; i < nsuccessors; ++i ) { SCIP_VAR* succvar; int distance; succvar = jobs[successors[i]]; assert(succvar != NULL); (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "precedences_(%d,%d)", j, successors[i]); distance = (int)(size_t)distances[i]; if( distance == INT_MAX ) distance = durations[j]; SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, predvar, succvar, -1.0, -SCIPinfinity(scip), -distance, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } else { /* add precedence constraints for those jobs without successor */ (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "precedences_(%d,%d)", j, njobs); SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, predvar, jobs[njobs-1], -1.0, -SCIPinfinity(scip), -durations[j], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } SCIP_CALL( SCIPallocBufferArray(scip, &vars, njobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &consdemands, njobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &consdurations, njobs) ); /* create resource constraints */ for( r = 0; r < nresources; ++r ) { nvars = 0; for( j = 0; j < njobs; ++j ) /* also makespan constraint! */ { if( demands[j][r] > 0 ) { vars[nvars] = jobs[j]; consdemands[nvars] = demands[j][r]; consdurations[nvars] = durations[j]; nvars++; } } if( nvars > 0 ) { /* construct constraint name */ if( resourcenames != NULL ) (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "R%s", resourcenames[r]); else (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "R%d", r); SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, consdurations, consdemands, capacities[r], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } /* initialize the problem specific heuristic */ SCIP_CALL( SCIPinitializeHeurListScheduling(scip, precedencegraph, jobs, durations, demands, capacities, njobs, nresources) ); /* free buffer array */ SCIPfreeBufferArray(scip, &consdurations); SCIPfreeBufferArray(scip, &consdemands); SCIPfreeBufferArray(scip, &vars); SCIPfreeBufferArray(scip, &jobs); return SCIP_OKAY; }