Scippy

SCIP

Solving Constraint Integer Programs

scip_dcmp.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 2002-2022 Zuse Institute Berlin */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file scip_dcmp.c
26  * @ingroup OTHER_CFILES
27  * @brief methods for working with decompositions
28  * @author Gregor Hendel
29  */
30 
31 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32 
33 #include <assert.h>
34 #include "scip/struct_dcmp.h"
35 #include "scip/debug.h"
36 #include "scip/dcmp.h"
37 #include "scip/mem.h"
38 #include "scip/pub_misc.h"
39 #include "scip/pub_var.h"
40 #include "scip/scip_cons.h"
41 #include "scip/scip_prob.h"
42 #include "scip/scip_var.h"
43 #include "scip/scip_mem.h"
44 #include "scip/struct_scip.h"
45 #include "scip/pub_cons.h"
46 #include "scip/pub_dcmp.h"
47 #include "scip/scip_dcmp.h"
48 #include "scip/scip_general.h"
49 #include "scip/scip_param.h"
50 #include "scip/scip_var.h"
52 #include "scip/scip_message.h"
53 
54 
55 #define LABEL_UNASSIGNED INT_MIN /* label constraints or variables as unassigned. Only for internal use */
56 
57 /** count occurrences of label in array, starting from pos */
58 static
60  int* labels, /**< array of labels */
61  int pos, /**< position to start counting from */
62  int nlabels /**< the number of labels */
63  )
64 {
65  int endpos = pos;
66  int currlabel;
67 
68  assert(labels != NULL);
69  assert(pos < nlabels);
70 
71  currlabel = labels[pos];
72 
73  do
74  {
75  endpos++;
76  }
77  while( endpos < nlabels && labels[endpos] == currlabel );
78 
79  return endpos - pos;
80 }
81 
82 /** raises an error if the condition is not TRUE */
83 static
85  SCIP_Bool condition /**< some condition that must hold */
86  )
87 {
88  return condition ? SCIP_OKAY : SCIP_ERROR;
89 }
90 
91 /** get variable buffer storage size for the buffer to be large enough to hold all variables */
92 static
94  SCIP* scip /**< SCIP data structure */
95  )
96 {
97  int norigvars;
98  int ntransvars;
99 
100  norigvars = SCIPgetNOrigVars(scip);
101  ntransvars = SCIPgetNVars(scip);
102 
103  return 2 * MAX(norigvars, ntransvars);
104 }
105 
106 /** get variables and constraints of the original or transformed problem, to which the decomposition corresponds */
107 static
109  SCIP* scip, /**< SCIP data structure */
110  SCIP_DECOMP* decomp, /**< decomposition data structure */
111  SCIP_VAR*** vars, /**< pointer to store original/transformed variables array, or NULL */
112  SCIP_CONS*** conss, /**< pointer to store original/transformed constraints array, or NULL */
113  int* nvars, /**< pointer to store original/transformed variables array's length, or NULL */
114  int* nconss /**< pointer to store original/transformed constraints array's length, or NULL */
115  )
116 {
117  SCIP_Bool original;
118  assert(scip != NULL);
119  assert(decomp != NULL);
120 
121  original = SCIPdecompIsOriginal(decomp);
122 
123  if( vars )
124  *vars = original ? SCIPgetOrigVars(scip) : SCIPgetVars(scip);
125 
126  if( nvars )
127  *nvars = original ? SCIPgetNOrigVars(scip) : SCIPgetNVars(scip);
128 
129  if( conss )
130  *conss = original ? SCIPgetOrigConss(scip) : SCIPgetConss(scip);
131 
132  if( nconss )
133  *nconss = original ? SCIPgetNOrigConss(scip) : SCIPgetNConss(scip);
134 }
135 
136 /** query the constraints active variables and their labels */
137 static
139  SCIP* scip, /**< SCIP data structure */
140  SCIP_DECOMP* decomp, /**< decomposition data structure */
141  SCIP_CONS* cons, /**< the constraint */
142  SCIP_VAR** varbuf, /**< variable buffer array */
143  int* labelbuf, /**< buffer to store labels, or NULL if not needed */
144  int bufsize, /**< size of buffer arrays */
145  int* nvars, /**< pointer to store number of variables */
146  int* requiredsize, /**< pointer to store required size */
147  SCIP_Bool* success /**< pointer to store whether variables and labels were successfully inserted */
148  )
149 {
150  SCIP_Bool success2;
151 
152  assert(scip != NULL);
153  assert(decomp != NULL);
154  assert(cons != NULL);
155  assert(varbuf != NULL);
156  assert(nvars != NULL);
157  assert(requiredsize != NULL);
158  assert(success != NULL);
159 
160  *success = FALSE;
161  *requiredsize = 0;
162  *nvars = 0;
163  SCIP_CALL( SCIPgetConsNVars(scip, cons, nvars, &success2) );
164 
165  /* the constraint does not have the corresponding callback */
166  if( ! success2 )
167  {
168  return SCIP_OKAY;
169  }
170 
171  if( bufsize < *nvars )
172  {
173  *requiredsize = *nvars;
174 
175  return SCIP_OKAY;
176  }
177 
178  SCIP_CALL( SCIPgetConsVars(scip, cons, varbuf, bufsize, &success2) );
179  /* the constraint does not have the corresponding callback */
180  if( ! success2 )
181  {
182  return SCIP_OKAY;
183  }
184 
185  if( ! SCIPdecompIsOriginal(decomp) )
186  {
187  SCIP_CALL( SCIPgetActiveVars(scip, varbuf, nvars, bufsize, requiredsize) );
188 
189  if( *requiredsize > bufsize )
190  return SCIP_OKAY;
191  }
192  else
193  {
194  int v;
195  for( v = 0; v < *nvars; ++v )
196  {
197  assert(SCIPvarIsActive(varbuf[v]) || SCIPvarIsNegated(varbuf[v]));
198 
199  /* some constraint handlers such as indicator may already return inactive variables */
200  if( SCIPvarIsNegated(varbuf[v]) )
201  varbuf[v] = SCIPvarGetNegatedVar(varbuf[v]);
202  }
203  }
204 
205  /* get variables labels, if requested */
206  if( labelbuf != NULL )
207  {
208  SCIPdecompGetVarsLabels(decomp, varbuf, labelbuf, *nvars);
209  }
210 
211  *success = TRUE;
212 
213  return SCIP_OKAY;
214 }
215 
216 /** creates a decomposition */
218  SCIP* scip, /**< SCIP data structure */
219  SCIP_DECOMP** decomp, /**< pointer to store the decomposition data structure */
220  int nblocks, /**< the number of blocks (without the linking block) */
221  SCIP_Bool original, /**< is this a decomposition in the original (TRUE) or transformed space? */
222  SCIP_Bool benderslabels /**< should the variables be labeled for the application of Benders' decomposition */
223  )
224 {
225  assert(scip != NULL);
226 
227  SCIP_CALL( SCIPdecompCreate(decomp, SCIPblkmem(scip), nblocks, original, benderslabels) );
228 
229  return SCIP_OKAY;
230 }
231 
232 /** frees a decomposition */
234  SCIP* scip, /**< SCIP data structure */
235  SCIP_DECOMP** decomp /**< pointer to free the decomposition data structure */
236  )
237 {
238  assert(scip != NULL);
239 
240  SCIPdecompFree(decomp, SCIPblkmem(scip));
241 }
242 
243 /** adds decomposition to SCIP */
245  SCIP* scip, /**< SCIP data structure */
246  SCIP_DECOMP* decomp /**< decomposition to add */
247  )
248 {
249  assert(scip != NULL);
250  assert(decomp != NULL);
251 
252  SCIP_CALL( SCIPcheckStage(scip, "SCIPaddDecomp", FALSE, SCIPdecompIsOriginal(decomp), SCIPdecompIsOriginal(decomp),
254  !SCIPdecompIsOriginal(decomp), !SCIPdecompIsOriginal(decomp), FALSE, FALSE, FALSE) );
255 
256  SCIP_CALL( SCIPdecompstoreAdd(scip->decompstore, decomp) );
257 
258  return SCIP_OKAY;
259 }
260 
261 /** gets available user decompositions for either the original or transformed problem */
263  SCIP* scip, /**< SCIP data structure */
264  SCIP_DECOMP*** decomps, /**< pointer to store decompositions array */
265  int* ndecomps, /**< pointer to store number of decompositions */
266  SCIP_Bool original /**< should the decompositions for the original problem be returned? */
267  )
268 {
269  assert(scip != NULL);
270 
271  SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetDecomps", FALSE, original, original, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
272 
273  if( decomps != NULL )
275 
276  if( ndecomps != NULL )
278 }
279 
280 /** returns TRUE if the constraint \p cons contains only linking variables in decomposition \p decomp */
282  SCIP* scip, /**< SCIP data structure */
283  SCIP_DECOMP* decomp, /**< decomposition data structure */
284  SCIP_CONS* cons, /**< the constraint */
285  SCIP_Bool* hasonlylinkvars /**< will be set to TRUE if this constraint has only linking variables */
286  )
287 {
288  SCIP_VAR** consvars;
289  int nvars;
290  int i;
291  SCIP_Bool success;
292 
293  assert(scip != NULL);
294  assert(cons != NULL);
295  assert(decomp != NULL);
296  assert(hasonlylinkvars != NULL);
297 
298  SCIP_CALL( SCIPgetConsNVars(scip, cons, &nvars, &success) );
299  SCIP_CALL( ensureCondition(success) );
300 
301  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
302 
303  SCIP_CALL( SCIPgetConsVars(scip, cons, consvars, nvars, &success) );
304  SCIP_CALL( ensureCondition(success) );
305 
306  if( ! SCIPdecompIsOriginal(decomp) )
307  {
308  int requiredsize;
309  SCIP_CALL( SCIPgetActiveVars(scip, consvars, &nvars, nvars, &requiredsize) );
310  assert(requiredsize <= nvars);
311  }
312 
313  *hasonlylinkvars = TRUE;
314  /* check if variables are all linking variables */
315  for( i = 0; i < nvars && *hasonlylinkvars; ++i )
316  {
317  int label;
318 
319  SCIPdecompGetVarsLabels(decomp, &consvars[i], &label, 1);
320 
321  *hasonlylinkvars = (label == SCIP_DECOMP_LINKVAR);
322  }
323 
324  SCIPfreeBufferArray(scip, &consvars);
325 
326  return SCIP_OKAY;
327 }
328 
329 
330 /** computes constraint labels from variable labels
331  *
332  * Existing labels for the constraints are simply overridden
333  *
334  * The computed labels depend on the flag SCIPdecompUseBendersLabels() of the decomposition. If the flag is set
335  * to FALSE, the labeling assigns
336  *
337  * - label i, if only variables labeled i are present in the constraint (and optionally linking variables)
338  * - SCIP_DECOMP_LINKCONS, if there are either only variables labeled with SCIP_DECOMP_LINKVAR present, or
339  * if there are variables with more than one block label.
340  *
341  * If the flag is set to TRUE, the assignment is the same, unless variables from 2 named blocks occur in the same
342  * constraint, which is an invalid labeling for the Benders case.
343  */
345  SCIP* scip, /**< SCIP data structure */
346  SCIP_DECOMP* decomp, /**< decomposition data structure */
347  SCIP_CONS** conss, /**< array of constraints */
348  int nconss /**< number of constraints */
349  )
350 {
351  SCIP_VAR** varbuffer;
352  int c;
353  int varbufsize;
354  int* varlabels;
355  int* conslabels;
356  SCIP_Bool benderserror;
357  SCIP_Bool benderslabels;
358 
359  assert(decomp != NULL);
360 
361  if( nconss == 0 )
362  return SCIP_OKAY;
363 
364  varbufsize = getVarbufSize(scip);
365 
366  SCIP_CALL( SCIPallocBufferArray(scip, &varbuffer, varbufsize) );
367  SCIP_CALL( SCIPallocBufferArray(scip, &varlabels, varbufsize) );
368  SCIP_CALL( SCIPallocBufferArray(scip, &conslabels, nconss) );
369 
370  benderslabels = SCIPdecompUseBendersLabels(decomp);
371  benderserror = FALSE;
372 
373  /* assign label to each individual constraint */
374  for( c = 0; c < nconss && ! benderserror; ++c )
375  {
376  int nconsvars;
377  int v;
378  int nlinkingvars = 0;
379  int conslabel;
380  int requiredsize;
381 
382  SCIP_Bool success;
383 
384  SCIP_CALL( decompGetConsVarsAndLabels(scip, decomp, conss[c], varbuffer, varlabels,
385  varbufsize, &nconsvars, &requiredsize, &success) );
386  SCIP_CALL( ensureCondition(success) );
387 
388  /* loop over variable labels to compute the constraint label */
389  conslabel = LABEL_UNASSIGNED;
390  for( v = 0; v < nconsvars; ++v )
391  {
392  int varlabel = varlabels[v];
393 
394  /* count the number of linking variables, and keep track if there are two variables with different labels */
395  if( varlabel == SCIP_DECOMP_LINKVAR )
396  ++nlinkingvars;
397  else if( conslabel == LABEL_UNASSIGNED )
398  conslabel = varlabel;
399  else if( conslabel != varlabel )
400  {
401  /* there must not be two variables from different named blocks in a single constraint, since the presence
402  * of named block variables forbids this constraint from the master (linking) block
403  */
404  if( benderslabels )
405  benderserror = TRUE;
406 
407  conslabel = SCIP_DECOMP_LINKCONS;
408  break;
409  }
410  }
411 
412  assert(nlinkingvars == nconsvars || conslabel != LABEL_UNASSIGNED);
413  assert(v == nconsvars || conslabel == SCIP_DECOMP_LINKCONS);
414 
415  /* if there are only linking variables, the constraint is unassigned */
416  if( conslabel == LABEL_UNASSIGNED )
417  conslabel = SCIP_DECOMP_LINKCONS;
418  conslabels[c] = conslabel;
419  }
420 
421  SCIP_CALL( SCIPdecompSetConsLabels(decomp, conss, conslabels, nconss) );
422 
423  SCIPfreeBufferArray(scip, &conslabels);
424  SCIPfreeBufferArray(scip, &varlabels);
425  SCIPfreeBufferArray(scip, &varbuffer);
426 
427  /* throw an error and inform the user if the variable block decomposition does not allow a benders constraint labeling */
428  if( benderserror )
429  {
430  SCIPerrorMessage("Error in constraint label computation; variables from multiple named blocks in a single constraint\n");
431 
432  return SCIP_INVALIDDATA;
433  }
434 
435  return SCIP_OKAY;
436 }
437 
438 /** creates a decomposition of the variables from a labeling of the constraints
439  *
440  * NOTE: by default, the variable labeling is based on a Dantzig-Wolfe decomposition. This means that constraints in named
441  * blocks have have precedence over linking constraints. If a variable exists in constraints from
442  * two or more named blocks, then this variable is marked as a linking variable.
443  * If a variable occurs in exactly one named block i>=0, it is assigned label i.
444  * Variables which are only in linking constraints are unlabeled. However, SCIPdecompGetVarsLabels() will
445  * label them as linking variables.
446  *
447  * If the variables should be labeled for the application of Benders' decomposition, the decomposition must be
448  * flagged explicitly via SCIPdecompSetUseBendersLabels().
449  * With this setting, the presence in linking constraints takes precedence over the presence in named blocks.
450  * Now, a variable is considered linking if it is present in at least one linking constraint and an arbitrary
451  * number of constraints from named blocks.
452  */
454  SCIP* scip, /**< SCIP data structure */
455  SCIP_DECOMP* decomp, /**< decomposition data structure */
456  SCIP_CONS** conss, /**< array of constraints */
457  int nconss /**< number of constraints */
458  )
459 {
460  int c;
461  int* conslabels;
462  SCIP_VAR** varbuffer;
463  int varbufsize;
464  SCIP_Bool benderslabels;
465 
466  assert(scip != NULL);
467  assert(decomp != NULL);
468  assert(conss != NULL);
469 
470  /* make the buffer array large enough such that we do not have to reallocate buffer */
471  varbufsize = getVarbufSize(scip);
472 
473  /* allocate buffer to store constraint variables and labels */
474  SCIP_CALL( SCIPallocBufferArray(scip, &conslabels, nconss) );
475  SCIP_CALL( SCIPallocBufferArray(scip, &varbuffer, varbufsize) );
476 
477  /* query constraint labels */
478  SCIPdecompGetConsLabels(decomp, conss, conslabels, nconss);
479 
480  benderslabels = SCIPdecompUseBendersLabels(decomp);
481  /* iterate over constraints and query the corresponding constraint labels */
482  for( c = 0; c < nconss; ++c )
483  {
484  int conslabel;
485  int v;
486  int nconsvars;
487  SCIP_Bool success;
488  int requiredsize;
489  int newvarlabel;
490 
491  conslabel = conslabels[c];
492 
493  if( conslabel == SCIP_DECOMP_LINKCONS )
494  {
495  /* skip linking constraints unless Benders labeling is used */
496  if( ! benderslabels )
497  continue;
498  else
499  newvarlabel = SCIP_DECOMP_LINKVAR;
500  }
501  else
502  newvarlabel = conslabel;
503 
504  SCIP_CALL( decompGetConsVarsAndLabels(scip, decomp, conss[c], varbuffer, NULL,
505  varbufsize, &nconsvars, &requiredsize, &success) );
506  SCIP_CALL( ensureCondition(success) );
507 
508  /* each variable in this constraint gets the constraint label unless it already has a different label -> make it a linking variable */
509  for( v = 0; v < nconsvars; ++v )
510  {
511  SCIP_VAR* var = varbuffer[v];
512 
513  assert(SCIPvarIsActive(var) || (SCIPdecompIsOriginal(decomp) && SCIPvarIsNegated(var)));
514 
515  /* some constraint handlers such as indicator may already return inactive variables */
516  if( SCIPvarIsNegated(var) )
517  var = SCIPvarGetNegatedVar(var);
518 
519  if( SCIPhashmapExists(decomp->var2block, (void *)var) )
520  {
521  int varlabel = SCIPhashmapGetImageInt(decomp->var2block, (void *)var);
522 
523  /* store the label linking variable explicitly to distinguish it from the default */
524  if( varlabel != SCIP_DECOMP_LINKVAR && varlabel != newvarlabel )
526  }
527  else
528  {
529  SCIP_CALL( SCIPhashmapInsertInt(decomp->var2block, (void *)var, newvarlabel) );
530  }
531  }
532  }
533 
534  SCIPfreeBufferArray(scip, &varbuffer);
535  SCIPfreeBufferArray(scip, &conslabels);
536 
537  return SCIP_OKAY;
538 }
539 
540 /** assigns linking constraints to blocks
541  *
542  * Each linking constraint is assigned to the most frequent block among its variables.
543  * Variables of other blocks are relabeled as linking variables.
544  * Constraints that have only linking variables are skipped.
545  *
546  * @note: In contrast to SCIPcomputeDecompConsLabels(), this method potentially relabels variables.
547  */
549  SCIP* scip, /**< SCIP data structure */
550  SCIP_DECOMP* decomp, /**< decomposition data structure */
551  SCIP_CONS** conss, /**< array of linking constraints that should be reassigned */
552  int nconss, /**< number of constraints */
553  int* nskipconss /**< pointer to store the number of constraints that were skipped, or NULL */
554  )
555 {
556  SCIP_VAR** vars;
557  SCIP_VAR** allvars;
558  int* varslabels;
559  int requiredsize;
560  int nvars;
561  int nconsvars;
562  int varbufsize;
563  int c;
564  int nskipconsslocal;
565  int defaultlabel;
566 
567  assert(scip != NULL);
568  assert(decomp != NULL);
569 
570  nvars = SCIPgetNVars(scip);
571  varbufsize = getVarbufSize(scip);
572 
573  SCIP_CALL( SCIPallocBufferArray(scip, &varslabels, varbufsize) );
574  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varbufsize) );
575 
576  /* get one label as default label */
577  allvars = SCIPdecompIsOriginal(decomp) ? SCIPgetOrigVars(scip) : SCIPgetVars(scip);
578  SCIPdecompGetVarsLabels(decomp, allvars, varslabels, nvars);
579  for( c = 0; c < nvars; c++ )
580  {
581  if( varslabels[c] != SCIP_DECOMP_LINKVAR )
582  {
583  defaultlabel = varslabels[c];
584  break;
585  }
586  }
587 
588  nskipconsslocal = 0;
589  for( c = 0; c < nconss; c++ )
590  {
591  SCIP_Bool success;
592 
593  SCIP_CALL( decompGetConsVarsAndLabels(scip, decomp, conss[c], vars, varslabels, varbufsize,
594  &nconsvars, &requiredsize, &success) );
595  SCIP_CALL( ensureCondition(success) );
596 
597  SCIPsortIntPtr(varslabels, (void **)vars, nconsvars);
598  /* constraint contains no (active) variables */
599  if( nconsvars == 0 )
600  {
601  SCIP_CALL( SCIPdecompSetConsLabels(decomp, &conss[c], &defaultlabel, 1) );
602  }
603  /* constraint contains only linking variables */
604  else if( varslabels[nconsvars - 1] == SCIP_DECOMP_LINKVAR )
605  {
606  nskipconsslocal++;
607 
608  continue;
609  }
610  else
611  {
612  int startposs[2];
613  int endposs[2];
614  int nlinkvars;
615  int block;
616  int maxnblockvars;
617  int curr;
618  int v;
619  int p;
620 
621  /* count linking variables */
622  if( varslabels[0] == SCIP_DECOMP_LINKVAR )
623  {
624  nlinkvars = countLabelFromPos(varslabels, 0, nconsvars);
625  }
626  else
627  {
628  nlinkvars = 0;
629  }
630 
631  assert(nlinkvars < nconsvars);
632 
633  curr = nlinkvars;
634  /* find the most frequent block label among the nonlinking variables */
635  maxnblockvars = 0;
636  block = -1;
637  do
638  {
639  int nblockvars = countLabelFromPos(varslabels, curr, nconsvars);
640  if( nblockvars > maxnblockvars )
641  {
642  maxnblockvars = nblockvars;
643  block = curr;
644  }
645  curr += nblockvars;
646  }
647  while( curr < nconsvars );
648 
649  /* reassign all variables from other blocks as linking variables */
650  startposs[0] = nlinkvars;
651  endposs[0] = block;
652  startposs[1] = block + maxnblockvars;
653  endposs[1] = nconsvars;
654 
655  /* loop over all variables before (p==0) and after (p==1) the most frequent block label */
656  for( p = 0; p < 2; ++p )
657  {
658  /* relabel */
659  for( v = startposs[p]; v < endposs[p]; ++v )
660  varslabels[v] = SCIP_DECOMP_LINKVAR;
661 
662  /* set labels in the decomposition */
663  SCIP_CALL( SCIPdecompSetVarsLabels(decomp, &vars[startposs[p]], &varslabels[startposs[p]], endposs[p] - startposs[p]) );
664  }
665 
666  SCIP_CALL( SCIPdecompSetConsLabels(decomp, &conss[c], &varslabels[block], 1) );
667  }
668  }
669 
670  if( nskipconss != NULL )
671  *nskipconss = nskipconsslocal;
672 
673  SCIPfreeBufferArray(scip, &vars);
674  SCIPfreeBufferArray(scip, &varslabels);
675 
676  return SCIP_OKAY;
677 }
678 
679 /** return position of a label in decomp array */
680 static
682  SCIP_DECOMP* decomp, /**< decomposition data structure */
683  int label /**< the label */
684  )
685 {
686  int pos;
687 
688  (void)SCIPsortedvecFindInt(decomp->labels, label, decomp->nblocks + 1, &pos);
689 
690  return pos;
691 }
692 
693 /** compute decomposition modularity (comparison of within block edges against a random decomposition) */
694 static
696  SCIP* scip, /**< SCIP data structure */
697  SCIP_DECOMP* decomp, /**< decomposition data structure */
698  SCIP_Real* modularity /**< pointer to store modularity value */
699  )
700 {
701  SCIP_CONS** conss;
702  SCIP_VAR** varbuf;
703  int* varslabels;
704  int* conslabels;
705  int* totaldegrees; /* the total degree for every block */
706  int* withinedges; /* the number of edges within each block */
707  int nnonzeroes = 0;
708  int varbufsize;
709  int nconss;
710  int c;
711  int b;
712 
713  /* allocate buffer arrays to hold constraint and variable labels, and store within-edges and total community degrees */
714  getDecompVarsConssData(scip, decomp, NULL, &conss, NULL, &nconss);
715  varbufsize = getVarbufSize(scip);
716 
717  SCIP_CALL( SCIPallocBufferArray(scip, &conslabels, nconss) );
718  SCIP_CALL( SCIPallocBufferArray(scip, &varslabels, varbufsize) );
719  SCIP_CALL( SCIPallocBufferArray(scip, &varbuf, varbufsize) );
720 
721  SCIP_CALL( SCIPallocClearBufferArray(scip, &totaldegrees, decomp->nblocks + 1) );
722  SCIP_CALL( SCIPallocClearBufferArray(scip, &withinedges, decomp->nblocks + 1) );
723 
724  SCIPdecompGetConsLabels(decomp, conss, conslabels, nconss);
725 
726  /*
727  * loop over all nonzeros, consider the labels of the incident nodes (cons and variable)
728  * and increase the corresponding counters
729  */
730  for( c = 0; c < nconss; ++c )
731  {
732  int nconsvars;
733  int conslabel = conslabels[c];
734  int blockpos;
735  int varblockstart;
736  int requiredsize;
737  SCIP_Bool success;
738 
739  /* linking constraints do not contribute to the modularity */
740  if( conslabel == SCIP_DECOMP_LINKCONS )
741  continue;
742 
743  /* find the position of the constraint label. Constraints of the border always belong to the first block at index 0 */
744  blockpos = findLabelIdx(decomp, conslabel);
745 
746  SCIP_CALL( decompGetConsVarsAndLabels(scip, decomp, conss[c], varbuf, varslabels,
747  varbufsize, &nconsvars, &requiredsize, &success) );
748  SCIP_CALL( ensureCondition(success) );
749 
750  SCIPsortInt(varslabels, nconsvars);
751 
752  /* count occurrences of labels (blocks) in the sorted labels array */
753  varblockstart = 0;
754  while( varblockstart < nconsvars )
755  {
756  int varblockpos;
757  int nblockvars = countLabelFromPos(varslabels, varblockstart, nconsvars);
758 
759  varblockpos = findLabelIdx(decomp, varslabels[varblockstart]);
760 
761  /* don't consider linking variables for modularity statistics */
762  if( varslabels[varblockstart] != SCIP_DECOMP_LINKVAR )
763  {
764  /* increase the number of within edges for variable and constraints from the same block */
765  if( varblockpos == blockpos )
766  withinedges[varblockpos] += nblockvars;
767 
768  /* increase the total degrees and nonzero (edge) counts; it is intended that the total degrees sum up
769  * to twice the number of edges
770  */
771  totaldegrees[blockpos] += nblockvars;
772  totaldegrees[varblockpos] += nblockvars;
773  nnonzeroes += nblockvars;
774  }
775 
776  varblockstart += nblockvars;
777  }
778  }
779 
780 /* ensure that total degrees sum up to twice the number of edges */
781 #ifndef NDEBUG
782  {
783  int totaldegreesum = 0;
784  for( b = 1; b < decomp->nblocks + 1; ++b )
785  totaldegreesum += totaldegrees[b];
786 
787  assert(totaldegreesum == 2 * nnonzeroes);
788  }
789 #endif
790 
791  /* compute modularity */
792  *modularity = 0.0;
793  nnonzeroes = MAX(nnonzeroes, 1);
794  for( b = 1; b < decomp->nblocks + 1; ++b )
795  {
796  SCIP_Real expectedval;
797  expectedval = totaldegrees[b] / (2.0 * nnonzeroes);
798  expectedval = SQR(expectedval);
799  *modularity += (withinedges[b] / (SCIP_Real)nnonzeroes) - expectedval;
800  }
801 
802  SCIPfreeBufferArray(scip, &withinedges);
803  SCIPfreeBufferArray(scip, &totaldegrees);
804  SCIPfreeBufferArray(scip, &varbuf);
805  SCIPfreeBufferArray(scip, &varslabels);
806  SCIPfreeBufferArray(scip, &conslabels);
807 
808  return SCIP_OKAY;
809 }
810 
811 /** compute the area score */
812 static
814  SCIP* scip, /**< SCIP data structure */
815  SCIP_DECOMP* decomp /**< decomposition data structure */
816  )
817 {
818  SCIP_Real areascore = 1.0;
819  int nvars;
820  int nconss;
821 
822  getDecompVarsConssData(scip, decomp, NULL, NULL, &nvars, &nconss);
823 
824  if( nvars > 0 && nconss > 0 )
825  {
826  int nlinkconss = decomp->consssize[0];
827  int nlinkvars = decomp->varssize[0];
828  SCIP_Real factor = 1.0 / ((SCIP_Real)nvars * nconss);
829 
830  int i;
831 
832  /* compute diagonal contributions to the area score */
833  for( i = 1; i < decomp->nblocks + 1; ++i )
834  {
835  areascore -= (factor * decomp->consssize[i]) * decomp->varssize[i];
836  }
837 
838  areascore -= ((SCIP_Real)nlinkconss * nvars + (SCIP_Real)nconss * nlinkvars - (SCIP_Real)nlinkconss * nlinkvars) * factor;
839  }
840 
841  decomp->areascore = areascore;
842 }
843 
844 /** build the block decomposition graph */
845 static
847  SCIP* scip, /**< SCIP data structure */
848  SCIP_DECOMP* decomp, /**< decomposition data structure */
849  int maxgraphedge /**< maximum number of edges in block graph computation (-1: no limit, 0: disable block graph computation) */
850  )
851 {
852  SCIP_VAR** vars;
853  SCIP_CONS** conss;
854  SCIP_VAR** consvars;
855  SCIP_DIGRAPH* blocklinkingvargraph;
856  SCIP_DIGRAPH* blockgraph = NULL;
857  int* varlabels;
858  int* conslabels;
859  SCIP_CONS** consscopy; /* working copy of the constraints */
860  int* linkvaridx;
861  int* succnodesblk;
862  int* succnodesvar;
863  SCIP_Bool success;
864  int varbufsize;
865  int nvars;
866  int nconss;
867  int nblocks;
868  int nlinkingvars = 0;
869  int nconsvars;
870  int conspos;
871  int tempmin;
872  int tempmax;
873  int nblockgraphedges;
874  int blocknodeidx;
875  int i;
876  int j;
877  int v;
878  int n;
879 
880  if( maxgraphedge == -1 )
881  maxgraphedge = INT_MAX;
882 
883  assert(scip != NULL);
884  assert(decomp != NULL);
885  assert(decomp->statscomplete == FALSE);
886 
887  /* capture the trivial case that no linking variables are present */
888  if( decomp->varssize[0] == 0 || decomp->nblocks == 0 )
889  {
890  decomp->mindegree = 0;
891  decomp->maxdegree = 0;
892  decomp->nedges = 0;
893  decomp->ncomponents = SCIPdecompGetNBlocks(decomp);
894  decomp->narticulations = 0;
895  decomp->statscomplete = TRUE;
896 
897  return SCIP_OKAY;
898  }
899 
900  getDecompVarsConssData(scip, decomp, &vars, &conss, &nvars, &nconss);
901  varbufsize = getVarbufSize(scip);
902  nblocks = SCIPdecompGetNBlocks(decomp);
903 
904  SCIP_CALL( SCIPallocBufferArray(scip, &conslabels, nconss) );
905  SCIP_CALL( SCIPallocBufferArray(scip, &varlabels, varbufsize) );
906  SCIP_CALL( SCIPallocBufferArray(scip, &linkvaridx, varbufsize) );
907  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, varbufsize) );
908 
909  /* store variable and constraint labels in buffer arrays */
910  SCIPdecompGetConsLabels(decomp, conss, conslabels, nconss);
911  SCIPdecompGetVarsLabels(decomp, vars, varlabels, nvars);
912 
913  /* create a mapping of all linking variables to 0,..,nlinkingvars -1 and store it in array linkvaridx */
914  for( v = 0; v < nvars; ++v )
915  {
916  if( varlabels[v] == SCIP_DECOMP_LINKVAR )
917  {
918  linkvaridx[v] = nlinkingvars;
919  assert(SCIPvarGetProbindex(vars[v]) == v);
920  ++nlinkingvars;
921  }
922  else
923  linkvaridx[v] = -1;
924  }
925 
926  /* create a bipartite graph composed of block and linking var nodes */
927  SCIP_CALL( SCIPcreateDigraph(scip, &blocklinkingvargraph, nblocks + nlinkingvars) );/* nblocks does not include the linking constraints block */
928 
929  /* initialize position to start after the linking constraints, which we skip anyway */
930  SCIP_CALL( SCIPduplicateBufferArray(scip, &consscopy, conss, nconss) );
931  SCIPsortIntPtr(conslabels, (void**)consscopy, nconss);
932  if( conslabels[0] == SCIP_DECOMP_LINKCONS )
933  conspos = countLabelFromPos(conslabels, 0, nconss);
934  else
935  /* no linking constraints present */
936  conspos = 0;
937 
938  blocknodeidx = -1;
939  /* loop over each block */
940  while( conspos < nconss )
941  {
942  SCIP_Bool* adjacent;
943  int* adjacentidxs;
944  int nblockconss = countLabelFromPos(conslabels, conspos, nconss);
945  int nblocklinkingvars = 0;
946  int c;
947 
948  ++blocknodeidx;
949  /* allocate buffer storage to store all linking variable indices adjacent to this block */
950  SCIP_CALL( SCIPallocCleanBufferArray(scip, &adjacent, nlinkingvars) );
951  SCIP_CALL( SCIPallocBufferArray(scip, &adjacentidxs, nlinkingvars) );
952 
953  /* loop over the constraints of this block; stop if the block vertex has maximum degree */
954  for( c = conspos; c < conspos + nblockconss && nblocklinkingvars < nlinkingvars; ++c )
955  {
956  int requiredsize;
957  SCIP_CONS* cons = consscopy[c];
958  assert(conslabels[c] != SCIP_DECOMP_LINKCONS);
959 
960  SCIP_CALL( decompGetConsVarsAndLabels(scip, decomp, cons, consvars, varlabels,
961  varbufsize, &nconsvars, &requiredsize, &success) );
962  SCIP_CALL( ensureCondition(success) );
963 
964  /* search for linking variables that are not connected so far; stop as soon as block vertex has max degree */
965  for( j = 0; j < nconsvars && nblocklinkingvars < nlinkingvars; ++j )
966  {
967  int linkingvarnodeidx;
968  /* consider only linking variables */
969  if( varlabels[j] != SCIP_DECOMP_LINKVAR )
970  continue;
971 
972  linkingvarnodeidx = linkvaridx[SCIPvarGetProbindex(consvars[j])];
973  assert(linkingvarnodeidx >= 0);
974 
975  if( !adjacent[linkingvarnodeidx] )
976  {
977  adjacent[linkingvarnodeidx] = TRUE;
978  adjacentidxs[nblocklinkingvars++] = linkingvarnodeidx;
979  }
980  }
981  }
982 
983  /* connect block and linking variables in the digraph */
984  assert(blocknodeidx == findLabelIdx(decomp, conslabels[conspos]) - 1);
985  for( i = 0; i < nblocklinkingvars; ++i )
986  {
987  SCIP_CALL( SCIPdigraphAddArc(blocklinkingvargraph, blocknodeidx, nblocks + adjacentidxs[i], NULL) );
988  SCIP_CALL( SCIPdigraphAddArc(blocklinkingvargraph, nblocks + adjacentidxs[i], blocknodeidx, NULL) );
989  }
990 
991  /* clean up the adjacent array before freeing */
992  for( i = 0; i < nblocklinkingvars; ++i )
993  adjacent[adjacentidxs[i]] = FALSE;
994 
995  /* check that adjacent has been entirely cleaned up */
996 #ifndef NDEBUG
997  for( i = 0; i < nlinkingvars; ++i )
998  assert(adjacent[i] == FALSE);
999 #endif
1000 
1001  SCIPfreeBufferArray(scip, &adjacentidxs);
1002  SCIPfreeCleanBufferArray(scip, &adjacent);
1003 
1004  conspos += nblockconss;
1005  }
1006 
1007  SCIPfreeBufferArray(scip, &consscopy);
1008 
1009  assert(SCIPdigraphGetNNodes(blocklinkingvargraph) > 0);
1010  /* check first if any of the linking variables is connected with all blocks -> block graph is complete and connected */
1011  for( n = nblocks; n < SCIPdigraphGetNNodes(blocklinkingvargraph); ++n )
1012  {
1013  int nsuccvar;
1014  nsuccvar = (int) SCIPdigraphGetNSuccessors(blocklinkingvargraph, n);
1015 
1016  if( nsuccvar == nblocks )
1017  {
1018  decomp->nedges = nblocks * (nblocks - 1) / 2;
1019  decomp->mindegree = decomp->maxdegree = nblocks - 1;
1020  decomp->narticulations = 0;
1021  decomp->ncomponents = 1;
1022  decomp->statscomplete = TRUE;
1023 
1024  goto TERMINATE;
1025  }
1026  }
1027 
1028  /* from the information of the above bipartite graph, build the block-decomposition graph: nodes -> blocks and double-direction arcs -> linking variables */
1029  SCIP_CALL( SCIPcreateDigraph(scip, &blockgraph, nblocks) );
1030 
1031  /* we count the number of block graph edges manually, because SCIPdigraphGetNArcs() iterates over all nodes */
1032  nblockgraphedges = 0;
1033  for( n = 0; n < nblocks - 1 && nblockgraphedges < maxgraphedge; ++n )
1034  {
1035  SCIP_Bool* adjacent; /* an array to mark the adjacent blocks to the current block */
1036  int* adjacentidxs;
1037  int nsuccblk;
1038  int nadjacentblks = 0;
1039  SCIP_CALL( SCIPallocCleanBufferArray(scip, &adjacent, nblocks) );
1040  SCIP_CALL( SCIPallocBufferArray(scip, &adjacentidxs, nblocks) );
1041 
1042  assert(n < SCIPdigraphGetNNodes(blocklinkingvargraph));
1043 
1044  /* loop over the connected linking variables to the current block and their connected blocks to update the adjacency array */
1045  nsuccblk = SCIPdigraphGetNSuccessors(blocklinkingvargraph, n);
1046  succnodesblk = SCIPdigraphGetSuccessors(blocklinkingvargraph, n);
1047  for( i = 0; i < nsuccblk && nadjacentblks < nblocks - (n + 1); ++i )
1048  {
1049  int startpos;
1050  int nsuccvar;
1051 
1052  assert(succnodesblk[i] < SCIPdigraphGetNNodes(blocklinkingvargraph));
1053 
1054  nsuccvar = SCIPdigraphGetNSuccessors(blocklinkingvargraph, succnodesblk[i]);
1055  succnodesvar = SCIPdigraphGetSuccessors(blocklinkingvargraph, succnodesblk[i]);
1056 
1057  /* previously visited blocks can be skipped in this step */
1058  if( ! SCIPsortedvecFindInt(succnodesvar, n, nsuccvar, &startpos) )
1059  SCIPABORT();
1060  for( j = startpos + 1; j < nsuccvar; ++j )
1061  {
1062  assert( succnodesvar[j] > n );
1063  if( !adjacent[succnodesvar[j]] )
1064  {
1065  adjacent[succnodesvar[j]] = TRUE;
1066  adjacentidxs[nadjacentblks] = succnodesvar[j];
1067  ++nadjacentblks;
1068  }
1069  }
1070  }
1071 
1072  /* double-direction arcs are added in this step between the current block and its adjacent block nodes */
1073  for( i = 0; i < nadjacentblks && nblockgraphedges < maxgraphedge; ++i )
1074  {
1075  SCIP_CALL( SCIPdigraphAddArc(blockgraph, n, adjacentidxs[i], NULL) );
1076  SCIP_CALL( SCIPdigraphAddArc(blockgraph, adjacentidxs[i], n, NULL) );
1077 
1078  ++nblockgraphedges;
1079  }
1080 
1081  /* clean up the adjacent array and free it */
1082  for( i = 0; i < nadjacentblks; ++i )
1083  adjacent[adjacentidxs[i]] = FALSE;
1084 
1085  SCIPfreeBufferArray(scip, &adjacentidxs);
1086  SCIPfreeCleanBufferArray(scip, &adjacent);
1087  }
1088 
1089  assert(SCIPdigraphGetNNodes(blockgraph) > 0);
1090 
1091  /* Get the number of edges in the block-decomposition graph.*/
1092  decomp->nedges = nblockgraphedges;
1093  decomp->statscomplete = nblockgraphedges < maxgraphedge;
1094 
1095  /* Get the minimum and maximum degree of the block-decomposition graph */
1096  tempmin = (int) SCIPdigraphGetNSuccessors(blockgraph, 0);
1097  tempmax = (int) SCIPdigraphGetNSuccessors(blockgraph, 0);
1098  for( n = 1; n < SCIPdigraphGetNNodes(blockgraph); ++n )
1099  {
1100  int nsuccblk = SCIPdigraphGetNSuccessors(blockgraph, n);
1101 
1102  if( nsuccblk < tempmin )
1103  tempmin = nsuccblk;
1104  else if( nsuccblk > tempmax )
1105  tempmax = nsuccblk;
1106  }
1107 
1108  decomp->mindegree = tempmin;
1109  decomp->maxdegree = tempmax;
1110 
1111  /* Get the number of connected components in the block-decomposition graph.*/
1113  decomp->ncomponents = SCIPdigraphGetNComponents(blockgraph);
1114 
1115  /* Get the number of articulation points in the block-decomposition graph using DFS.*/
1117 
1118 TERMINATE:
1119  SCIPfreeBufferArray(scip, &consvars);
1120  SCIPfreeBufferArray(scip, &linkvaridx);
1121  SCIPfreeBufferArray(scip, &varlabels);
1122  SCIPfreeBufferArray(scip, &conslabels);
1123 
1124  /* blockgraph has probably not been allocated */
1125  if( blockgraph != NULL)
1126  SCIPdigraphFree(&blockgraph);
1127 
1128  SCIPdigraphFree(&blocklinkingvargraph);
1129 
1130  return SCIP_OKAY;
1131 }
1132 
1133 /** computes decomposition statistics and store them in the decomposition object */
1135  SCIP* scip, /**< SCIP data structure */
1136  SCIP_DECOMP* decomp, /**< decomposition data structure */
1137  SCIP_Bool uselimits /**< respect user limits on potentially expensive graph statistics? */
1138  )
1139 {
1140  SCIP_VAR** vars;
1141  SCIP_CONS** conss;
1142  SCIP_CONS** conssarray;
1143  SCIP_VAR** varsarray;
1144  int* varslabels;
1145  int* conslabels;
1146  int nvars;
1147  int nconss;
1148  int varblockstart;
1149  int consblockstart;
1150  int currlabelidx;
1151  int varidx;
1152  int considx;
1153  int i;
1154  int maxgraphedge;
1155  SCIP_Bool disablemeasures;
1156 
1157  assert(scip != NULL);
1158  assert(decomp != NULL);
1159 
1160  getDecompVarsConssData(scip, decomp, &vars, &conss, &nvars, &nconss);
1161 
1162  /* return if problem is empty
1163  *
1164  * TODO ensure that statistics reflect this correctly
1165  */
1166  if( nvars == 0 || nconss == 0 )
1167  {
1168  decomp->nblocks = 0;
1169  decomp->varssize[0] = nvars;
1170  decomp->consssize[0] = nconss;
1171  decomp->labels[0] = SCIP_DECOMP_LINKVAR;
1172  return SCIP_OKAY;
1173  }
1174 
1175  decomp->statscomplete = FALSE;
1176 
1177  /* store variable and constraint labels in buffer arrays */
1178  SCIP_CALL( SCIPduplicateBufferArray(scip, &conssarray, conss, nconss) );
1179  SCIP_CALL( SCIPallocBufferArray(scip, &conslabels, nconss) );
1180  SCIP_CALL( SCIPduplicateBufferArray(scip, &varsarray, vars, nvars) );
1181  SCIP_CALL( SCIPallocBufferArray(scip, &varslabels, nvars) );
1182 
1183  SCIPdecompGetVarsLabels(decomp, varsarray, varslabels, nvars);
1184  SCIPdecompGetConsLabels(decomp, conssarray, conslabels, nconss);
1185 
1186  /* sort both buffer arrays for quick counting */
1187  SCIPsortIntPtr(varslabels, (void**)varsarray, nvars);
1188  SCIPsortIntPtr(conslabels, (void**)conssarray, nconss);
1189 
1190  /* the first label is always LINKVAR, even if Benders' variable labels are used. We can ignore the variables
1191  * labelled as LINKCONS since this label is only required when computing the variable labels for Benders'
1192  * decomposition.
1193  */
1194  decomp->labels[0] = SCIP_DECOMP_LINKVAR;
1195 
1196  /* treating the linking variables first */
1197  if( varslabels[0] == SCIP_DECOMP_LINKVAR )
1198  decomp->varssize[0] = countLabelFromPos(varslabels, 0, nvars);
1199  else
1200  decomp->varssize[0] = 0;
1201 
1202  /* count border constraints and store their number */
1203  if( conslabels[0] == SCIP_DECOMP_LINKCONS )
1204  decomp->consssize[0] = countLabelFromPos(conslabels, 0, nconss);
1205  else
1206  decomp->consssize[0] = 0;
1207 
1208  /* merge labels (except for border at position 0) since neither variable nor constraint labels by themselves need to be complete */
1209  currlabelidx = 1;
1210  varidx = decomp->varssize[0];
1211  considx = decomp->consssize[0];
1212 
1213  while( varidx < nvars || considx < nconss )
1214  {
1215  int varlabel;
1216  int conslabel;
1217 
1218  varlabel = varidx < nvars ? varslabels[varidx] : INT_MAX;
1219  conslabel = considx < nconss ? conslabels[considx] : INT_MAX;
1220 
1221  assert(currlabelidx < decomp->memsize);
1222  /* store the smaller of the two current labels */
1223  decomp->labels[currlabelidx] = MIN(varlabel, conslabel);
1224 
1225  /* a strictly larger variable label means that there are no variables for the current label */
1226  if( varlabel <= conslabel )
1227  decomp->varssize[currlabelidx] = countLabelFromPos(varslabels, varidx, nvars);
1228  else
1229  decomp->varssize[currlabelidx] = 0;
1230 
1231  /* the same for constraint labels */
1232  if( conslabel <= varlabel )
1233  decomp->consssize[currlabelidx] = countLabelFromPos(conslabels, considx, nconss);
1234  else
1235  decomp->consssize[currlabelidx] = 0;
1236 
1237  /* increase indices appropriately */
1238  varidx += decomp->varssize[currlabelidx];
1239  considx += decomp->consssize[currlabelidx];
1240 
1241  currlabelidx++;
1242  }
1243 
1244  SCIPdebugMsg(scip, "Counted %d different labels (should be %d)\n", currlabelidx, decomp->nblocks + 1);
1245 
1246  /* strip the remaining, unused blocks */
1247  if( currlabelidx < decomp->nblocks + 1 )
1248  decomp->nblocks = currlabelidx - 1;
1249 
1250  /* delete empty blocks from statistics, relabel the corresponding constraints/variables as linking */
1251  varblockstart = decomp->varssize[0];
1252  consblockstart = decomp->consssize[0];
1253 
1254  for( i = 1; i < decomp->nblocks + 1; ++i )
1255  {
1256  assert(MAX(decomp->varssize[i], decomp->consssize[i]) > 0);
1257  /* relabel constraint blocks as linking, if there are no corresponding variables */
1258  if( decomp->varssize[i] == 0 )
1259  {
1260  int nblockconss = decomp->consssize[i];
1261  int c;
1262  /* relabel these constraints as linking */
1263  for( c = consblockstart; c < consblockstart + nblockconss; ++c )
1264  conslabels[c] = SCIP_DECOMP_LINKCONS;
1265 
1266  SCIP_CALL( SCIPdecompSetConsLabels(decomp, &conssarray[consblockstart], &conslabels[consblockstart], nblockconss) );
1267 
1268  /* increase number of linking constraints */
1269  decomp->consssize[0] += nblockconss;
1270  }
1271 
1272  /* same for constraints */
1273  if( decomp->consssize[i] == 0 )
1274  {
1275  int nblockvars = decomp->varssize[i];
1276  int v;
1277 
1278  /* relabel the variables as linking variables */
1279  for( v = varblockstart; v < varblockstart + nblockvars; ++v )
1280  varslabels[v] = SCIP_DECOMP_LINKVAR;
1281 
1282  SCIP_CALL( SCIPdecompSetVarsLabels(decomp, &varsarray[varblockstart], &varslabels[varblockstart], nblockvars) );
1283 
1284  /* increase number of linking variables */
1285  decomp->varssize[0] += nblockvars;
1286  }
1287 
1288  varblockstart += decomp->varssize[i];
1289  consblockstart += decomp->consssize[i];
1290  }
1291 
1292  currlabelidx = 1;
1293 
1294  /* delete empty blocks; they are no longer present */
1295  for( i = 1; i < decomp->nblocks + 1; ++i )
1296  {
1297  /* keep only nonempty blocks */
1298  if( decomp->varssize[i] > 0 && decomp->consssize[i] > 0 )
1299  {
1300  decomp->labels[currlabelidx] = decomp->labels[i];
1301  decomp->varssize[currlabelidx] = decomp->varssize[i];
1302  decomp->consssize[currlabelidx] = decomp->consssize[i];
1303 
1304  currlabelidx++;
1305  }
1306  }
1307 
1308  decomp->nblocks = currlabelidx - 1;
1309 
1310  decomp->idxsmallestblock = decomp->idxlargestblock = -1;
1311  /* now that indices are fixed, store indices with largest and smallest number of constraints */
1312  for( i = 1; i < decomp->nblocks + 1; ++i )
1313  {
1314  if( decomp->idxsmallestblock == -1 )
1315  decomp->idxsmallestblock = decomp->idxlargestblock = i;
1316  else if( decomp->consssize[decomp->idxsmallestblock] > decomp->consssize[i] )
1317  decomp->idxsmallestblock = i;
1318  else if( decomp->consssize[decomp->idxlargestblock] < decomp->consssize[i] )
1319  decomp->idxlargestblock = i;
1320  }
1321 
1322  /* compute more involved statistics such as the area score, the modularity, and the block graph statistics */
1323  SCIP_CALL( SCIPgetBoolParam(scip, "decomposition/disablemeasures", &disablemeasures) );
1324  if( !disablemeasures )
1325  {
1326  SCIP_CALL( computeModularity(scip, decomp, &decomp->modularity) );
1327  computeAreaScore(scip, decomp);
1328  }
1329 
1330  if( uselimits )
1331  {
1332  SCIP_CALL( SCIPgetIntParam(scip, "decomposition/maxgraphedge", &maxgraphedge) );
1333  }
1334  else
1335  maxgraphedge = -1;
1336 
1337  /* do not start computation of the block graph if maxgraphedge is set to 0 */
1338  if( maxgraphedge != 0 )
1339  {
1340  SCIP_CALL( buildBlockGraph(scip, decomp, maxgraphedge) );
1341  }
1342 
1343  SCIPfreeBufferArray(scip, &varslabels);
1344  SCIPfreeBufferArray(scip, &varsarray);
1345  SCIPfreeBufferArray(scip, &conslabels);
1346  SCIPfreeBufferArray(scip, &conssarray);
1347 
1348  return SCIP_OKAY;
1349 }
public methods for SCIP parameter handling
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3306
int SCIPdecompstoreGetNOrigDecomps(SCIP_DECOMPSTORE *decompstore)
Definition: dcmp.c:639
void SCIPdecompGetConsLabels(SCIP_DECOMP *decomp, SCIP_CONS **conss, int *labels, int nconss)
Definition: dcmp.c:197
SCIP_RETCODE SCIPcomputeDecompVarsLabels(SCIP *scip, SCIP_DECOMP *decomp, SCIP_CONS **conss, int nconss)
Definition: scip_dcmp.c:453
public methods for memory management
SCIP_RETCODE SCIPassignDecompLinkConss(SCIP *scip, SCIP_DECOMP *decomp, SCIP_CONS **conss, int nconss, int *nskipconss)
Definition: scip_dcmp.c:548
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
SCIP_RETCODE SCIPdigraphComputeUndirectedComponents(SCIP_DIGRAPH *digraph, int minsize, int *components, int *ncomponents)
Definition: misc.c:8000
SCIP_DECOMP ** SCIPdecompstoreGetDecomps(SCIP_DECOMPSTORE *decompstore)
Definition: dcmp.c:610
SCIP_RETCODE SCIPcomputeDecompStats(SCIP *scip, SCIP_DECOMP *decomp, SCIP_Bool uselimits)
Definition: scip_dcmp.c:1134
int SCIPgetNOrigVars(SCIP *scip)
Definition: scip_prob.c:2440
SCIP_Real areascore
Definition: struct_dcmp.h:49
int * SCIPdigraphGetSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7730
static void getDecompVarsConssData(SCIP *scip, SCIP_DECOMP *decomp, SCIP_VAR ***vars, SCIP_CONS ***conss, int *nvars, int *nconss)
Definition: scip_dcmp.c:108
#define FALSE
Definition: def.h:96
SCIP_RETCODE SCIPcomputeDecompConsLabels(SCIP *scip, SCIP_DECOMP *decomp, SCIP_CONS **conss, int nconss)
Definition: scip_dcmp.c:344
static SCIP_RETCODE ensureCondition(SCIP_Bool condition)
Definition: scip_dcmp.c:84
#define TRUE
Definition: def.h:95
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3141
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17609
SCIP_VAR ** SCIPgetOrigVars(SCIP *scip)
Definition: scip_prob.c:2413
void SCIPdecompGetVarsLabels(SCIP_DECOMP *decomp, SCIP_VAR **vars, int *labels, int nvars)
Definition: dcmp.c:148
SCIP_RETCODE SCIPdecompSetVarsLabels(SCIP_DECOMP *decomp, SCIP_VAR **vars, int *labels, int nvars)
Definition: dcmp.c:123
public methods for problem variables
int SCIPdigraphGetNComponents(SCIP_DIGRAPH *digraph)
Definition: misc.c:8195
#define SCIP_DECOMP_LINKCONS
Definition: type_dcmp.h:45
void SCIPfreeDecomp(SCIP *scip, SCIP_DECOMP **decomp)
Definition: scip_dcmp.c:233
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition: scip_prob.c:3096
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
SCIP_Bool SCIPdecompIsOriginal(SCIP_DECOMP *decomp)
Definition: dcmp.c:245
#define LABEL_UNASSIGNED
Definition: scip_dcmp.c:55
public methods for SCIP variables
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17735
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3372
void SCIPsortIntPtr(int *intarray, void **ptrarray, int len)
int SCIPdigraphGetNNodes(SCIP_DIGRAPH *digraph)
Definition: misc.c:7657
void SCIPgetDecomps(SCIP *scip, SCIP_DECOMP ***decomps, int *ndecomps, SCIP_Bool original)
Definition: scip_dcmp.c:262
SCIP_DECOMP ** SCIPdecompstoreGetOrigDecomps(SCIP_DECOMPSTORE *decompstore)
Definition: dcmp.c:629
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:142
SCIP_Real modularity
Definition: struct_dcmp.h:48
public methods for decompositions
public methods for managing constraints
int SCIPdecompstoreGetNDecomps(SCIP_DECOMPSTORE *decompstore)
Definition: dcmp.c:620
#define SCIPerrorMessage
Definition: pub_message.h:64
SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
Definition: scip_cons.c:2567
static int findLabelIdx(SCIP_DECOMP *decomp, int label)
Definition: scip_dcmp.c:681
methods for block memory pools and memory buffers
SCIP_RETCODE SCIPdecompstoreAdd(SCIP_DECOMPSTORE *decompstore, SCIP_DECOMP *decomp)
Definition: dcmp.c:574
SCIP_RETCODE SCIPcheckStage(SCIP *scip, const char *method, SCIP_Bool init, SCIP_Bool problem, SCIP_Bool transforming, SCIP_Bool transformed, SCIP_Bool initpresolve, SCIP_Bool presolving, SCIP_Bool exitpresolve, SCIP_Bool presolved, SCIP_Bool initsolve, SCIP_Bool solving, SCIP_Bool solved, SCIP_Bool exitsolve, SCIP_Bool freetrans, SCIP_Bool freescip)
Definition: debug.c:2186
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
int * consssize
Definition: struct_dcmp.h:53
SCIP_CONS ** SCIPgetOrigConss(SCIP *scip)
Definition: scip_prob.c:3169
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition: scip_param.c:250
int ncomponents
Definition: struct_dcmp.h:60
int SCIPdecompGetNBlocks(SCIP_DECOMP *decomp)
Definition: dcmp.c:278
#define NULL
Definition: lpi_spx1.cpp:164
int * varssize
Definition: struct_dcmp.h:52
int idxlargestblock
Definition: struct_dcmp.h:50
SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
Definition: scip_param.c:269
#define SCIP_CALL(x)
Definition: def.h:393
static SCIP_RETCODE computeModularity(SCIP *scip, SCIP_DECOMP *decomp, SCIP_Real *modularity)
Definition: scip_dcmp.c:695
SCIP main data structure.
int SCIPgetNOrigConss(SCIP *scip)
Definition: scip_prob.c:3142
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:7573
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
SCIP_DECOMPSTORE * decompstore
Definition: struct_scip.h:82
SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
Definition: scip_cons.c:2523
public methods for constraint handler plugins and constraints
#define SCIP_DECOMP_LINKVAR
Definition: type_dcmp.h:44
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
public data structures and miscellaneous methods
SCIP_RETCODE SCIPdecompSetConsLabels(SCIP_DECOMP *decomp, SCIP_CONS **conss, int *labels, int nconss)
Definition: dcmp.c:172
int SCIPdigraphGetNSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7715
static void computeAreaScore(SCIP *scip, SCIP_DECOMP *decomp)
Definition: scip_dcmp.c:813
#define SCIP_Bool
Definition: def.h:93
static SCIP_RETCODE buildBlockGraph(SCIP *scip, SCIP_DECOMP *decomp, int maxgraphedge)
Definition: scip_dcmp.c:846
data structures for a decomposition and a decomposition store
#define MAX(x, y)
Definition: tclique_def.h:92
methods for debugging
SCIP_RETCODE SCIPdecompCreate(SCIP_DECOMP **decomp, BMS_BLKMEM *blkmem, int nblocks, SCIP_Bool original, SCIP_Bool benderslabels)
Definition: dcmp.c:56
SCIP_RETCODE SCIPdigraphGetArticulationPoints(SCIP_DIGRAPH *digraph, int **articulations, int *narticulations)
Definition: misc.c:7911
int idxsmallestblock
Definition: struct_dcmp.h:51
SCIP_RETCODE SCIPhasConsOnlyLinkVars(SCIP *scip, SCIP_DECOMP *decomp, SCIP_CONS *cons, SCIP_Bool *hasonlylinkvars)
Definition: scip_dcmp.c:281
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2000
internal methods for decompositions and the decomposition store
SCIP_VAR ** b
Definition: circlepacking.c:65
general public methods
int * labels
Definition: struct_dcmp.h:54
static SCIP_RETCODE decompGetConsVarsAndLabels(SCIP *scip, SCIP_DECOMP *decomp, SCIP_CONS *cons, SCIP_VAR **varbuf, int *labelbuf, int bufsize, int *nvars, int *requiredsize, SCIP_Bool *success)
Definition: scip_dcmp.c:138
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3050
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1955
#define SCIP_Real
Definition: def.h:186
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:146
public methods for message handling
public methods for data structures
SCIP_RETCODE SCIPcreateDecomp(SCIP *scip, SCIP_DECOMP **decomp, int nblocks, SCIP_Bool original, SCIP_Bool benderslabels)
Definition: scip_dcmp.c:217
void SCIPsortInt(int *intarray, int len)
SCIP_RETCODE SCIPaddDecomp(SCIP *scip, SCIP_DECOMP *decomp)
Definition: scip_dcmp.c:244
static int countLabelFromPos(int *labels, int pos, int nlabels)
Definition: scip_dcmp.c:59
void SCIPdecompFree(SCIP_DECOMP **decomp, BMS_BLKMEM *blkmem)
Definition: dcmp.c:98
SCIP_Bool SCIPdecompUseBendersLabels(SCIP_DECOMP *decomp)
Definition: dcmp.c:268
SCIP_Bool statscomplete
Definition: struct_dcmp.h:64
static int getVarbufSize(SCIP *scip)
Definition: scip_dcmp.c:93
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3230
#define SCIP_CALL_ABORT(x)
Definition: def.h:372
public methods for decompositions
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:7479
#define SCIPABORT()
Definition: def.h:365
public methods for global and local (sub)problems
SCIP_RETCODE SCIPgetActiveVars(SCIP *scip, SCIP_VAR **vars, int *nvars, int varssize, int *requiredsize)
Definition: scip_var.c:1836
int narticulations
Definition: struct_dcmp.h:61
SCIP_HASHMAP * var2block
Definition: struct_dcmp.h:46
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17589
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17415