Scippy

SCIP

Solving Constraint Integer Programs

branch_cloud.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file branch_cloud.c
26 * @ingroup DEFPLUGINS_BRANCH
27 * @brief cloud branching rule
28 * @author Timo Berthold
29 * @author Domenico Salvagnin
30 *
31 * Branching rule based on muliple optimal solutions to the current LP relaxation. See@n
32 * Cloud Branching@n
33 * Timo Berthold and Domenico Salvagnin@n
34 * Integration of AI and OR Techniques in Constraint Programming for Combinatorial Optimization Problems, CPAIOR 2013, LNCS 7874@n
35 * Preliminary version available as <a href="http://opus4.kobv.de/opus4-zib/frontdoor/index/index/docId/1730">ZIB-Report 13-01</a>.
36 */
37
38/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
39
42#include "scip/branch_cloud.h"
44#include "scip/pub_branch.h"
45#include "scip/pub_lp.h"
46#include "scip/pub_message.h"
47#include "scip/pub_tree.h"
48#include "scip/pub_var.h"
49#include "scip/scip_branch.h"
50#include "scip/scip_exact.h"
51#include "scip/scip_general.h"
52#include "scip/scip_lp.h"
53#include "scip/scip_mem.h"
54#include "scip/scip_message.h"
55#include "scip/scip_numerics.h"
56#include "scip/scip_param.h"
57#include "scip/scip_prob.h"
58#include "scip/scip_sol.h"
60#include "scip/scip_timing.h"
61#include "scip/scip_tree.h"
62#include "scip/scip_var.h"
63#include <string.h>
64
65
66#define BRANCHRULE_NAME "cloud"
67#define BRANCHRULE_DESC "branching rule that considers several alternative LP optima"
68#define BRANCHRULE_PRIORITY 0
69#define BRANCHRULE_MAXDEPTH -1
70#define BRANCHRULE_MAXBOUNDDIST 1.0
71
72#define DEFAULT_USECLOUD TRUE /**< should a cloud of points be used? */
73#define DEFAULT_USEUNION FALSE /**< should the union of candidates be used? */
74#define DEFAULT_MAXPOINTS -1 /**< maximum number of points for the cloud (-1 means no limit) */
75#define DEFAULT_MINSUCCESSRATE 0.0 /**< minimum success rate for the cloud */
76#define DEFAULT_MINSUCCESSUNION 0.0 /**< minimum success rate for the union */
77#define DEFAULT_MAXDEPTHUNION 65000 /**< maximum depth for the union */
78#define DEFAULT_ONLYF2 FALSE /**< should only F2 be used? */
79
80/*
81 * Data structures
82 */
83
84/** branching rule data */
85struct SCIP_BranchruleData
86{
87 int lastcand; /**< last evaluated candidate of last branching rule execution */
88 SCIP_Bool usecloud; /**< should a cloud of points be used? */
89 SCIP_Bool useunion; /**< should the union of candidates be used? */
90 SCIP_Bool onlyF2; /**< should only F2 be used? */
91 int maxpoints; /**< maximum number of points for the cloud (-1 means no limit) */
92 SCIP_Real minsuccessrate; /**< minimum success rate for the cloud */
93 SCIP_Real minsuccessunion; /**< minimum success rate for the union */
94 SCIP_CLOCK* cloudclock; /**< clock for cloud diving */
95 SCIP_Bool* skipdown; /**< should down branch be skiped? */
96 SCIP_Bool* skipup; /**< should up branch be skiped? */
97 int ntried; /**< number of times the cloud was tried */
98 int ntriedunions; /**< number of times the cloud was tried */
99 int nuseful; /**< number of times the cloud was useful (at least one LP skipped) */
100 int nusefulunions; /**< number of times the union was useful (took candidate from new list) */
101 int ncloudpoints; /**< sum of cloud points taken over all nodes with at least two poitns in cloud */
102 int nsavedlps; /**< sum of saved LPs taken over all nodes with at least two points in cloud */
103 int maxdepthunion; /**< maximum depth for the union */
104 int skipsize; /**< size of skipdown and skipup array */
105};
106
107/*
108 * Callback methods of branching rule
109 */
110
111/** copy method for branchrule plugins (called when SCIP copies plugins) */
112static
113SCIP_DECL_BRANCHCOPY(branchCopyCloud)
114{ /*lint --e{715}*/
115 assert(scip != NULL);
116 assert(branchrule != NULL);
117 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
118
119 /* call inclusion method of branchrule */
121
122 return SCIP_OKAY;
123}
124
125/** destructor of branching rule to free user data (called when SCIP is exiting) */
126static
127SCIP_DECL_BRANCHFREE(branchFreeCloud)
128{ /*lint --e{715}*/
129 SCIP_BRANCHRULEDATA* branchruledata;
130
131 /* free branching rule data */
132 branchruledata = SCIPbranchruleGetData(branchrule);
133
134 if( branchruledata->cloudclock != NULL)
135 {
137 int ntried;
138 int nuseful;
139 int ncloudpoints;
140 int nsavedlps;
141
142 ntried = branchruledata->ntried;
143 nuseful = branchruledata->nuseful;
144 ncloudpoints = branchruledata->ncloudpoints;
145 nsavedlps = branchruledata->nsavedlps;
146
147 SCIPstatisticMessage("time spent diving in cloud branching: %g\n", SCIPgetClockTime(scip, branchruledata->cloudclock));
148 SCIPstatisticMessage("cloud branching tried: %6d found cloud: %6d \n", ntried, nuseful);
149 SCIPstatisticMessage("cloud used points: %6d saved LPs: %6d \n", ncloudpoints, nsavedlps);
150 SCIPstatisticMessage("cloud success rates useful/tried: %8.6g points/useful: %8.6g saved/useful: %8.6g \n",
151 ntried == 0 ? -1 : (SCIP_Real)nuseful / ntried, nuseful == 0 ? -1 : (SCIP_Real)ncloudpoints / nuseful, nuseful == 0 ? -1 : (SCIP_Real)nsavedlps / nuseful);
152 )
153
154 SCIP_CALL( SCIPfreeClock(scip, &(branchruledata->cloudclock)) );
155 }
156
157 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipdown, branchruledata->skipsize);
158 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipup, branchruledata->skipsize);
159
160 SCIPfreeBlockMemory(scip, &branchruledata);
161 SCIPbranchruleSetData(branchrule, NULL);
162
163 return SCIP_OKAY;
164}
165
166
167/** initialization method of branching rule (called after problem was transformed) */
168static
169SCIP_DECL_BRANCHINIT(branchInitCloud)
170{ /*lint --e{715}*/
171 SCIP_BRANCHRULEDATA* branchruledata;
172
173 /* initialize branching rule data */
174 branchruledata = SCIPbranchruleGetData(branchrule);
175 branchruledata->lastcand = 0;
176 branchruledata->nuseful = 0;
177 branchruledata->nusefulunions = 0;
178 branchruledata->ntried = 0;
179 branchruledata->ntriedunions = 0;
180 branchruledata->ncloudpoints = 0;
181 branchruledata->nsavedlps = 0;
182
183 if( branchruledata->cloudclock != NULL)
184 {
185 SCIP_CALL( SCIPresetClock(scip, branchruledata->cloudclock) );
186 }
187
188 return SCIP_OKAY;
189}
190
191/** branching execution method for fractional LP solutions */
192static
193SCIP_DECL_BRANCHEXECLP(branchExeclpCloud)
194{ /*lint --e{715}*/
195 SCIP_BRANCHRULEDATA* branchruledata;
196
197 SCIP_VAR** lpcands;
198 SCIP_VAR** lpcandscopy;
199
200 SCIP_VAR** vars;
201 SCIP_ROW** lprows;
202 SCIP_Real* lpcandsfrac;
203 SCIP_Real* lpcandssol;
204 SCIP_Real* lpcandsfraccopy;
205 SCIP_Real* lpcandssolcopy;
206 SCIP_Real* lpcandsmin;
207 SCIP_Real* lpcandsmax;
208 SCIP_Real* newlpcandsmin;
209 SCIP_Real* newlpcandsmax;
210
211 SCIP_Real bestdown;
212 SCIP_Real bestup;
213 SCIP_Real bestscore;
214 SCIP_Real provedbound;
215
216 SCIP_Bool bestdownvalid;
217 SCIP_Bool bestupvalid;
218 SCIP_Bool newpoint;
219 SCIP_Bool lperror;
220
221 int nlpcands;
222 int npriolpcands;
223 int nvars;
224 int bestcand;
225 int nlprows;
226 int i;
227 int counter;
228 int ncomplete;
229 int ndiscvars;
230
231 assert(branchrule != NULL);
232 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
233 assert(scip != NULL);
234 assert(result != NULL);
235
236 if( !SCIPisLPSolBasic(scip) )
237 return SCIP_OKAY;
238
239 SCIPdebugMsg(scip, "Execlp method of " BRANCHRULE_NAME " branching\n");
240
241 /* get problem variables and LP row data */
242 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
244 nlprows = SCIPgetNLPRows(scip);
245 lprows = SCIPgetLPRows(scip);
246
247 /* get branching candidates */
248 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, &npriolpcands, NULL) );
249 nlpcands = SCIPgetNLPBranchCands(scip);
250 assert(nlpcands > 0);
251
252 /* get branching rule data */
253 branchruledata = SCIPbranchruleGetData(branchrule);
254 assert(branchruledata != NULL);
255
256 /* allocate skipping arrays on first call */
257 if( branchruledata->skipdown == NULL )
258 {
259 assert(branchruledata->skipup == NULL);
260
261 branchruledata->skipsize = nvars;
262 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize) );
263 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize) );
264 }
265
266 /* reset skipping arrays to zero */
267 BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
268 BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
269
270 /* allocate required data structures */
271 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandsmin, nlpcands) );
272 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandsmax, nlpcands) );
273 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandscopy, nlpcands) );
274 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandsfraccopy, nlpcands) );
275 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandssolcopy, nlpcands) );
276 newlpcandsmin = NULL;
277 newlpcandsmax = NULL;
278 if( branchruledata->useunion && SCIPgetDepth(scip) < branchruledata->maxdepthunion && !branchruledata->onlyF2)
279 {
280 SCIP_CALL( SCIPallocBufferArray(scip, &newlpcandsmin, ndiscvars) );
281 SCIP_CALL( SCIPallocBufferArray(scip, &newlpcandsmax, ndiscvars) );
282 }
283 BMScopyMemoryArray(lpcandsmin, lpcandssol, nlpcands);
284 BMScopyMemoryArray(lpcandsmax, lpcandssol, nlpcands);
285 BMScopyMemoryArray(lpcandssolcopy, lpcandssol, nlpcands);
286 BMScopyMemoryArray(lpcandsfraccopy, lpcandsfrac, nlpcands);
287 BMScopyMemoryArray(lpcandscopy, lpcands, nlpcands);
288
289 SCIP_CALL( SCIPstartClock(scip, branchruledata->cloudclock) );
290 branchruledata->ntried++;
291
292 /* start diving to calculate the solution cloud */
294
295 /* fix variables with nonzero reduced costs to reduce LP to the optimal face */
296 for( i = 0; i < nvars; ++i )
297 {
298 SCIP_Real solval;
299 solval = SCIPgetSolVal(scip, NULL, vars[i]);
300
301 if( !SCIPisFeasZero(scip, SCIPgetVarRedcost(scip, vars[i])) )
302 {
303 SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], solval) );
304 SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], solval) );
305 }
306 /* for non-implied integral variables with zero cost and fractional value we only allow the next integral values */
307 else if( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_INTEGER && !SCIPvarIsImpliedIntegral(vars[i])
308 && !SCIPisIntegral(scip, solval) )
309 {
310 SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], SCIPfloor(scip, solval)) );
311 SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], SCIPceil(scip, solval)) );
312 }
313
314 SCIP_CALL( SCIPchgVarObjDive(scip, vars[i], 0.0) );
315 }
316
317 /* fix LP rows with nonzero dual solution to reduce LP to the optimal face */
318 for( i = 0; i < nlprows; ++i )
319 {
320 SCIP_Real dualsol;
321 dualsol = SCIProwGetDualsol(lprows[i]);
322 if( !SCIPisZero(scip, dualsol) )
323 {
324 if( dualsol > 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(lprows[i]), SCIPgetRowActivity(scip,lprows[i])) )
325 {
326 SCIP_CALL( SCIPchgRowRhsDive(scip, lprows[i], SCIProwGetLhs(lprows[i])) );
327 }
328 else if( dualsol < 0 && SCIPisFeasEQ(scip, SCIProwGetRhs(lprows[i]), SCIPgetRowActivity(scip,lprows[i])) )
329 {
330 SCIP_CALL( SCIPchgRowLhsDive(scip, lprows[i], SCIProwGetRhs(lprows[i])) );
331 }
332 }
333 }
334
335 newpoint = TRUE;
336 counter = 0;
337
338 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion )
339 {
340 /* update cloud intervals for candidates that have been integral in original LP, but have been fractional in previous cloud points */
341 for( i = 0; i < ndiscvars; ++i)
342 {
343 SCIP_Real solval;
344 solval = SCIPgetSolVal(scip, NULL, vars[i]);
345
346 assert(newlpcandsmin != NULL);
347 assert(newlpcandsmax != NULL);
348
349 newlpcandsmin[i] = solval;
350 newlpcandsmax[i] = solval;
351 }
352 }
353
354 /* loop that generates new cloud point */
355 while( newpoint && branchruledata->usecloud )
356 {
357#ifdef NDEBUG
358 SCIP_RETCODE retcode;
359#endif
360
361 /* apply feasibility pump objective function to fractional variables */
362 for( i = 0; i < nlpcands; ++i )
363 {
364 SCIP_Real frac;
365 frac = SCIPfrac(scip, SCIPgetSolVal(scip, NULL, lpcandscopy[i]));
366
367 if( !SCIPisZero(scip, frac) && !SCIPisIntegral(scip, lpcandsmin[i]) && !SCIPisIntegral(scip, lpcandsmax[i]) )
368 {
369 if( frac < 0.5 )
370 {
371 SCIP_CALL( SCIPchgVarObjDive(scip, vars[i], 1.0) );
372 }
373 else
374 {
375 SCIP_CALL( SCIPchgVarObjDive(scip, vars[i], -1.0) );
376 }
377 }
378 }
379
380 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
381 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
382 */
383#ifdef NDEBUG
384 retcode = SCIPsolveDiveLP(scip, -1, &lperror, NULL);
385 if( retcode != SCIP_OKAY )
386 {
387 SCIPwarningMessage(scip, "Error while solving LP in " BRANCHRULE_NAME "; LP solve terminated with code <%d>\n",retcode);
388 }
389#else
390 SCIP_CALL( SCIPsolveDiveLP(scip, -1, &lperror, NULL) );
391#endif
392
393 if( lperror || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
394 break;
395
396 /* check if a solution has been found */
397 if( SCIPgetNLPBranchCands(scip) == 0 )
398 {
399 SCIP_Bool success;
400 SCIP_SOL* sol;
401
402 /* create solution from diving LP */
403 SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) );
405 SCIPdebugMsg(scip, "cloud branching found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, sol));
406
407 /* try to add solution to SCIP */
408 SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
409
410 /* check, if solution was feasible and good enough */
411 if( success )
412 {
413 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
415 *result = SCIP_CUTOFF;
416 goto TERMINATE;
417 }
418 }
419
420 /* update cloud intervals for candidates that have been fractional in original LP */
421 newpoint = FALSE;
422 for( i = 0; i < nlpcands; ++i)
423 {
424 SCIP_Real solval;
425 solval = SCIPgetSolVal(scip, NULL, lpcandscopy[i]);
426
427 if( SCIPisFeasIntegral(scip,solval) && !SCIPisFeasIntegral(scip, lpcandsmin[i]) && !SCIPisFeasIntegral(scip, lpcandsmax[i]) )
428 newpoint = TRUE;
429
430 lpcandsmin[i] = MIN(lpcandsmin[i], solval);
431 lpcandsmax[i] = MAX(lpcandsmax[i], solval);
432 }
433
434 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion )
435 {
436 /* update cloud intervals for candidates that have been integral in original LP, but have been fractional in previous cloud points */
437 for( i = 0; i < ndiscvars; ++i)
438 {
439 SCIP_Real solval;
440 solval = SCIPgetSolVal(scip, NULL, vars[i]);
441
442 assert(newlpcandsmin != NULL);
443 assert(newlpcandsmax != NULL);
444
445 newlpcandsmin[i] = MIN(newlpcandsmin[i], solval);
446 newlpcandsmax[i] = MAX(newlpcandsmax[i], solval);
447 }
448 }
449
450 if( newpoint )
451 counter++;
452
453 if( branchruledata->maxpoints != -1 && counter >= branchruledata->maxpoints )
454 break;
455 }
456
457 SCIPdebugMsg(scip, "considered %d additional points in the cloud\n",counter);
458
459 /* terminate the diving */
461
462 SCIP_CALL( SCIPstopClock(scip, branchruledata->cloudclock) );
463 ncomplete = nlpcands;
464
465 if( counter > 0 )
466 {
467 branchruledata->ncloudpoints += (counter+1);
468 branchruledata->nuseful++;
469
470 counter = 0;
471
472 /* sort all variables for which both bounds are fractional to the front */
473 for( i = 0; i < nlpcands; ++i)
474 {
475 if( !SCIPisFeasIntegral(scip, lpcandsmin[i]) && !SCIPisFeasIntegral(scip, lpcandsmax[i]) )
476 {
477 assert(counter <= i);
478 lpcandscopy[counter] = lpcandscopy[i];
479 lpcandssolcopy[counter] = lpcandssolcopy[i];
480 lpcandsfraccopy[counter] = lpcandsfraccopy[i];
481 counter++;
482 }
483 }
484
485 /* should only be in that if condition when at least one bound could be made integral */
486 assert(nlpcands - counter > 0);
487
488 ncomplete = counter;
489
490 /* filter all variables for which exactly one interval bound is fractional */
491 for( i = 0; i < nlpcands && !branchruledata->onlyF2; ++i)
492 {
493 if( SCIPisFeasIntegral(scip, lpcandsmin[i]) != SCIPisFeasIntegral(scip, lpcandsmax[i]) )
494 {
495 assert(counter < nlpcands);
496 lpcandscopy[counter] = lpcandscopy[i];
497 lpcandssolcopy[counter] = lpcandssolcopy[i];
498 lpcandsfraccopy[counter] = lpcandsfraccopy[i];
499
500 if( SCIPisFeasIntegral(scip, lpcandsmin[i]) )
501 branchruledata->skipdown[counter] = TRUE;
502 if( SCIPisFeasIntegral(scip, lpcandsmax[i]) )
503 branchruledata->skipup[counter] = TRUE;
504 assert(branchruledata->skipdown[counter] != branchruledata->skipup[counter]);
505
506 counter++;
507 }
508 }
509
510 SCIPdebugMsg(scip, "can fully skip %d/%d strong branching candidates\n", nlpcands - counter, nlpcands);
511 SCIPdebugMsg(scip, "can half skip %d/%d strong branching candidates\n", counter - ncomplete, nlpcands);
512 }
513 else
514 counter = nlpcands;
515
516 /* if cloud sampling was not successful enough, disable it */
517 if( branchruledata->usecloud &&
518 branchruledata->ntried > 100 &&
519 (SCIP_Real)branchruledata->nuseful / branchruledata->ntried < branchruledata->minsuccessrate )
520 {
521 SCIPdebugMsg(scip, "Disabling cloud branching (not effective)\n");
522 branchruledata->usecloud = FALSE;
523 }
524
525 if( branchruledata->onlyF2 )
526 counter = MAX(counter,1);
527
528 /* the second counter should maybe be replaced at some point */
529 SCIP_CALL( SCIPselectVarStrongBranching(scip, lpcandscopy, lpcandssolcopy, lpcandsfraccopy, branchruledata->skipdown,
530 branchruledata->skipup, counter, counter, ncomplete, &branchruledata->lastcand, 0, FALSE, FALSE,
531 &bestcand, &bestdown, &bestup, &bestscore, &bestdownvalid, &bestupvalid, &provedbound, result) );
532
533 if( branchruledata->lastcand <= ncomplete )
534 {
535 SCIPdebugMsg(scip, "saved %d of %d LPs\n", 2*(nlpcands - ncomplete), 2*nlpcands);
536 branchruledata->nsavedlps += 2*(nlpcands - ncomplete);
537 }
538 else
539 {
540 SCIPdebugMsg(scip, "saved %d of %d LPs\n", 2*(nlpcands - counter)+counter - ncomplete, 2*nlpcands);
541 branchruledata->nsavedlps += 2*(nlpcands - counter)+counter - ncomplete;
542 }
543
544 /* perform the branching */
545 if( *result != SCIP_CUTOFF && *result != SCIP_REDUCEDDOM && *result != SCIP_CONSADDED && counter > 0 )
546 {
547 SCIP_NODE* downchild;
548 SCIP_NODE* upchild;
549 SCIP_VAR* var;
550 SCIP_Bool allcolsinlp;
551 SCIP_Bool exactsolve;
552 SCIP_Bool newselected;
553
554 assert(*result == SCIP_DIDNOTRUN);
555 assert(0 <= bestcand && bestcand < nlpcands);
556 assert(SCIPisLT(scip, provedbound, SCIPgetCutoffbound(scip)));
557
558 var = lpcandscopy[bestcand];
559 newselected = FALSE;
560
561 /* if there are new candidates variables, also try them */
562 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion && branchruledata->lastcand > ncomplete )
563 {
564 SCIP_VAR** newlpcands;
565
566 counter = 0;
567 /* reset skipping arrays to zero */
568 BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
569 BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
570
571 SCIP_CALL( SCIPallocBufferArray(scip, &newlpcands, ndiscvars) );
572
573 /* get new LP candidates with one fractional bound */
574 for( i = 0; i < ndiscvars; ++i)
575 {
576 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, vars[i])) )
577 continue;
578
579 assert(newlpcandsmin != NULL);
580 assert(newlpcandsmax != NULL);
581
582 if( SCIPisFeasIntegral(scip, newlpcandsmin[i]) != SCIPisFeasIntegral(scip, newlpcandsmax[i]) )
583 {
584 newlpcands[counter] = vars[i];
585
586 if( SCIPisFeasIntegral(scip, newlpcandsmin[i]) )
587 branchruledata->skipdown[counter] = TRUE;
588 if( SCIPisFeasIntegral(scip, newlpcandsmax[i]) )
589 branchruledata->skipup[counter] = TRUE;
590 assert(branchruledata->skipdown[counter] != branchruledata->skipup[counter]);
591
592 counter++;
593 }
594 }
595
596 /* when there are new candidates, also try these */
597 if( counter > 0 )
598 {
599 SCIP_Real newdown;
600 SCIP_Real newup;
601 SCIP_Real newscore;
602 int newcand;
603 SCIP_Bool newdownvalid;
604 SCIP_Bool newupvalid;
605 SCIP_Real newbound;
606
607 branchruledata->ntriedunions++;
608 newscore = -SCIPinfinity(scip);
609 SCIP_CALL( SCIPselectVarPseudoStrongBranching(scip, newlpcands, branchruledata->skipdown, branchruledata->skipup, counter, counter,
610 &newcand, &newdown, &newup, &newscore, &newdownvalid, &newupvalid, &newbound, result) );
611
612 if( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM || *result == SCIP_CONSADDED )
613 {
614 SCIPfreeBufferArray(scip, &newlpcands);
615 goto TERMINATE;
616 }
617
618 if( newscore > bestscore )
619 {
620 bestcand = newcand;
621 var = newlpcands[newcand];
622 bestdown = newdown;
623 bestup = newup;
624 bestdownvalid = newdownvalid;
625 bestupvalid = newupvalid;
626 bestscore = newscore;
627 newselected = TRUE;
628 branchruledata->nusefulunions++;
629 }
630 }
631 /* free temporary array for new union candidates */
632 SCIPfreeBufferArray(scip, &newlpcands);
633 }
634
635 /* perform the branching */
636 if( !newselected )
637 {
638 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s> (solval=%g, down=%g, up=%g, score=%g)\n",
639 counter, bestcand, SCIPvarGetName(var), lpcandssolcopy[bestcand], bestdown, bestup, bestscore);
640 }
641 else
642 {
643 SCIPdebugMsg(scip, " -> selected from %d new candidates, candidate %d: variable <%s> (down=%g, up=%g, score=%g)\n",
644 counter, bestcand, SCIPvarGetName(var), bestdown, bestup, bestscore);
645 }
646
647 assert(!SCIPisFeasIntegral(scip, SCIPvarGetSol(lpcands[bestcand], TRUE)));
648
649 SCIP_CALL( SCIPbranchVar(scip, var, &downchild, NULL, &upchild) );
650 assert(downchild != NULL);
651 assert(upchild != NULL);
652
653 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
654 * for cutting off sub problems and improving lower bounds of children
655 */
656 exactsolve = SCIPisExact(scip);
657
658 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
659 allcolsinlp = SCIPallColsInLP(scip);
660
661 /* update the lower bounds in the children */
662 if( allcolsinlp && !exactsolve )
663 {
664 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) );
665 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) );
666 }
667 SCIPdebugMsg(scip, " -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild));
668 SCIPdebugMsg(scip, " -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild));
669
670 *result = SCIP_BRANCHED;
671 }
672
673 TERMINATE:
674 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion )
675 {
676 SCIPfreeBufferArray(scip, &newlpcandsmax);
677 SCIPfreeBufferArray(scip, &newlpcandsmin);
678 }
679 SCIPfreeBufferArray(scip, &lpcandscopy);
680 SCIPfreeBufferArray(scip, &lpcandssolcopy);
681 SCIPfreeBufferArray(scip, &lpcandsfraccopy);
682 SCIPfreeBufferArray(scip, &lpcandsmax);
683 SCIPfreeBufferArray(scip, &lpcandsmin);
684
685 /* if union usage was not successful enough, disable it */
686 if( branchruledata->useunion &&
687 branchruledata->ntriedunions > 10 &&
688 (SCIP_Real)branchruledata->nusefulunions / branchruledata->ntriedunions < branchruledata->minsuccessunion )
689 {
690 SCIPdebugMsg(scip, "Disabling union usage (not effective)\n");
691 branchruledata->useunion = FALSE;
692 }
693
694 return SCIP_OKAY; /*lint !e438*/
695}
696
697/*
698 * branching rule specific interface methods
699 */
700
701/** creates the cloud branching rule and includes it in SCIP */
703 SCIP* scip /**< SCIP data structure */
704 )
705{
706 SCIP_BRANCHRULEDATA* branchruledata;
707 SCIP_BRANCHRULE* branchrule;
708
709 /* create cloud branching rule data */
710 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
711 branchruledata->lastcand = 0;
712 branchruledata->skipsize = 0;
713 branchruledata->skipup = NULL;
714 branchruledata->skipdown = NULL;
715 SCIP_CALL( SCIPcreateClock(scip, &(branchruledata->cloudclock)) );
716
717 /* include branching rule */
718 branchrule = NULL;
721 assert(branchrule != NULL);
722
723 /* set non-fundamental callbacks via setter functions */
724 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyCloud) );
725 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeCloud) );
726 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitCloud) );
727 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpCloud) );
728
729 /* add cloud branching rule parameters */
731 "branching/" BRANCHRULE_NAME "/usecloud",
732 "should a cloud of points be used?",
733 &branchruledata->usecloud, FALSE, DEFAULT_USECLOUD, NULL, NULL) );
735 "branching/" BRANCHRULE_NAME "/onlyF2",
736 "should only F2 be used?",
737 &branchruledata->onlyF2, FALSE, DEFAULT_ONLYF2, NULL, NULL) );
739 "branching/" BRANCHRULE_NAME "/useunion",
740 "should the union of candidates be used?",
741 &branchruledata->useunion, FALSE, DEFAULT_USEUNION, NULL, NULL) );
743 "branching/" BRANCHRULE_NAME "/maxpoints",
744 "maximum number of points for the cloud (-1 means no limit)",
745 &branchruledata->maxpoints, FALSE, DEFAULT_MAXPOINTS, -1, INT_MAX, NULL, NULL) );
747 "branching/" BRANCHRULE_NAME "/minsuccessrate",
748 "minimum success rate for the cloud",
749 &branchruledata->minsuccessrate, FALSE, DEFAULT_MINSUCCESSRATE, 0.0, 1.0, NULL, NULL) );
751 "branching/" BRANCHRULE_NAME "/minsuccessunion",
752 "minimum success rate for the union",
753 &branchruledata->minsuccessunion, FALSE, DEFAULT_MINSUCCESSUNION, 0.0, 1.0, NULL, NULL) );
755 "branching/" BRANCHRULE_NAME "/maxdepthunion",
756 "maximum depth for the union",
757 &branchruledata->maxdepthunion, FALSE, DEFAULT_MAXDEPTHUNION, 0, 65000, NULL, NULL) );
758
759 return SCIP_OKAY;
760}
SCIP_RETCODE SCIPselectVarPseudoStrongBranching(SCIP *scip, SCIP_VAR **pseudocands, SCIP_Bool *skipdown, SCIP_Bool *skipup, int npseudocands, int npriopseudocands, int *bestpseudocand, SCIP_Real *bestdown, SCIP_Real *bestup, SCIP_Real *bestscore, SCIP_Bool *bestdownvalid, SCIP_Bool *bestupvalid, SCIP_Real *provedbound, SCIP_RESULT *result)
all variables full strong LP branching rule
#define BRANCHRULE_DESC
Definition: branch_cloud.c:67
static SCIP_DECL_BRANCHINIT(branchInitCloud)
Definition: branch_cloud.c:169
#define BRANCHRULE_PRIORITY
Definition: branch_cloud.c:68
#define DEFAULT_MAXPOINTS
Definition: branch_cloud.c:74
#define DEFAULT_MINSUCCESSUNION
Definition: branch_cloud.c:76
#define DEFAULT_USEUNION
Definition: branch_cloud.c:73
#define BRANCHRULE_NAME
Definition: branch_cloud.c:66
static SCIP_DECL_BRANCHCOPY(branchCopyCloud)
Definition: branch_cloud.c:113
#define DEFAULT_MAXDEPTHUNION
Definition: branch_cloud.c:77
static SCIP_DECL_BRANCHEXECLP(branchExeclpCloud)
Definition: branch_cloud.c:193
#define DEFAULT_ONLYF2
Definition: branch_cloud.c:78
#define DEFAULT_MINSUCCESSRATE
Definition: branch_cloud.c:75
static SCIP_DECL_BRANCHFREE(branchFreeCloud)
Definition: branch_cloud.c:127
#define DEFAULT_USECLOUD
Definition: branch_cloud.c:72
#define BRANCHRULE_MAXDEPTH
Definition: branch_cloud.c:69
#define BRANCHRULE_MAXBOUNDDIST
Definition: branch_cloud.c:70
cloud branching rule
full strong LP branching rule
#define NULL
Definition: def.h:248
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPselectVarStrongBranching(SCIP *scip, SCIP_VAR **lpcands, SCIP_Real *lpcandssol, SCIP_Real *lpcandsfrac, SCIP_Bool *skipdown, SCIP_Bool *skipup, int nlpcands, int npriolpcands, int ncomplete, int *start, int maxproprounds, SCIP_Bool probingbounds, SCIP_Bool forcestrongbranch, int *bestcand, SCIP_Real *bestdown, SCIP_Real *bestup, SCIP_Real *bestscore, SCIP_Bool *bestdownvalid, SCIP_Bool *bestupvalid, SCIP_Real *provedbound, SCIP_RESULT *result)
SCIP_RETCODE SCIPincludeBranchruleCloud(SCIP *scip)
Definition: branch_cloud.c:702
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2340
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:2115
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2293
SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
Definition: scip_prob.c:4354
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
Definition: scip_branch.c:256
SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
Definition: scip_branch.c:160
SCIP_RETCODE SCIPincludeBranchruleBasic(SCIP *scip, SCIP_BRANCHRULE **branchruleptr, const char *name, const char *desc, int priority, int maxdepth, SCIP_Real maxbounddist, SCIP_BRANCHRULEDATA *branchruledata)
Definition: scip_branch.c:123
const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:2018
SCIP_BRANCHRULEDATA * SCIPbranchruleGetData(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:1886
SCIP_RETCODE SCIPsetBranchruleFree(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHFREE((*branchfree)))
Definition: scip_branch.c:176
SCIP_RETCODE SCIPsetBranchruleInit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHINIT((*branchinit)))
Definition: scip_branch.c:192
void SCIPbranchruleSetData(SCIP_BRANCHRULE *branchrule, SCIP_BRANCHRULEDATA *branchruledata)
Definition: branch.c:1896
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:402
SCIP_RETCODE SCIPbranchVar(SCIP *scip, SCIP_VAR *var, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1058
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:436
SCIP_Bool SCIPisExact(SCIP *scip)
Definition: scip_exact.c:193
SCIP_RETCODE SCIPchgVarLbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_lp.c:2384
SCIP_RETCODE SCIPchgVarUbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_lp.c:2416
SCIP_RETCODE SCIPchgRowLhsDive(SCIP *scip, SCIP_ROW *row, SCIP_Real newlhs)
Definition: scip_lp.c:2487
SCIP_RETCODE SCIPchgRowRhsDive(SCIP *scip, SCIP_ROW *row, SCIP_Real newrhs)
Definition: scip_lp.c:2520
SCIP_RETCODE SCIPstartDive(SCIP *scip)
Definition: scip_lp.c:2206
SCIP_RETCODE SCIPchgVarObjDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_lp.c:2343
SCIP_RETCODE SCIPsolveDiveLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_lp.c:2643
SCIP_RETCODE SCIPendDive(SCIP *scip)
Definition: scip_lp.c:2255
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:611
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:632
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_Bool SCIPallColsInLP(SCIP *scip)
Definition: scip_lp.c:655
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:673
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
Definition: tree.c:8503
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17686
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17696
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2068
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17706
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_RETCODE SCIPtrySolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
Definition: scip_sol.c:4109
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1295
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1892
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:76
SCIP_RETCODE SCIPresetClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:144
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:178
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:127
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:319
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:161
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_Real SCIPvarGetSol(SCIP_VAR *var, SCIP_Bool getlpval)
Definition: var.c:19007
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:2608
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
public methods for branching rules
public methods for LP management
public methods for message output
#define SCIPstatisticMessage
Definition: pub_message.h:123
#define SCIPstatistic(x)
Definition: pub_message.h:120
public methods for branch and bound tree
public methods for problem variables
public methods for branching rule plugins and branching
public methods for exact solving
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for solutions
public methods for querying solving statistics
public methods for timing
public methods for the branch-and-bound tree
public methods for SCIP variables
struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
Definition: type_branch.h:57
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_CONSADDED
Definition: type_result.h:52
@ SCIP_BRANCHED
Definition: type_result.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:65