Scippy

SCIP

Solving Constraint Integer Programs

branch_multaggr.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-2022 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 visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 /**@file branch_multaggr.c
16  * @ingroup DEFPLUGINS_BRANCH
17  * @brief fullstrong branching on fractional and multi-aggregated variables
18  * @author Anna Melchiori
19  * @author Gerald Gamrath
20  *
21  * This branching rule uses all fractional binary and integer variables as candidates,
22  * as well as fractional multiaggregated binary and integer variables. Although not
23  * directly contained in the presolved problem anymore, the multi-aggregation provides
24  * an affine linear sum of integer variables, on which branching can be performed.
25  *
26  * For more details, see
27  * G.Gamrath, A.Melchiori, T.Berthold, A.M.Gleixner, D.Salvagnin: Branching on Multi-aggregated Variables
28  * (http://dx.doi.org/10.1007/978-3-319-18008-3_10)
29  */
30 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
31 
32 #include "blockmemshell/memory.h"
33 #include "scip/branch_fullstrong.h"
34 #include "scip/branch_multaggr.h"
35 #include "scip/cons_linear.h"
36 #include "scip/pub_branch.h"
37 #include "scip/pub_cons.h"
38 #include "scip/pub_message.h"
39 #include "scip/pub_tree.h"
40 #include "scip/pub_var.h"
41 #include "scip/scip_branch.h"
42 #include "scip/scip_cons.h"
43 #include "scip/scip_general.h"
44 #include "scip/scip_lp.h"
45 #include "scip/scip_mem.h"
46 #include "scip/scip_message.h"
47 #include "scip/scip_numerics.h"
48 #include "scip/scip_param.h"
49 #include "scip/scip_prob.h"
50 #include "scip/scip_probing.h"
51 #include "scip/scip_solvingstats.h"
52 #include "scip/scip_timing.h"
53 #include "scip/scip_tree.h"
54 #include "scip/scip_var.h"
55 #include "scip/set.h"
56 #include "scip/struct_scip.h"
57 #include "scip/var.h"
58 #include <string.h>
59 
60 #define BRANCHRULE_NAME "multaggr"
61 #define BRANCHRULE_DESC "fullstrong branching on fractional and multi-aggregated variables"
62 #define BRANCHRULE_PRIORITY 0
63 #define BRANCHRULE_MAXDEPTH -1
64 #define BRANCHRULE_MAXBOUNDDIST 1.0
65 
66 
67 #define DEFAULT_REEVALAGE 0LL /**< number of intermediate LPs solved to trigger reevaluation of strong branching
68  * value for a variable that was already evaluated at the current node */
69 #define DEFAULT_MAXPROPROUNDS 0 /**< maximum number of propagation rounds to be performed during multaggr branching
70  * before solving the LP (-1: no limit, -2: parameter settings) */
71 #define DEFAULT_PROBINGBOUNDS TRUE /**< should valid bounds be identified in a probing-like fashion during multi-aggr
72  * branching (only with propagation)? */
73 
74 /*
75  * Data structures
76  */
77 
78 /** branching rule data */
79 struct SCIP_BranchruleData
80 {
81  SCIP_Longint reevalage; /**< number of intermediate LPs solved to trigger reevaluation of strong branching
82  * value for a variable that was already evaluated at the current node */
83  SCIP_Bool probingbounds; /**< should valid bounds be identified in a probing-like fashion during strong
84  * branching (only with propagation)? */
85  int lastcand; /**< last evaluated candidate of last branching rule execution */
86  int maxproprounds; /**< maximum number of propagation rounds to be performed during strong branching
87  * before solving the LP (-1: no limit, -2: parameter settings) */
88  int skipsize; /**< size of skipdown and skipup array */
89  SCIP_Bool* skipdown; /**< should be branching on down child be skipped? */
90  SCIP_Bool* skipup; /**< should be branching on up child be skipped? */
91 #ifdef SCIP_STATISTIC
92  SCIP_CLOCK* clckstrongbr; /**< clock to store the time spent inside the strong branching function on fractional variables */
93  SCIP_CLOCK* clckmultaggrbr; /**< clock to store the time spent inside the strong branching function on multi-aggragated variables */
94  SCIP_Real* ratioggain; /**< for each occurence of a branching on a multi-aggregated variable we store the ratio of the gain that
95  * we would have obtained branching on the best fractional variable over the gain obtained
96  * branching on the current multi-aggregated variable */
97  SCIP_Real ameanratio; /**< arithmetic mean of the ratioggain array */
98  SCIP_Bool noupdate; /**< pointer to store if the probing LP has not been solved so we do not want to
99  * update statistics */
100  int firstmultaggrdepth; /**< depth of the first branching on a multi-aggregated variable */
101  int rundepth; /**< the run of the first multi-aggregated branching */
102  int nmultaggrbranch; /**< number of branchings on multi-aggregated variables */
103  int nfracbranch; /**< number of branchings on fractional variables */
104  int nEscore; /**< number of times that the bestscore over all multi-aggregated variables is equal to the best
105  * fractional variables score and thus we do not branch on the multi-aggregate variable */
106  int nmultaggrcutoff; /**< number of cutoffs detected during the probing mode on multi-aggregated variables */
107  int nmultaggrconsadd; /**< number of times that a probing constraint of a multi-aggregated variable has been
108  * added to the original problem */
109  int nfractcutoff; /**< number of cutoffs detected during strong branching on fractional variables */
110  int nfractconsadd; /**< number of times that during strong branching on fractional variables a constraint has been
111  * added to the original problem or a variables domain has been reduced */
112  int nmultaggrvars; /**< number of multi-aggregated variables in the problem of the last run */
113  int nrun; /**< number of restarts */
114  int size; /**< size of the provided array to store the ratio gain */
115  int nstrongbrcall; /**< number of times that the selectVarstrongBranching function has been called */
116  int nmultaggrbrcall; /**< number of times that the selectVarMultAggrBranching function has been called */
117  int totallpcands; /**< total number of observed lpcands over all selectVarstrongBranching function calls */
118  int totalmultaggrcands; /**< total number of observed multi-aggregregated candidates over all selectVarMultAggrBranching
119  * function calls */
120 #endif
121 };
122 
123 
124 /*
125  * Local methods
126  */
127 
128 /* this function ensures that the allocated memory is enough to store statistics data */
129 #ifdef SCIP_STATISTIC
130 static
131 SCIP_RETCODE ensureArraySize(
132  SCIP* scip, /**< original SCIP data structure */
133  SCIP_BRANCHRULEDATA* branchruledata /**< branching rule data */
134  )
135 {
136  assert(scip != NULL);
137  assert(branchruledata != NULL);
138  assert(branchruledata->ratioggain != NULL);
139  assert(branchruledata->nmultaggrbranch >= 0);
140  assert(branchruledata->size >= 0);
141 
142  /* check whether the size of the array is big enough; reallocate memory if needed */
143  if( branchruledata->nmultaggrbranch + 1 > branchruledata->size )
144  {
145  int newsize = SCIPcalcMemGrowSize(scip, branchruledata->nmultaggrbranch + 1);
146  assert(newsize >= branchruledata->nmultaggrbranch + 1);
147  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &branchruledata->ratioggain, branchruledata->size, newsize) );
148  branchruledata->size = newsize;
149  }
150  return SCIP_OKAY;
151 }
152 #endif
153 
154 /* this function gives us the best candidate for branching among the multi-aggregated variables of the problem
155  * and the best fractional integer variable already selected by strong branching
156 */
157 static
159  SCIP* scip, /**< original SCIP data structure */
160  SCIP_VAR** bestcand, /**< the best candidate variable selected by strong branching */
161  SCIP_Real* bestscore, /**< score of the best branching candidate */
162  SCIP_Real* bestsol, /**< solution value of the best branching candidate */
163  SCIP_Real* bestdown, /**< objective value of the down node when branching on bestcand */
164  SCIP_Real* bestup, /**< objective value of the up node when branching on bestcand */
165  SCIP_Bool* bestdownvalid, /**< is bestdown a valid dual bound for the down branch? */
166  SCIP_Bool* bestupvalid, /**< is bestup a valid dual bound for the up branch? */
167  SCIP_Real* provedbound, /**< proved dual bound for the current subtree */
168  SCIP_Real* estimatedown, /**< pointer to store the down child nodes estimate */
169  SCIP_Real* estimateup, /**< pointer to store the up child nodes estimate */
170 #ifdef SCIP_STATISTIC
171  SCIP_Real* bestmultaggrscore, /**< pointer to store the multi aggregated score */
172 #endif
173  SCIP_RESULT* result /**< pointer to store results of branching */
174  )
175 {
176  SCIP_VAR** fixvars;
177  SCIP_CONS* probingconsdown;
178  SCIP_CONS* probingconsup;
179  SCIP_NODE* node;
180  SCIP_Real* fixvarssols;
181  SCIP_Real fixvarssol;
182  SCIP_Real lpobjval;
183  SCIP_Bool exactsolve;
184  SCIP_Bool allcolsinlp;
185  SCIP_Bool downnodeinf = FALSE;
186  SCIP_Bool startprobing = TRUE;
187  SCIP_Bool endprobing = FALSE;
188  int nfixvars;
189  int i;
190  int j;
191  int k;
192 
193  /* import branchrule data for statistics */
194 #ifdef SCIP_STATISTIC
195  SCIP_BRANCHRULE* branchrule;
196  SCIP_BRANCHRULEDATA* branchruledata;
197 
198  branchrule = SCIPfindBranchrule(scip, BRANCHRULE_NAME);
199  assert(branchrule != NULL);
200 
201  branchruledata = SCIPbranchruleGetData(branchrule);
202  assert(branchruledata != NULL);
203 #endif
204 
205  assert(scip != NULL);
206  assert(bestcand != NULL);
207  assert(bestscore != NULL);
208 
209  /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
210  * for cutting off sub problems and improving lower bounds of children
211  */
212  exactsolve = SCIPisExactSolve(scip);
213 
214  /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
215  allcolsinlp = SCIPallColsInLP(scip);
216 
217  /* get fixed variables */
218  fixvars = SCIPgetFixedVars(scip);
219  nfixvars = SCIPgetNFixedVars(scip);
220  SCIPdebugMsg(scip, " fractional variable: <%s> with value: %f is selected by strong branching\n", SCIPvarGetName(*bestcand), *bestsol);
221 
222  /* check if we would exceed the depth limit */
223  if( SCIP_MAXTREEDEPTH <= SCIPgetDepth(scip) )
224  {
225  SCIPdebugMsg(scip, "cannot perform probing in selectVarMultAggrBranching, depth limit reached.\n");
226  *result = SCIP_DIDNOTRUN;
227  return SCIP_OKAY;
228  }
229 
230  if( nfixvars != 0 )
231  {
232  assert(fixvars != NULL);
233 
234  SCIP_CALL( SCIPallocBufferArray(scip, &fixvarssols, nfixvars) );
235  lpobjval = SCIPgetLPObjval(scip);
236 
237  /* store the values of the fixed variables at the current optimal solution */
238  for( i = 0; i < nfixvars; i++ )
239  {
240  assert(fixvars[i] != NULL);
241  fixvarssols[i] = SCIPvarGetLPSol(fixvars[i]);
242  }
243 
244  for( i = 0; i < nfixvars; i++ )
245  {
246  assert(fixvars[i] != NULL);
247 
248  /* only integer and binary multi-aggregated variables are potential branching candidates */
249  if( SCIPvarGetStatus(fixvars[i]) == SCIP_VARSTATUS_MULTAGGR && (SCIPvarGetType(fixvars[i]) == SCIP_VARTYPE_INTEGER ||
250  SCIPvarGetType(fixvars[i]) == SCIP_VARTYPE_BINARY) )
251  {
252  fixvarssol = fixvarssols[i];
253 
254  /* start probing mode for the fractional multi-aggregated variable */
255  if( !SCIPisFeasIntegral(scip, fixvarssol) )
256  {
257  SCIP_VAR** downvars = NULL;
258  SCIP_VAR** upvars = NULL;
259  SCIP_Real* downvarssols = NULL;
260  SCIP_Real* upvarssols = NULL;
261  SCIP_LPSOLSTAT solstatdown;
262  SCIP_LPSOLSTAT solstatup;
263  SCIP_Real downobjval;
264  SCIP_Real upobjval;
265  SCIP_Real estimateprobdown = 0.0;
266  SCIP_Real estimateprobup = 0.0;
267  SCIP_Bool downinf;
268  SCIP_Bool upinf;
269  SCIP_Bool lperror;
270  int ndownvars;
271  int nupvars;
272 
273  /* start the probing mode if this is the first entrance */
274  if( startprobing )
275  {
276  SCIP_CALL( SCIPstartProbing(scip) );
277  startprobing = FALSE;
278  endprobing = TRUE;
279 
280  SCIPdebugMsg(scip, "PROBING MODE:\n");
281  }
282 
283  SCIPdebugMsg(scip, " multi-aggregated variable: <%s> with value: %f\n", SCIPvarGetName(fixvars[i]), fixvarssol);
284 
285  SCIPstatistic(branchruledata->totalmultaggrcands += 1);
286 
287  /* create the multi-aggregated rounded down constraint */
288  SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsdown, "probingconsdown", SCIPvarGetMultaggrNVars(fixvars[i]),
289  SCIPvarGetMultaggrVars(fixvars[i]), SCIPvarGetMultaggrScalars(fixvars[i]), -SCIPinfinity(scip),
290  SCIPfeasFloor(scip, fixvarssol) - SCIPvarGetMultaggrConstant(fixvars[i]), TRUE, TRUE, FALSE, FALSE,
291  TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) );
292  assert(probingconsdown != NULL);
293 
294  /* create the down child probing node */
295  SCIP_CALL( SCIPnewProbingNode(scip) );
296  node = SCIPgetCurrentNode(scip);
297  assert(node != NULL);
298 
299  SCIP_CALL( SCIPaddConsNode(scip, node, probingconsdown, NULL) );
300  SCIP_CALL( SCIPreleaseCons(scip, &probingconsdown) );
301 
302 #ifdef PRINTNODECONS
303  SCIPdebugMsg(scip, " created down probing node with constraint:\n");
304  SCIP_CALL( SCIPprintCons(scip, probingconsdown, NULL) );
305  SCIPinfoMessage(scip, NULL, "\n");
306 #endif
307 
308  /* solve the down child probing node */
309  SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &downinf) );
310  solstatdown = SCIPgetLPSolstat(scip);
311  lperror = lperror || (solstatdown == SCIP_LPSOLSTAT_NOTSOLVED && downinf == 0) || (solstatdown == SCIP_LPSOLSTAT_ITERLIMIT) ||
312  (solstatdown == SCIP_LPSOLSTAT_TIMELIMIT);
313  assert(solstatdown != SCIP_LPSOLSTAT_UNBOUNDEDRAY);
314 
315  /* break the branching rule if an error occurred, problem was not solved, iteration or time limit was reached */
316  if( lperror )
317  {
318  SCIPdebugMsg(scip, "error solving down node probing LP: status=%d\n", solstatdown);
319  SCIPstatistic(branchruledata->noupdate = TRUE);
320  break;
321  }
322 
323  downobjval = SCIPgetLPObjval(scip);
324  downinf = downinf || SCIPisGE(scip, downobjval, SCIPgetCutoffbound(scip));
325  assert(((solstatdown != SCIP_LPSOLSTAT_INFEASIBLE) && (solstatdown != SCIP_LPSOLSTAT_OBJLIMIT)) || downinf);
326 
327  if( !downinf )
328  {
329  /* when an optimal solution has been found calculate down child's estimate based on pseudo costs */
330  /* estimate = lowerbound + sum(min{f_j * pscdown_j, (1-f_j) * pscup_j}) */
331  estimateprobdown = SCIPnodeGetLowerbound(node);
332  SCIP_CALL( SCIPgetLPBranchCands(scip, &downvars, &downvarssols, NULL, &ndownvars, NULL, NULL) );
333 
334  for( j = 0 ; j < ndownvars; j++ )
335  {
336  SCIP_Real estimateincr;
337  SCIP_Real pscdown;
338  SCIP_Real pscup;
339 
340  assert(downvars != NULL);
341  assert(downvars[j] != NULL);
342 
343  pscdown = SCIPvarGetPseudocost(downvars[j], scip->stat, SCIPsetFeasFloor(scip->set, downvarssols[j]) - downvarssols[j]);
344  pscup = SCIPvarGetPseudocost(downvars[j], scip->stat, SCIPsetFeasCeil(scip->set, downvarssols[j]) - downvarssols[j]);
345  estimateincr = MIN(pscdown, pscup);
346 
347  estimateprobdown += estimateincr;
348  }
349  }
350  SCIP_CALL( SCIPbacktrackProbing(scip, 0) );
351 
352  /* create the multi-aggregated rounded up constraint */
353  SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsup, "probingconsup", SCIPvarGetMultaggrNVars(fixvars[i]), SCIPvarGetMultaggrVars(fixvars[i]),
354  SCIPvarGetMultaggrScalars(fixvars[i]), SCIPfeasCeil(scip, fixvarssol) - SCIPvarGetMultaggrConstant(fixvars[i]), SCIPinfinity(scip),
356  assert(probingconsup != NULL);
357 
358  /* create the up child probing node */
359  SCIP_CALL( SCIPnewProbingNode(scip) );
360  node = SCIPgetCurrentNode(scip);
361 
362  SCIP_CALL( SCIPaddConsNode(scip, node, probingconsup, NULL) );
363  SCIP_CALL( SCIPreleaseCons(scip, &probingconsup) );
364 
365 #ifdef PRINTNODECONS
366  SCIPdebugMsg(scip, " created up probing node with constraint:\n");
367  SCIP_CALL( SCIPprintCons(scip, probingconsup, NULL) );
368  SCIPinfoMessage(scip, NULL, "\n");
369 #endif
370  /* solve the up child probing node */
371  SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &upinf) );
372  solstatup = SCIPgetLPSolstat(scip);
373  lperror = lperror || (solstatup == SCIP_LPSOLSTAT_NOTSOLVED && upinf == 0) || (solstatup == SCIP_LPSOLSTAT_ITERLIMIT) ||
374  (solstatup == SCIP_LPSOLSTAT_TIMELIMIT);
375  assert(solstatup != SCIP_LPSOLSTAT_UNBOUNDEDRAY);
376 
377  /* break the branching rule if an error occurred, problem was not solved, iteration or time limit was reached */
378  if( lperror )
379  {
380  SCIPdebugMsg(scip, "error solving up node probing LP: status=%d\n", solstatup);
381  SCIPstatistic(branchruledata->noupdate = TRUE);
382  break;
383  }
384 
385  upobjval = SCIPgetLPObjval(scip);
386  upinf = upinf || SCIPisGE(scip, upobjval, SCIPgetCutoffbound(scip));
387  assert(((solstatup != SCIP_LPSOLSTAT_INFEASIBLE) && (solstatup != SCIP_LPSOLSTAT_OBJLIMIT)) || upinf);
388 
389  SCIPdebugMsg(scip, " down node objval: %g up node objval: %g\n", downobjval, upobjval);
390 
391  if( !upinf )
392  {
393  /* when an optimal solution has been found calculate up child's estimate based on pseudo costs */
394  /* estimate = lowerbound + sum(min{f_j * pscdown_j, (1-f_j) * pscup_j}) */
395  estimateprobup = SCIPnodeGetLowerbound(node);
396  SCIP_CALL( SCIPgetLPBranchCands(scip, &upvars, &upvarssols, NULL, &nupvars, NULL, NULL) );
397 
398  for( k = 0 ; k < nupvars; k++ )
399  {
400  SCIP_Real estimateincr;
401  SCIP_Real pscdown;
402  SCIP_Real pscup;
403 
404  assert(upvars != NULL);
405  assert(upvars[k] != NULL);
406 
407  pscdown = SCIPvarGetPseudocost(upvars[k], scip->stat, SCIPsetFeasFloor(scip->set, upvarssols[k]) - upvarssols[k]);
408  pscup = SCIPvarGetPseudocost(upvars[k], scip->stat, SCIPsetFeasCeil(scip->set, upvarssols[k]) - upvarssols[k]);
409  estimateincr = MIN(pscdown, pscup);
410  estimateprobup += estimateincr;
411  }
412  }
413  SCIP_CALL( SCIPbacktrackProbing(scip, 0) );
414 
415  /* check whether the children nodes are solved to optimality and give a valid new lower bound or not */
416  if( downinf || upinf )
417  {
418  /* check if the LP is a valid relaxation and we can then collect new information */
419  if( allcolsinlp )
420  {
421  /* cut off the node either when both children are infeasible or the objective limit was reached;
422  * if only one child is feasible with LP value smaller than objective limit, add the corresponding
423  * constraint to the problem and break the branching rule in order to solve the updated LP
424  */
425  if( downinf && upinf )
426  {
427  SCIPdebugMsg(scip, "node can be cut off due to strong branching on multi-aggregated variable <%s>\n",
428  SCIPvarGetName(fixvars[i]));
429  SCIPstatistic(branchruledata->nmultaggrcutoff += 1);
430 
431  *result = SCIP_CUTOFF;
432  break;
433  }
434  else
435  {
436  assert(!lperror);
437 
438  if( downinf )
439  downnodeinf = TRUE;
440 
441  SCIPdebugMsg(scip, "%s child of multi-aggregated variable <%s> is infeasible\n",
442  downinf ? "down" : "up", SCIPvarGetName(fixvars[i]) );
443  SCIPstatistic(branchruledata->nmultaggrconsadd += 1);
444 
445  *result = SCIP_CONSADDED;
446  break;
447  }
448  }
449  }
450  else
451  {
452  /* if both children are solved to optimality and they both give a new valid bound, calculate the score of the
453  * multi-aggregated variable
454  */
455  SCIP_Real downgain;
456  SCIP_Real upgain;
457  SCIP_Real down;
458  SCIP_Real up;
459  SCIP_Real score;
460  SCIP_Real minbound;
461 
462  assert(!downinf);
463  assert(!upinf);
464  assert(!lperror);
465 
466  SCIPdebugMsg(scip, " both probing nodes are valid while branching on multi-aggregated variable: <%s>\n ", SCIPvarGetName(fixvars[i]));
467 
468  down = MAX(downobjval, lpobjval);
469  up = MAX(upobjval, lpobjval);
470  downgain = down - lpobjval;
471  upgain = up - lpobjval;
472  score = SCIPgetBranchScore(scip, NULL, downgain, upgain);
473 
474  if( allcolsinlp && !exactsolve )
475  {
476  /* the minimal lower bound of both children is a proved lower bound of the current subtree */
477  minbound = MIN(downobjval, upobjval);
478  *provedbound = MAX(*provedbound, minbound);
479  }
480 
482  if( score > *bestmultaggrscore )
483  *bestmultaggrscore = score;
484  );
485 
486  /* update the best branching candidate and all its values if a strictly greater score has been found */
487  if( score > *bestscore )
488  {
490  if( branchruledata->nmultaggrbranch == 0 )
491  {
492  branchruledata->rundepth = SCIPgetNRuns(scip);
493  branchruledata->firstmultaggrdepth = SCIPgetFocusDepth(scip);
494  }
495  )
496 
497  SCIPdebugMsg(scip, " <%s> is a better candidate for branching\n", SCIPvarGetName(fixvars[i]));
498 
499  *bestscore = MAX(score, *bestscore);
500  *bestcand = fixvars[i];
501  *bestsol = fixvarssol;
502  *bestdown = downobjval;
503  *bestup = upobjval;
504  *bestdownvalid = TRUE;
505  *bestupvalid = TRUE;
506  *estimatedown = estimateprobdown;
507  *estimateup = estimateprobup;
508  }
509  assert(bestscore != NULL);
510  assert(bestcand != NULL);
511  assert(bestup != NULL);
512  assert(bestdown != NULL);
513  }
514  }
515  }
516  }
517 
518  /* end probing mode */
519  if( endprobing )
520  {
521  SCIP_CALL( SCIPendProbing(scip) );
522  }
523 
524  SCIPdebugMsg(scip, "\n");
525 
526  /* one of the child nodes was infeasible, add the other constraint to the current node */
527  if( *result == SCIP_CONSADDED )
528  {
529  node = SCIPgetCurrentNode(scip);
530  if( downnodeinf )
531  {
532  SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsup, "infconsup", SCIPvarGetMultaggrNVars(fixvars[i]),
533  SCIPvarGetMultaggrVars(fixvars[i]), SCIPvarGetMultaggrScalars(fixvars[i]),
534  SCIPfeasCeil(scip, fixvarssols[i]) - SCIPvarGetMultaggrConstant(fixvars[i]), SCIPinfinity(scip),
536  assert(probingconsup != NULL);
537  SCIP_CALL( SCIPaddConsNode(scip, node, probingconsup, NULL) );
538  SCIPdebugMsg(scip, " <%s> new valid constraint has been added to the original problem\n", SCIPconsGetName(probingconsup));
539  SCIP_CALL( SCIPreleaseCons(scip, &probingconsup) );
540  }
541  else
542  {
543  SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsdown, "infconsdown", SCIPvarGetMultaggrNVars(fixvars[i]),
544  SCIPvarGetMultaggrVars(fixvars[i]), SCIPvarGetMultaggrScalars(fixvars[i]), - SCIPinfinity(scip),
545  SCIPfeasFloor(scip, fixvarssols[i]) - SCIPvarGetMultaggrConstant(fixvars[i]), TRUE, TRUE, FALSE, FALSE,
546  TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) );
547  assert(probingconsdown != NULL);
548  SCIP_CALL( SCIPaddConsNode(scip, node, probingconsdown, NULL) );
549  SCIPdebugMsg(scip, " <%s> new valid constraint has been added to the original problem\n", SCIPconsGetName(probingconsdown));
550  SCIP_CALL( SCIPreleaseCons(scip, &probingconsdown) );
551  }
552  }
553  SCIPfreeBufferArray(scip, &fixvarssols);
554  }
555  return SCIP_OKAY;
556 }
557 
558 
559 /*
560  * Callback methods of branching rule
561  */
562 
563 /** copy method for branchrule plugins (called when SCIP copies plugins) */
564 static
565 SCIP_DECL_BRANCHCOPY(branchCopyMultAggr)
566 { /*lint --e{715}*/
567  assert(scip != NULL);
568  assert(branchrule != NULL);
569  assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
570 
571  /* call inclusion method of branchrule */
573 
574  return SCIP_OKAY;
575 }
576 
577 /** destructor of branching rule to free user data (called when SCIP is exiting) */
578 static
579 SCIP_DECL_BRANCHFREE(branchFreeMultAggr)
580 { /*lint --e{715}*/
581  SCIP_BRANCHRULEDATA* branchruledata;
583  /* free branching rule data */
584  branchruledata = SCIPbranchruleGetData(branchrule);
585  assert(branchruledata != NULL);
586 
587  SCIPstatistic(SCIPfreeBlockMemoryArrayNull(scip , &branchruledata->ratioggain, branchruledata->size));
588  SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipdown, branchruledata->skipsize);
589  SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipup, branchruledata->skipsize);
590 
591  SCIPfreeBlockMemory(scip, &branchruledata);
592  SCIPbranchruleSetData(branchrule, NULL);
593 
594  return SCIP_OKAY;
595 }
596 
597 /** initialization method of branching rule (called after problem was transformed) */
598 static
599 SCIP_DECL_BRANCHINIT(branchInitMultAggr)
600 { /*lint --e{715}*/
601  SCIP_BRANCHRULEDATA* branchruledata;
603  branchruledata = SCIPbranchruleGetData(branchrule);
604  assert(branchruledata != NULL);
605 
606  branchruledata->lastcand = 0;
608  branchruledata->firstmultaggrdepth = 0;
609  branchruledata->nmultaggrbranch = 0;
610  branchruledata->nfracbranch = 0;
611  branchruledata->nEscore = 0;
612  branchruledata->nmultaggrcutoff = 0;
613  branchruledata->nmultaggrconsadd = 0;
614  branchruledata->nfractcutoff = 0;
615  branchruledata->nfractconsadd = 0;
616  branchruledata->nrun = 0;
617  branchruledata->size = 100;
618  branchruledata->ameanratio = 0.0;
619  branchruledata->noupdate = FALSE;
620  branchruledata->clckstrongbr = NULL;
621  branchruledata->clckmultaggrbr = NULL;
622  branchruledata->nstrongbrcall = 0;
623  branchruledata->nmultaggrbrcall = 0;
624  branchruledata->totalmultaggrcands = 0;
625  branchruledata->totallpcands = 0;
626  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->ratioggain, branchruledata->size) );
627  BMSclearMemoryArray(branchruledata->ratioggain, branchruledata->size);
628  SCIP_CALL( SCIPcreateClock(scip, &branchruledata->clckstrongbr) );
629  SCIP_CALL( SCIPcreateClock(scip, &branchruledata->clckmultaggrbr) );
630  )
631  return SCIP_OKAY;
632 }
633 
634 /** deinitialization method of branching rule (called before transformed problem is freed) */
635 static
636 SCIP_DECL_BRANCHEXIT(branchExitMultAggr)
637 { /*lint --e{715}*/
638  SCIP_BRANCHRULEDATA* branchruledata;
639  SCIPstatistic(int j = 0);
640 
641  /* initialize branching rule data */
642  branchruledata = SCIPbranchruleGetData(branchrule);
643  assert(branchruledata != NULL);
644  assert((branchruledata->skipdown != NULL) == (branchruledata->skipup != NULL));
645 
646  /* print statistics */
649  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Multi-aggregated branching stats : \n");
650  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrvars : %d (last run)\n",
651  branchruledata->nmultaggrvars);
652  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " firstmultaggrbranchdepth : %d (in run %d)\n",
653  branchruledata->firstmultaggrdepth,
654  branchruledata->rundepth);
655  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrbranch : %d (tot %d)\n",
656  branchruledata->nmultaggrbranch, branchruledata->nmultaggrbranch + branchruledata->nfracbranch);
657  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrcutoff : %d\n", branchruledata->nmultaggrcutoff);
658  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrconsadd : %d\n", branchruledata->nmultaggrconsadd);
659  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nfractcutoff : %d\n", branchruledata->nfractcutoff);
660  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nfractconsadd : %d\n", branchruledata->nfractconsadd);
661  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nEscore : %d\n", branchruledata->nEscore);
662 
663  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " Branching Time : \n");
664  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nstrongbrcall : %d\n", branchruledata->nstrongbrcall);
665  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totalstrongbrtime : %g\n",
666  SCIPgetClockTime(scip, branchruledata->clckstrongbr));
667  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totallpcands : %d\n", branchruledata->totallpcands);
668 
669  if( branchruledata->totallpcands != 0 )
670  {
671  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimestrongbr : %g\n",
672  SCIPgetClockTime(scip, branchruledata->clckstrongbr) / branchruledata->totallpcands);
673  }
674  else
675  {
676  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimestrongbr : %s\n", "--");
677  }
678 
679  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrbrcall : %d\n", branchruledata->nmultaggrbrcall);
680  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totalmultaggrbrtime : %g\n",
681  SCIPgetClockTime(scip, branchruledata->clckmultaggrbr));
682  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totalmultaggrcands : %d\n", branchruledata->totalmultaggrcands);
683 
684  if( branchruledata->totalmultaggrcands != 0 )
685  {
686  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimemultaggrbr : %g\n",
687  SCIPgetClockTime(scip, branchruledata->clckmultaggrbr) / branchruledata->totalmultaggrcands);
688  }
689  else
690  {
691  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimemultaggrbr : %s\n", "--");
692  }
693 
694  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " Ratioggain :\n");
695  if( branchruledata->nmultaggrbranch != 0 )
696  {
697  for( j = 0; j < branchruledata->nmultaggrbranch; j++ )
698  {
699  branchruledata->ameanratio += branchruledata->ratioggain[j];
700  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " %g", branchruledata->ratioggain[j]);
701  }
702 
704  branchruledata->ameanratio = branchruledata->ameanratio / branchruledata->nmultaggrbranch;
706  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " ameanratio : %4.2f\n", branchruledata->ameanratio);
707  }
708  else
709  {
710  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " ameanratio : %s\n", "--");
711  }
712 
714 
715  /* free arrays */
716  SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->ratioggain, branchruledata->size);
717  SCIP_CALL( SCIPfreeClock(scip, &branchruledata->clckstrongbr) );
718  SCIP_CALL( SCIPfreeClock(scip, &branchruledata->clckmultaggrbr) );
719  )
720  if( branchruledata->skipdown != NULL )
721  {
722  SCIPfreeBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize);
723  SCIPfreeBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize);
724  branchruledata->skipdown = NULL;
725  branchruledata->skipup = NULL;
726  branchruledata->skipsize = 0;
727  }
728  return SCIP_OKAY;
729 }
730 
731 /** branching execution method for fractional LP solutions */
732 static
733 SCIP_DECL_BRANCHEXECLP(branchExeclpMultAggr)
734 { /*lint --e{715}*/
735  SCIP_BRANCHRULEDATA* branchruledata;
736  SCIP_VAR** lpcands;
737  SCIP_VAR** tmplpcands;
738  SCIP_Real* lpcandssol;
739  SCIP_Real* lpcandsfrac;
740  SCIP_Real* tmplpcandssol;
741  SCIP_Real* tmplpcandsfrac;
742  SCIP_NODE* downchild;
743  SCIP_NODE* upchild;
744  SCIP_Real bestup;
745  SCIP_Real bestdown;
746  SCIP_Real bestscore;
747  SCIP_Real provedbound;
748  SCIP_Real estimatedown = 0.0;
749  SCIP_Real estimateup = 0.0;
750  SCIP_Bool bestdownvalid;
751  SCIP_Bool bestupvalid;
752  SCIP_Longint oldreevalage;
753  int bestcandpos;
754  int nlpcands;
755  int npriolpcands;
757  SCIP_Real lpobjval;
759  )
760 
761  assert(branchrule != NULL);
762  assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
763  assert(scip != NULL);
764  assert(result != NULL);
765 
766  SCIPdebugMsg(scip, "Execlp method of mult-aggreg branching\n ");
767  *result = SCIP_DIDNOTRUN;
768 
769  /* get branching rule data */
770  branchruledata = SCIPbranchruleGetData(branchrule);
771  assert(branchruledata != NULL);
772 
773  SCIP_CALL( SCIPgetLongintParam(scip, "branching/fullstrong/reevalage", &oldreevalage) );
774  SCIP_CALL( SCIPsetLongintParam(scip, "branching/fullstrong/reevalage", branchruledata->reevalage) );
775 
776  /* get the lpobjval and the number of multi aggregated variables of the problem as a statistic counter */
778  reoptimize = FALSE;
779  lpobjval = SCIPgetLPObjval(scip);
780 
781  if( SCIPgetNRuns(scip) != branchruledata->nrun )
782  {
783  SCIP_VAR** fixvars;
784  int nfixvars;
785  int i;
786 
787  branchruledata->nmultaggrvars = 0;
788  fixvars = SCIPgetFixedVars(scip);
789  nfixvars = SCIPgetNFixedVars(scip);
790 
791  if( nfixvars != 0 )
792  {
793  for( i = 0; i < nfixvars; i++ )
794  {
795  if( SCIPvarGetStatus(fixvars[i]) == SCIP_VARSTATUS_MULTAGGR && (SCIPvarGetType(fixvars[i]) == SCIP_VARTYPE_INTEGER ||
796  SCIPvarGetType(fixvars[i]) == SCIP_VARTYPE_BINARY) )
797  {
798  branchruledata->nmultaggrvars += 1;
799  }
800  }
801  }
802  branchruledata->nrun = SCIPgetNRuns(scip);
803  }
804  )
805 
806  /* get all branching candidates */
807  SCIP_CALL( SCIPgetLPBranchCands(scip, &tmplpcands, &tmplpcandssol, &tmplpcandsfrac, &nlpcands, &npriolpcands, NULL) );
808  assert(nlpcands > 0);
809  assert(npriolpcands > 0);
810 
811  /* copy LP branching candidates and solution values, because they will be updated w.r.t. the strong branching LP
812  * solution
813  */
814  SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcands, tmplpcands, nlpcands) );
815  SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandssol, tmplpcandssol, nlpcands) );
816  SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandsfrac, tmplpcandsfrac, nlpcands) );
817 
818  if( branchruledata->skipdown == NULL )
819  {
820  assert(branchruledata->skipup == NULL);
821 
822  branchruledata->skipsize = SCIPgetNVars(scip);
823  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize) );
824  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize) );
825  BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
826  BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
827  }
828 
829  /* start the clock to get the time spent inside the function */
831  SCIP_CALL( SCIPstartClock(scip, branchruledata->clckstrongbr) );
832  );
833 
834  /* compute strong branching among the array of fractional variables in order to get the best one */
835  SCIP_CALL( SCIPselectVarStrongBranching(scip, lpcands, lpcandssol, lpcandsfrac, branchruledata->skipdown,
836  branchruledata->skipup, nlpcands, npriolpcands, nlpcands, &branchruledata->lastcand,
837  branchruledata->maxproprounds, branchruledata->probingbounds, TRUE,
838  &bestcandpos, &bestdown, &bestup, &bestscore, &bestdownvalid, &bestupvalid, &provedbound, result) );
839 
841  SCIP_CALL( SCIPstopClock(scip, branchruledata->clckstrongbr) );
842  branchruledata->totallpcands += SCIPgetNLPBranchCands(scip);
843  branchruledata->nstrongbrcall += 1;
844  )
845 
846  if( *result != SCIP_CUTOFF && *result != SCIP_REDUCEDDOM && *result != SCIP_CONSADDED )
847  {
848  SCIP_VAR* bestcand = lpcands[bestcandpos];
849  SCIP_Real bestsol = lpcandssol[bestcandpos];
850  SCIPstatistic( SCIP_Real bestmultaggrscore = -SCIPinfinity(scip); )
851 
853  SCIP_Real fdowngain = 0.0;
854  SCIP_Real fupgain = 0.0;
855 
856  /* reoptimize is set to true if strong branching on fractional variables did not explicitly evaluate the objective
857  * values of the probing child nodes and thus we do not have updated information
858  */
859  if( SCIPisLT(scip, SCIPgetVarStrongbranchLPAge(scip, bestcand), branchruledata->reevalage)
860  || branchruledata->maxproprounds != 0 )
861  reoptimize = TRUE;
862 
863  /* store values needed for the ratioggain statistic */
864  if( !reoptimize )
865  {
866  SCIP_Real fdown;
867  SCIP_Real fup;
868 
869  fdown = MAX(bestdown, lpobjval);
870  fup = MAX(bestup, lpobjval);
871  fdowngain = fdown - lpobjval;
872  fupgain = fup - lpobjval;
873  }
874 
875  /* start and then stop the clock to get the time spent inside the function */
876  SCIP_CALL( SCIPstartClock(scip, branchruledata->clckmultaggrbr) );
877  )
878 
879  /* compute strong branching among the multi-aggregated variables and the best fractional variable */
880 #ifdef SCIP_STATISTIC
881  SCIP_CALL( selectVarMultAggrBranching(scip, &bestcand, &bestscore, &bestsol, &bestdown, &bestup, &bestdownvalid, &bestupvalid, &provedbound,
882  &estimatedown, &estimateup, &bestmultaggrscore, result) );
883 #else
884  SCIP_CALL( selectVarMultAggrBranching(scip, &bestcand, &bestscore, &bestsol, &bestdown, &bestup, &bestdownvalid, &bestupvalid, &provedbound,
885  &estimatedown, &estimateup, result) );
886 #endif
888  SCIP_CALL( SCIPstopClock(scip, branchruledata->clckmultaggrbr) );
889  branchruledata->nmultaggrbrcall += 1;
890  )
891 
892  if( *result != SCIP_CUTOFF && *result != SCIP_CONSADDED )
893  {
895  if( !(branchruledata->noupdate) )
896  {
897  if( SCIPisEQ(scip, bestmultaggrscore, bestscore) )
898  branchruledata->nEscore += 1;
899  }
900  )
901 
902  assert(bestcand != NULL);
903  SCIPdebugMsg(scip, "BRANCHING MODE:\n");
904 
905  /* perform branching on the best found candidate */
906  if( SCIPvarGetStatus(bestcand) == SCIP_VARSTATUS_MULTAGGR )
907  {
908  SCIP_CONS* multaggrconsdown;
909  SCIP_CONS* multaggrconsup;
910 
912  if( !(branchruledata->noupdate) )
913  {
914  branchruledata->nmultaggrbranch += 1;
915 
916  if( !reoptimize )
917  {
918  SCIP_Real gfractbranch;
919  SCIP_Real gmultaggrbranch;
920  SCIP_Real downgain;
921  SCIP_Real upgain;
922  SCIP_Real down;
923  SCIP_Real up;
924  int nmultaggrbranch;
925 
926  down = MAX(bestdown, lpobjval);
927  up = MAX(bestup, lpobjval);
928  downgain = down - lpobjval;
929  upgain = up - lpobjval;
930 
931  SCIP_CALL( ensureArraySize(scip, branchruledata) );
932 
933  gfractbranch= SQRT(MAX(fdowngain,1e-06) * MAX(fupgain,1e-06));
934  gmultaggrbranch = SQRT(MAX(downgain,1e-06) * MAX(upgain,1e-06));
935 
936  nmultaggrbranch = branchruledata->nmultaggrbranch;
937 
938  if( gmultaggrbranch == 0.0 )
939  {
940  branchruledata->ratioggain[nmultaggrbranch - 1] = 1;
941  }
942  else
943  {
944  branchruledata->ratioggain[nmultaggrbranch - 1] = gfractbranch / gmultaggrbranch;
945  }
946  }
947  }
948  )
949 
950  /* create the multi-aggregated constraints rounded up and down */
951  SCIP_CALL( SCIPcreateConsLinear(scip, &multaggrconsdown, "consdown", SCIPvarGetMultaggrNVars(bestcand),
952  SCIPvarGetMultaggrVars(bestcand), SCIPvarGetMultaggrScalars(bestcand), - SCIPinfinity(scip),
953  SCIPfeasFloor(scip, bestsol) - SCIPvarGetMultaggrConstant(bestcand),
955 
956  SCIP_CALL( SCIPcreateConsLinear(scip, &multaggrconsup, "consup", SCIPvarGetMultaggrNVars(bestcand),
958  SCIPfeasCeil(scip, bestsol) - SCIPvarGetMultaggrConstant(bestcand), SCIPinfinity(scip),
960 
961  /* create the child nodes */
962  SCIP_CALL( SCIPcreateChild(scip, &downchild, 1.0, estimatedown) );
963  SCIPdebugMsg(scip, " down node: lowerbound %f estimate %f\n", SCIPnodeGetLowerbound(downchild), SCIPnodeGetEstimate(downchild));
964 
965  SCIP_CALL( SCIPcreateChild(scip, &upchild, 1.0, estimateup) );
966  SCIPdebugMsg(scip, " up node: lowerbound %f estimate %f\n", SCIPnodeGetLowerbound(upchild), SCIPnodeGetEstimate(upchild));
967 
968  assert(downchild != NULL);
969  assert(upchild != NULL);
970 
971  SCIP_CALL( SCIPaddConsNode(scip, downchild, multaggrconsdown, NULL) );
972  SCIP_CALL( SCIPaddConsNode(scip, upchild, multaggrconsup, NULL) );
973 
974 #ifdef PRINTNODECONS
975  SCIPdebugMsg(scip, "branching at node %lld\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
976 
977  SCIPdebugMsg(scip, "created child node %lld with constraint:\n", SCIPnodeGetNumber(downchild));
978  SCIP_CALL( SCIPprintCons(scip, multaggrconsdown, NULL) );
979  SCIPinfoMessage(scip, NULL, "\n");
980 
981  SCIPdebugMsg(scip, "created child node %lld with constraint:\n", SCIPnodeGetNumber(upchild));
982  SCIP_CALL( SCIPprintCons(scip, multaggrconsup, NULL) );
983  SCIPinfoMessage(scip, NULL, "\n");
984 #endif
985 
986  /* relase constraints */
987  SCIP_CALL( SCIPreleaseCons(scip, &multaggrconsdown) );
988  SCIP_CALL( SCIPreleaseCons(scip, &multaggrconsup) );
989 
990  SCIPdebugMsg(scip, "BRANCHED on multi-aggregated variable <%s>\n", SCIPvarGetName(bestcand));
991 
992  *result = SCIP_BRANCHED;
993  }
994  else
995  {
997  if( !(branchruledata->noupdate) )
998  branchruledata->nfracbranch += 1
999  );
1000 
1001  assert(*result == SCIP_DIDNOTRUN);
1002  assert(SCIPisLT(scip, provedbound, SCIPgetCutoffbound(scip)));
1003 
1004  SCIP_CALL( SCIPbranchVarVal(scip, bestcand, bestsol, &downchild, NULL, &upchild) );
1005 
1006  assert(downchild != NULL);
1007  assert(upchild != NULL);
1008 
1009  SCIPdebugMsg(scip, "BRANCHED on fractional variable <%s>\n", SCIPvarGetName(bestcand));
1010 
1011  *result = SCIP_BRANCHED;
1012  }
1013 
1014  /* update the lower bounds in the children; we must not do this if columns are missing in the LP
1015  * (e.g., because we are doing branch-and-price) or the problem should be solved exactly
1016  */
1017  if( SCIPallColsInLP(scip) && !SCIPisExactSolve(scip) )
1018  {
1019  SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) );
1020  SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) );
1021  }
1022  SCIPdebugMsg(scip, " -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild));
1023  SCIPdebugMsg(scip, " -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild));
1024  }
1025  }
1026  else
1027  {
1028  SCIPdebugMsg(scip, "strong branching breaks\n" );
1029 
1030  SCIPstatistic(
1031  if( *result == SCIP_CUTOFF )
1032  {
1033  branchruledata->nfractcutoff += 1;
1034  }
1035  else
1036  {
1037  branchruledata->nfractconsadd += 1;
1038  }
1039  )
1040  }
1041 
1042  SCIPfreeBufferArray(scip, &lpcandsfrac);
1043  SCIPfreeBufferArray(scip, &lpcandssol);
1044  SCIPfreeBufferArray(scip, &lpcands);
1045 
1046  SCIP_CALL( SCIPsetLongintParam(scip, "branching/fullstrong/reevalage", oldreevalage) );
1047 
1048  return SCIP_OKAY;
1049 }
1050 
1051 /*
1052  * branching rule specific interface methods
1053  */
1054 
1055 /** creates the multi-aggregated branching rule and includes it in SCIP */
1057  SCIP* scip /**< SCIP data structure */
1058  )
1060  SCIP_BRANCHRULEDATA* branchruledata;
1061  SCIP_BRANCHRULE* branchrule;
1062 
1063  /* create multaggr branching rule data */
1064  SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
1065  branchruledata->lastcand = 0;
1066  branchruledata->skipsize = 0;
1067  branchruledata->skipup = NULL;
1068  branchruledata->skipdown = NULL;
1069  SCIPstatistic(branchruledata->ratioggain = NULL);
1070 
1071  /* include branching rule */
1073  BRANCHRULE_MAXDEPTH, BRANCHRULE_MAXBOUNDDIST, branchruledata) );
1074 
1075  assert(branchrule != NULL);
1076 
1077  /* set non fundamental callbacks via setter functions */
1078  SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyMultAggr) );
1079  SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeMultAggr) );
1080  SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitMultAggr) );
1081  SCIP_CALL( SCIPsetBranchruleExit(scip, branchrule, branchExitMultAggr) );
1082  SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpMultAggr) );
1083 
1084  /* multi-aggregated branching rule parameters */
1086  "branching/multaggr/reevalage",
1087  "number of intermediate LPs solved to trigger reevaluation of strong branching value for a variable that was already evaluated at the current node",
1088  &branchruledata->reevalage, TRUE, DEFAULT_REEVALAGE, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1089  SCIP_CALL( SCIPaddIntParam(scip,
1090  "branching/multaggr/maxproprounds",
1091  "maximum number of propagation rounds to be performed during multaggr branching before solving the LP (-1: no limit, -2: parameter settings)",
1092  &branchruledata->maxproprounds, TRUE, DEFAULT_MAXPROPROUNDS, -2, INT_MAX, NULL, NULL) );
1094  "branching/multaggr/probingbounds",
1095  "should valid bounds be identified in a probing-like fashion during multaggr branching (only with propagation)?",
1096  &branchruledata->probingbounds, TRUE, DEFAULT_PROBINGBOUNDS, NULL, NULL) );
1097 
1098  return SCIP_OKAY;
1099 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:386
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:101
SCIP_STAT * stat
Definition: struct_scip.h:70
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:90
static SCIP_DECL_BRANCHFREE(branchFreeMultAggr)
SCIP_BRANCHRULEDATA * SCIPbranchruleGetData(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:1840
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
public methods for SCIP parameter handling
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:82
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17702
public methods for branch and bound tree
SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
Definition: scip_probing.c:216
public methods for memory management
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
Definition: tree.c:7452
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17690
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
Definition: type_branch.h:48
public methods for timing
#define DEFAULT_REEVALAGE
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:169
SCIP_RETCODE SCIPsetBranchruleExit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXIT((*branchexit)))
Definition: scip_branch.c:192
SCIP_RETCODE SCIPsetBranchruleFree(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHFREE((*branchfree)))
Definition: scip_branch.c:160
#define FALSE
Definition: def.h:87
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 SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:102
#define BRANCHRULE_MAXDEPTH
SCIP_Real SCIPinfinity(SCIP *scip)
#define TRUE
Definition: def.h:86
SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
Definition: scip_branch.c:144
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
SCIP_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
Definition: scip_branch.c:288
static SCIP_DECL_BRANCHEXIT(branchExitMultAggr)
public methods for problem variables
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
#define DEFAULT_MAXPROPROUNDS
public methods for branching rules
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:107
#define DEFAULT_PROBINGBOUNDS
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:123
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:118
#define SCIP_LONGINT_MAX
Definition: def.h:163
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:42
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:419
public methods for SCIP variables
#define SCIPdebugMsg
Definition: scip_message.h:69
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:74
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
static SCIP_RETCODE selectVarMultAggrBranching(SCIP *scip, SCIP_VAR **bestcand, SCIP_Real *bestscore, SCIP_Real *bestsol, SCIP_Real *bestdown, SCIP_Real *bestup, SCIP_Bool *bestdownvalid, SCIP_Bool *bestupvalid, SCIP_Real *provedbound, SCIP_Real *estimatedown, SCIP_Real *estimateup, SCIP_RESULT *result)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
public methods for numerical tolerances
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
Definition: scip_branch.c:240
public methods for querying solving statistics
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:840
public methods for the branch-and-bound tree
int SCIPgetNFixedVars(SCIP *scip)
Definition: scip_prob.c:2308
#define BRANCHRULE_NAME
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7432
SCIP_VAR ** SCIPgetFixedVars(SCIP *scip)
Definition: scip_prob.c:2265
public methods for managing constraints
SCIP_Real SCIPvarGetPseudocost(SCIP_VAR *var, SCIP_STAT *stat, SCIP_Real solvaldelta)
Definition: var.c:14476
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:67
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE reoptimize(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol, BLOCKPROBLEM **blockproblem, int nblocks, SCIP_SOL **newsol, SCIP_Bool *success)
Definition: heur_dps.c:1339
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8085
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip_probing.c:251
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
SCIP_Real SCIPsetFeasCeil(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6776
#define NULL
Definition: lpi_spx1.cpp:155
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:18284
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip_branch.c:1008
internal methods for global SCIP settings
#define SCIP_CALL(x)
Definition: def.h:384
SCIP main data structure.
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_probing.c:810
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17714
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1117
SCIP_Longint SCIPgetVarStrongbranchLPAge(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:4191
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:216
SCIP_RETCODE SCIPgetLongintParam(SCIP *scip, const char *name, SCIP_Longint *value)
Definition: scip_param.c:279
#define BRANCHRULE_MAXBOUNDDIST
public methods for constraint handler plugins and constraints
SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3322
internal methods for problem variables
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
full strong LP branching rule
fullstrong branching on fractional and multi-aggregated variables
#define SCIP_Bool
Definition: def.h:84
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:159
static SCIP_DECL_BRANCHINIT(branchInitMultAggr)
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:310
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:661
SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
Definition: scip_prob.c:3756
void SCIPbranchruleSetData(SCIP_BRANCHRULE *branchrule, SCIP_BRANCHRULEDATA *branchruledata)
Definition: branch.c:1850
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
#define MAX(x, y)
Definition: tclique_def.h:83
int SCIPgetNRuns(SCIP *scip)
Constraint handler for linear constraints in their most general form, .
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17678
#define SCIP_MAXTREEDEPTH
Definition: def.h:320
#define BRANCHRULE_DESC
public methods for the LP relaxation, rows and columns
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1991
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7462
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPsetFeasFloor(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6765
public methods for branching rule plugins and branching
general public methods
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:238
SCIP_RETCODE SCIPincludeBranchruleMultAggr(SCIP *scip)
public methods for the probing mode
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
SCIP_SET * set
Definition: struct_scip.h:63
public methods for message output
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17370
#define SCIPstatistic(x)
Definition: pub_message.h:111
static SCIP_DECL_BRANCHCOPY(branchCopyMultAggr)
#define SCIP_Real
Definition: def.h:177
const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:1962
static SCIP_DECL_BRANCHEXECLP(branchExeclpMultAggr)
SCIP_RETCODE SCIPsetBranchruleInit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHINIT((*branchinit)))
Definition: scip_branch.c:176
public methods for message handling
#define BRANCHRULE_PRIORITY
#define SCIP_Longint
Definition: def.h:162
SCIP_Bool SCIPallColsInLP(SCIP *scip)
Definition: scip_lp.c:640
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17416
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:102
SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
Definition: scip_probing.c:156
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip_probing.c:110
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:123
SCIPallocBlockMemory(scip, subsol))
public methods for global and local (sub)problems
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:152
SCIP_Bool SCIPisExactSolve(SCIP *scip)
Definition: scip_general.c:581
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:536
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:48
memory allocation routines