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