/** sets up the problem data */ SCIP_RETCODE SCIPprobdataCreate( SCIP* scip, /**< SCIP data structure */ const char* probname, /**< problem name */ int* ids, /**< array of item ids */ SCIP_Longint* weights, /**< array containing the item weights */ int nitems, /**< number of items */ SCIP_Longint capacity /**< bin capacity */ ) { SCIP_PROBDATA* probdata; SCIP_CONS** conss; char name[SCIP_MAXSTRLEN]; int i; assert(scip != NULL); /* create event handler if it does not exist yet */ if( SCIPfindEventhdlr(scip, EVENTHDLR_NAME) == NULL ) { SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecAddedVar, NULL) ); } /* create problem in SCIP and add non-NULL callbacks via setter functions */ SCIP_CALL( SCIPcreateProbBasic(scip, probname) ); SCIP_CALL( SCIPsetProbDelorig(scip, probdelorigBinpacking) ); SCIP_CALL( SCIPsetProbTrans(scip, probtransBinpacking) ); SCIP_CALL( SCIPsetProbDeltrans(scip, probdeltransBinpacking) ); SCIP_CALL( SCIPsetProbInitsol(scip, probinitsolBinpacking) ); SCIP_CALL( SCIPsetProbExitsol(scip, probexitsolBinpacking) ); /* set objective sense */ SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MINIMIZE) ); /* tell SCIP that the objective will be always integral */ SCIP_CALL( SCIPsetObjIntegral(scip) ); SCIP_CALL( SCIPallocBufferArray(scip, &conss, nitems) ); /* create set covering constraints for each item */ for( i = 0; i < nitems; ++i ) { (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "item_%d", ids[i]); SCIP_CALL( SCIPcreateConsBasicSetcover(scip, &conss[i], name, 0, NULL) ); /* declare constraint modifiable for adding variables during pricing */ SCIP_CALL( SCIPsetConsModifiable(scip, conss[i], TRUE) ); SCIP_CALL( SCIPaddCons(scip, conss[i]) ); } /* create problem data */ SCIP_CALL( probdataCreate(scip, &probdata, NULL, conss, weights, ids, 0, nitems, capacity) ); SCIP_CALL( createInitialColumns(scip, probdata) ); /* set user problem data */ SCIP_CALL( SCIPsetProbData(scip, probdata) ); SCIP_CALL( SCIPpricerBinpackingActivate(scip, conss, weights, ids, nitems, capacity) ); /* free local buffer arrays */ SCIPfreeBufferArray(scip, &conss); return SCIP_OKAY; }
/** reduced cost pricing method of variable pricer for feasible LPs */ static SCIP_DECL_PRICERREDCOST(pricerRedcostBinpacking) { /*lint --e{715}*/ SCIP* subscip; SCIP_PRICERDATA* pricerdata; SCIP_CONS** conss; SCIP_VAR** vars; int* ids; SCIP_Bool addvar; SCIP_SOL** sols; int nsols; int s; int nitems; SCIP_Longint capacity; SCIP_Real timelimit; SCIP_Real memorylimit; assert(scip != NULL); assert(pricer != NULL); (*result) = SCIP_DIDNOTRUN; /* get the pricer data */ pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); capacity = pricerdata->capacity; conss = pricerdata->conss; ids = pricerdata->ids; nitems = pricerdata->nitems; /* get the remaining time and memory limit */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; /* initialize SCIP */ SCIP_CALL( SCIPcreate(&subscip) ); SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* create problem in sub SCIP */ SCIP_CALL( SCIPcreateProbBasic(subscip, "pricing") ); SCIP_CALL( SCIPsetObjsense(subscip, SCIP_OBJSENSE_MAXIMIZE) ); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* set time and memory limit */ SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPallocMemoryArray(subscip, &vars, nitems) ); /* initialization local pricing problem */ SCIP_CALL( initPricing(scip, pricerdata, subscip, vars) ); SCIPdebugMessage("solve pricer problem\n"); /* solve sub SCIP */ SCIP_CALL( SCIPsolve(subscip) ); sols = SCIPgetSols(subscip); nsols = SCIPgetNSols(subscip); addvar = FALSE; /* loop over all solutions and create the corresponding column to master if the reduced cost are negative for master, * that is the objective value i greater than 1.0 */ for( s = 0; s < nsols; ++s ) { SCIP_Bool feasible; SCIP_SOL* sol; /* the soultion should be sorted w.r.t. the objective function value */ assert(s == 0 || SCIPisFeasGE(subscip, SCIPgetSolOrigObj(subscip, sols[s-1]), SCIPgetSolOrigObj(subscip, sols[s]))); sol = sols[s]; assert(sol != NULL); /* check if solution is feasible in original sub SCIP */ SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE ) ); if( !feasible ) { SCIPwarningMessage(scip, "solution in pricing problem (capacity <%d>) is infeasible\n", capacity); continue; } /* check if the solution has a value greater than 1.0 */ if( SCIPisFeasGT(subscip, SCIPgetSolOrigObj(subscip, sol), 1.0) ) { SCIP_VAR* var; SCIP_VARDATA* vardata; int* consids; char strtmp[SCIP_MAXSTRLEN]; char name[SCIP_MAXSTRLEN]; int nconss; int o; int v; SCIPdebug( SCIP_CALL( SCIPprintSol(subscip, sol, NULL, FALSE) ) ); nconss = 0; (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "items"); SCIP_CALL( SCIPallocBufferArray(scip, &consids, nitems) ); /* check which variables are fixed -> which item belongs to this packing */ for( o = 0, v = 0; o < nitems; ++o ) { if( !SCIPconsIsEnabled(conss[o]) ) continue; assert(SCIPgetNFixedonesSetppc(scip, conss[o]) == 0); if( SCIPgetSolVal(subscip, sol, vars[v]) > 0.5 ) { (void) SCIPsnprintf(strtmp, SCIP_MAXSTRLEN, "_%d", ids[o]); strcat(name, strtmp); consids[nconss] = o; nconss++; } else assert( SCIPisFeasEQ(subscip, SCIPgetSolVal(subscip, sol, vars[v]), 0.0) ); v++; } SCIP_CALL( SCIPvardataCreateBinpacking(scip, &vardata, consids, nconss) ); /* create variable for a new column with objective function coefficient 0.0 */ SCIP_CALL( SCIPcreateVarBinpacking(scip, &var, name, 1.0, FALSE, TRUE, vardata) ); /* add the new variable to the pricer store */ SCIP_CALL( SCIPaddPricedVar(scip, var, 1.0) ); addvar = TRUE; /* change the upper bound of the binary variable to lazy since the upper bound is already enforced due to * the objective function the set covering constraint; The reason for doing is that, is to avoid the bound * of x <= 1 in the LP relaxation since this bound constraint would produce a dual variable which might have * a positive reduced cost */ SCIP_CALL( SCIPchgVarUbLazy(scip, var, 1.0) ); /* check which variable are fixed -> which orders belong to this packing */ for( v = 0; v < nconss; ++v ) { assert(SCIPconsIsEnabled(conss[consids[v]])); SCIP_CALL( SCIPaddCoefSetppc(scip, conss[consids[v]], var) ); } SCIPdebug(SCIPprintVar(scip, var, NULL) ); SCIP_CALL( SCIPreleaseVar(scip, &var) ); SCIPfreeBufferArray(scip, &consids); } else break; } /* free pricer MIP */ SCIPfreeMemoryArray(subscip, &vars); if( addvar || SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL ) (*result) = SCIP_SUCCESS; /* free sub SCIP */ SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }