41 #include "scip/cons_linear.h"
42 #include "scip/cons_knapsack.h"
48 #define SOLVER_NAME "knapsack"
49 #define SOLVER_DESC "knapsack solver for pricing problems"
50 #define SOLVER_PRIORITY 200
52 #define SOLVER_HEURENABLED FALSE
53 #define SOLVER_EXACTENABLED TRUE
71 SCIP_Real* lowerbound,
76 SCIP_CONSHDLR* conshdlr;
78 SCIP_Longint* consvals;
83 SCIP_VAR** pricingprobvars;
88 SCIP_Longint* weights;
91 SCIP_Longint capacity;
92 SCIP_Longint prelcapacity;
101 SCIP_Bool inferbounds;
107 assert(scip != NULL);
108 assert(pricingprob != NULL);
109 assert(solver != NULL);
110 assert(lowerbound != NULL);
111 assert(status != NULL);
113 assert(SCIPgetObjsense(pricingprob) == SCIP_OBJSENSE_MINIMIZE);
115 pricingprobvars = SCIPgetVars(pricingprob);
116 npricingprobvars = SCIPgetNVars(pricingprob);
118 SCIPdebugMessage(
"Knapsack solver -- checking prerequisites\n");
126 if( SCIPgetNBinVars(pricingprob) + SCIPgetNIntVars(pricingprob) < npricingprobvars )
128 SCIPdebugMessage(
" -> pricing problem has continuous variables\n");
131 for( i = SCIPgetNBinVars(pricingprob); i < SCIPgetNBinVars(pricingprob) + SCIPgetNIntVars(pricingprob); ++i )
133 if( SCIPisNegative(pricingprob, SCIPvarGetLbLocal(pricingprobvars[i])) )
135 SCIPdebugMessage(
" -> pricing problem has variables with negative lower bounds\n");
140 nconss = SCIPgetNConss(pricingprob);
143 SCIPdebugMessage(
" -> pricing problem has more than one constraint\n");
147 cons = SCIPgetConss(pricingprob)[0];
148 assert(cons != NULL);
150 conshdlr = SCIPconsGetHdlr(cons);
151 assert(conshdlr != NULL);
163 if( strcmp(SCIPconshdlrGetName(conshdlr),
"linear") == 0 )
165 SCIP_Real* realconsvals;
167 if( !SCIPisIntegral(pricingprob, SCIPgetRhsLinear(pricingprob, cons)) ||
168 !SCIPisInfinity(pricingprob, - SCIPgetLhsLinear(pricingprob, cons)) )
170 SCIPdebugMessage(
" -> pricing constraint is bounded from below or has fractional rhs\n");
174 consvars = SCIPgetVarsLinear(pricingprob, cons);
175 realconsvals = SCIPgetValsLinear(pricingprob, cons);
176 nconsvars = SCIPgetNVarsLinear(pricingprob, cons);
178 SCIP_CALL( SCIPallocBufferArray(pricingprob, &consvals, nconsvars) );
181 for( i = 0; i < nconsvars; i++ )
183 if( !SCIPisIntegral(pricingprob, realconsvals[i]) )
185 SCIPdebugMessage(
" -> pricing constraint has fractional coefficient\n");
186 SCIPfreeBufferArray(pricingprob, &consvals);
190 consvals[i] = (SCIP_Longint) SCIPfloor(pricingprob, realconsvals[i]);
192 capacity = (SCIP_Longint) SCIPfloor(pricingprob, SCIPgetRhsLinear(pricingprob, cons));
197 prelcapacity = capacity;
199 for( i = 0; i < nconsvars; i++ )
201 if( SCIPisInfinity(pricingprob, SCIPvarGetUbLocal(consvars[i])) )
204 if( consvals[i] < 0 )
207 if( SCIPisInfinity(pricingprob, SCIPvarGetUbLocal(consvars[i])) )
209 SCIPdebugMessage(
" -> variable with negative coefficient has no upper bound\n");
210 SCIPfreeBufferArray(pricingprob, &consvals);
215 prelcapacity -= (SCIP_Longint) SCIPfloor(pricingprob, consvals[i] * SCIPvarGetUbLocal(consvars[i]));
219 SCIP_CALL( SCIPallocBufferArray(pricingprob, &ubs, nconsvars) );
221 SCIPdebugMessage(
"Set variable upper bounds\n");
224 for( i = 0; i < nconsvars; i++ )
226 if( inferbounds && SCIPisInfinity(pricingprob, SCIPvarGetUbLocal(consvars[i])) )
228 ubs[i] = SCIPfloor(pricingprob, ABS((SCIP_Real)prelcapacity/consvals[i]));
229 SCIPdebugMessage(
" -> var <%s> %.2f/%"SCIP_LONGINT_FORMAT
" = %.2f\n",
230 SCIPvarGetName(consvars[i]), (SCIP_Real)prelcapacity, consvals[i], ubs[i]);
234 ubs[i] = SCIPvarGetUbLocal(consvars[i]);
235 SCIPdebugMessage(
" -> var <%s> %.2f\n", SCIPvarGetName(consvars[i]), ubs[i]);
240 else if( strcmp(SCIPconshdlrGetName(conshdlr),
"knapsack") == 0 )
242 SCIP_Longint* consweights = SCIPgetWeightsKnapsack(pricingprob, cons);
244 SCIPdebugMessage(
"Use knapsack solver – constraint is already of type 'knapsack'\n");
246 consvars = SCIPgetVarsKnapsack(pricingprob, cons);
247 nconsvars = SCIPgetNVarsKnapsack(pricingprob, cons);
248 capacity = SCIPgetCapacityKnapsack(pricingprob, cons);
250 SCIP_CALL( SCIPallocBufferArray(pricingprob, &consvals, nconsvars) );
251 SCIP_CALL( SCIPallocBufferArray(pricingprob, &ubs, nconsvars) );
252 BMScopyMemoryArray(consvals, consweights, nconsvars);
254 for( i = 0; i < nconsvars; ++i )
256 assert(consvals[i] >= 0);
257 assert(SCIPisGE(pricingprob, SCIPvarGetLbLocal(consvars[i]), 0.0));
258 assert(SCIPisLE(pricingprob, SCIPvarGetUbLocal(consvars[i]), 1.0));
260 ubs[i] = SCIPvarGetUbLocal(consvars[i]);
265 SCIPdebugMessage(
" -> constraint is of unknown type\n");
272 SCIPdebugMessage(
"Count number of knapsack items:\n");
274 for( i = 0; i < nconsvars; i++ )
276 assert(!SCIPisInfinity(pricingprob, ubs[i]));
277 SCIPdebugMessage(
" -> <%s>: %d+%d\n", SCIPvarGetName(consvars[i]), nitems, (
int)(ubs[i] - SCIPvarGetLbLocal(consvars[i]) + 0.5));
278 nitems += (int)(ubs[i] - SCIPvarGetLbLocal(consvars[i]) + 0.5);
280 SCIPdebugMessage(
"-> %d items\n", nitems);
282 SCIP_CALL( SCIPallocBufferArray(pricingprob, &solvars, npricingprobvars) );
283 SCIP_CALL( SCIPallocBufferArray(pricingprob, &solvals, npricingprobvars) );
285 SCIP_CALL( SCIPallocBufferArray(pricingprob, &items, nitems) );
286 SCIP_CALL( SCIPallocBufferArray(pricingprob, &weights, nitems) );
287 SCIP_CALL( SCIPallocBufferArray(pricingprob, &profits, nitems) );
288 SCIP_CALL( SCIPallocBufferArray(pricingprob, &solitems, nitems) );
289 SCIP_CALL( SCIPallocBufferArray(pricingprob, &nonsolitems, nitems) );
291 BMSclearMemoryArray(weights, nitems);
294 SCIPdebugMessage(
"Set knapsack items\n");
296 for( i = 0; i < nconsvars; i++ )
298 assert(!SCIPisInfinity(pricingprob, ubs[i]));
299 for( j = 0; j < (int)(ubs[i] - SCIPvarGetLbLocal(consvars[i]) + 0.5); ++j )
302 profits[k] = - SCIPvarGetObj(consvars[i]);
303 SCIPdebugMessage(
" -> item %3d: <%s> (index %3d)\n", k, SCIPvarGetName(consvars[i]), i);
311 SCIPdebugMessage(
"Compute knapsack capacity, current capacity = %"SCIP_LONGINT_FORMAT
"\n", capacity);
312 for( i = 0; i < nconsvars; i++ )
314 if( SCIPisEQ(pricingprob, SCIPvarGetUbLocal(consvars[i]), 0.0) )
316 if( SCIPisGE(pricingprob, SCIPvarGetLbLocal(consvars[i]), 1.0) )
318 SCIPdebugMessage(
" -> variable <%s> has coeff %"SCIP_LONGINT_FORMAT
" and lb %f --> increase capacity by %"SCIP_LONGINT_FORMAT
"\n",
319 SCIPvarGetName(consvars[i]), consvals[i], SCIPvarGetLbLocal(consvars[i]),
320 (SCIP_Longint)SCIPfloor(pricingprob, SCIPvarGetLbLocal(consvars[i]) * consvals[i]));
321 capacity -= (SCIP_Longint)SCIPfloor(pricingprob, SCIPvarGetLbLocal(consvars[i])) * consvals[i];
325 SCIPdebugMessage(
"Compute weights\n");
327 for( k = 0; k < nitems; k++ )
330 if( consvals[i] > 0 )
332 weights[k] = consvals[i];
333 SCIPdebugMessage(
" -> item %3d: weight = %"SCIP_LONGINT_FORMAT
"\n", k, weights[k]);
337 capacity -= consvals[i];
338 weights[k] = -consvals[i];
341 SCIPdebugMessage(
" -> item %3d: weight = %"SCIP_LONGINT_FORMAT
" (negated from consval = %"SCIP_LONGINT_FORMAT
")\n", k, weights[k], consvals[i]);
345 SCIPdebugMessage(
"Knapsack capacity = %"SCIP_LONGINT_FORMAT
"\n", capacity);
352 SCIPdebugMessage(
"Pricing problem is infeasible\n");
356 else if( capacity == 0 )
358 SCIPdebugMessage(
"Knapsack has zero capacity\n");
361 nnonsolitems = nitems;
362 for( i = 0; i < nitems; ++i )
363 nonsolitems[i] = items[i];
367 SCIPdebugMessage(
"Solve pricing problem as knapsack\n");
372 SCIP_CALL( SCIPsolveKnapsackExactly(pricingprob, nitems, weights, profits, capacity, items, solitems,
373 nonsolitems, &nsolitems, &nnonsolitems, &solval, &success ));
377 SCIP_CALL( SCIPsolveKnapsackApproximately(pricingprob, nitems, weights, profits, capacity, items, solitems,
378 nonsolitems, &nsolitems, &nnonsolitems, &solval ));
383 SCIPwarningMessage(pricingprob,
"Knapsack solver could not solve pricing problem!");
389 SCIPdebugMessage(
"Knapsack solved, solval = %g\n", solval);
394 for( i = 0; i < nsolitems; i++ )
396 assert(consvals[solitems[i]] >= 0 || !SCIPvarIsNegated(consvars[solitems[i]]));
398 if( consvals[solitems[i]] >= 0 && !SCIPvarIsNegated(consvars[solitems[i]]) )
400 for( j = 0; j < nsolvars; ++j )
401 if( solvars[j] == consvars[solitems[i]] )
406 solvars[j] = consvars[solitems[i]];
415 for( i = 0; i < nnonsolitems; i++ )
417 assert(consvals[nonsolitems[i]] >= 0 || !SCIPvarIsNegated(consvars[nonsolitems[i]]));
419 if( consvals[nonsolitems[i]] < 0 || SCIPvarIsNegated(consvars[nonsolitems[i]]) )
421 SCIP_VAR* solvar = SCIPvarIsNegated(consvars[nonsolitems[i]]) ? SCIPvarGetNegatedVar(consvars[nonsolitems[i]]) : consvars[nonsolitems[i]];
423 for( j = 0; j < nsolvars; ++j )
424 if( solvars[j] == solvar )
438 for( i = 0; i < npricingprobvars; i++ )
440 if( SCIPisGE(pricingprob, SCIPvarGetLbLocal(pricingprobvars[i]), 1.0) )
442 for( j = 0; j < nsolvars; ++j )
443 if( solvars[j] == pricingprobvars[i] )
448 solvars[j] = pricingprobvars[i];
449 solvals[j] = SCIPfloor(pricingprob, SCIPvarGetLbLocal(pricingprobvars[i]));
453 solvals[j] += SCIPfloor(pricingprob, SCIPvarGetLbLocal(pricingprobvars[i]));
457 SCIP_CALL(
GCGcreateGcgCol(pricingprob, &col, probnr, solvars, solvals, nsolvars, FALSE, SCIPinfinity(pricingprob)) );
462 for( i = 0; i < nsolvars; ++i )
463 solval += solvals[i] * SCIPvarGetObj(solvars[i]);
465 *lowerbound = exactly ? solval : -SCIPinfinity(pricingprob);
468 SCIPfreeBufferArray(pricingprob, &nonsolitems);
469 SCIPfreeBufferArray(pricingprob, &solitems);
470 SCIPfreeBufferArray(pricingprob, &profits);
471 SCIPfreeBufferArray(pricingprob, &weights);
472 SCIPfreeBufferArray(pricingprob, &items);
473 SCIPfreeBufferArray(pricingprob, &solvals);
474 SCIPfreeBufferArray(pricingprob, &solvars);
475 SCIPfreeBufferArray(pricingprob, &ubs);
476 SCIPfreeBufferArray(pricingprob, &consvals);
485 #define solverFreeKnapsack NULL
486 #define solverInitsolKnapsack NULL
487 #define solverExitsolKnapsack NULL
488 #define solverInitKnapsack NULL
489 #define solverExitKnapsack NULL
490 #define solverUpdateKnapsack NULL
498 SCIP_CALL(
solveKnapsack(TRUE, scip, pricingprob, solver, probnr, lowerbound, status) );
510 SCIP_CALL(
solveKnapsack(FALSE, scip, pricingprob, solver, probnr, lowerbound, status) );