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_general.h"
51#include "scip/scip_lp.h"
52#include "scip/scip_mem.h"
53#include "scip/scip_message.h"
54#include "scip/scip_numerics.h"
55#include "scip/scip_param.h"
56#include "scip/scip_prob.h"
57#include "scip/scip_sol.h"
59#include "scip/scip_timing.h"
60#include "scip/scip_tree.h"
61#include "scip/scip_var.h"
62#include <string.h>
63
64
65#define BRANCHRULE_NAME "cloud"
66#define BRANCHRULE_DESC "branching rule that considers several alternative LP optima"
67#define BRANCHRULE_PRIORITY 0
68#define BRANCHRULE_MAXDEPTH -1
69#define BRANCHRULE_MAXBOUNDDIST 1.0
70
71#define DEFAULT_USECLOUD TRUE /**< should a cloud of points be used? */
72#define DEFAULT_USEUNION FALSE /**< should the union of candidates be used? */
73#define DEFAULT_MAXPOINTS -1 /**< maximum number of points for the cloud (-1 means no limit) */
74#define DEFAULT_MINSUCCESSRATE 0.0 /**< minimum success rate for the cloud */
75#define DEFAULT_MINSUCCESSUNION 0.0 /**< minimum success rate for the union */
76#define DEFAULT_MAXDEPTHUNION 65000 /**< maximum depth for the union */
77#define DEFAULT_ONLYF2 FALSE /**< should only F2 be used? */
78
79/*
80 * Data structures
81 */
82
83/** branching rule data */
84struct SCIP_BranchruleData
85{
86 int lastcand; /**< last evaluated candidate of last branching rule execution */
87 SCIP_Bool usecloud; /**< should a cloud of points be used? */
88 SCIP_Bool useunion; /**< should the union of candidates be used? */
89 SCIP_Bool onlyF2; /**< should only F2 be used? */
90 int maxpoints; /**< maximum number of points for the cloud (-1 means no limit) */
91 SCIP_Real minsuccessrate; /**< minimum success rate for the cloud */
92 SCIP_Real minsuccessunion; /**< minimum success rate for the union */
93 SCIP_CLOCK* cloudclock; /**< clock for cloud diving */
94 SCIP_Bool* skipdown; /**< should down branch be skiped? */
95 SCIP_Bool* skipup; /**< should up branch be skiped? */
96 int ntried; /**< number of times the cloud was tried */
97 int ntriedunions; /**< number of times the cloud was tried */
98 int nuseful; /**< number of times the cloud was useful (at least one LP skipped) */
99 int nusefulunions; /**< number of times the union was useful (took candidate from new list) */
100 int ncloudpoints; /**< sum of cloud points taken over all nodes with at least two poitns in cloud */
101 int nsavedlps; /**< sum of saved LPs taken over all nodes with at least two points in cloud */
102 int maxdepthunion; /**< maximum depth for the union */
103 int skipsize; /**< size of skipdown and skipup array */
104};
105
106/*
107 * Callback methods of branching rule
108 */
109
110/** copy method for branchrule plugins (called when SCIP copies plugins) */
111static
112SCIP_DECL_BRANCHCOPY(branchCopyCloud)
113{ /*lint --e{715}*/
114 assert(scip != NULL);
115 assert(branchrule != NULL);
116 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
117
118 /* call inclusion method of branchrule */
120
121 return SCIP_OKAY;
122}
123
124/** destructor of branching rule to free user data (called when SCIP is exiting) */
125static
126SCIP_DECL_BRANCHFREE(branchFreeCloud)
127{ /*lint --e{715}*/
128 SCIP_BRANCHRULEDATA* branchruledata;
129
130 /* free branching rule data */
131 branchruledata = SCIPbranchruleGetData(branchrule);
132
133 if( branchruledata->cloudclock != NULL)
134 {
136 int ntried;
137 int nuseful;
138 int ncloudpoints;
139 int nsavedlps;
140
141 ntried = branchruledata->ntried;
142 nuseful = branchruledata->nuseful;
143 ncloudpoints = branchruledata->ncloudpoints;
144 nsavedlps = branchruledata->nsavedlps;
145
146 SCIPstatisticMessage("time spent diving in cloud branching: %g\n", SCIPgetClockTime(scip, branchruledata->cloudclock));
147 SCIPstatisticMessage("cloud branching tried: %6d found cloud: %6d \n", ntried, nuseful);
148 SCIPstatisticMessage("cloud used points: %6d saved LPs: %6d \n", ncloudpoints, nsavedlps);
149 SCIPstatisticMessage("cloud success rates useful/tried: %8.6g points/useful: %8.6g saved/useful: %8.6g \n",
150 ntried == 0 ? -1 : (SCIP_Real)nuseful / ntried, nuseful == 0 ? -1 : (SCIP_Real)ncloudpoints / nuseful, nuseful == 0 ? -1 : (SCIP_Real)nsavedlps / nuseful);
151 )
152
153 SCIP_CALL( SCIPfreeClock(scip, &(branchruledata->cloudclock)) );
154 }
155
156 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipdown, branchruledata->skipsize);
157 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipup, branchruledata->skipsize);
158
159 SCIPfreeBlockMemory(scip, &branchruledata);
160 SCIPbranchruleSetData(branchrule, NULL);
161
162 return SCIP_OKAY;
163}
164
165
166/** initialization method of branching rule (called after problem was transformed) */
167static
168SCIP_DECL_BRANCHINIT(branchInitCloud)
169{ /*lint --e{715}*/
170 SCIP_BRANCHRULEDATA* branchruledata;
171
172 /* initialize branching rule data */
173 branchruledata = SCIPbranchruleGetData(branchrule);
174 branchruledata->lastcand = 0;
175 branchruledata->nuseful = 0;
176 branchruledata->nusefulunions = 0;
177 branchruledata->ntried = 0;
178 branchruledata->ntriedunions = 0;
179 branchruledata->ncloudpoints = 0;
180 branchruledata->nsavedlps = 0;
181
182 if( branchruledata->cloudclock != NULL)
183 {
184 SCIP_CALL( SCIPresetClock(scip, branchruledata->cloudclock) );
185 }
186
187 return SCIP_OKAY;
188}
189
190/** branching execution method for fractional LP solutions */
191static
192SCIP_DECL_BRANCHEXECLP(branchExeclpCloud)
193{ /*lint --e{715}*/
194 SCIP_BRANCHRULEDATA* branchruledata;
195
196 SCIP_VAR** lpcands;
197 SCIP_VAR** lpcandscopy;
198
199 SCIP_VAR** vars;
200 SCIP_ROW** lprows;
201 SCIP_Real* lpcandsfrac;
202 SCIP_Real* lpcandssol;
203 SCIP_Real* lpcandsfraccopy;
204 SCIP_Real* lpcandssolcopy;
205 SCIP_Real* lpcandsmin;
206 SCIP_Real* lpcandsmax;
207 SCIP_Real* newlpcandsmin;
208 SCIP_Real* newlpcandsmax;
209
210 SCIP_Real bestdown;
211 SCIP_Real bestup;
212 SCIP_Real bestscore;
213 SCIP_Real provedbound;
214
215 SCIP_Bool bestdownvalid;
216 SCIP_Bool bestupvalid;
217 SCIP_Bool newpoint;
218 SCIP_Bool lperror;
219
220 int nlpcands;
221 int npriolpcands;
222 int nvars;
223 int bestcand;
224 int nlprows;
225 int i;
226 int counter;
227 int ncomplete;
228 int ndiscvars;
229
230 assert(branchrule != NULL);
231 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
232 assert(scip != NULL);
233 assert(result != NULL);
234
235 if( !SCIPisLPSolBasic(scip) )
236 return SCIP_OKAY;
237
238 SCIPdebugMsg(scip, "Execlp method of " BRANCHRULE_NAME " branching\n");
239
240 /* get problem variables and LP row data */
241 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
243 nlprows = SCIPgetNLPRows(scip);
244 lprows = SCIPgetLPRows(scip);
245
246 /* get branching candidates */
247 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, &npriolpcands, NULL) );
248 nlpcands = SCIPgetNLPBranchCands(scip);
249 assert(nlpcands > 0);
250
251 /* get branching rule data */
252 branchruledata = SCIPbranchruleGetData(branchrule);
253 assert(branchruledata != NULL);
254
255 /* allocate skipping arrays on first call */
256 if( branchruledata->skipdown == NULL )
257 {
258 assert(branchruledata->skipup == NULL);
259
260 branchruledata->skipsize = nvars;
261 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize) );
262 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize) );
263 }
264
265 /* reset skipping arrays to zero */
266 BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
267 BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
268
269 /* allocate required data structures */
270 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandsmin, nlpcands) );
271 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandsmax, nlpcands) );
272 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandscopy, nlpcands) );
273 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandsfraccopy, nlpcands) );
274 SCIP_CALL( SCIPallocBufferArray(scip, &lpcandssolcopy, nlpcands) );
275 newlpcandsmin = NULL;
276 newlpcandsmax = NULL;
277 if( branchruledata->useunion && SCIPgetDepth(scip) < branchruledata->maxdepthunion && !branchruledata->onlyF2)
278 {
279 SCIP_CALL( SCIPallocBufferArray(scip, &newlpcandsmin, ndiscvars) );
280 SCIP_CALL( SCIPallocBufferArray(scip, &newlpcandsmax, ndiscvars) );
281 }
282 BMScopyMemoryArray(lpcandsmin, lpcandssol, nlpcands);
283 BMScopyMemoryArray(lpcandsmax, lpcandssol, nlpcands);
284 BMScopyMemoryArray(lpcandssolcopy, lpcandssol, nlpcands);
285 BMScopyMemoryArray(lpcandsfraccopy, lpcandsfrac, nlpcands);
286 BMScopyMemoryArray(lpcandscopy, lpcands, nlpcands);
287
288 SCIP_CALL( SCIPstartClock(scip, branchruledata->cloudclock) );
289 branchruledata->ntried++;
290
291 /* start diving to calculate the solution cloud */
293
294 /* fix variables with nonzero reduced costs to reduce LP to the optimal face */
295 for( i = 0; i < nvars; ++i )
296 {
297 SCIP_Real solval;
298 solval = SCIPgetSolVal(scip, NULL, vars[i]);
299
300 if( !SCIPisFeasZero(scip, SCIPgetVarRedcost(scip, vars[i])) )
301 {
302 SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], solval) );
303 SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], solval) );
304 }
305 else if( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_INTEGER && !SCIPisIntegral(scip, solval) )
306 {
307 SCIP_CALL( SCIPchgVarLbDive(scip, vars[i], SCIPfloor(scip, solval)) );
308 SCIP_CALL( SCIPchgVarUbDive(scip, vars[i], SCIPceil(scip, solval)) );
309 }
310
311 SCIP_CALL( SCIPchgVarObjDive(scip, vars[i], 0.0) );
312 }
313
314 /* fix LP rows with nonzero dual solution to reduce LP to the optimal face */
315 for( i = 0; i < nlprows; ++i )
316 {
317 SCIP_Real dualsol;
318 dualsol = SCIProwGetDualsol(lprows[i]);
319 if( !SCIPisZero(scip, dualsol) )
320 {
321 if( dualsol > 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(lprows[i]), SCIPgetRowActivity(scip,lprows[i])) )
322 {
323 SCIP_CALL( SCIPchgRowRhsDive(scip, lprows[i], SCIProwGetLhs(lprows[i])) );
324 }
325 else if( dualsol < 0 && SCIPisFeasEQ(scip, SCIProwGetRhs(lprows[i]), SCIPgetRowActivity(scip,lprows[i])) )
326 {
327 SCIP_CALL( SCIPchgRowLhsDive(scip, lprows[i], SCIProwGetRhs(lprows[i])) );
328 }
329 }
330 }
331
332 newpoint = TRUE;
333 counter = 0;
334
335 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion )
336 {
337 /* update cloud intervals for candidates that have been integral in original LP, but have been fractional in previous cloud points */
338 for( i = 0; i < ndiscvars; ++i)
339 {
340 SCIP_Real solval;
341 solval = SCIPgetSolVal(scip, NULL, vars[i]);
342
343 assert(newlpcandsmin != NULL);
344 assert(newlpcandsmax != NULL);
345
346 newlpcandsmin[i] = solval;
347 newlpcandsmax[i] = solval;
348 }
349 }
350
351 /* loop that generates new cloud point */
352 while( newpoint && branchruledata->usecloud )
353 {
354#ifdef NDEBUG
355 SCIP_RETCODE retcode;
356#endif
357
358 /* apply feasibility pump objective function to fractional variables */
359 for( i = 0; i < nlpcands; ++i )
360 {
361 SCIP_Real frac;
362 frac = SCIPfrac(scip, SCIPgetSolVal(scip, NULL, lpcandscopy[i]));
363
364 if( !SCIPisZero(scip, frac) && !SCIPisIntegral(scip, lpcandsmin[i]) && !SCIPisIntegral(scip, lpcandsmax[i]) )
365 {
366 if( frac < 0.5 )
367 {
368 SCIP_CALL( SCIPchgVarObjDive(scip, vars[i], 1.0) );
369 }
370 else
371 {
372 SCIP_CALL( SCIPchgVarObjDive(scip, vars[i], -1.0) );
373 }
374 }
375 }
376
377 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
378 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
379 */
380#ifdef NDEBUG
381 retcode = SCIPsolveDiveLP(scip, -1, &lperror, NULL);
382 if( retcode != SCIP_OKAY )
383 {
384 SCIPwarningMessage(scip, "Error while solving LP in " BRANCHRULE_NAME "; LP solve terminated with code <%d>\n",retcode);
385 }
386#else
387 SCIP_CALL( SCIPsolveDiveLP(scip, -1, &lperror, NULL) );
388#endif
389
390 if( lperror || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
391 break;
392
393 /* check if a solution has been found */
394 if( SCIPgetNLPBranchCands(scip) == 0 )
395 {
396 SCIP_Bool success;
397 SCIP_SOL* sol;
398
399 /* create solution from diving LP */
400 SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) );
402 SCIPdebugMsg(scip, "cloud branching found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, sol));
403
404 /* try to add solution to SCIP */
405 SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
406
407 /* check, if solution was feasible and good enough */
408 if( success )
409 {
410 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
412 *result = SCIP_CUTOFF;
413 goto TERMINATE;
414 }
415 }
416
417 /* update cloud intervals for candidates that have been fractional in original LP */
418 newpoint = FALSE;
419 for( i = 0; i < nlpcands; ++i)
420 {
421 SCIP_Real solval;
422 solval = SCIPgetSolVal(scip, NULL, lpcandscopy[i]);
423
424 if( SCIPisFeasIntegral(scip,solval) && !SCIPisFeasIntegral(scip, lpcandsmin[i]) && !SCIPisFeasIntegral(scip, lpcandsmax[i]) )
425 newpoint = TRUE;
426
427 lpcandsmin[i] = MIN(lpcandsmin[i], solval);
428 lpcandsmax[i] = MAX(lpcandsmax[i], solval);
429 }
430
431 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion )
432 {
433 /* update cloud intervals for candidates that have been integral in original LP, but have been fractional in previous cloud points */
434 for( i = 0; i < ndiscvars; ++i)
435 {
436 SCIP_Real solval;
437 solval = SCIPgetSolVal(scip, NULL, vars[i]);
438
439 assert(newlpcandsmin != NULL);
440 assert(newlpcandsmax != NULL);
441
442 newlpcandsmin[i] = MIN(newlpcandsmin[i], solval);
443 newlpcandsmax[i] = MAX(newlpcandsmax[i], solval);
444 }
445 }
446
447 if( newpoint )
448 counter++;
449
450 if( branchruledata->maxpoints != -1 && counter >= branchruledata->maxpoints )
451 break;
452 }
453
454 SCIPdebugMsg(scip, "considered %d additional points in the cloud\n",counter);
455
456 /* terminate the diving */
458
459 SCIP_CALL( SCIPstopClock(scip, branchruledata->cloudclock) );
460 ncomplete = nlpcands;
461
462 if( counter > 0 )
463 {
464 branchruledata->ncloudpoints += (counter+1);
465 branchruledata->nuseful++;
466
467 counter = 0;
468
469 /* sort all variables for which both bounds are fractional to the front */
470 for( i = 0; i < nlpcands; ++i)
471 {
472 if( !SCIPisFeasIntegral(scip, lpcandsmin[i]) && !SCIPisFeasIntegral(scip, lpcandsmax[i]) )
473 {
474 assert(counter <= i);
475 lpcandscopy[counter] = lpcandscopy[i];
476 lpcandssolcopy[counter] = lpcandssolcopy[i];
477 lpcandsfraccopy[counter] = lpcandsfraccopy[i];
478 counter++;
479 }
480 }
481
482 /* should only be in that if condition when at least one bound could be made integral */
483 assert(nlpcands - counter > 0);
484
485 ncomplete = counter;
486
487 /* filter all variables for which exactly one interval bound is fractional */
488 for( i = 0; i < nlpcands && !branchruledata->onlyF2; ++i)
489 {
490 if( SCIPisFeasIntegral(scip, lpcandsmin[i]) != SCIPisFeasIntegral(scip, lpcandsmax[i]) )
491 {
492 assert(counter < nlpcands);
493 lpcandscopy[counter] = lpcandscopy[i];
494 lpcandssolcopy[counter] = lpcandssolcopy[i];
495 lpcandsfraccopy[counter] = lpcandsfraccopy[i];
496
497 if( SCIPisFeasIntegral(scip, lpcandsmin[i]) )
498 branchruledata->skipdown[counter] = TRUE;
499 if( SCIPisFeasIntegral(scip, lpcandsmax[i]) )
500 branchruledata->skipup[counter] = TRUE;
501 assert(branchruledata->skipdown[counter] != branchruledata->skipup[counter]);
502
503 counter++;
504 }
505 }
506
507 SCIPdebugMsg(scip, "can fully skip %d/%d strong branching candidates\n", nlpcands - counter, nlpcands);
508 SCIPdebugMsg(scip, "can half skip %d/%d strong branching candidates\n", counter - ncomplete, nlpcands);
509 }
510 else
511 counter = nlpcands;
512
513 /* if cloud sampling was not successful enough, disable it */
514 if( branchruledata->usecloud &&
515 branchruledata->ntried > 100 &&
516 (SCIP_Real)branchruledata->nuseful / branchruledata->ntried < branchruledata->minsuccessrate )
517 {
518 SCIPdebugMsg(scip, "Disabling cloud branching (not effective)\n");
519 branchruledata->usecloud = FALSE;
520 }
521
522 if( branchruledata->onlyF2 )
523 counter = MAX(counter,1);
524
525 /* the second counter should maybe be replaced at some point */
526 SCIP_CALL( SCIPselectVarStrongBranching(scip, lpcandscopy, lpcandssolcopy, lpcandsfraccopy, branchruledata->skipdown,
527 branchruledata->skipup, counter, counter, ncomplete, &branchruledata->lastcand, 0, FALSE, FALSE,
528 &bestcand, &bestdown, &bestup, &bestscore, &bestdownvalid, &bestupvalid, &provedbound, result) );
529
530 if( branchruledata->lastcand <= ncomplete )
531 {
532 SCIPdebugMsg(scip, "saved %d of %d LPs\n", 2*(nlpcands - ncomplete), 2*nlpcands);
533 branchruledata->nsavedlps += 2*(nlpcands - ncomplete);
534 }
535 else
536 {
537 SCIPdebugMsg(scip, "saved %d of %d LPs\n", 2*(nlpcands - counter)+counter - ncomplete, 2*nlpcands);
538 branchruledata->nsavedlps += 2*(nlpcands - counter)+counter - ncomplete;
539 }
540
541 /* perform the branching */
542 if( *result != SCIP_CUTOFF && *result != SCIP_REDUCEDDOM && *result != SCIP_CONSADDED && counter > 0 )
543 {
544 SCIP_NODE* downchild;
545 SCIP_NODE* upchild;
546 SCIP_VAR* var;
547 SCIP_Bool allcolsinlp;
548 SCIP_Bool exactsolve;
549 SCIP_Bool newselected;
550
551 assert(*result == SCIP_DIDNOTRUN);
552 assert(0 <= bestcand && bestcand < nlpcands);
553 assert(SCIPisLT(scip, provedbound, SCIPgetCutoffbound(scip)));
554
555 var = lpcandscopy[bestcand];
556 newselected = FALSE;
557
558 /* if there are new candidates variables, also try them */
559 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion && branchruledata->lastcand > ncomplete )
560 {
561 SCIP_VAR** newlpcands;
562
563 counter = 0;
564 /* reset skipping arrays to zero */
565 BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
566 BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
567
568 SCIP_CALL( SCIPallocBufferArray(scip, &newlpcands, ndiscvars) );
569
570 /* get new LP candidates with one fractional bound */
571 for( i = 0; i < ndiscvars; ++i)
572 {
573 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, vars[i])) )
574 continue;
575
576 assert(newlpcandsmin != NULL);
577 assert(newlpcandsmax != NULL);
578
579 if( SCIPisFeasIntegral(scip, newlpcandsmin[i]) != SCIPisFeasIntegral(scip, newlpcandsmax[i]) )
580 {
581 newlpcands[counter] = vars[i];
582
583 if( SCIPisFeasIntegral(scip, newlpcandsmin[i]) )
584 branchruledata->skipdown[counter] = TRUE;
585 if( SCIPisFeasIntegral(scip, newlpcandsmax[i]) )
586 branchruledata->skipup[counter] = TRUE;
587 assert(branchruledata->skipdown[counter] != branchruledata->skipup[counter]);
588
589 counter++;
590 }
591 }
592
593 /* when there are new candidates, also try these */
594 if( counter > 0 )
595 {
596 SCIP_Real newdown;
597 SCIP_Real newup;
598 SCIP_Real newscore;
599 int newcand;
600 SCIP_Bool newdownvalid;
601 SCIP_Bool newupvalid;
602 SCIP_Real newbound;
603
604 branchruledata->ntriedunions++;
605 newscore = -SCIPinfinity(scip);
606 SCIP_CALL( SCIPselectVarPseudoStrongBranching(scip, newlpcands, branchruledata->skipdown, branchruledata->skipup, counter, counter,
607 &newcand, &newdown, &newup, &newscore, &newdownvalid, &newupvalid, &newbound, result) );
608
609 if( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM || *result == SCIP_CONSADDED )
610 {
611 SCIPfreeBufferArray(scip, &newlpcands);
612 goto TERMINATE;
613 }
614
615 if( newscore > bestscore )
616 {
617 bestcand = newcand;
618 var = newlpcands[newcand];
619 bestdown = newdown;
620 bestup = newup;
621 bestdownvalid = newdownvalid;
622 bestupvalid = newupvalid;
623 bestscore = newscore;
624 newselected = TRUE;
625 branchruledata->nusefulunions++;
626 }
627 }
628 /* free temporary array for new union candidates */
629 SCIPfreeBufferArray(scip, &newlpcands);
630 }
631
632 /* perform the branching */
633 if( !newselected )
634 {
635 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s> (solval=%g, down=%g, up=%g, score=%g)\n",
636 counter, bestcand, SCIPvarGetName(var), lpcandssolcopy[bestcand], bestdown, bestup, bestscore);
637 }
638 else
639 {
640 SCIPdebugMsg(scip, " -> selected from %d new candidates, candidate %d: variable <%s> (down=%g, up=%g, score=%g)\n",
641 counter, bestcand, SCIPvarGetName(var), bestdown, bestup, bestscore);
642 }
643
644 assert(!SCIPisFeasIntegral(scip, SCIPvarGetSol(lpcands[bestcand], TRUE)));
645
646 SCIP_CALL( SCIPbranchVar(scip, var, &downchild, NULL, &upchild) );
647 assert(downchild != NULL);
648 assert(upchild != NULL);
649
650 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
651 * for cutting off sub problems and improving lower bounds of children
652 */
653 exactsolve = SCIPisExactSolve(scip);
654
655 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
656 allcolsinlp = SCIPallColsInLP(scip);
657
658 /* update the lower bounds in the children */
659 if( allcolsinlp && !exactsolve )
660 {
661 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) );
662 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) );
663 }
664 SCIPdebugMsg(scip, " -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild));
665 SCIPdebugMsg(scip, " -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild));
666
667 *result = SCIP_BRANCHED;
668 }
669
670 TERMINATE:
671 if( branchruledata->useunion && !branchruledata->onlyF2 && SCIPgetDepth(scip) < branchruledata->maxdepthunion )
672 {
673 SCIPfreeBufferArray(scip, &newlpcandsmax);
674 SCIPfreeBufferArray(scip, &newlpcandsmin);
675 }
676 SCIPfreeBufferArray(scip, &lpcandscopy);
677 SCIPfreeBufferArray(scip, &lpcandssolcopy);
678 SCIPfreeBufferArray(scip, &lpcandsfraccopy);
679 SCIPfreeBufferArray(scip, &lpcandsmax);
680 SCIPfreeBufferArray(scip, &lpcandsmin);
681
682 /* if union usage was not successful enough, disable it */
683 if( branchruledata->useunion &&
684 branchruledata->ntriedunions > 10 &&
685 (SCIP_Real)branchruledata->nusefulunions / branchruledata->ntriedunions < branchruledata->minsuccessunion )
686 {
687 SCIPdebugMsg(scip, "Disabling union usage (not effective)\n");
688 branchruledata->useunion = FALSE;
689 }
690
691 return SCIP_OKAY; /*lint !e438*/
692}
693
694/*
695 * branching rule specific interface methods
696 */
697
698/** creates the cloud branching rule and includes it in SCIP */
700 SCIP* scip /**< SCIP data structure */
701 )
702{
703 SCIP_BRANCHRULEDATA* branchruledata;
704 SCIP_BRANCHRULE* branchrule;
705
706 /* create cloud branching rule data */
707 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
708 branchruledata->lastcand = 0;
709 branchruledata->skipsize = 0;
710 branchruledata->skipup = NULL;
711 branchruledata->skipdown = NULL;
712 SCIP_CALL( SCIPcreateClock(scip, &(branchruledata->cloudclock)) );
713
714 /* include branching rule */
715 branchrule = NULL;
718 assert(branchrule != NULL);
719
720 /* set non-fundamental callbacks via setter functions */
721 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyCloud) );
722 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeCloud) );
723 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitCloud) );
724 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpCloud) );
725
726 /* add cloud branching rule parameters */
728 "branching/" BRANCHRULE_NAME "/usecloud",
729 "should a cloud of points be used?",
730 &branchruledata->usecloud, FALSE, DEFAULT_USECLOUD, NULL, NULL) );
732 "branching/" BRANCHRULE_NAME "/onlyF2",
733 "should only F2 be used?",
734 &branchruledata->onlyF2, FALSE, DEFAULT_ONLYF2, NULL, NULL) );
736 "branching/" BRANCHRULE_NAME "/useunion",
737 "should the union of candidates be used?",
738 &branchruledata->useunion, FALSE, DEFAULT_USEUNION, NULL, NULL) );
740 "branching/" BRANCHRULE_NAME "/maxpoints",
741 "maximum number of points for the cloud (-1 means no limit)",
742 &branchruledata->maxpoints, FALSE, DEFAULT_MAXPOINTS, -1, INT_MAX, NULL, NULL) );
744 "branching/" BRANCHRULE_NAME "/minsuccessrate",
745 "minimum success rate for the cloud",
746 &branchruledata->minsuccessrate, FALSE, DEFAULT_MINSUCCESSRATE, 0.0, 1.0, NULL, NULL) );
748 "branching/" BRANCHRULE_NAME "/minsuccessunion",
749 "minimum success rate for the union",
750 &branchruledata->minsuccessunion, FALSE, DEFAULT_MINSUCCESSUNION, 0.0, 1.0, NULL, NULL) );
752 "branching/" BRANCHRULE_NAME "/maxdepthunion",
753 "maximum depth for the union",
754 &branchruledata->maxdepthunion, FALSE, DEFAULT_MAXDEPTHUNION, 0, 65000, NULL, NULL) );
755
756 return SCIP_OKAY;
757}
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:66
static SCIP_DECL_BRANCHINIT(branchInitCloud)
Definition: branch_cloud.c:168
#define BRANCHRULE_PRIORITY
Definition: branch_cloud.c:67
#define DEFAULT_MAXPOINTS
Definition: branch_cloud.c:73
#define DEFAULT_MINSUCCESSUNION
Definition: branch_cloud.c:75
#define DEFAULT_USEUNION
Definition: branch_cloud.c:72
#define BRANCHRULE_NAME
Definition: branch_cloud.c:65
static SCIP_DECL_BRANCHCOPY(branchCopyCloud)
Definition: branch_cloud.c:112
#define DEFAULT_MAXDEPTHUNION
Definition: branch_cloud.c:76
static SCIP_DECL_BRANCHEXECLP(branchExeclpCloud)
Definition: branch_cloud.c:192
#define DEFAULT_ONLYF2
Definition: branch_cloud.c:77
#define DEFAULT_MINSUCCESSRATE
Definition: branch_cloud.c:74
static SCIP_DECL_BRANCHFREE(branchFreeCloud)
Definition: branch_cloud.c:126
#define DEFAULT_USECLOUD
Definition: branch_cloud.c:71
#define BRANCHRULE_MAXDEPTH
Definition: branch_cloud.c:68
#define BRANCHRULE_MAXBOUNDDIST
Definition: branch_cloud.c:69
cloud branching rule
full strong LP branching rule
#define NULL
Definition: def.h:266
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:242
#define SCIP_Real
Definition: def.h:172
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:238
#define SCIP_CALL(x)
Definition: def.h:373
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:699
SCIP_Bool SCIPisExactSolve(SCIP *scip)
Definition: scip_general.c:621
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2082
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1866
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
Definition: scip_prob.c:3762
#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:249
SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
Definition: scip_branch.c:153
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:116
const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:1971
SCIP_BRANCHRULEDATA * SCIPbranchruleGetData(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:1849
SCIP_RETCODE SCIPsetBranchruleFree(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHFREE((*branchfree)))
Definition: scip_branch.c:169
SCIP_RETCODE SCIPsetBranchruleInit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHINIT((*branchinit)))
Definition: scip_branch.c:185
void SCIPbranchruleSetData(SCIP_BRANCHRULE *branchrule, SCIP_BRANCHRULEDATA *branchruledata)
Definition: branch.c:1859
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:395
SCIP_RETCODE SCIPbranchVar(SCIP *scip, SCIP_VAR *var, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1050
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:428
SCIP_RETCODE SCIPchgVarLbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_lp.c:2419
SCIP_RETCODE SCIPchgVarUbDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_lp.c:2451
SCIP_RETCODE SCIPchgRowLhsDive(SCIP *scip, SCIP_ROW *row, SCIP_Real newlhs)
Definition: scip_lp.c:2522
SCIP_RETCODE SCIPchgRowRhsDive(SCIP *scip, SCIP_ROW *row, SCIP_Real newrhs)
Definition: scip_lp.c:2555
SCIP_RETCODE SCIPstartDive(SCIP *scip)
Definition: scip_lp.c:2242
SCIP_RETCODE SCIPchgVarObjDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_lp.c:2378
SCIP_RETCODE SCIPsolveDiveLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_lp.c:2678
SCIP_RETCODE SCIPendDive(SCIP *scip)
Definition: scip_lp.c:2291
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:605
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:626
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:168
SCIP_Bool SCIPallColsInLP(SCIP *scip)
Definition: scip_lp.c:649
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:667
#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:7535
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17292
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17302
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2104
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17312
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:180
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:3046
SCIP_RETCODE SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:878
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1296
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1213
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:13277
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17604
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17439
SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1864
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
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:43
@ 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:63