Scippy

SCIP

Solving Constraint Integer Programs

presol_components.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 presol_components.c
17  * @ingroup PRESOLVERS
18  * @brief solve independent components in advance
19  * @author Dieter Weninger
20  * @author Gerald Gamrath
21  *
22  * This presolver looks for independent components at the end of the presolving.
23  * If independent components are found in which a maximum number of discrete variables
24  * is not exceeded, the presolver tries to solve them in advance as subproblems.
25  * Afterwards, if a subproblem was solved to optimality, the corresponding
26  * variables/constraints can be fixed/deleted in the main problem.
27  *
28  * @todo simulation of presolving without solve
29  * @todo solve all components with less than given size, count number of components with nodelimit reached;
30  * if all components could be solved within nodelimit (or all but x), continue solving components in
31  * increasing order until one hit the node limit
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include <assert.h>
37 
38 #include "scip/presol_components.h"
39 
40 #define PRESOL_NAME "components"
41 #define PRESOL_DESC "components presolver"
42 #define PRESOL_PRIORITY -9200000 /**< priority of the presolver (>= 0: before, < 0: after constraint handlers); combined with propagators */
43 #define PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
44 #define PRESOL_DELAY TRUE /**< should presolver be delayed, if other presolvers found reductions? */
45 
46 #define DEFAULT_WRITEPROBLEMS FALSE /**< should the single components be written as an .lp-file? */
47 #define DEFAULT_MAXINTVARS 500 /**< maximum number of integer (or binary) variables to solve a subproblem directly (-1: no solving) */
48 #define DEFAULT_NODELIMIT 10000LL /**< maximum number of nodes to be solved in subproblems */
49 #define DEFAULT_INTFACTOR 1.0 /**< the weight of an integer variable compared to binary variables */
50 #define DEFAULT_RELDECREASE 0.2 /**< percentage by which the number of variables has to be decreased after the last component solving
51  * to allow running again (1.0: do not run again) */
52 #define DEFAULT_FEASTOLFACTOR 1.0 /**< default value for parameter to increase the feasibility tolerance in all sub-SCIPs */
53 
54 #ifdef SCIP_STATISTIC
55 static int NCATEGORIES = 6;
56 static int CATLIMITS[] = {0,20,50,100,500};
57 #endif
58 
59 /*
60  * Data structures
61  */
62 
63 /** control parameters */
64 struct SCIP_PresolData
65 {
66  SCIP* subscip; /** sub-SCIP used to solve single components */
67  SCIP_Longint nodelimit; /** maximum number of nodes to be solved in subproblems */
68  SCIP_Real intfactor; /** the weight of an integer variable compared to binary variables */
69  SCIP_Real reldecrease; /** percentage by which the number of variables has to be decreased after the last component solving
70  * to allow running again (1.0: do not run again) */
71  SCIP_Real feastolfactor; /** parameter to increase the feasibility tolerance in all sub-SCIPs */
72  SCIP_Bool didsearch; /** did the presolver already search for components? */
73  SCIP_Bool pluginscopied; /** was the copying of the plugins successful? */
74  SCIP_Bool writeproblems; /** should the single components be written as an .lp-file? */
75  int maxintvars; /** maximum number of integer (or binary) variables to solve a subproblem directly (-1: no solving) */
76  int lastnvars; /** number of variables after last run of the presolver */
77 #ifdef SCIP_STATISTIC
78  int* compspercat; /** number of components of the different categories */
79  SCIP_Real subsolvetime; /** total solving time of the subproblems */
80  int nsinglevars; /** number of components with a single variable without constraint */
81 #endif
82 };
83 
84 /*
85  * Statistic methods
86  */
87 
88 #ifdef SCIP_STATISTIC
89 /** initialize data for statistics */
90 static
91 SCIP_RETCODE initStatistics(
92  SCIP* scip, /**< SCIP data structure */
93  SCIP_PRESOLDATA* presoldata /**< presolver data */
94  )
95 {
96  assert(scip != NULL);
97  assert(presoldata != NULL);
98 
99  SCIP_CALL( SCIPallocMemoryArray(scip, &presoldata->compspercat, NCATEGORIES) );
100  BMSclearMemoryArray(presoldata->compspercat, NCATEGORIES);
101 
102  presoldata->nsinglevars = 0;
103  presoldata->subsolvetime = 0.0;
104 
105  return SCIP_OKAY;
106 }
107 
108 /** free data for statistics */
109 static
110 void freeStatistics(
111  SCIP* scip, /**< SCIP data structure */
112  SCIP_PRESOLDATA* presoldata /**< presolver data */
113  )
114 {
115  assert(scip != NULL);
116  assert(presoldata != NULL);
117 
118  SCIPfreeMemoryArray(scip, &presoldata->compspercat);
119 }
120 
121 /** reset data for statistics */
122 static
123 void resetStatistics(
124  SCIP* scip, /**< SCIP data structure */
125  SCIP_PRESOLDATA* presoldata /**< presolver data */
126  )
127 {
128  assert(scip != NULL);
129  assert(presoldata != NULL);
130 
131  BMSclearMemoryArray(presoldata->compspercat, NCATEGORIES);
132 
133  presoldata->nsinglevars = 0;
134  presoldata->subsolvetime = 0.0;
135 }
136 
137 
138 /** statistics: categorize the component with the given number of binary and integer variables */
139 static
140 void updateStatisticsComp(
141  SCIP_PRESOLDATA* presoldata, /**< presolver data */
142  int nbinvars, /**< number of binary variables */
143  int nintvars /**< number of integer variables */
144  )
145 {
146  int ndiscretevars;
147  int i;
148 
149  assert(presoldata != NULL);
150 
151  ndiscretevars = nbinvars + nintvars;
152 
153  /* check into which category the component belongs by looking at the number of discrete variables */
154  for( i = 0; i < (NCATEGORIES - 1); ++i )
155  {
156  if( ndiscretevars <= CATLIMITS[i] )
157  {
158  presoldata->compspercat[i]++;
159  break;
160  }
161  }
162 
163  /* number of discrete variables greater than all limits, so component belongs to last category */
164  if( i == (NCATEGORIES - 1) )
165  presoldata->compspercat[i]++;
166 }
167 
168 /** statistics: increase the number of components with a single variable and no constraints */
169 static
170 void updateStatisticsSingleVar(
171  SCIP_PRESOLDATA* presoldata /**< presolver data */
172  )
173 {
174  assert(presoldata != NULL);
175 
176  presoldata->nsinglevars++;
177 }
178 
179 /** statistics: update the total subproblem solving time */
180 static
181 void updateStatisticsSubsolvetime(
182  SCIP_PRESOLDATA* presoldata, /**< presolver data */
183  SCIP_Real subsolvetime /**< subproblem solving time to add to the statistics */
184  )
185 {
186  assert(presoldata != NULL);
187 
188  presoldata->subsolvetime += subsolvetime;
189 }
190 
191 /** print statistics */
192 static
193 void printStatistics(
194  SCIP_PRESOLDATA* presoldata /**< presolver data */
195  )
196 {
197  int i;
198 
199  assert(presoldata != NULL);
200 
201  printf("############\n");
202  printf("# Connected Components Presolver Statistics:\n");
203 
204  printf("# Categorization:");
205  for( i = 0; i < NCATEGORIES - 1; ++i )
206  {
207  printf("[<= %d: %d]", CATLIMITS[i], presoldata->compspercat[i]);
208  }
209  printf("[> %d: %d]\n", CATLIMITS[NCATEGORIES - 2], presoldata->compspercat[NCATEGORIES - 1]);
210  printf("# Components without constraints: %d\n", presoldata->nsinglevars);
211  printf("# Total subproblem solving time: %.2f\n", presoldata->subsolvetime);
212  printf("############\n");
213 }
214 #endif
215 
216 
217 /*
218  * Local methods
219  */
220 
221 /** copies a connected component consisting of the given constraints and variables into a sub-SCIP
222  * and tries to solve the sub-SCIP to optimality
223  */
224 static
226  SCIP* scip, /**< SCIP data structure */
227  SCIP_PRESOLDATA* presoldata, /**< presolver data */
228  SCIP_HASHMAP* consmap, /**< constraint hashmap used to improve performance */
229  int compnr, /**< number of the component */
230  SCIP_CONS** conss, /**< constraints contained in this component */
231  int nconss, /**< number of constraints contained in this component */
232  SCIP_VAR** vars, /**< variables contained in this component */
233  SCIP_Real* fixvals, /**< array to store the values to fix the variables to */
234  int nvars, /**< number of variables contained in this component */
235  int nbinvars, /**< number of binary variables contained in this component */
236  int nintvars, /**< number of integer variables contained in this component */
237  int* nsolvedprobs, /**< pointer to increase, if the subproblem was solved */
238  int* ndeletedvars, /**< pointer to increase by the number of deleted variables */
239  int* ndeletedconss, /**< pointer to increase by the number of deleted constraints */
240  SCIP_RESULT* result /**< pointer to store the result of the presolving call */
241  )
242 {
243  char name[SCIP_MAXSTRLEN];
244  SCIP* subscip;
245  SCIP_HASHMAP* varmap;
246  SCIP_CONS* newcons;
247  SCIP_Real timelimit;
248  SCIP_Real memorylimit;
249  SCIP_Real feastol;
250  SCIP_Bool success;
251  int i;
252 
253  assert(scip != NULL);
254  assert(presoldata != NULL);
255  assert(conss != NULL);
256  assert(nconss > 0);
257  assert(vars != NULL);
258  assert(nvars > 0);
259  assert(nsolvedprobs != NULL);
260 
261  *result = SCIP_DIDNOTRUN;
262 
263 #ifndef SCIP_DEBUG
264  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "build sub-SCIP for component %d: %d vars (%d bin, %d int, %d cont), %d conss\n",
265  compnr, nvars, nbinvars, nintvars, nvars - nintvars - nbinvars, nconss);
266 #else
267  SCIPdebugMessage("build sub-SCIP for component %d: %d vars (%d bin, %d int, %d cont), %d conss\n",
268  compnr, nvars, nbinvars, nintvars, nvars - nintvars - nbinvars, nconss);
269 #endif
270 
271  /* stop if the problem has too many integer variables; only if the problems should be written we have to build it anyway */
272  if( presoldata->maxintvars != -1 && (nbinvars + presoldata->intfactor * nintvars > presoldata->maxintvars)
273  && !presoldata->writeproblems )
274  {
275 #ifndef SCIP_DEBUG
276  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "--> not created (too many integer variables)\n");
277 #else
278  SCIPdebugMessage("--> not created (too many integer variables)\n");
279 #endif
280 
281  return SCIP_OKAY;
282  }
283 
284  /* check whether there is enough time and memory left */
285  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
286  if( !SCIPisInfinity(scip, timelimit) )
287  timelimit -= SCIPgetSolvingTime(scip);
288  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
289 
290  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
291  if( !SCIPisInfinity(scip, memorylimit) )
292  {
293  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
294  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
295  }
296 
297  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
298  if( timelimit <= 0.0 || memorylimit <= (1.0 * nvars / SCIPgetNVars(scip)) * (1.0 * nconss / SCIPgetNConss(scip)) *
299  ((SCIPgetMemUsed(scip) + SCIPgetMemExternEstim(scip))/1048576.0) )
300  {
301  SCIPdebugMessage("--> not created (not enough memory or time left)\n");
302  return SCIP_OKAY;
303  }
304 
305  /* create sub-SCIP */
306  if( presoldata->subscip == NULL )
307  {
308  SCIP_CALL( SCIPcreate(&presoldata->subscip) );
309  subscip = presoldata->subscip;
310 
311  /* copy plugins, we omit pricers (because we do not run if there are active pricers) and dialogs */
312  success = TRUE;
313  SCIP_CALL( SCIPcopyPlugins(scip, subscip, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
314  TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, &success) );
315 
316  /* abort if the plugins were not successfully copied */
317  if( !success )
318  {
319  SCIP_CALL( SCIPfree(&presoldata->subscip) );
320  presoldata->subscip = NULL;
321  presoldata->pluginscopied = FALSE;
322 
323  return SCIP_OKAY;
324  }
325  /* copy parameter settings */
326  SCIP_CALL( SCIPcopyParamSettings(scip, subscip) );
327 
328  if( !SCIPisParamFixed(subscip, "limits/solutions") )
329  {
330  SCIP_CALL( SCIPsetIntParam(subscip, "limits/solutions", -1) );
331  }
332  if( !SCIPisParamFixed(subscip, "limits/bestsol") )
333  {
334  SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", -1) );
335  }
336 
337  /* set gap limit to 0 */
338  SCIP_CALL( SCIPsetRealParam(subscip, "limits/gap", 0.0) );
339 
340  /* reduce the effort spent for hash tables */
341  if( !SCIPisParamFixed(subscip, "misc/usevartable") )
342  {
343  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/usevartable", FALSE) );
344  }
345  if( !SCIPisParamFixed(subscip, "misc/useconstable") )
346  {
347  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/useconstable", FALSE) );
348  }
349  if( !SCIPisParamFixed(subscip, "misc/usesmalltables") )
350  {
351  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/usesmalltables", TRUE) );
352  }
353 
354  /* increase feasibility tolerance if asked for */
355  if( !SCIPisEQ(scip, presoldata->feastolfactor, 1.0) )
356  {
357  SCIP_CALL( SCIPgetRealParam(scip, "numerics/feastol", &feastol) );
358  SCIP_CALL( SCIPsetRealParam(subscip, "numerics/feastol", feastol * presoldata->feastolfactor) );
359  }
360 
361  /* do not catch control-C */
362  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
363 
364 #ifndef SCIP_MORE_DEBUG
365  /* disable output */
366  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
367 #endif
368  }
369  else
370  {
371  subscip = presoldata->subscip;
372  }
373 
374  /* set time and memory limit for the subproblem */
375  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
376  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
377 
378  if( nbinvars + nintvars > 0 )
379  {
380  /* set node limit */
381  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", presoldata->nodelimit) );
382  }
383  else
384  {
385  /* if we have only continuous variables, solving the root should be enough;
386  * this avoids to spend much time in a nonlinear subscip with only continuous variables */
387  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", 1LL) );
388  }
389 
390  /* create problem in sub-SCIP */
391  /* get name of the original problem and add "comp_nr" */
392  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp_%d", SCIPgetProbName(scip), compnr);
393  SCIP_CALL( SCIPcreateProb(subscip, name, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
394 
395  /* create variable hashmap */
396  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(subscip), 10 * nvars) );
397 
398  for( i = 0; i < nconss; ++i )
399  {
400  /* copy the constraint */
401  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(conss[i]));
402  SCIP_CALL( SCIPgetConsCopy(scip, subscip, conss[i], &newcons, SCIPconsGetHdlr(conss[i]), varmap, consmap, name,
403  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, &success) );
404 
405  /* abort if constraint was not successfully copied */
406  if( !success )
407  goto TERMINATE;
408 
409  SCIP_CALL( SCIPaddCons(subscip, newcons) );
410  SCIP_CALL( SCIPreleaseCons(subscip, &newcons) );
411  }
412 
413  /* write the problem, if requested */
414  if( presoldata->writeproblems )
415  {
416  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp_%d.cip", SCIPgetProbName(scip), compnr);
417  SCIPdebugMessage("write problem to file %s\n", name);
418  SCIP_CALL( SCIPwriteOrigProblem(subscip, name, NULL, FALSE) );
419  }
420 
421  /* the following asserts are not true, because some aggregations in the original scip instance could not get resolved
422  * inside some constraints, so the copy (subscip) will have also some inactive variables which were copied
423  */
424 #if 0
425  /* there might be less variables in the subscip, because variables might be cancelled out during copying constraint
426  * when transferring variables to active variables
427  */
428  assert(nbinvars >= SCIPgetNBinVars(subscip));
429  assert(nintvars >= SCIPgetNIntVars(subscip));
430 #endif
431 
432  /* In extended debug mode, we want to be informed if the number of variables was reduced during copying.
433  * This might happen, since the components presolver uses SCIPgetConsVars() and then SCIPgetActiveVars() to get the
434  * active representation, while SCIPgetConsCopy() might use SCIPgetProbvarLinearSum() and this might cancel out some
435  * of the active variables and cannot be avoided. However, we want to notice it and check whether the constraint
436  * handler could do something more clever.
437  */
438 #ifdef SCIP_MORE_DEBUG
439  if( nvars > SCIPgetNVars(subscip) )
440  {
441  SCIPinfoMessage(scip, NULL, "copying component %d reduced number of variables: %d -> %d\n", compnr, nvars, SCIPgetNVars(subscip));
442  }
443 #endif
444 
445  if( presoldata->maxintvars == -1 || (SCIPgetNBinVars(subscip) + presoldata->intfactor * SCIPgetNIntVars(subscip) <= presoldata->maxintvars) )
446  {
447  /* solve the subproblem */
448  SCIP_CALL( SCIPsolve(subscip) );
449 
450 #ifdef SCIP_MORE_DEBUG
451  SCIP_CALL( SCIPprintStatistics(subscip, NULL) );
452 #endif
453 
454  SCIPstatistic( updateStatisticsSubsolvetime(presoldata, SCIPgetSolvingTime(subscip)) );
455 
456  if( SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL )
457  {
458  SCIP_SOL* sol;
459  SCIP_VAR* subvar;
460  SCIP_Bool feasible;
461  SCIP_Bool infeasible;
462  SCIP_Bool fixed;
463 
464  ++(*nsolvedprobs);
465 
466  sol = SCIPgetBestSol(subscip);
467 
468 #ifdef SCIP_DEBUG
469  SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, TRUE, TRUE) );
470 #else
471  SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE) );
472 #endif
473 
474  SCIPdebugMessage("--> solved to optimality: time=%.2f, solution is%s feasible\n", SCIPgetSolvingTime(subscip), feasible ? "" : " not");
475 
476  if( feasible )
477  {
478  SCIP_Real glb;
479  SCIP_Real gub;
480 
481  /* get values of variables in the optimal solution */
482  for( i = 0; i < nvars; ++i )
483  {
484  subvar = (SCIP_VAR*)SCIPhashmapGetImage(varmap, vars[i]);
485 
486  /* get global bounds */
487  glb = SCIPvarGetLbGlobal(vars[i]);
488  gub = SCIPvarGetUbGlobal(vars[i]);
489 
490  if( subvar != NULL )
491  {
492  /* get solution value from optimal solution of the component */
493  fixvals[i] = SCIPgetSolVal(subscip, sol, subvar);
494 
495  assert(SCIPisFeasLE(scip, fixvals[i], SCIPvarGetUbLocal(vars[i])));
496  assert(SCIPisFeasGE(scip, fixvals[i], SCIPvarGetLbLocal(vars[i])));
497 
498  /* checking a solution is done with a relative tolerance of feasibility epsilon, if we really want to
499  * change the bounds of the variables by fixing them, the old bounds must not be violated by more than
500  * the absolute epsilon; therefore, we change the fixing values, if needed, and mark that the solution
501  * has to be checked again
502  */
503  if( SCIPisGT(scip, fixvals[i], gub) )
504  {
505  SCIPdebugMessage("variable <%s> fixval: %f violates global upperbound: %f\n",
506  SCIPvarGetName(vars[i]), fixvals[i], gub);
507  fixvals[i] = gub;
508  feasible = FALSE;
509  }
510  else if( SCIPisLT(scip, fixvals[i], glb) )
511  {
512  SCIPdebugMessage("variable <%s> fixval: %f violates global lowerbound: %f\n",
513  SCIPvarGetName(vars[i]), fixvals[i], glb);
514  fixvals[i] = glb;
515  feasible = FALSE;
516  }
517  assert(SCIPisLE(scip, fixvals[i], SCIPvarGetUbLocal(vars[i])));
518  assert(SCIPisGE(scip, fixvals[i], SCIPvarGetLbLocal(vars[i])));
519  }
520  else
521  {
522  /* the variable was not copied, so it was cancelled out of constraints during copying;
523  * thus, the variable is not constrained and we fix it to its best bound
524  */
525  if( SCIPisPositive(scip, SCIPvarGetObj(vars[i])) )
526  fixvals[i] = glb;
527  else if( SCIPisNegative(scip, SCIPvarGetObj(vars[i])) )
528  fixvals[i] = gub;
529  else
530  {
531  fixvals[i] = 0.0;
532  fixvals[i] = MIN(fixvals[i], gub);
533  fixvals[i] = MAX(fixvals[i], glb);
534  }
535  }
536  }
537 
538  /* the solution value of at least one variable is feasible with a relative tolerance of feasibility epsilon,
539  * but infeasible with an absolute tolerance of epsilon; try to set the variables to the bounds and check
540  * solution again (changing the values might now introduce infeasibilities of constraints)
541  */
542  if( !feasible )
543  {
544  SCIP_Real origobj;
545 
546  SCIPdebugMessage("solution violates bounds by more than epsilon, check the corrected solution...\n");
547 
548  origobj = SCIPgetSolOrigObj(subscip, SCIPgetBestSol(subscip));
549 
550  SCIP_CALL( SCIPfreeTransform(subscip) );
551 
552  SCIP_CALL( SCIPcreateOrigSol(subscip, &sol, NULL) );
553 
554  /* get values of variables in the optimal solution */
555  for( i = 0; i < nvars; ++i )
556  {
557  subvar = (SCIP_VAR*)SCIPhashmapGetImage(varmap, vars[i]);
558 
559  SCIP_CALL( SCIPsetSolVal(subscip, sol, subvar, fixvals[i]) );
560  }
561 
562  /* check the solution; integrality and bounds should be fulfilled and do not have to be checked */
563  SCIP_CALL( SCIPcheckSol(subscip, sol, FALSE, FALSE, FALSE, TRUE, &feasible) );
564 
565 #ifndef NDEBUG
566  /* in debug mode, we additionally check integrality and bounds */
567  if( feasible )
568  {
569  SCIP_CALL( SCIPcheckSol(subscip, sol, FALSE, TRUE, TRUE, FALSE, &feasible) );
570  assert(feasible);
571  }
572 #endif
573 
574  SCIPdebugMessage("--> corrected solution is%s feasible\n", feasible ? "" : " not");
575 
576  if( !SCIPisFeasEQ(subscip, SCIPsolGetOrigObj(sol), origobj) )
577  {
578  SCIPdebugMessage("--> corrected solution has a different objective value (old=%16.9g, corrected=%16.9g)\n",
579  origobj, SCIPsolGetOrigObj(sol));
580 
581  feasible = FALSE;
582  }
583 
584  SCIP_CALL( SCIPfreeSol(subscip, &sol) );
585  }
586 
587  /* if the solution is feasible, fix variables and delete constraints of the component */
588  if( feasible )
589  {
590  /* fix variables */
591  for( i = 0; i < nvars; ++i )
592  {
593  assert(SCIPisLE(scip, fixvals[i], SCIPvarGetUbLocal(vars[i])));
594  assert(SCIPisGE(scip, fixvals[i], SCIPvarGetLbLocal(vars[i])));
595  assert(SCIPisLE(scip, fixvals[i], SCIPvarGetUbGlobal(vars[i])));
596  assert(SCIPisGE(scip, fixvals[i], SCIPvarGetLbGlobal(vars[i])));
597 
598  SCIP_CALL( SCIPfixVar(scip, vars[i], fixvals[i], &infeasible, &fixed) );
599  assert(!infeasible);
600  assert(fixed);
601  (*ndeletedvars)++;
602  }
603 
604  /* delete constraints */
605  for( i = 0; i < nconss; ++i )
606  {
607  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
608  (*ndeletedconss)++;
609  }
610  }
611  }
612  }
613  else if( SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE )
614  {
615  *result = SCIP_CUTOFF;
616  }
617  else if( SCIPgetStatus(subscip) == SCIP_STATUS_UNBOUNDED || SCIPgetStatus(subscip) == SCIP_STATUS_INFORUNBD )
618  {
619  /* TODO: store unbounded ray in original SCIP data structure */
620  *result = SCIP_UNBOUNDED;
621  }
622  else
623  {
624  SCIPdebugMessage("--> solving interrupted (status=%d, time=%.2f)\n",
625  SCIPgetStatus(subscip), SCIPgetSolvingTime(subscip));
626 
627  /* transfer global fixings to the original problem; we can only do this, if we did not find a solution in the
628  * subproblem, because otherwise, the primal bound might lead to dual reductions that cannot be transferred to
629  * the original problem without also transferring the possibly suboptimal solution (which is currently not
630  * possible)
631  */
632  if( SCIPgetNSols(subscip) == 0 )
633  {
634  SCIP_Bool infeasible;
635  SCIP_Bool tightened;
636  int ntightened;
637 
638  ntightened = 0;
639 
640  for( i = 0; i < nvars; ++i )
641  {
642  assert( SCIPhashmapExists(varmap, vars[i]) );
643 
644  SCIP_CALL( SCIPtightenVarLb(scip, vars[i], SCIPvarGetLbGlobal((SCIP_VAR*)SCIPhashmapGetImage(varmap, vars[i])), FALSE,
645  &infeasible, &tightened) );
646  assert(!infeasible);
647  if( tightened )
648  ntightened++;
649 
650  SCIP_CALL( SCIPtightenVarUb(scip, vars[i], SCIPvarGetUbGlobal((SCIP_VAR*)SCIPhashmapGetImage(varmap, vars[i])), FALSE,
651  &infeasible, &tightened) );
652  assert(!infeasible);
653  if( tightened )
654  ntightened++;
655  }
656  SCIPdebugMessage("--> tightened %d bounds of variables due to global bounds in the sub-SCIP\n", ntightened);
657  }
658  }
659  }
660  else
661  {
662  SCIPdebugMessage("--> not solved (too many integer variables)\n");
663  }
664 
665  TERMINATE:
666  SCIPhashmapFree(&varmap);
667 
668  return SCIP_OKAY;
669 }
670 
671 /** loop over constraints, get active variables and fill directed graph */
672 static
674  SCIP* scip, /**< SCIP data structure */
675  SCIP_DIGRAPH* digraph, /**< directed graph */
676  SCIP_CONS** conss, /**< constraints */
677  int nconss, /**< number of constraints */
678  int* firstvaridxpercons, /**< array to store for each constraint the index in the local vars array
679  * of the first variable of the constraint */
680  SCIP_Bool* success /**< flag indicating successful directed graph filling */
681  )
682 {
683  SCIP_VAR** consvars;
684  int requiredsize;
685  int nconsvars;
686  int nvars;
687  int idx1;
688  int idx2;
689  int c;
690  int v;
691 
692  assert(scip != NULL);
693  assert(digraph != NULL);
694  assert(conss != NULL);
695  assert(firstvaridxpercons != NULL);
696  assert(success != NULL);
697 
698  *success = TRUE;
699 
700  nconsvars = 0;
701  requiredsize = 0;
702  nvars = SCIPgetNVars(scip);
703 
704  /* use big buffer for storing active variables per constraint */
705  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
706 
707  for( c = 0; c < nconss; ++c )
708  {
709  /* check for reached timelimit */
710  if( (c % 1000 == 0) && SCIPisStopped(scip) )
711  {
712  *success = FALSE;
713  break;
714  }
715 
716  /* get number of variables for this constraint */
717  SCIP_CALL( SCIPgetConsNVars(scip, conss[c], &nconsvars, success) );
718 
719  if( !(*success) )
720  break;
721 
722  if( nconsvars > nvars )
723  {
724  nvars = nconsvars;
725  SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, nvars) );
726  }
727 
728 #ifndef NDEBUG
729  /* clearing variables array to check for consistency */
730  if( nconsvars == nvars )
731  {
732  BMSclearMemoryArray(consvars, nconsvars);
733  }
734  else
735  {
736  assert(nconsvars < nvars);
737  BMSclearMemoryArray(consvars, nconsvars + 1);
738  }
739 #endif
740 
741  /* get variables for this constraint */
742  SCIP_CALL( SCIPgetConsVars(scip, conss[c], consvars, nvars, success) );
743 
744  if( !(*success) )
745  {
746 #ifndef NDEBUG
747  /* it looks strange if returning the number of variables was successful but not returning the variables */
748  SCIPwarningMessage(scip, "constraint <%s> returned number of variables but returning variables failed\n", SCIPconsGetName(conss[c]));
749 #endif
750  break;
751  }
752 
753 #ifndef NDEBUG
754  /* check if returned variables are consistent with the number of variables that were returned */
755  for( v = nconsvars - 1; v >= 0; --v )
756  assert(consvars[v] != NULL);
757  if( nconsvars < nvars )
758  assert(consvars[nconsvars] == NULL);
759 #endif
760 
761  /* transform given variables to active variables */
762  SCIP_CALL( SCIPgetActiveVars(scip, consvars, &nconsvars, nvars, &requiredsize) );
763  assert(requiredsize <= nvars);
764 
765  if( nconsvars > 0 )
766  {
767  idx1 = SCIPvarGetProbindex(consvars[0]);
768  assert(idx1 >= 0);
769 
770  /* save index of the first variable for later component assignment */
771  firstvaridxpercons[c] = idx1;
772 
773  if( nconsvars > 1 )
774  {
775  /* create sparse directed graph
776  * sparse means, to add only those edges necessary for component calculation
777  */
778  for( v = 1; v < nconsvars; ++v )
779  {
780  idx2 = SCIPvarGetProbindex(consvars[v]);
781  assert(idx2 >= 0);
782 
783  /* we add only one directed edge, because the other direction is automatically added for component computation */
784  SCIP_CALL( SCIPdigraphAddArc(digraph, idx1, idx2, NULL) );
785  }
786  }
787  }
788  else
789  firstvaridxpercons[c] = -1;
790  }
791 
792  SCIPfreeBufferArray(scip, &consvars);
793 
794  return SCIP_OKAY;
795 }
796 
797 #ifdef COMPONENTS_PRINT_STRUCTURE
798 
799 static
800 SCIP_RETCODE printStructure(
801  SCIP* scip, /**< SCIP data structure */
802  SCIP_VAR** vars, /**< variables */
803  SCIP_CONS** conss, /**< constraints */
804  int* components, /**< array with component number for every variable */
805  int* conscomponents, /**< array with component number for every constraint */
806  int nvars, /**< number of variables */
807  int nconss, /**< number of constraints */
808  int ncomponents /**< number of components */
809  )
810 {
811  char probname[SCIP_MAXSTRLEN];
812  char outname[SCIP_MAXSTRLEN];
813  char filename[SCIP_MAXSTRLEN];
814  char* name;
815  FILE* file;
816  SCIP_VAR** consvars;
817  SCIP_VAR* var;
818  int* varidx;
819  int* compstartvars;
820  int* compstartconss;
821  int ncalls;
822  int requiredsize;
823  int nconsvars;
824  int i;
825  int c;
826  int v;
827  SCIP_Bool success;
828 
829  SCIP_CALL( SCIPallocBufferArray(scip, &varidx, nvars) );
830  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
831  SCIP_CALL( SCIPallocBufferArray(scip, &compstartvars, ncomponents + 1) );
832  SCIP_CALL( SCIPallocBufferArray(scip, &compstartconss, ncomponents + 1) );
833 
835  compstartvars[0] = 0;
836  compstartconss[0] = 0;
837 
838  for( v = 0; v < nvars; ++v )
839  {
840  assert(v == 0 || components[v] == components[v-1] || components[v] == components[v-1]+1);
841  varidx[SCIPvarGetProbindex(vars[v])] = v;
842 
843  if( v > 0 && components[v] == components[v-1] + 1 )
844  {
845  compstartvars[components[v]] = v;
846  }
847  }
848 
849  for( v = 0; v < nconss; ++v )
850  {
851  assert(v == 0 || conscomponents[v] == conscomponents[v-1] || conscomponents[v] == conscomponents[v-1]+1);
852 
853  if( v > 0 && conscomponents[v] == conscomponents[v-1] + 1 )
854  {
855  compstartconss[conscomponents[v]] = v;
856  }
857  }
858 
859  compstartvars[ncomponents] = nvars;
860  compstartconss[ncomponents] = nconss;
861 
862  /* split problem name */
863  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPgetProbName(scip));
864  SCIPsplitFilename(probname, NULL, &name, NULL, NULL);
865 
866  /* define file name depending on instance name, number of presolver calls and number of components */
867  (void) SCIPsnprintf(outname, SCIP_MAXSTRLEN, "%s_%d_%d", name, ncalls, ncomponents);
868  (void) SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gp", outname);
869 
870  /* open output file */
871  file = fopen(filename, "w");
872  if( file == NULL )
873  {
874  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
875  SCIPprintSysError(filename);
876  return SCIP_FILECREATEERROR;
877  }
878 
879  /* print header of gnuplot file */
880  SCIPinfoMessage(scip, file, "set terminal pdf\nset output \"%s.pdf\"\nunset xtics\nunset ytics\n\n", outname);
881  SCIPinfoMessage(scip, file, "unset border\nunset key\nset style fill solid 1.0 noborder\nset size ratio -1\n");
882  SCIPinfoMessage(scip, file, "set xrange [0:%d]\nset yrange[%d:0]\n", nvars + 1, nconss + 1);
883 
884  /* write rectangles around blocks */
885  for( i = 0; i < ncomponents; ++i )
886  {
887  assert(compstartvars[i] <= nvars);
888  assert(compstartconss[i] <= nconss);
889  assert(compstartvars[i+1] <= nvars);
890  assert(compstartconss[i+1] <= nconss);
891  SCIPinfoMessage(scip, file, "set object %d rect from %.1f,%.1f to %.1f,%.1f fc rgb \"grey\"\n",
892  i + 1, nvars - compstartvars[i] + 0.5, nconss - compstartconss[i] + 0.5,
893  nvars - compstartvars[i+1] + 0.5, nconss - compstartconss[i+1] + 0.5);
894  }
895 
896  /* write the plot header */
897  SCIPinfoMessage(scip, file, "plot \"-\" using 1:2:3 with circles fc rgb \"black\"\n");
898 
899  /* write data */
900  for( c = 0; c < nconss; ++c )
901  {
902  /* get variables for this constraint */
903  SCIP_CALL( SCIPgetConsNVars(scip, conss[c], &nconsvars, &success) );
904  SCIP_CALL( SCIPgetConsVars(scip, conss[c], consvars, nvars, &success) );
905  assert(success);
906 
907  /* transform given variables to active variables */
908  SCIP_CALL( SCIPgetActiveVars(scip, consvars, &nconsvars, nvars, &requiredsize) );
909  assert(requiredsize <= nvars);
910 
911  for( v = 0; v < nconsvars; ++v )
912  {
913  var = consvars[v];
914  SCIPinfoMessage(scip, file, "%d %d 0.5\n", nvars - varidx[SCIPvarGetProbindex(var)], nconss - c);
915  }
916  }
917 
918  /* write file end */
919  SCIPinfoMessage(scip, file, "e\n");
920 
921  (void) fclose(file);
922 
923  SCIPfreeBufferArray(scip, &compstartconss);
924  SCIPfreeBufferArray(scip, &compstartvars);
925  SCIPfreeBufferArray(scip, &consvars);
926  SCIPfreeBufferArray(scip, &varidx);
927 
928  return SCIP_OKAY;
929 }
930 
931 #endif
932 
933 /** use components to assign variables and constraints to the subscips
934  * and try to solve all subscips having not too many integer variables
935  */
936 static
938  SCIP* scip, /**< SCIP data structure */
939  SCIP_PRESOLDATA* presoldata, /**< presolver data */
940  SCIP_CONS** conss, /**< constraints */
941  SCIP_VAR** vars, /**< variables */
942  SCIP_Real* fixvals, /**< array to store the fixing values */
943  int nconss, /**< number of constraints */
944  int nvars, /**< number of variables */
945  int* components, /**< array with component number for every variable */
946  int ncomponents, /**< number of components */
947  int* firstvaridxpercons, /**< array with index of first variable in vars array for each constraint */
948  int* nsolvedprobs, /**< pointer to store the number of solved subproblems */
949  int* ndeletedvars, /**< pointer to store the number of deleted variables */
950  int* ndeletedconss, /**< pointer to store the number of deleted constraints */
951  SCIP_RESULT* result /**< pointer to store the result of the presolving call */
952  )
953 {
954  SCIP_HASHMAP* consmap;
955  SCIP_CONS** compconss;
956  SCIP_VAR** compvars;
957  SCIP_Real* compfixvals;
958  int* conscomponent;
959  int ncompconss;
960  int ncompvars;
961  int nbinvars;
962  int nintvars;
963  int comp;
964  int compvarsstart;
965  int compconssstart;
966  int v;
967  int c;
968 
969  assert(scip != NULL);
970  assert(presoldata != NULL);
971  assert(conss != NULL);
972  assert(components != NULL);
973  assert(firstvaridxpercons != NULL);
974  assert(nsolvedprobs != NULL);
975  assert(result != NULL);
976 
977  *nsolvedprobs = 0;
978 
979  /* hashmap mapping from original constraints to constraints in the sub-SCIPs (for performance reasons) */
980  SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), 10 * SCIPgetNConss(scip)) );
981 
982  SCIP_CALL( SCIPallocBufferArray(scip, &conscomponent, nconss) );
983 
984  /* do the mapping from calculated components per variable to corresponding
985  * constraints and sort the component-arrays for faster finding the
986  * actual variables and constraints belonging to one component
987  */
988  for( c = 0; c < nconss; c++ )
989  conscomponent[c] = (firstvaridxpercons[c] == -1 ? -1 : components[firstvaridxpercons[c]]);
990 
991  SCIPsortIntPtr(components, (void**)vars, nvars);
992  SCIPsortIntPtr(conscomponent, (void**)conss, nconss);
993 
994 #ifdef COMPONENTS_PRINT_STRUCTURE
995  SCIP_CALL( printStructure(scip, vars, conss, components, conscomponent, nvars, nconss, ncomponents) );
996 #endif
997 
998  compvarsstart = 0;
999  compconssstart = 0;
1000 
1001  while( compconssstart < nconss && conscomponent[compconssstart] == -1 )
1002  ++compconssstart;
1003 
1004  /* loop over all components */
1005  for( comp = 0; comp < ncomponents && !SCIPisStopped(scip); comp++ )
1006  {
1007  nbinvars = 0;
1008  nintvars = 0;
1009 
1010  /* count variables present in this component and categorize them */
1011  for( v = compvarsstart; v < nvars && components[v] == comp; ++v )
1012  {
1013  /* check whether variable is of binary or integer type */
1014  if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY )
1015  nbinvars++;
1016  else if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_INTEGER )
1017  nintvars++;
1018  }
1019 
1020  /* count constraints present in this component */
1021  c = compconssstart;
1022  while( c < nconss && conscomponent[c] == comp )
1023  ++c;
1024 
1025  /* collect some statistical information */
1026  SCIPstatistic( updateStatisticsComp(presoldata, nbinvars, nintvars) );
1027 
1028  compvars = &(vars[compvarsstart]);
1029  compfixvals = &(fixvals[compvarsstart]);
1030  compconss = &(conss[compconssstart]);
1031  ncompvars = v - compvarsstart;
1032  ncompconss = c - compconssstart;
1033  compvarsstart = v;
1034  compconssstart = c;
1035 
1036  /* single variable without constraint */
1037  if( ncompconss == 0 )
1038  {
1039  SCIP_Bool infeasible;
1040  SCIP_Bool fixed;
1041 
1042  /* there is no constraint to connect variables, so there should be only one variable in the component */
1043  assert(ncompvars == 1);
1044 
1045  /* is the variable still locked? */
1046  if( SCIPvarGetNLocksUp(compvars[0]) == 0 && SCIPvarGetNLocksDown(compvars[0]) == 0 )
1047  {
1048  /* fix variable to its best bound (or 0.0, if objective is 0) */
1049  if( SCIPisPositive(scip, SCIPvarGetObj(compvars[0])) )
1050  compfixvals[0] = SCIPvarGetLbGlobal(compvars[0]);
1051  else if( SCIPisNegative(scip, SCIPvarGetObj(compvars[0])) )
1052  compfixvals[0] = SCIPvarGetUbGlobal(compvars[0]);
1053  else
1054  {
1055  compfixvals[0] = 0.0;
1056  compfixvals[0] = MIN(compfixvals[0], SCIPvarGetUbGlobal(compvars[0])); /*lint !e666*/
1057  compfixvals[0] = MAX(compfixvals[0], SCIPvarGetLbGlobal(compvars[0])); /*lint !e666*/
1058  }
1059 
1060 #ifdef SCIP_MORE_DEBUG
1061  SCIPinfoMessage(scip, NULL, "presol components: fix variable <%s>[%g,%g] (locks [%d, %d]) to %g because it occurs in no constraint\n",
1062  SCIPvarGetName(compvars[0]), SCIPvarGetLbGlobal(compvars[0]), SCIPvarGetUbGlobal(compvars[0]),
1063  SCIPvarGetNLocksUp(compvars[0]), SCIPvarGetNLocksDown(compvars[0]), compfixvals[0]);
1064 #else
1065  SCIPdebugMessage("presol components: fix variable <%s>[%g,%g] (locks [%d, %d]) to %g because it occurs in no constraint\n",
1066  SCIPvarGetName(compvars[0]), SCIPvarGetLbGlobal(compvars[0]), SCIPvarGetUbGlobal(compvars[0]),
1067  SCIPvarGetNLocksUp(compvars[0]), SCIPvarGetNLocksDown(compvars[0]), compfixvals[0]);
1068 #endif
1069 
1070  SCIP_CALL( SCIPfixVar(scip, compvars[0], compfixvals[0], &infeasible, &fixed) );
1071  assert(!infeasible);
1072  assert(fixed);
1073  ++(*ndeletedvars);
1074  ++(*nsolvedprobs);
1075 
1076  /* update statistics */
1077  SCIPstatistic( updateStatisticsSingleVar(presoldata) );
1078  }
1079  else
1080  {
1081  /* variable is still locked */
1082  SCIPdebugMessage("strange?! components with single variable variable <%s>[%g,%g] (locks [%d, %d]) that won't be fixed due to locks\n",
1083  SCIPvarGetName(compvars[0]), SCIPvarGetLbGlobal(compvars[0]), SCIPvarGetUbGlobal(compvars[0]),
1084  SCIPvarGetNLocksUp(compvars[0]), SCIPvarGetNLocksDown(compvars[0]));
1085  }
1086  }
1087  /* we do not want to solve the component, if it is the last unsolved one */
1088  else if( ncompvars < SCIPgetNVars(scip) )
1089  {
1090  SCIP_RESULT subscipresult;
1091 
1092  assert(ncompconss > 0);
1093 
1094  /* in extended debug mode, we want to be informed about components with single constraints;
1095  * this is only for noticing this case and possibly handling it within the constraint handler
1096  */
1097 #ifdef SCIP_MORE_DEBUG
1098  if( ncompconss == 1 )
1099  {
1100  SCIPinfoMessage(scip, NULL, "presol component detected component with a single constraint:\n");
1101  SCIP_CALL( SCIPprintCons(scip, compconss[0], NULL) );
1102  SCIPinfoMessage(scip, NULL, ";\n");
1103  }
1104 #endif
1105 
1106  /* build subscip for one component and try to solve it */
1107  SCIP_CALL( copyAndSolveComponent(scip, presoldata, consmap, comp, compconss, ncompconss, compvars,
1108  compfixvals, ncompvars, nbinvars, nintvars, nsolvedprobs, ndeletedvars, ndeletedconss,
1109  &subscipresult) );
1110 
1111  if( subscipresult == SCIP_CUTOFF || subscipresult == SCIP_UNBOUNDED )
1112  {
1113  *result = subscipresult;
1114  break;
1115  }
1116 
1117  if( !presoldata->pluginscopied )
1118  break;
1119  }
1120  }
1121 
1122  if( presoldata->subscip != NULL )
1123  {
1124  SCIP_CALL( SCIPfree(&presoldata->subscip) );
1125  presoldata->subscip = NULL;
1126  }
1127 
1128  SCIPfreeBufferArray(scip, &conscomponent);
1129  SCIPhashmapFree(&consmap);
1130 
1131  return SCIP_OKAY;
1132 }
1133 
1134 /** performs presolving by searching for components */
1135 static
1137  SCIP* scip, /**< SCIP main data structure */
1138  SCIP_PRESOL* presol, /**< the presolver itself */
1139  int* nfixedvars, /**< counter to increase by the number of fixed variables */
1140  int* ndelconss, /**< counter to increase by the number of deleted constrains */
1141  SCIP_RESULT* result /**< pointer to store the result of the presolving call */
1142  )
1143 {
1144  SCIP_PRESOLDATA* presoldata;
1145  SCIP_CONS** conss;
1146  SCIP_CONS** tmpconss;
1147  SCIP_Bool success;
1148  int nconss;
1149  int ntmpconss;
1150  int nvars;
1151  int ncomponents;
1152  int ndeletedconss;
1153  int ndeletedvars;
1154  int nsolvedprobs;
1155  int c;
1156 
1157  assert(scip != NULL);
1158  assert(presol != NULL);
1159  assert(result != NULL);
1160 
1161  *result = SCIP_DIDNOTRUN;
1162 
1163  if( SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING || SCIPinProbing(scip) )
1164  return SCIP_OKAY;
1165 
1166  /* do not run, if not all variables are explicitly known */
1167  if( SCIPgetNActivePricers(scip) > 0 )
1168  return SCIP_OKAY;
1169 
1170  presoldata = SCIPpresolGetData(presol);
1171  assert(presoldata != NULL);
1172 
1173  nvars = SCIPgetNVars(scip);
1174 
1175  /* we do not want to run, if there are no variables left */
1176  if( nvars == 0 )
1177  return SCIP_OKAY;
1178 
1179  /* the presolver should be executed only if it didn't run so far or the number of variables was significantly reduced
1180  * since tha last run
1181  */
1182  if( (presoldata->didsearch && nvars > (1 - presoldata->reldecrease) * presoldata->lastnvars) )
1183  return SCIP_OKAY;
1184 
1185  /* if we were not able to copy all plugins, we cannot run the components presolver */
1186  if( !presoldata->pluginscopied )
1187  return SCIP_OKAY;
1188 
1189  /* only call the component presolver, if presolving would be stopped otherwise */
1190  if( !SCIPisPresolveFinished(scip) )
1191  return SCIP_OKAY;
1192 
1193  /* check for a reached timelimit */
1194  if( SCIPisStopped(scip) )
1195  return SCIP_OKAY;
1196 
1197  SCIPstatistic( resetStatistics(scip, presoldata) );
1198 
1199  *result = SCIP_DIDNOTFIND;
1200  presoldata->didsearch = TRUE;
1201 
1202  ncomponents = 0;
1203  ndeletedvars = 0;
1204  ndeletedconss = 0;
1205  nsolvedprobs = 0;
1206 
1207  /* collect checked constraints for component presolving */
1208  ntmpconss = SCIPgetNConss(scip);
1209  tmpconss = SCIPgetConss(scip);
1210  SCIP_CALL( SCIPallocBufferArray(scip, &conss, ntmpconss) );
1211  nconss = 0;
1212  for( c = 0; c < ntmpconss; c++ )
1213  {
1214  if( SCIPconsIsChecked(tmpconss[c]) )
1215  {
1216  conss[nconss] = tmpconss[c];
1217  nconss++;
1218  }
1219  }
1220 
1221  if( nvars > 1 && nconss > 1 )
1222  {
1223  SCIP_DIGRAPH* digraph;
1224  SCIP_VAR** vars;
1225  SCIP_Real* fixvals;
1226  int* firstvaridxpercons;
1227  int* varlocks;
1228  int v;
1229 
1230  /* copy variables into a local array */
1231  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1232  SCIP_CALL( SCIPallocBufferArray(scip, &fixvals, nvars) );
1233  SCIP_CALL( SCIPallocBufferArray(scip, &firstvaridxpercons, nconss) );
1234  SCIP_CALL( SCIPallocBufferArray(scip, &varlocks, nvars) );
1235  BMScopyMemoryArray(vars, SCIPgetVars(scip), nvars);
1236 
1237  /* count number of varlocks for each variable (up + down locks) and multiply it by 2;
1238  * that value is used as an estimate of the number of arcs incident to the variable's node in the digraph
1239  */
1240  for( v = 0; v < nvars; ++v )
1241  varlocks[v] = 4 * (SCIPvarGetNLocksDown(vars[v]) + SCIPvarGetNLocksUp(vars[v]));
1242 
1243  /* create and fill directed graph */
1244  SCIP_CALL( SCIPdigraphCreate(&digraph, nvars) );
1245  SCIP_CALL( SCIPdigraphSetSizes(digraph, varlocks) );
1246  SCIP_CALL( fillDigraph(scip, digraph, conss, nconss, firstvaridxpercons, &success) );
1247 
1248  if( success )
1249  {
1250  int* components;
1251 
1252  SCIP_CALL( SCIPallocBufferArray(scip, &components, nvars) );
1253 
1254  /* compute independent components */
1255  SCIP_CALL( SCIPdigraphComputeUndirectedComponents(digraph, 1, components, &ncomponents) );
1256 
1257  SCIPdebugMessage("presol components found %d undirected components\n", ncomponents);
1258 
1259  /* We want to sort the components in increasing size (number of variables).
1260  * Therefore, we now get the number of variables for each component, and rename the components
1261  * such that for i < j, component i has no more variables than component j.
1262  * @todo Perhaps sort the components by the number of binary/integer variables?
1263  */
1264  if( ncomponents > 0 )
1265  {
1266  int* compsize;
1267  int* permu;
1268  int* compvars;
1269  int ncompvars;
1270  int nbinvars;
1271  int nintvars;
1272  int ncontvars;
1273 
1274  SCIP_CALL( SCIPallocBufferArray(scip, &compsize, ncomponents) );
1275  SCIP_CALL( SCIPallocBufferArray(scip, &permu, ncomponents) );
1276 
1277  /* get number of variables in the components */
1278  for( c = 0; c < ncomponents; ++c )
1279  {
1280  SCIPdigraphGetComponent(digraph, c, &compvars, &ncompvars);
1281  permu[c] = c;
1282  nbinvars = 0;
1283  nintvars = 0;
1284 
1285  for( v = 0; v < ncompvars; ++v )
1286  {
1287  /* check whether variable is of binary or integer type */
1288  if( SCIPvarGetType(vars[compvars[v]]) == SCIP_VARTYPE_BINARY )
1289  nbinvars++;
1290  else if( SCIPvarGetType(vars[compvars[v]]) == SCIP_VARTYPE_INTEGER )
1291  nintvars++;
1292  }
1293  ncontvars = ncompvars - nintvars - nbinvars;
1294  compsize[c] = (int)((1000 * (nbinvars + presoldata->intfactor * nintvars) + (950.0 * ncontvars)/nvars));
1295  }
1296 
1297  /* get permutation of component numbers such that the size of the components is increasing */
1298  SCIPsortIntInt(compsize, permu, ncomponents);
1299 
1300  /* now, we need the reverse direction, i.e., for each component number, we store its new number
1301  * such that the components are sorted; for this, we abuse the compsize array
1302  */
1303  for( c = 0; c < ncomponents; ++c )
1304  compsize[permu[c]] = c;
1305 
1306  /* for each variable, replace the old component number by the new one */
1307  for( c = 0; c < nvars; ++c )
1308  components[c] = compsize[components[c]];
1309 
1310  /* create subproblems from independent components and solve them in dependence of their size */
1311  SCIP_CALL( splitProblem(scip, presoldata, conss, vars, fixvals, nconss, nvars, components, ncomponents, firstvaridxpercons,
1312  &nsolvedprobs, &ndeletedvars, &ndeletedconss, result) );
1313 
1314  (*nfixedvars) += ndeletedvars;
1315  (*ndelconss) += ndeletedconss;
1316 
1317  SCIPfreeBufferArray(scip, &permu);
1318  SCIPfreeBufferArray(scip, &compsize);
1319  }
1320 
1321  SCIPfreeBufferArray(scip, &components);
1322  }
1323 
1324  SCIPdigraphFree(&digraph);
1325 
1326  SCIPfreeBufferArray(scip, &varlocks);
1327  SCIPfreeBufferArray(scip, &firstvaridxpercons);
1328  SCIPfreeBufferArray(scip, &fixvals);
1329  SCIPfreeBufferArray(scip, &vars);
1330  }
1331 
1332  SCIPfreeBufferArray(scip, &conss);
1333 
1334  /* update result to SCIP_SUCCESS, if reductions were found;
1335  * if result was set to infeasible or unbounded before, leave it as it is
1336  */
1337  if( (ndeletedvars > 0 || ndeletedconss > 0) && ((*result) == SCIP_DIDNOTFIND) )
1338  *result = SCIP_SUCCESS;
1339 
1340  /* print statistics */
1341  SCIPstatistic( printStatistics(presoldata) );
1342 
1343  SCIPdebugMessage("%d components, %d solved, %d deleted constraints, %d deleted variables, result = %d\n",
1344  ncomponents, nsolvedprobs, ndeletedconss, ndeletedvars, *result);
1345 #ifdef NDEBUG
1346  SCIPstatisticMessage("%d components, %d solved, %d deleted constraints, %d deleted variables, result = %d\n",
1347  ncomponents, nsolvedprobs, ndeletedconss, ndeletedvars, *result);
1348 #endif
1349 
1350  presoldata->lastnvars = SCIPgetNVars(scip);
1351 
1352  return SCIP_OKAY;
1353 }
1354 
1355 
1356 /*
1357  * Callback methods of presolver
1358  */
1359 
1360 /** destructor of presolver to free user data (called when SCIP is exiting) */
1361 static
1362 SCIP_DECL_PRESOLFREE(presolFreeComponents)
1363 { /*lint --e{715}*/
1364  SCIP_PRESOLDATA* presoldata;
1365 
1366  /* free presolver data */
1367  presoldata = SCIPpresolGetData(presol);
1368  assert(presoldata != NULL);
1369 
1370  SCIPfreeMemory(scip, &presoldata);
1371  SCIPpresolSetData(presol, NULL);
1372 
1373  return SCIP_OKAY;
1374 }
1375 
1376 /** initialization method of presolver (called after problem was transformed) */
1377 static
1378 SCIP_DECL_PRESOLINIT(presolInitComponents)
1379 { /*lint --e{715}*/
1380  SCIP_PRESOLDATA* presoldata;
1381 
1382  /* free presolver data */
1383  presoldata = SCIPpresolGetData(presol);
1384  assert(presoldata != NULL);
1385 
1386  /* initialize statistics */
1387  SCIPstatistic( SCIP_CALL( initStatistics(scip, presoldata) ) );
1388 
1389  presoldata->subscip = NULL;
1390  presoldata->didsearch = FALSE;
1391  presoldata->pluginscopied = TRUE;
1392 
1393  return SCIP_OKAY;
1394 }
1395 
1396 #ifdef SCIP_STATISTIC
1397 /** deinitialization method of presolver (called before transformed problem is freed) */
1398 static
1399 SCIP_DECL_PRESOLEXIT(presolExitComponents)
1400 { /*lint --e{715}*/
1401  SCIP_PRESOLDATA* presoldata;
1402 
1403  /* free presolver data */
1404  presoldata = SCIPpresolGetData(presol);
1405  assert(presoldata != NULL);
1406 
1407  SCIPstatistic( freeStatistics(scip, presoldata) );
1408 
1409  return SCIP_OKAY;
1410 }
1411 #endif
1412 
1413 
1414 /** execution method of presolver */
1415 static
1416 SCIP_DECL_PRESOLEXEC(presolExecComponents)
1417 { /*lint --e{715}*/
1418 
1419  SCIP_CALL( presolComponents(scip, presol, nfixedvars, ndelconss, result) );
1420 
1421  return SCIP_OKAY;
1422 }
1423 
1424 
1425 /*
1426  * presolver specific interface methods
1427  */
1428 
1429 /** creates the components presolver and includes it in SCIP */
1431  SCIP* scip /**< SCIP data structure */
1432  )
1433 {
1434  SCIP_PRESOLDATA* presoldata;
1435  SCIP_PRESOL* presol;
1436 
1437  /* create components presolver data */
1438  SCIP_CALL( SCIPallocMemory(scip, &presoldata) );
1439 
1440  /* include presolver */
1442  PRESOL_DELAY, presolExecComponents, presoldata) );
1443 
1444  /* currently, the components presolver is not copied; if a copy callback is added, we need to avoid recursion
1445  * by one of the following means:
1446  * - turn off the components presolver in SCIPsetSubscipsOff()
1447  * - call SCIPsetSubscipsOff() for the component sub-SCIP
1448  * - disable the components presolver in the components sub-SCIP
1449  */
1450  SCIP_CALL( SCIPsetPresolCopy(scip, presol, NULL) );
1451  SCIP_CALL( SCIPsetPresolFree(scip, presol, presolFreeComponents) );
1452  SCIP_CALL( SCIPsetPresolInit(scip, presol, presolInitComponents) );
1453  SCIPstatistic( SCIP_CALL( SCIPsetPresolExit(scip, presol, presolExitComponents) ) );
1454 
1455  /* add presolver parameters */
1457  "presolving/components/writeproblems",
1458  "should the single components be written as an .lp-file?",
1459  &presoldata->writeproblems, FALSE, DEFAULT_WRITEPROBLEMS, NULL, NULL) );
1460  SCIP_CALL( SCIPaddIntParam(scip,
1461  "presolving/components/maxintvars",
1462  "maximum number of integer (or binary) variables to solve a subproblem directly (-1: unlimited)",
1463  &presoldata->maxintvars, FALSE, DEFAULT_MAXINTVARS, -1, INT_MAX, NULL, NULL) );
1465  "presolving/components/nodelimit",
1466  "maximum number of nodes to be solved in subproblems",
1467  &presoldata->nodelimit, FALSE, DEFAULT_NODELIMIT, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
1469  "presolving/components/intfactor",
1470  "the weight of an integer variable compared to binary variables",
1471  &presoldata->intfactor, FALSE, DEFAULT_INTFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1473  "presolving/components/reldecrease",
1474  "percentage by which the number of variables has to be decreased after the last component solving to allow running again (1.0: do not run again)",
1475  &presoldata->reldecrease, FALSE, DEFAULT_RELDECREASE, 0.0, 1.0, NULL, NULL) );
1477  "presolving/components/feastolfactor",
1478  "factor to increase the feasibility tolerance of the main SCIP in all sub-SCIPs, default value 1.0",
1479  &presoldata->feastolfactor, TRUE, DEFAULT_FEASTOLFACTOR, 0.0, 1000000.0, NULL, NULL) );
1480 
1481  return SCIP_OKAY;
1482 }
1483