Scippy

SCIP

Solving Constraint Integer Programs

cuts.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-2019 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 cuts.c
17  * @brief methods for aggregation of rows
18  * @author Jakob Witzig
19  * @author Robert Lion Gottwald
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include "blockmemshell/memory.h"
25 #include "scip/cuts.h"
26 #include "scip/dbldblarith.h"
27 #include "scip/lp.h"
28 #include "scip/pub_lp.h"
29 #include "scip/pub_message.h"
30 #include "scip/pub_misc.h"
31 #include "scip/pub_misc_select.h"
32 #include "scip/pub_misc_sort.h"
33 #include "scip/pub_var.h"
34 #include "scip/scip_cut.h"
35 #include "scip/scip_lp.h"
36 #include "scip/scip_mem.h"
37 #include "scip/scip_message.h"
38 #include "scip/scip_numerics.h"
39 #include "scip/scip_prob.h"
40 #include "scip/scip_sol.h"
41 #include "scip/scip_solvingstats.h"
42 #include "scip/scip_var.h"
43 #include "scip/struct_lp.h"
44 #include "scip/struct_scip.h"
45 #include "scip/struct_set.h"
46 
47 /* =========================================== general static functions =========================================== */
48 #ifdef SCIP_DEBUG
49 static
50 void printCutQuad(
51  SCIP* scip, /**< SCIP data structure */
52  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
53  SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
54  QUAD(SCIP_Real cutrhs), /**< right hand side of the MIR row */
55  int* cutinds, /**< indices of problem variables for non-zero coefficients */
56  int cutnnz, /**< number of non-zeros in cut */
57  SCIP_Bool ignorsol,
58  SCIP_Bool islocal
59  )
60 {
61  SCIP_Real QUAD(activity);
62  SCIP_VAR** vars;
63  int i;
64 
65  assert(scip != NULL);
66  vars = SCIPgetVars(scip);
67 
68  SCIPdebugMessage("CUT:");
69  QUAD_ASSIGN(activity, 0.0);
70  for( i = 0; i < cutnnz; ++i )
71  {
72  SCIP_Real QUAD(coef);
73 
74  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
75 
76  SCIPdebugPrintf(" %+g<%s>", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
77 
78  if( !ignorsol )
79  {
80  SCIPquadprecProdQD(coef, coef, (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]])));
81  }
82  else
83  {
84  if( cutcoefs[i] > 0.0 )
85  {
86  SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]])));
87  }
88  else
89  {
90  SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]])));
91  }
92  }
93 
94  SCIPquadprecSumQQ(activity, activity, coef);
95  }
96  SCIPdebugPrintf(" <= %.6f (activity: %g)\n", QUAD_TO_DBL(cutrhs), QUAD_TO_DBL(activity));
97 }
98 #endif
99 
100 /** macro to make sure a value is not equal to zero, i.e. NONZERO(x) != 0.0
101  * will be TRUE for every x including 0.0
102  *
103  * To avoid branches it will add 1e-100 with the same sign as x to x which will
104  * be rounded away for any sane non-zero value but will make sure the value is
105  * never exactly 0.0.
106  */
107 #define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
108 
109 /** add a scaled row to a dense vector indexed over the problem variables and keep the
110  * index of non-zeros up-to-date
111  */
112 static
114  int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
115  SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
116  int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
117  SCIP_ROW* row, /**< row coefficients to add to variable vector */
118  SCIP_Real scale /**< scale for adding given row to variable vector */
119  )
120 {
121  /* add up coefficients */
122  int i;
123 
124  assert(inds != NULL);
125  assert(vals != NULL);
126  assert(nnz != NULL);
127  assert(row != NULL);
128 
129  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
130  for( i = 0 ; i < row->len; ++i )
131  {
132  SCIP_Real val;
133  int probindex = row->cols[i]->var_probindex;
134 
135  val = vals[probindex];
136 
137  if( val == 0.0 )
138  inds[(*nnz)++] = probindex;
139 
140  val += row->vals[i] * scale;
141 
142  /* the value must not be exactly zero due to sparsity pattern */
143  val = NONZERO(val);
144 
145  assert(val != 0.0);
146  vals[probindex] = val;
147  }
148 
149  return SCIP_OKAY;
150 }
151 
152 /** add a scaled row to a dense vector indexed over the problem variables and keep the
153  * index of non-zeros up-to-date
154  */
155 static
157  int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
158  SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
159  int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
160  SCIP_ROW* row, /**< row coefficients to add to variable vector */
161  SCIP_Real scale /**< scale for adding given row to variable vector */
162  )
163 {
164  /* add up coefficients */
165  int i;
166 
167  assert(inds != NULL);
168  assert(vals != NULL);
169  assert(nnz != NULL);
170  assert(row != NULL);
171 
172  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
173  for( i = 0 ; i < row->len; ++i )
174  {
175  SCIP_Real QUAD(val);
176  int probindex = row->cols[i]->var_probindex;
177 
178  QUAD_ARRAY_LOAD(val, vals, probindex);
179 
180  if( QUAD_HI(val) == 0.0 )
181  inds[(*nnz)++] = probindex;
182 
183  SCIPquadprecSumQD(val, val, row->vals[i] * scale);
184 
185  /* the value must not be exactly zero due to sparsity pattern */
186  QUAD_HI(val) = NONZERO(QUAD_HI(val));
187  assert(QUAD_HI(val) != 0.0);
188 
189  QUAD_ARRAY_STORE(vals, probindex, val);
190  }
191 
192  return SCIP_OKAY;
193 }
194 
195 /** calculates the cuts efficacy for the given solution */
196 static
198  SCIP* scip, /**< SCIP data structure */
199  SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
200  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
201  SCIP_Real cutrhs, /**< the right hand side of the cut */
202  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
203  int cutnnz /**< the number of non-zeros in the cut */
204  )
205 {
206  SCIP_VAR** vars;
207  SCIP_Real norm;
208  SCIP_Real activity;
209  int i;
210 
211  assert(scip != NULL);
212  assert(cutcoefs != NULL);
213  assert(cutinds != NULL);
214 
215  vars = SCIPgetVars(scip);
216 
217  activity = 0.0;
218  for( i = 0; i < cutnnz; ++i )
219  activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
220 
221  norm = SCIPgetVectorEfficacyNorm(scip, cutcoefs, cutnnz);
222  return (activity - cutrhs) / MAX(1e-6, norm);
223 }
224 
225 /** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter */
226 static
228  SCIP* scip, /**< SCIP data structure */
229  SCIP_Real* vals, /**< array of the non-zero coefficients in the vector; this is a quad precision array! */
230  int* inds, /**< array of the problem indices of variables with a non-zero coefficient in the vector */
231  int nnz /**< the number of non-zeros in the vector */
232  )
233 {
234  SCIP_Real norm = 0.0;
235  SCIP_Real QUAD(coef);
236  int i;
237 
238  assert(scip != NULL);
239  assert(scip->set != NULL);
240 
241  switch( scip->set->sepa_efficacynorm )
242  {
243  case 'e':
244  for( i = 0; i < nnz; ++i )
245  {
246  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
247  norm += SQR(QUAD_TO_DBL(coef));
248  }
249  norm = SQRT(norm);
250  break;
251  case 'm':
252  for( i = 0; i < nnz; ++i )
253  {
254  SCIP_Real absval;
255  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
256 
257  absval = REALABS(QUAD_TO_DBL(coef));
258  norm = MAX(norm, absval);
259  }
260  break;
261  case 's':
262  for( i = 0; i < nnz; ++i )
263  {
264  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
265  norm += REALABS(QUAD_TO_DBL(coef));
266  }
267  break;
268  case 'd':
269  for( i = 0; i < nnz; ++i )
270  {
271  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
272  if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
273  {
274  norm = 1.0;
275  break;
276  }
277  }
278  break;
279  default:
280  SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", scip->set->sepa_efficacynorm);
281  assert(FALSE);
282  }
283 
284  return norm;
285 }
286 
287 /** calculates the cuts efficacy for the given solution; the cut coefs are stored densely and in quad precision */
288 static
290  SCIP* scip, /**< SCIP data structure */
291  SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
292  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
293  SCIP_Real cutrhs, /**< the right hand side of the cut */
294  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
295  int cutnnz /**< the number of non-zeros in the cut */
296  )
297 {
298  SCIP_VAR** vars;
299  SCIP_Real norm;
300  SCIP_Real activity;
301  SCIP_Real QUAD(coef);
302  int i;
303 
304  assert(scip != NULL);
305  assert(cutcoefs != NULL);
306  assert(cutinds != NULL);
307  assert(scip->set != NULL);
308 
309  vars = SCIPgetVars(scip);
310 
311  activity = 0.0;
312  for( i = 0; i < cutnnz; ++i )
313  {
314  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
315  activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
316  }
317 
318  norm = calcEfficacyNormQuad(scip, cutcoefs, cutinds, cutnnz);
319  return (activity - cutrhs) / MAX(1e-6, norm);
320 }
321 
322 /** safely remove all coefficients below the given value; returns TRUE if the cut became redundant */
323 static
325  SCIP* scip, /**< SCIP data structure */
326  SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
327  SCIP_Bool cutislocal, /**< is the cut local? */
328  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
329  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
330  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
331  int* cutnnz /**< the number of non-zeros in the cut */
332  )
333 {
334  int i;
335  SCIP_VAR** vars;
336 
337  vars = SCIPgetVars(scip);
338 
339  for( i = 0; i < *cutnnz; )
340  {
341  SCIP_Real QUAD(val);
342 
343  int v = cutinds[i];
344  QUAD_ARRAY_LOAD(val, cutcoefs, v);
345 
346  if( EPSZ(QUAD_TO_DBL(val), minval) )
347  {
348  if( REALABS(QUAD_TO_DBL(val)) > QUAD_EPSILON )
349  {
350  /* adjust left and right hand sides with max contribution */
351  if( QUAD_TO_DBL(val) < 0.0 )
352  {
353  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[v]) : SCIPvarGetUbGlobal(vars[v]);
354  if( SCIPisInfinity(scip, ub) )
355  return TRUE;
356  else
357  {
358  SCIPquadprecProdQD(val, val, ub);
359  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
360  }
361  }
362  else
363  {
364  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[v]) : SCIPvarGetLbGlobal(vars[v]);
365  if( SCIPisInfinity(scip, -lb) )
366  return TRUE;
367  else
368  {
369  SCIPquadprecProdQD(val, val, lb);
370  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
371  }
372  }
373  }
374 
375  QUAD_ASSIGN(val, 0.0);
376  QUAD_ARRAY_STORE(cutcoefs, v, val);
377 
378  /* remove non-zero entry */
379  --(*cutnnz);
380  cutinds[i] = cutinds[*cutnnz];
381  }
382  else
383  ++i;
384  }
385 
386  /* relax rhs to zero, if it's very close to */
387  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
388  QUAD_ASSIGN(*cutrhs, 0.0);
389 
390  return FALSE;
391 }
392 
393 /** safely remove all coefficients below the given value; returns TRUE if the cut became redundant */
394 static
396  SCIP* scip, /**< SCIP data structure */
397  SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
398  SCIP_Bool cutislocal, /**< is the cut local? */
399  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
400  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
401  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
402  int* cutnnz /**< the number of non-zeros in the cut */
403  )
404 {
405  int i;
406  SCIP_VAR** vars;
407 
408  vars = SCIPgetVars(scip);
409 
410  /* loop over non-zeros and remove values below minval; values above QUAD_EPSILON are cancelled with their bound
411  * to avoid numerical rounding errors
412  */
413  for( i = 0; i < *cutnnz; )
414  {
415  SCIP_Real val;
416 
417  int v = cutinds[i];
418  val = cutcoefs[v];
419 
420  if( EPSZ(val, minval) )
421  {
422  if( REALABS(val) > QUAD_EPSILON )
423  {
424  /* adjust left and right hand sides with max contribution */
425  if( val < 0.0 )
426  {
427  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[v]) : SCIPvarGetUbGlobal(vars[v]);
428  if( SCIPisInfinity(scip, ub) )
429  return TRUE;
430  else
431  {
432  SCIPquadprecSumQD(*cutrhs, *cutrhs, -val * ub);
433  }
434  }
435  else
436  {
437  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[v]) : SCIPvarGetLbGlobal(vars[v]);
438  if( SCIPisInfinity(scip, -lb) )
439  return TRUE;
440  else
441  {
442  SCIPquadprecSumQD(*cutrhs, *cutrhs, -val * lb);
443  }
444  }
445  }
446 
447  cutcoefs[v] = 0.0;
448 
449  /* remove non-zero entry */
450  --(*cutnnz);
451  cutinds[i] = cutinds[*cutnnz];
452  }
453  else
454  ++i;
455  }
456 
457  /* relax rhs to zero, if it's very close to */
458  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
459  QUAD_ASSIGN(*cutrhs, 0.0);
460 
461  return FALSE;
462 }
463 
464 static
465 SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
466 {
467  SCIP_Real abscoef1;
468  SCIP_Real abscoef2;
469  SCIP_Real QUAD(coef1);
470  SCIP_Real QUAD(coef2);
471  SCIP_Real* coefs = (SCIP_Real*) dataptr;
472 
473  QUAD_ARRAY_LOAD(coef1, coefs, ind1);
474  QUAD_ARRAY_LOAD(coef2, coefs, ind2);
475 
476  abscoef1 = REALABS(QUAD_TO_DBL(coef1));
477  abscoef2 = REALABS(QUAD_TO_DBL(coef2));
478 
479  if( abscoef1 < abscoef2 )
480  return -1;
481  if( abscoef2 < abscoef1 )
482  return 1;
483 
484  return 0;
485 }
486 
487 static
488 SCIP_DECL_SORTINDCOMP(compareAbsCoefs)
489 {
490  SCIP_Real abscoef1;
491  SCIP_Real abscoef2;
492  SCIP_Real* coefs = (SCIP_Real*) dataptr;
493 
494  abscoef1 = REALABS(coefs[ind1]);
495  abscoef2 = REALABS(coefs[ind2]);
496 
497  if( abscoef1 < abscoef2 )
498  return -1;
499  if( abscoef2 < abscoef1 )
500  return 1;
501 
502  return 0;
503 }
504 
505 /** change given coefficient to new given value, adjust right hand side using the variables bound;
506  * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
507  */
508 static
510  SCIP* scip, /**< SCIP data structure */
511  SCIP_VAR* var, /**< variable the coefficient belongs to */
512  SCIP_Real oldcoeff, /**< old coefficient value */
513  SCIP_Real newcoeff, /**< new coefficient value */
514  SCIP_Bool cutislocal, /**< is the cut local? */
515  QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
516  )
517 {
518  SCIP_Real QUAD(delta);
519  SCIPquadprecSumDD(delta, newcoeff, -oldcoeff);
520 
521  if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
522  {
523  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
524  if( SCIPisInfinity(scip, ub) )
525  return TRUE;
526  else
527  {
528  SCIPquadprecProdQD(delta, delta, ub);
529  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
530  }
531  }
532  else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
533  {
534  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
535  if( SCIPisInfinity(scip, -lb) )
536  return TRUE;
537  else
538  {
539  SCIPquadprecProdQD(delta, delta, lb);
540  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
541  }
542  }
543 
544  return FALSE;
545 }
546 
547 /** change given (quad) coefficient to new given value, adjust right hand side using the variables bound;
548  * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
549  */
550 static
552  SCIP* scip, /**< SCIP data structure */
553  SCIP_VAR* var, /**< variable the coefficient belongs to */
554  QUAD(SCIP_Real oldcoeff), /**< old coefficient value */
555  SCIP_Real newcoeff, /**< new coefficient value */
556  SCIP_Bool cutislocal, /**< is the cut local? */
557  QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
558  )
559 {
560  SCIP_Real QUAD(delta);
561 
562  SCIPquadprecSumQD(delta, -oldcoeff, newcoeff);
563 
564  if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
565  {
566  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
567  if( SCIPisInfinity(scip, ub) )
568  return TRUE;
569  else
570  {
571  SCIPquadprecProdQD(delta, delta, ub);
572  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
573  }
574  }
575  else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
576  {
577  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
578  if( SCIPisInfinity(scip, -lb) )
579  return TRUE;
580  else
581  {
582  SCIPquadprecProdQD(delta, delta, lb);
583  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
584  }
585  }
586 
587  return FALSE;
588 }
589 
590 /** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
591  * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse quad precision array;
592  */
593 static
595  SCIP* scip, /**< SCIP data structure */
596  SCIP_Bool cutislocal, /**< is the cut local? */
597  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
598  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
599  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
600  int* cutnnz, /**< the number of non-zeros in the cut */
601  SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
602  )
603 {
604  int i;
605  int nintegralvars;
606  SCIP_Bool isintegral;
607  SCIP_VAR** vars;
608  SCIP_Real QUAD(maxacttmp);
609  SCIP_Real maxact;
610  SCIP_Real maxabsintval;
611  SCIP_Real maxabscontval;
612 
613  QUAD_ASSIGN(maxacttmp, 0.0);
614 
615  vars = SCIPgetVars(scip);
616  maxabsintval = 0.0;
617  maxabscontval = 0.0;
618  nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
619  isintegral = TRUE;
620 
621  *redundant = FALSE;
622 
623  /* compute the maximum activity and maximum absolute coefficient values for all and for integral variables in the cut */
624  for( i = 0; i < *cutnnz; ++i )
625  {
626  SCIP_Real QUAD(val);
627 
628  assert(cutinds[i] >= 0);
629  assert(vars[cutinds[i]] != NULL);
630 
631  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
632 
633  if( QUAD_TO_DBL(val) < 0.0 )
634  {
635  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
636 
637  if( SCIPisInfinity(scip, -lb) )
638  return SCIP_OKAY;
639 
640  if( cutinds[i] < nintegralvars )
641  maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
642  else
643  {
644  maxabscontval = MAX(maxabscontval, -QUAD_TO_DBL(val));
645  isintegral = FALSE;
646  }
647 
648  SCIPquadprecProdQD(val, val, lb);
649 
650  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
651  }
652  else
653  {
654  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
655 
656  if( SCIPisInfinity(scip, ub) )
657  return SCIP_OKAY;
658 
659  if( cutinds[i] < nintegralvars )
660  maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
661  else
662  {
663  maxabscontval = MAX(maxabscontval, QUAD_TO_DBL(val));
664  isintegral = FALSE;
665  }
666 
667  SCIPquadprecProdQD(val, val, ub);
668 
669  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
670  }
671  }
672 
673  maxact = QUAD_TO_DBL(maxacttmp);
674 
675  /* cut is redundant in activity bounds */
676  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
677  {
678  *redundant = TRUE;
679  return SCIP_OKAY;
680  }
681 
682  /* cut is only on integral variables, try to scale to integral coefficients */
683  if( isintegral )
684  {
685  SCIP_Real equiscale;
686  SCIP_Real intscalar;
687  SCIP_Bool success;
688  SCIP_Real* intcoeffs;
689 
690  SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
691 
692  equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
693 
694  for( i = 0; i < *cutnnz; ++i )
695  {
696  SCIP_Real QUAD(val);
697 
698  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
699  SCIPquadprecProdQD(val, val, equiscale);
700 
701  intcoeffs[i] = QUAD_TO_DBL(val);
702  }
703 
704  SCIP_CALL( SCIPcalcIntegralScalar(intcoeffs, *cutnnz, -SCIPsumepsilon(scip), SCIPepsilon(scip),
705  (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
706 
707  SCIPfreeBufferArray(scip, &intcoeffs);
708 
709  if( success )
710  {
711  /* if successful, apply the scaling */
712  intscalar *= equiscale;
713 
714  SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
715 
716  for( i = 0; i < *cutnnz; )
717  {
718  SCIP_Real QUAD(val);
719  SCIP_Real intval;
720 
721  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
722  SCIPquadprecProdQD(val, val, intscalar);
723 
724  intval = SCIPround(scip, QUAD_TO_DBL(val));
725 
726  if( chgQuadCoeffWithBound(scip, vars[cutinds[i]], QUAD(val), intval, cutislocal, QUAD(cutrhs)) )
727  {
728  /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
729  *redundant = TRUE;
730  return SCIP_OKAY;
731  }
732 
733  if( intval != 0.0 )
734  {
735  QUAD_ASSIGN(val, intval);
736  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
737  ++i;
738  }
739  else
740  {
741  /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
742  QUAD_ASSIGN(val, 0.0);
743  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
744  --(*cutnnz);
745  cutinds[i] = cutinds[*cutnnz];
746  }
747  }
748 
749  SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
750 
751  /* recompute the maximal activity after scaling to integral values */
752  QUAD_ASSIGN(maxacttmp, 0.0);
753  maxabsintval = 0.0;
754 
755  for( i = 0; i < *cutnnz; ++i )
756  {
757  SCIP_Real QUAD(val);
758 
759  assert(cutinds[i] >= 0);
760  assert(vars[cutinds[i]] != NULL);
761 
762  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
763 
764  if( QUAD_TO_DBL(val) < 0.0 )
765  {
766  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
767 
768  maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
769 
770  SCIPquadprecProdQD(val, val, lb);
771 
772  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
773  }
774  else
775  {
776  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
777 
778  maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
779 
780  SCIPquadprecProdQD(val, val, ub);
781 
782  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
783  }
784  }
785 
786  maxact = QUAD_TO_DBL(maxacttmp);
787 
788  assert(EPSISINT(maxact, 1e-4));
789  maxact = SCIPround(scip, maxact);
790  QUAD_ASSIGN(maxacttmp, maxact);
791 
792  /* check again for redundancy */
793  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
794  {
795  *redundant = TRUE;
796  return SCIP_OKAY;
797  }
798  }
799  else
800  {
801  /* otherwise, apply the equilibrium scaling */
802  isintegral = FALSE;
803 
804  /* perform the scaling */
805  SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
806 
807  SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
808  maxabsintval *= equiscale;
809 
810  for( i = 0; i < *cutnnz; ++i )
811  {
812  SCIP_Real QUAD(val);
813 
814  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
815  SCIPquadprecProdQD(val, val, equiscale);
816  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
817  }
818  }
819  }
820  else
821  {
822  /* cut has integer and continuous variables, so scale it to equilibrium */
823  SCIP_Real scale;
824  SCIP_Real maxabsval;
825 
826  maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
827  maxabsval = MIN(maxabsval, maxabsintval);
828  maxabsval = MAX(maxabsval, maxabscontval);
829 
830  scale = 1.0 / maxabsval; /*lint !e795*/
831 
832  /* perform the scaling */
833  SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
834  maxact = QUAD_TO_DBL(maxacttmp);
835 
836  SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
837  maxabsintval *= scale;
838 
839  for( i = 0; i < *cutnnz; ++i )
840  {
841  SCIP_Real QUAD(val);
842 
843  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
844  SCIPquadprecProdQD(val, val, scale);
845  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
846  }
847  }
848 
849  /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
850  if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
851  return SCIP_OKAY;
852 
853  SCIPsortDownInd(cutinds, compareAbsCoefsQuad, (void*) cutcoefs, *cutnnz);
854 
855  /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
856  for( i = 0; i < *cutnnz; )
857  {
858  SCIP_Real QUAD(val);
859 
860  if( cutinds[i] >= nintegralvars )
861  {
862  ++i;
863  continue;
864  }
865 
866  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
867 
868  assert(SCIPvarIsIntegral(vars[cutinds[i]]));
869 
870  if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
871  {
872  SCIP_Real QUAD(coef);
873  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
874 
875  SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
876 
877  if( isintegral )
878  {
879  /* if the cut is integral, the true coefficient must also be integral;
880  * thus we round it to the exact integral value
881  */
882  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
883  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
884  }
885 
886  if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
887  {
888  SCIP_Real QUAD(delta);
889  SCIP_Real QUAD(tmp);
890 
891  SCIPquadprecSumQQ(delta, -val, coef);
892  SCIPquadprecProdQD(delta, delta, lb);
893 
894  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
895 
896  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
897  QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
898  cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
899 
900  QUAD_ASSIGN_Q(*cutrhs, tmp);
901 
902  assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
903 
904  if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
905  {
906  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
907  maxact = QUAD_TO_DBL(maxacttmp);
908  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
909  }
910  else
911  {
912  QUAD_ASSIGN(coef, 0.0);
913  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
914  --(*cutnnz);
915  cutinds[i] = cutinds[*cutnnz];
916  continue;
917  }
918  }
919  }
920  else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
921  {
922  SCIP_Real QUAD(coef);
923  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
924 
925  SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
926 
927  if( isintegral )
928  {
929  /* if the cut is integral, the true coefficient must also be integral;
930  * thus we round it to the exact integral value
931  */
932  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
933  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
934  }
935 
936  if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
937  {
938  SCIP_Real QUAD(delta);
939  SCIP_Real QUAD(tmp);
940 
941  SCIPquadprecSumQQ(delta, -val, coef);
942  SCIPquadprecProdQD(delta, delta, ub);
943 
944  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
945 
946  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
947  QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
948  cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
949 
950  QUAD_ASSIGN_Q(*cutrhs, tmp);
951 
952  assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
953  if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
954  {
955  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
956  maxact = QUAD_TO_DBL(maxacttmp);
957  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
958  }
959  else
960  {
961  QUAD_ASSIGN(coef, 0.0);
962  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
963  --(*cutnnz);
964  cutinds[i] = cutinds[*cutnnz];
965  continue;
966  }
967  }
968  }
969  else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
970  break;
971 
972  ++i;
973  }
974 
975  return SCIP_OKAY;
976 }
977 
978 /** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
979  * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse array;
980  */
981 static
983  SCIP* scip, /**< SCIP data structure */
984  SCIP_Bool cutislocal, /**< is the cut local? */
985  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
986  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
987  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
988  int* cutnnz, /**< the number of non-zeros in the cut */
989  SCIP_Bool* redundant /**< pointer to return whtether the cut was detected to be redundant */
990  )
991 {
992  int i;
993  int nintegralvars;
994  SCIP_Bool isintegral;
995  SCIP_VAR** vars;
996  SCIP_Real QUAD(maxacttmp);
997  SCIP_Real maxact;
998  SCIP_Real maxabsintval;
999  SCIP_Real maxabscontval;
1000 
1001  QUAD_ASSIGN(maxacttmp, 0.0);
1002 
1003  vars = SCIPgetVars(scip);
1004  maxabsintval = 0.0;
1005  maxabscontval = 0.0;
1006  isintegral = TRUE;
1007  *redundant = FALSE;
1008  nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1009 
1010  for( i = 0; i < *cutnnz; ++i )
1011  {
1012  SCIP_Real val;
1013 
1014  assert(cutinds[i] >= 0);
1015  assert(vars[cutinds[i]] != NULL);
1016 
1017  val = cutcoefs[cutinds[i]];
1018 
1019  if( val < 0.0 )
1020  {
1021  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1022 
1023  if( SCIPisInfinity(scip, -lb) )
1024  return SCIP_OKAY;
1025 
1026  if( cutinds[i] < nintegralvars )
1027  maxabsintval = MAX(maxabsintval, -val);
1028  else
1029  {
1030  maxabscontval = MAX(maxabscontval, -val);
1031  isintegral = FALSE;
1032  }
1033 
1034  SCIPquadprecSumQD(maxacttmp, maxacttmp, val * lb);
1035  }
1036  else
1037  {
1038  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1039 
1040  if( SCIPisInfinity(scip, ub) )
1041  return SCIP_OKAY;
1042 
1043  if( cutinds[i] < nintegralvars )
1044  maxabsintval = MAX(maxabsintval, val);
1045  else
1046  {
1047  maxabscontval = MAX(maxabscontval, val);
1048  isintegral = FALSE;
1049  }
1050 
1051  SCIPquadprecSumQD(maxacttmp, maxacttmp, val * ub);
1052  }
1053  }
1054 
1055  maxact = QUAD_TO_DBL(maxacttmp);
1056 
1057  /* cut is redundant in activity bounds */
1058  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1059  {
1060  *redundant = TRUE;
1061  return SCIP_OKAY;
1062  }
1063 
1064  /* cut is only on integral variables, try to scale to integral coefficients */
1065  if( isintegral )
1066  {
1067  SCIP_Real equiscale;
1068  SCIP_Real intscalar;
1069  SCIP_Bool success;
1070  SCIP_Real* intcoeffs;
1071 
1072  SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
1073 
1074  equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
1075 
1076  for( i = 0; i < *cutnnz; ++i )
1077  {
1078  SCIP_Real scaleval;
1079  SCIP_Real val;
1080 
1081  val = cutcoefs[cutinds[i]];
1082 
1083  scaleval = val * equiscale;
1084 
1085  intcoeffs[i] = scaleval;
1086  }
1087 
1088  SCIP_CALL( SCIPcalcIntegralScalar(intcoeffs, *cutnnz, -SCIPsumepsilon(scip), SCIPepsilon(scip),
1089  (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
1090 
1091  SCIPfreeBufferArray(scip, &intcoeffs);
1092 
1093  if( success )
1094  {
1095  /* if successful, apply the scaling */
1096  intscalar *= equiscale;
1097 
1098  SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
1099 
1100  for( i = 0; i < *cutnnz; )
1101  {
1102  SCIP_Real val;
1103  SCIP_Real intval;
1104 
1105  val = cutcoefs[cutinds[i]];
1106  val *= intscalar;
1107 
1108  intval = SCIPround(scip, val);
1109 
1110  if( chgCoeffWithBound(scip, vars[cutinds[i]], val, intval, cutislocal, QUAD(cutrhs)) )
1111  {
1112  /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1113  *redundant = TRUE;
1114  return SCIP_OKAY;
1115  }
1116 
1117  if( intval != 0.0 )
1118  {
1119  cutcoefs[cutinds[i]] = intval;
1120  ++i;
1121  }
1122  else
1123  {
1124  /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
1125  cutcoefs[cutinds[i]] = 0.0;
1126  --(*cutnnz);
1127  cutinds[i] = cutinds[*cutnnz];
1128  }
1129  }
1130 
1131  SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
1132 
1133  /* recompute the maximal activity after scaling to integral values */
1134  QUAD_ASSIGN(maxacttmp, 0.0);
1135  maxabsintval = 0.0;
1136 
1137  for( i = 0; i < *cutnnz; ++i )
1138  {
1139  SCIP_Real val;
1140 
1141  assert(cutinds[i] >= 0);
1142  assert(vars[cutinds[i]] != NULL);
1143 
1144  val = cutcoefs[cutinds[i]];
1145 
1146  if( val < 0.0 )
1147  {
1148  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1149 
1150  maxabsintval = MAX(maxabsintval, -val);
1151 
1152  val *= lb;
1153 
1154  SCIPquadprecSumQD(maxacttmp, maxacttmp, val);
1155  }
1156  else
1157  {
1158  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1159 
1160  maxabsintval = MAX(maxabsintval, val);
1161 
1162  val *= ub;
1163 
1164  SCIPquadprecSumQD(maxacttmp, maxacttmp, val);
1165  }
1166  }
1167 
1168  maxact = QUAD_TO_DBL(maxacttmp);
1169 
1170  assert(EPSISINT(maxact, 1e-4));
1171  maxact = SCIPround(scip, maxact);
1172  QUAD_ASSIGN(maxacttmp, maxact);
1173 
1174  /* check again for redundancy */
1175  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1176  {
1177  *redundant = TRUE;
1178  return SCIP_OKAY;
1179  }
1180  }
1181  else
1182  {
1183  /* otherwise, apply the equilibrium scaling */
1184  isintegral = FALSE;
1185 
1186  /* perform the scaling */
1187  SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
1188 
1189  SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
1190  maxabsintval *= equiscale;
1191 
1192  for( i = 0; i < *cutnnz; ++i )
1193  cutcoefs[cutinds[i]] *= equiscale;
1194  }
1195  }
1196  else
1197  {
1198  /* cut has integer and continuous variables, so scale it to equilibrium */
1199  SCIP_Real scale;
1200  SCIP_Real maxabsval;
1201 
1202  maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
1203  maxabsval = MIN(maxabsval, maxabsintval);
1204  maxabsval = MAX(maxabsval, maxabscontval);
1205 
1206  scale = 1.0 / maxabsval; /*lint !e795*/
1207 
1208  /* perform the scaling */
1209  SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
1210  maxact = QUAD_TO_DBL(maxacttmp);
1211 
1212  SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
1213  maxabsintval *= scale;
1214 
1215  for( i = 0; i < *cutnnz; ++i )
1216  cutcoefs[cutinds[i]] *= scale;
1217  }
1218 
1219  /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1220  if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
1221  return SCIP_OKAY;
1222 
1223  SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
1224 
1225  /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1226  for( i = 0; i < *cutnnz; )
1227  {
1228  SCIP_Real val;
1229 
1230  if( cutinds[i] >= nintegralvars )
1231  {
1232  ++i;
1233  continue;
1234  }
1235 
1236  val = cutcoefs[cutinds[i]];
1237 
1238  assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1239 
1240  if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
1241  {
1242  SCIP_Real QUAD(coef);
1243  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1244 
1245  SCIPquadprecSumQQ(coef, -maxacttmp, *cutrhs);
1246 
1247  if( isintegral )
1248  {
1249  /* if the cut is integral, the true coefficient must also be integral;
1250  * thus we round it to the exact integral value
1251  */
1252  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1253  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1254  }
1255 
1256  if( QUAD_TO_DBL(coef) > val )
1257  {
1258  SCIP_Real QUAD(delta);
1259  SCIP_Real QUAD(tmp);
1260 
1261  SCIPquadprecSumQD(delta, coef, -val);
1262  SCIPquadprecProdQD(delta, delta, lb);
1263 
1264  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1265  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1266  val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
1267  cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1268 
1269  QUAD_ASSIGN_Q(*cutrhs, tmp);
1270 
1271  assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
1272 
1273  if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1274  {
1275  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1276  maxact = QUAD_TO_DBL(maxacttmp);
1277  cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
1278  }
1279  else
1280  {
1281  cutcoefs[cutinds[i]] = 0.0;
1282  --(*cutnnz);
1283  cutinds[i] = cutinds[*cutnnz];
1284  continue;
1285  }
1286  }
1287  }
1288  else if( val > 0.0 && SCIPisLE(scip, maxact - val, QUAD_TO_DBL(*cutrhs)) )
1289  {
1290  SCIP_Real QUAD(coef);
1291  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1292 
1293  SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
1294 
1295  if( isintegral )
1296  {
1297  /* if the cut is integral, the true coefficient must also be integral;
1298  * thus we round it to the exact integral value
1299  */
1300  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1301  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1302  }
1303 
1304  if( QUAD_TO_DBL(coef) < val )
1305  {
1306  SCIP_Real QUAD(delta);
1307  SCIP_Real QUAD(tmp);
1308 
1309  SCIPquadprecSumQD(delta, coef, -val);
1310  SCIPquadprecProdQD(delta, delta, ub);
1311 
1312  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1313  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1314  val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
1315  cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1316 
1317  QUAD_ASSIGN_Q(*cutrhs, tmp);
1318 
1319  assert(! SCIPisNegative(scip, QUAD_TO_DBL(coef)));
1320 
1321  if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1322  {
1323  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1324  maxact = QUAD_TO_DBL(maxacttmp);
1325  cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
1326  }
1327  else
1328  {
1329  cutcoefs[cutinds[i]] = 0.0;
1330  --(*cutnnz);
1331  cutinds[i] = cutinds[*cutnnz];
1332  continue;
1333  }
1334  }
1335  }
1336  else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1337  break;
1338 
1339  ++i;
1340  }
1341 
1342  return SCIP_OKAY;
1343 }
1344 
1345 /** perform activity based coefficient tightening on the given cut; returns TRUE if the cut was detected
1346  * to be redundant due to activity bounds
1347  */
1349  SCIP* scip, /**< SCIP data structure */
1350  SCIP_Bool cutislocal, /**< is the cut local? */
1351  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1352  SCIP_Real* cutrhs, /**< the right hand side of the cut */
1353  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1354  int* cutnnz, /**< the number of non-zeros in the cut */
1355  int* nchgcoefs /**< number of changed coefficients */
1356  )
1357 {
1358  int i;
1359  int nintegralvars;
1360  SCIP_VAR** vars;
1361  SCIP_Real* absvals;
1362  SCIP_Real QUAD(maxacttmp);
1363  SCIP_Real maxact;
1364  SCIP_Real maxabsval;
1365  SCIP_Bool redundant;
1366 
1367  assert(nchgcoefs != NULL);
1368 
1369  QUAD_ASSIGN(maxacttmp, 0.0);
1370 
1371  vars = SCIPgetVars(scip);
1372  nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1373  maxabsval = 0.0;
1374  SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &absvals, *cutnnz) );
1375 
1376  *nchgcoefs = 0;
1377  redundant = FALSE;
1378 
1379  for( i = 0; i < *cutnnz; ++i )
1380  {
1381  assert(cutinds[i] >= 0);
1382  assert(vars[cutinds[i]] != NULL);
1383 
1384  if( cutcoefs[i] < 0.0 )
1385  {
1386  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1387 
1388  if( SCIPisInfinity(scip, -lb) )
1389  goto TERMINATE;
1390 
1391  if( cutinds[i] < nintegralvars )
1392  {
1393  maxabsval = MAX(maxabsval, -cutcoefs[i]);
1394  absvals[i] = -cutcoefs[i];
1395  }
1396  else
1397  {
1398  absvals[i] = 0.0;
1399  }
1400 
1401  SCIPquadprecSumQD(maxacttmp, maxacttmp, lb * cutcoefs[i]);
1402  }
1403  else
1404  {
1405  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1406 
1407  if( SCIPisInfinity(scip, ub) )
1408  goto TERMINATE;
1409 
1410  if( cutinds[i] < nintegralvars )
1411  {
1412  maxabsval = MAX(maxabsval, cutcoefs[i]);
1413  absvals[i] = cutcoefs[i];
1414  }
1415  else
1416  {
1417  absvals[i] = 0.0;
1418  }
1419 
1420  SCIPquadprecSumQD(maxacttmp, maxacttmp, ub * cutcoefs[i]);
1421  }
1422  }
1423 
1424  maxact = QUAD_TO_DBL(maxacttmp);
1425 
1426  /* cut is redundant in activity bounds */
1427  if( SCIPisFeasLE(scip, maxact, *cutrhs) )
1428  {
1429  redundant = TRUE;
1430  goto TERMINATE;
1431  }
1432 
1433  /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1434  if( SCIPisGT(scip, maxact - maxabsval, *cutrhs) )
1435  goto TERMINATE;
1436 
1437  SCIPsortDownRealRealInt(absvals, cutcoefs, cutinds, *cutnnz);
1438  SCIPfreeBufferArray(scip, &absvals);
1439 
1440  /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1441  for( i = 0; i < *cutnnz;)
1442  {
1443  if( cutinds[i] >= nintegralvars )
1444  {
1445  ++i;
1446  continue;
1447  }
1448 
1449  assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1450 
1451  if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
1452  {
1453  SCIP_Real coef = (*cutrhs) - maxact;
1454  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1455 
1456  coef = floor(coef);
1457 
1458  if( coef > cutcoefs[i] )
1459  {
1460  SCIP_Real QUAD(delta);
1461  SCIP_Real QUAD(tmp);
1462 
1463  SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
1464  SCIPquadprecProdQD(delta, delta, lb);
1465 
1466  SCIPquadprecSumQD(tmp, delta, *cutrhs);
1467  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1468  cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp), lb,
1469  cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1470 
1471  *cutrhs = QUAD_TO_DBL(tmp);
1472 
1473  assert(!SCIPisPositive(scip, coef));
1474 
1475  ++(*nchgcoefs);
1476 
1477  if( SCIPisNegative(scip, coef) )
1478  {
1479  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1480  maxact = QUAD_TO_DBL(maxacttmp);
1481  cutcoefs[i] = coef;
1482  }
1483  else
1484  {
1485  --(*cutnnz);
1486  cutinds[i] = cutinds[*cutnnz];
1487  cutcoefs[i] = cutcoefs[*cutnnz];
1488  continue;
1489  }
1490  }
1491  }
1492  else if( cutcoefs[i] > 0.0 && SCIPisLE(scip, maxact - cutcoefs[i], *cutrhs) )
1493  {
1494  SCIP_Real coef = maxact - (*cutrhs);
1495  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1496 
1497  coef = ceil(coef);
1498 
1499  if( coef < cutcoefs[i] )
1500  {
1501  SCIP_Real QUAD(delta);
1502  SCIP_Real QUAD(tmp);
1503 
1504  SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
1505  SCIPquadprecProdQD(delta, delta, ub);
1506 
1507  SCIPquadprecSumQD(tmp, delta, *cutrhs);
1508  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1509  cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp),
1510  cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1511 
1512  *cutrhs = QUAD_TO_DBL(tmp);
1513 
1514  assert(!SCIPisNegative(scip, coef));
1515 
1516  ++(*nchgcoefs);
1517 
1518  if( SCIPisPositive(scip, coef) )
1519  {
1520  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1521  maxact = QUAD_TO_DBL(maxacttmp);
1522  cutcoefs[i] = coef;
1523  }
1524  else
1525  {
1526  --(*cutnnz);
1527  cutinds[i] = cutinds[*cutnnz];
1528  cutcoefs[i] = cutcoefs[*cutnnz];
1529  continue;
1530  }
1531  }
1532  }
1533  else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1534  break;
1535 
1536  ++i;
1537  }
1538 
1539  TERMINATE:
1540  SCIPfreeBufferArrayNull(scip, &absvals);
1541 
1542  return redundant;
1543 }
1544 
1545 /* =========================================== aggregation row =========================================== */
1546 
1547 
1548 /** create an empty aggregation row */
1550  SCIP* scip, /**< SCIP data structure */
1551  SCIP_AGGRROW** aggrrow /**< pointer to return aggregation row */
1552  )
1553 {
1554  int nvars;
1555  assert(scip != NULL);
1556  assert(aggrrow != NULL);
1557 
1558  SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
1559 
1560  nvars = SCIPgetNVars(scip);
1561 
1562  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)) );
1563  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->inds, nvars) );
1564 
1565  BMSclearMemoryArray((*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars));
1566 
1567  (*aggrrow)->local = FALSE;
1568  (*aggrrow)->nnz = 0;
1569  (*aggrrow)->rank = 0;
1570  QUAD_ASSIGN((*aggrrow)->rhs, 0.0);
1571  (*aggrrow)->rowsinds = NULL;
1572  (*aggrrow)->slacksign = NULL;
1573  (*aggrrow)->rowweights = NULL;
1574  (*aggrrow)->nrows = 0;
1575  (*aggrrow)->rowssize = 0;
1576 
1577  return SCIP_OKAY;
1578 }
1579 
1580 /** free a aggregation row */
1582  SCIP* scip, /**< SCIP data structure */
1583  SCIP_AGGRROW** aggrrow /**< pointer to aggregation row that should be freed */
1584  )
1585 {
1586  int nvars;
1587  assert(scip != NULL);
1588  assert(aggrrow != NULL);
1589 
1590  nvars = SCIPgetNVars(scip);
1591 
1592  SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->inds, nvars);
1593  SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)); /*lint !e647*/
1594  SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowsinds, (*aggrrow)->rowssize);
1595  SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->slacksign, (*aggrrow)->rowssize);
1596  SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowweights, (*aggrrow)->rowssize);
1597  SCIPfreeBlockMemory(scip, aggrrow);
1598 }
1599 
1600 /** output aggregation row to file stream */
1602  SCIP* scip, /**< SCIP data structure */
1603  SCIP_AGGRROW* aggrrow, /**< pointer to return aggregation row */
1604  FILE* file /**< output file (or NULL for standard output) */
1605  )
1606 {
1607  SCIP_VAR** vars;
1608  SCIP_MESSAGEHDLR* messagehdlr;
1609  int i;
1610 
1611  assert(scip != NULL);
1612  assert(aggrrow != NULL);
1613 
1614  vars = SCIPgetVars(scip);
1615  assert(vars != NULL);
1616 
1617  messagehdlr = SCIPgetMessagehdlr(scip);
1618  assert(messagehdlr);
1619 
1620  /* print coefficients */
1621  if( aggrrow->nnz == 0 )
1622  SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
1623 
1624  for( i = 0; i < aggrrow->nnz; ++i )
1625  {
1626  SCIP_Real QUAD(val);
1627 
1628  QUAD_ARRAY_LOAD(val, aggrrow->vals, aggrrow->inds[i]);
1629  assert(SCIPvarGetProbindex(vars[aggrrow->inds[i]]) == aggrrow->inds[i]);
1630  SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", QUAD_TO_DBL(val), SCIPvarGetName(vars[aggrrow->inds[i]]));
1631  }
1632 
1633  /* print right hand side */
1634  SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", QUAD_TO_DBL(aggrrow->rhs));
1635 }
1636 
1637 /** copy a aggregation row */
1639  SCIP* scip, /**< SCIP data structure */
1640  SCIP_AGGRROW** aggrrow, /**< pointer to return aggregation row */
1641  SCIP_AGGRROW* source /**< source aggregation row */
1642  )
1643 {
1644  int nvars;
1645 
1646  assert(scip != NULL);
1647  assert(aggrrow != NULL);
1648  assert(source != NULL);
1649 
1650  nvars = SCIPgetNVars(scip);
1651  SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
1652 
1653  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->vals, source->vals, QUAD_ARRAY_SIZE(nvars)) );
1654  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->inds, source->inds, nvars) );
1655  (*aggrrow)->nnz = source->nnz;
1656  QUAD_ASSIGN_Q((*aggrrow)->rhs, source->rhs);
1657 
1658  if( source->nrows > 0 )
1659  {
1660  assert(source->rowsinds != NULL);
1661  assert(source->slacksign != NULL);
1662  assert(source->rowweights != NULL);
1663 
1664  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowsinds, source->rowsinds, source->nrows) );
1665  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->slacksign, source->slacksign, source->nrows) );
1666  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowweights, source->rowweights, source->nrows) );
1667  }
1668  else
1669  {
1670  (*aggrrow)->rowsinds = NULL;
1671  (*aggrrow)->slacksign = NULL;
1672  (*aggrrow)->rowweights = NULL;
1673  }
1674 
1675  (*aggrrow)->nrows = source->nrows;
1676  (*aggrrow)->rowssize = source->nrows;
1677  (*aggrrow)->rank = source->rank;
1678  (*aggrrow)->local = source->local;
1679 
1680  return SCIP_OKAY;
1681 }
1682 
1683 /** add weighted row to aggregation row */
1685  SCIP* scip, /**< SCIP data structure */
1686  SCIP_AGGRROW* aggrrow, /**< aggregation row */
1687  SCIP_ROW* row, /**< row to add to aggregation row */
1688  SCIP_Real weight, /**< scale for adding given row to aggregation row */
1689  int sidetype /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
1690  )
1691 {
1692  int i;
1693 
1694  assert(row->lppos >= 0);
1695 
1696  /* update local flag */
1697  aggrrow->local = aggrrow->local || row->local;
1698 
1699  /* update rank */
1700  aggrrow->rank = MAX(row->rank, aggrrow->rank);
1701 
1702  {
1703  SCIP_Real sideval;
1704  SCIP_Bool uselhs;
1705 
1706  i = aggrrow->nrows++;
1707 
1708  if( aggrrow->nrows > aggrrow->rowssize )
1709  {
1710  int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
1711  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
1712  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
1713  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
1714  aggrrow->rowssize = newsize;
1715  }
1716  aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
1717  aggrrow->rowweights[i] = weight;
1718 
1719  if ( sidetype == -1 )
1720  {
1721  assert( ! SCIPisInfinity(scip, -row->lhs) );
1722  uselhs = TRUE;
1723  }
1724  else if ( sidetype == 1 )
1725  {
1726  assert( ! SCIPisInfinity(scip, row->rhs) );
1727  uselhs = FALSE;
1728  }
1729  else
1730  {
1731  /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
1732  * If possible, use the side that leads to a positive slack value in the summation.
1733  */
1734  if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
1735  uselhs = TRUE;
1736  else
1737  uselhs = FALSE;
1738  }
1739 
1740  if( uselhs )
1741  {
1742  aggrrow->slacksign[i] = -1;
1743  sideval = row->lhs - row->constant;
1744  if( row->integral )
1745  sideval = SCIPceil(scip, sideval); /* row is integral: round left hand side up */
1746  }
1747  else
1748  {
1749  aggrrow->slacksign[i] = +1;
1750  sideval = row->rhs - row->constant;
1751  if( row->integral )
1752  sideval = SCIPfloor(scip, sideval); /* row is integral: round right hand side up */
1753  }
1754 
1755  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, weight * sideval);
1756  }
1757 
1758  /* add up coefficients */
1759  SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
1760 
1761  return SCIP_OKAY;
1762 }
1763 
1764 /** Removes a given variable @p var from position @p pos the aggregation row and updates the right-hand side according
1765  * to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
1766  *
1767  * @note: The choice of global or local bounds depend on the validity (global or local) of the aggregation row.
1768  *
1769  * @note: The list of non-zero indices will be updated by swapping the last non-zero index to @p pos.
1770  */
1772  SCIP* scip, /**< SCIP data structure */
1773  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
1774  SCIP_VAR* var, /**< variable that should be removed */
1775  int pos, /**< position of the variable in the aggregation row */
1776  SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
1777  )
1778 {
1779  SCIP_Real QUAD(val);
1780  int v;
1781 
1782  assert(valid != NULL);
1783  assert(pos >= 0);
1784 
1785  v = aggrrow->inds[pos];
1786  assert(v == SCIPvarGetProbindex(var));
1787 
1788  QUAD_ARRAY_LOAD(val, aggrrow->vals, v);
1789 
1790  *valid = TRUE;
1791 
1792  /* adjust left and right hand sides with max contribution */
1793  if( QUAD_TO_DBL(val) < 0.0 )
1794  {
1795  SCIP_Real ub = aggrrow->local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1796  if( SCIPisInfinity(scip, ub) )
1797  QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
1798  else
1799  {
1800  SCIPquadprecProdQD(val, val, ub);
1801  SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
1802  }
1803  }
1804  else
1805  {
1806  SCIP_Real lb = aggrrow->local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1807  if( SCIPisInfinity(scip, -lb) )
1808  QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
1809  else
1810  {
1811  SCIPquadprecProdQD(val, val, lb);
1812  SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
1813  }
1814  }
1815 
1816  QUAD_ASSIGN(val, 0.0);
1817  QUAD_ARRAY_STORE(aggrrow->vals, v, val);
1818 
1819  /* remove non-zero entry */
1820  --(aggrrow->nnz);
1821  aggrrow->inds[pos] = aggrrow->inds[aggrrow->nnz];
1822 
1823  if( SCIPisInfinity(scip, QUAD_HI(aggrrow->rhs)) )
1824  *valid = FALSE;
1825 }
1826 
1827 /** add the objective function with right-hand side @p rhs and scaled by @p scale to the aggregation row */
1829  SCIP* scip, /**< SCIP data structure */
1830  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
1831  SCIP_Real rhs, /**< right-hand side of the artificial row */
1832  SCIP_Real scale /**< scalar */
1833  )
1834 {
1835  SCIP_VAR** vars;
1836  SCIP_Real QUAD(val);
1837  int nvars;
1838 
1839  assert(scip != NULL);
1840  assert(aggrrow != NULL);
1841 
1842  vars = SCIPgetVars(scip);
1843  nvars = SCIPgetNVars(scip);
1844 
1845  /* add all variables straight forward if the aggregation row is empty */
1846  if( aggrrow->nnz == 0 )
1847  {
1848  int i;
1849  for( i = 0; i < nvars; ++i )
1850  {
1851  assert(SCIPvarGetProbindex(vars[i]) == i);
1852 
1853  /* skip all variables with zero objective coefficient */
1854  if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
1855  continue;
1856 
1857  QUAD_ASSIGN(val, scale * SCIPvarGetObj(vars[i]));
1858  QUAD_ARRAY_STORE(aggrrow->vals, i, val);
1859  aggrrow->inds[aggrrow->nnz++] = i;
1860  }
1861 
1862  /* add right-hand side value */
1863  QUAD_ASSIGN(aggrrow->rhs, scale * rhs);
1864  }
1865  else
1866  {
1867  int i;
1868  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
1869  for( i = 0 ; i < nvars; ++i )
1870  {
1871  assert(SCIPvarGetProbindex(vars[i]) == i);
1872 
1873  /* skip all variables with zero objective coefficient */
1874  if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
1875  continue;
1876 
1877  QUAD_ARRAY_LOAD(val, aggrrow->vals, i); /* val = aggrrow->vals[i] */
1878 
1879  if( QUAD_HI(val) == 0.0 )
1880  aggrrow->inds[aggrrow->nnz++] = i;
1881 
1882  SCIPquadprecSumQD(val, val, scale * SCIPvarGetObj(vars[i]));
1883 
1884  /* the value must not be exactly zero due to sparsity pattern */
1885  QUAD_HI(val) = NONZERO(QUAD_HI(val));
1886  assert(QUAD_HI(val) != 0.0);
1887 
1888  QUAD_ARRAY_STORE(aggrrow->vals, i, val);
1889  }
1890 
1891  /* add right-hand side value */
1892  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, scale * rhs);
1893  }
1894 
1895  return SCIP_OKAY;
1896 }
1897 
1898 /** add weighted constraint to the aggregation row */
1900  SCIP* scip, /**< SCIP data structure */
1901  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
1902  int* inds, /**< variable problem indices in constraint to add to the aggregation row */
1903  SCIP_Real* vals, /**< values of constraint to add to the aggregation row */
1904  int len, /**< length of constraint to add to the aggregation row */
1905  SCIP_Real rhs, /**< right hand side of constraint to add to the aggregation row */
1906  SCIP_Real weight, /**< (positive) scale for adding given constraint to the aggregation row */
1907  int rank, /**< rank to use for given constraint */
1908  SCIP_Bool local /**< is constraint only valid locally */
1909  )
1910 {
1911  int i;
1912 
1913  assert(weight >= 0.0);
1914  assert(!SCIPisInfinity(scip, REALABS(weight * rhs)));
1915 
1916  /* update local flag */
1917  aggrrow->local = aggrrow->local || local;
1918 
1919  /* update rank */
1920  aggrrow->rank = MAX(rank, aggrrow->rank);
1921 
1922  /* add right hand side value */
1923  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, weight * rhs);
1924 
1925  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
1926  for( i = 0 ; i < len; ++i )
1927  {
1928  SCIP_Real QUAD(val);
1929  int probindex = inds[i];
1930 
1931  QUAD_ARRAY_LOAD(val, aggrrow->vals, probindex); /* val = aggrrow->vals[probindex] */
1932 
1933  if( QUAD_HI(val) == 0.0 )
1934  aggrrow->inds[aggrrow->nnz++] = probindex;
1935 
1936  SCIPquadprecSumQD(val, val, vals[i] * weight);
1937 
1938  /* the value must not be exactly zero due to sparsity pattern */
1939  QUAD_HI(val) = NONZERO(QUAD_HI(val));
1940  assert(QUAD_HI(val) != 0.0);
1941 
1942  QUAD_ARRAY_STORE(aggrrow->vals, probindex, val);
1943  }
1944 
1945  return SCIP_OKAY;
1946 }
1947 
1948 /** clear all entries int the aggregation row but don't free memory */
1950  SCIP_AGGRROW* aggrrow /**< the aggregation row */
1951  )
1952 {
1953  int i;
1954  SCIP_Real QUAD(tmp);
1955 
1956  QUAD_ASSIGN(tmp, 0.0);
1957 
1958  for( i = 0; i < aggrrow->nnz; ++i )
1959  {
1960  QUAD_ARRAY_STORE(aggrrow->vals, aggrrow->inds[i], tmp);
1961  }
1962 
1963  aggrrow->nnz = 0;
1964  aggrrow->nrows = 0;
1965  aggrrow->rank = 0;
1966  QUAD_ASSIGN(aggrrow->rhs, 0.0);
1967  aggrrow->local = FALSE;
1968 }
1969 
1970 /** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
1971  *
1972  * @return the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
1973  */
1975  SCIP* scip, /**< SCIP data structure */
1976  SCIP_AGGRROW* aggrrow /**< the aggregation row */
1977  )
1978 {
1979  return calcEfficacyNormQuad(scip, aggrrow->vals, aggrrow->inds, aggrrow->nnz);
1980 }
1981 
1982 /** Adds one row to the aggregation row. Differs from SCIPaggrRowAddRow() by providing some additional
1983  * parameters required for SCIPaggrRowSumRows()
1984  */
1985 static
1987  SCIP* scip, /**< SCIP data structure */
1988  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
1989  SCIP_ROW* row, /**< the row to add */
1990  SCIP_Real weight, /**< weight of row to add */
1991  SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
1992  SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
1993  int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
1994  int maxaggrlen, /**< maximal length of aggregation row */
1995  SCIP_Bool* rowtoolong /**< is the aggregated row too long */
1996  )
1997 {
1998  SCIP_Real sideval;
1999  SCIP_Bool uselhs;
2000  int i;
2001 
2002  assert( rowtoolong != NULL );
2003  *rowtoolong = FALSE;
2004 
2005  if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
2006  {
2007  return SCIP_OKAY;
2008  }
2009 
2010  if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
2011  {
2013 
2014  if( stat == SCIP_BASESTAT_LOWER )
2015  {
2016  assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
2017  uselhs = TRUE;
2018  }
2019  else if( stat == SCIP_BASESTAT_UPPER )
2020  {
2021  assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
2022  uselhs = FALSE;
2023  }
2024  else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
2025  uselhs = TRUE;
2026  else
2027  uselhs = FALSE;
2028  }
2029  else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
2030  uselhs = TRUE;
2031  else
2032  uselhs = FALSE;
2033 
2034  if( uselhs )
2035  {
2036  assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
2037 
2038  if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
2039  return SCIP_OKAY;
2040 
2041  sideval = row->lhs - row->constant;
2042  /* row is integral? round left hand side up */
2043  if( row->integral )
2044  sideval = SCIPceil(scip, sideval);
2045  }
2046  else
2047  {
2048  assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
2049 
2050  if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
2051  return SCIP_OKAY;
2052 
2053  sideval = row->rhs - row->constant;
2054  /* row is integral? round right hand side down */
2055  if( row->integral )
2056  sideval = SCIPfloor(scip, sideval);
2057  }
2058 
2059  /* add right hand side, update rank and local flag */
2060  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, sideval * weight);
2061  aggrrow->rank = MAX(aggrrow->rank, row->rank);
2062  aggrrow->local = aggrrow->local || row->local;
2063 
2064  /* ensure the array for storing the row information is large enough */
2065  i = aggrrow->nrows++;
2066  if( aggrrow->nrows > aggrrow->rowssize )
2067  {
2068  int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
2069  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
2070  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
2071  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
2072  aggrrow->rowssize = newsize;
2073  }
2074 
2075  /* add information of addditional row */
2076  aggrrow->rowsinds[i] = row->lppos;
2077  aggrrow->rowweights[i] = weight;
2078  aggrrow->slacksign[i] = uselhs ? -1 : 1;
2079 
2080  /* add up coefficients */
2081  SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
2082 
2083  /* check if row is too long now */
2084  if( aggrrow->nnz > maxaggrlen )
2085  *rowtoolong = TRUE;
2086 
2087  return SCIP_OKAY;
2088 }
2089 
2090 /** aggregate rows using the given weights; the current content of the aggregation
2091  * row, \p aggrrow, gets overwritten
2092  */
2094  SCIP* scip, /**< SCIP data structure */
2095  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2096  SCIP_Real* weights, /**< row weights in row summation */
2097  int* rowinds, /**< array to store indices of non-zero entries of the weights array, or NULL */
2098  int nrowinds, /**< number of non-zero entries in weights array, -1 if rowinds is NULL */
2099  SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
2100  SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
2101  int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
2102  int maxaggrlen, /**< maximal length of aggregation row */
2103  SCIP_Bool* valid /**< is the aggregation valid */
2104  )
2105 {
2106  SCIP_ROW** rows;
2107  SCIP_VAR** vars;
2108  int nrows;
2109  int nvars;
2110  int k;
2111  SCIP_Bool rowtoolong;
2112 
2113  assert( scip != NULL );
2114  assert( aggrrow != NULL );
2115  assert( valid != NULL );
2116 
2117  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2118  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
2119 
2120  SCIPaggrRowClear(aggrrow);
2121  *valid = FALSE;
2122 
2123  if( rowinds != NULL && nrowinds > -1 )
2124  {
2125  for( k = 0; k < nrowinds; ++k )
2126  {
2127  SCIP_CALL( addOneRow(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
2128 
2129  if( rowtoolong )
2130  return SCIP_OKAY;
2131  }
2132  }
2133  else
2134  {
2135  for( k = 0; k < nrows; ++k )
2136  {
2137  SCIP_CALL( addOneRow(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
2138 
2139  if( rowtoolong )
2140  return SCIP_OKAY;
2141  }
2142  }
2143 
2144  SCIPaggrRowRemoveZeros(scip, aggrrow, valid);
2145 
2146  return SCIP_OKAY;
2147 }
2148 
2149 /** checks for cut redundancy and performs activity based coefficient tightening;
2150  * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
2151  * to remove small coefficients (relative to the maximum absolute coefficient)
2152  */
2153 static
2155  SCIP* scip, /**< SCIP data structure */
2156  SCIP_Bool cutislocal, /**< is the cut a local cut */
2157  int* cutinds, /**< variable problem indices of non-zeros in cut */
2158  SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
2159  int* nnz, /**< number non-zeros coefficients of cut */
2160  SCIP_Real* cutrhs, /**< right hand side of cut */
2161  SCIP_Bool* success /**< pointer to return whether post-processing was succesful or cut is redundant */
2162  )
2163 {
2164  int i;
2165  SCIP_Bool redundant;
2166  SCIP_Real maxcoef;
2167  SCIP_Real minallowedcoef;
2168  SCIP_Real QUAD(rhs);
2169 
2170  assert(scip != NULL);
2171  assert(cutinds != NULL);
2172  assert(cutcoefs != NULL);
2173  assert(cutrhs != NULL);
2174  assert(success != NULL);
2175 
2176  *success = FALSE;
2177 
2178  QUAD_ASSIGN(rhs, *cutrhs);
2179 
2180  if( removeZeros(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz) )
2181  {
2182  /* right hand side was changed to infinity -> cut is redundant */
2183  return SCIP_OKAY;
2184  }
2185 
2186  if( *nnz == 0 )
2187  return SCIP_OKAY;
2188 
2189  SCIP_CALL( cutTightenCoefs(scip, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz, &redundant) );
2190 
2191  if( redundant )
2192  {
2193  /* cut is redundant */
2194  return SCIP_OKAY;
2195  }
2196 
2197  maxcoef = 0.0;
2198  for( i = 0; i < *nnz; ++i )
2199  {
2200  SCIP_Real absval = REALABS(cutcoefs[cutinds[i]]);
2201  maxcoef = MAX(absval, maxcoef);
2202  }
2203 
2204  maxcoef /= scip->set->sepa_maxcoefratio;
2205  minallowedcoef = SCIPsumepsilon(scip);
2206  minallowedcoef = MAX(minallowedcoef, maxcoef);
2207 
2208  *success = ! removeZeros(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz);
2209  *cutrhs = QUAD_TO_DBL(rhs);
2210 
2211  return SCIP_OKAY;
2212 }
2213 
2214 
2215 /** checks for cut redundancy and performs activity based coefficient tightening;
2216  * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
2217  * to remove small coefficients (relative to the maximum absolute coefficient).
2218  * The cutcoefs must be a quad precision array, i.e. allocated with size
2219  * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
2220  * macros.
2221  */
2222 static
2224  SCIP* scip, /**< SCIP data structure */
2225  SCIP_Bool cutislocal, /**< is the cut a local cut */
2226  int* cutinds, /**< variable problem indices of non-zeros in cut */
2227  SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
2228  int* nnz, /**< number non-zeros coefficients of cut */
2229  QUAD(SCIP_Real* cutrhs), /**< right hand side of cut */
2230  SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
2231  )
2232 {
2233  int i;
2234  SCIP_Bool redundant;
2235  SCIP_Real maxcoef;
2236  SCIP_Real minallowedcoef;
2237 
2238  assert(scip != NULL);
2239  assert(cutinds != NULL);
2240  assert(cutcoefs != NULL);
2241  assert(QUAD_HI(cutrhs) != NULL);
2242  assert(success != NULL);
2243 
2244  *success = FALSE;
2245 
2246  if( removeZerosQuad(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz) )
2247  {
2248  /* right hand side was changed to infinity -> cut is redundant */
2249  return SCIP_OKAY;
2250  }
2251 
2252  if( *nnz == 0 )
2253  return SCIP_OKAY;
2254 
2255  SCIP_CALL( cutTightenCoefsQuad(scip, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz, &redundant) );
2256  if( redundant )
2257  {
2258  /* cut is redundant */
2259  return SCIP_OKAY;
2260  }
2261 
2262  maxcoef = 0.0;
2263  for( i = 0; i < *nnz; ++i )
2264  {
2265  SCIP_Real abscoef;
2266  SCIP_Real QUAD(coef);
2267  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]); /* coef = cutcoefs[cutinds[i]] */
2268  abscoef = REALABS(QUAD_TO_DBL(coef));
2269  maxcoef = MAX(abscoef, maxcoef);
2270  }
2271 
2272  maxcoef /= scip->set->sepa_maxcoefratio;
2273  minallowedcoef = SCIPsumepsilon(scip);
2274  minallowedcoef = MAX(minallowedcoef, maxcoef);
2275 
2276  *success = ! removeZerosQuad(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz);
2277 
2278  return SCIP_OKAY;
2279 }
2280 
2281 /** removes almost zero entries from the aggregation row. */
2283  SCIP* scip, /**< SCIP datastructure */
2284  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2285  SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
2286  )
2287 {
2288  assert(aggrrow != NULL);
2289  assert(valid != NULL);
2290 
2291  *valid = ! removeZerosQuad(scip, SCIPsumepsilon(scip), aggrrow->local, aggrrow->vals, QUAD(&aggrrow->rhs), aggrrow->inds, &aggrrow->nnz);
2292 }
2293 
2294 /** get number of aggregated rows */
2296  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2297  )
2298 {
2299  assert(aggrrow != NULL);
2300 
2301  return aggrrow->nrows;
2302 }
2303 
2304 /** get array with lp positions of rows used in aggregation */
2306  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2307  )
2308 {
2309  assert(aggrrow != NULL);
2310  assert(aggrrow->rowsinds != NULL || aggrrow->nrows == 0);
2311 
2312  return aggrrow->rowsinds;
2313 }
2314 
2315 /** get array with weights of aggregated rows */
2317  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2318  )
2319 {
2320  assert(aggrrow != NULL);
2321  assert(aggrrow->rowweights != NULL || aggrrow->nrows == 0);
2322 
2323  return aggrrow->rowweights;
2324 }
2325 
2326 /** checks whether a given row has been added to the aggregation row */
2328  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2329  SCIP_ROW* row /**< row for which it is checked whether it has been added to the aggregation */
2330  )
2331 {
2332  int i;
2333  int rowind;
2334 
2335  assert(aggrrow != NULL);
2336  assert(row != NULL);
2337 
2338  rowind = SCIProwGetLPPos(row);
2339 
2340  for( i = 0; i < aggrrow->nrows; ++i )
2341  {
2342  if( aggrrow->rowsinds[i] == rowind )
2343  return TRUE;
2344  }
2345 
2346  return FALSE;
2347 }
2348 
2349 /** gets the array of corresponding variable problem indices for each non-zero in the aggregation row */
2351  SCIP_AGGRROW* aggrrow /**< aggregation row */
2352  )
2353 {
2354  assert(aggrrow != NULL);
2355 
2356  return aggrrow->inds;
2357 }
2358 
2359 /** gets the number of non-zeros in the aggregation row */
2361  SCIP_AGGRROW* aggrrow /**< aggregation row */
2362  )
2363 {
2364  assert(aggrrow != NULL);
2365 
2366  return aggrrow->nnz;
2367 }
2368 
2369 /** gets the rank of the aggregation row */
2371  SCIP_AGGRROW* aggrrow /**< aggregation row */
2372  )
2373 {
2374  assert(aggrrow != NULL);
2375 
2376  return aggrrow->rank;
2377 }
2378 
2379 /** checks if the aggregation row is only valid locally */
2381  SCIP_AGGRROW* aggrrow /**< aggregation row */
2382  )
2383 {
2384  assert(aggrrow != NULL);
2385 
2386  return aggrrow->local;
2387 }
2388 
2389 /** gets the right hand side of the aggregation row */
2391  SCIP_AGGRROW* aggrrow /**< aggregation row */
2392  )
2393 {
2394  assert(aggrrow != NULL);
2395 
2396  return QUAD_TO_DBL(aggrrow->rhs);
2397 }
2398 
2399 /** filters the given array of cuts to enforce a maximum parallelism constraints
2400  * for the given cut; moves filtered cuts to the end of the array and returns number of selected cuts */
2401 static
2403  SCIP_ROW* cut, /**< cut to filter orthogonality with */
2404  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
2405  SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
2406  int ncuts, /**< number of cuts in given array */
2407  SCIP_Real goodscore, /**< threshold for the score to be considered a good cut */
2408  SCIP_Real goodmaxparall, /**< maximal parallelism for good cuts */
2409  SCIP_Real maxparall /**< maximal parallelism for all cuts that are not good */
2410  )
2411 {
2412  int i;
2413 
2414  assert( cut != NULL );
2415  assert( ncuts == 0 || cuts != NULL );
2416  assert( ncuts == 0 || scores != NULL );
2417 
2418  for( i = ncuts - 1; i >= 0; --i )
2419  {
2420  SCIP_Real thisparall;
2421  SCIP_Real thismaxparall;
2422 
2423  thisparall = SCIProwGetParallelism(cut, cuts[i], 'e');
2424  thismaxparall = scores[i] >= goodscore ? goodmaxparall : maxparall;
2425 
2426  if( thisparall > thismaxparall )
2427  {
2428  --ncuts;
2429  SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
2430  SCIPswapReals(&scores[i], &scores[ncuts]);
2431  }
2432  }
2433 
2434  return ncuts;
2435 }
2436 
2437 /** move the cut with the highest score to the first position in the array; there must be at least one cut */
2438 static
2440  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
2441  SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
2442  int ncuts /**< number of cuts in given array */
2443  )
2444 {
2445  int i;
2446  int bestpos;
2447  SCIP_Real bestscore;
2448 
2449  assert(ncuts > 0);
2450  assert(cuts != NULL);
2451  assert(scores != NULL);
2452 
2453  bestscore = scores[0];
2454  bestpos = 0;
2455 
2456  for( i = 1; i < ncuts; ++i )
2457  {
2458  if( scores[i] > bestscore )
2459  {
2460  bestpos = i;
2461  bestscore = scores[i];
2462  }
2463  }
2464 
2465  SCIPswapPointers((void**) &cuts[bestpos], (void**) &cuts[0]);
2466  SCIPswapReals(&scores[bestpos], &scores[0]);
2467 }
2468 
2469 /** perform a cut selection algorithm for the given array of cuts; the array is partitioned
2470  * so that the selected cuts come first and the remaining ones are at the end of the array
2471  */
2473  SCIP* scip, /**< SCIP data structure */
2474  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
2475  SCIP_RANDNUMGEN* randnumgen, /**< random number generator for tie-breaking, or NULL */
2476  SCIP_Real goodscorefac, /**< factor of best score among the given cuts to consider a cut good
2477  * and filter with less strict settings of the maximum parallelism */
2478  SCIP_Real badscorefac, /**< factor of best score among the given cuts to consider a cut bad
2479  * and discard it regardless of its parallelism to other cuts */
2480  SCIP_Real goodmaxparall, /**< maximum parallelism for good cuts */
2481  SCIP_Real maxparall, /**< maximum parallelism for non-good cuts */
2482  SCIP_Real dircutoffdistweight,/**< weight of directed cutoff distance in score calculation */
2483  SCIP_Real efficacyweight, /**< weight of efficacy (shortest cutoff distance) in score calculation */
2484  SCIP_Real objparalweight, /**< weight of objective parallelism in score calculation */
2485  SCIP_Real intsupportweight, /**< weight of integral support in score calculation */
2486  int ncuts, /**< number of cuts in given array */
2487  int nforcedcuts, /**< number of forced cuts at start of given array */
2488  int maxselectedcuts, /**< maximal number of cuts to select */
2489  int* nselectedcuts /**< pointer to return number of selected cuts */
2490  )
2491 {
2492  int i;
2493  SCIP_Real* scores;
2494  SCIP_Real goodscore;
2495  SCIP_Real badscore;
2496  SCIP_Real efficacyfac;
2497  SCIP_SOL* sol;
2498 
2499  assert( nselectedcuts != NULL );
2500 
2501  /* if all cuts are forced cuts, no selection is required */
2502  if( nforcedcuts >= MIN(ncuts, maxselectedcuts) )
2503  {
2504  *nselectedcuts = nforcedcuts;
2505  return SCIP_OKAY;
2506  }
2507  *nselectedcuts = 0;
2508 
2509  SCIP_CALL( SCIPallocBufferArray(scip, &scores, ncuts) );
2510 
2511  sol = SCIPgetBestSol(scip);
2512 
2513  efficacyfac = efficacyweight;
2514 
2515  goodscore = 0.0;
2516 
2517  /* if there is an incumbent and the factor is not 0.0, compute directed cutoff distances for the incumbent */
2518  if( sol != NULL && dircutoffdistweight > 0.0 )
2519  {
2520  for( i = 0; i < ncuts; ++i )
2521  {
2522  SCIP_Real objparallelism;
2523  SCIP_Real intsupport;
2524  SCIP_Real efficacy;
2525 
2526  intsupport = intsupportweight != 0.0 ?
2527  intsupportweight * SCIProwGetNumIntCols(cuts[i], scip->set) / (SCIP_Real) SCIProwGetNNonz(cuts[i]) :
2528  0.0;
2529 
2530  objparallelism = objparalweight != 0.0 ? objparalweight * SCIProwGetObjParallelism(cuts[i], scip->set, scip->lp) : 0.0;
2531 
2532  efficacy = SCIProwGetLPEfficacy(cuts[i], scip->set, scip->stat, scip->lp);
2533 
2534  if( SCIProwIsLocal(cuts[i]) )
2535  {
2536  scores[i] = dircutoffdistweight * efficacy;
2537  }
2538  else
2539  {
2540  scores[i] = SCIProwGetLPSolCutoffDistance(cuts[i], scip->set, scip->stat, sol, scip->lp);
2541  scores[i] = dircutoffdistweight * MAX(scores[i], efficacy);
2542  }
2543 
2544  efficacy *= efficacyfac;
2545  scores[i] += objparallelism + intsupport + efficacy;
2546 
2547  /* add small term to prefer global pool cuts */
2548  scores[i] += SCIProwIsInGlobalCutpool(cuts[i]) ? 1e-4 : 0.0;
2549 
2550  if( randnumgen != NULL )
2551  {
2552  scores[i] += SCIPrandomGetReal(randnumgen, 0.0, 1e-6);
2553  }
2554 
2555  goodscore = MAX(goodscore, scores[i]);
2556  }
2557  }
2558  else
2559  {
2560  efficacyfac += objparalweight;
2561  for( i = 0; i < ncuts; ++i )
2562  {
2563  SCIP_Real objparallelism;
2564  SCIP_Real intsupport;
2565  SCIP_Real efficacy;
2566 
2567  intsupport = intsupportweight > 0.0 ?
2568  intsupportweight * SCIProwGetNumIntCols(cuts[i], scip->set) / (SCIP_Real) SCIProwGetNNonz(cuts[i]) :
2569  0.0;
2570 
2571  objparallelism = objparalweight > 0.0 ? objparalweight * SCIProwGetObjParallelism(cuts[i], scip->set, scip->lp) : 0.0;
2572 
2573  efficacy = efficacyfac > 0.0 ?
2574  efficacyfac * SCIProwGetLPEfficacy(cuts[i], scip->set, scip->stat, scip->lp) :
2575  0.0;
2576 
2577  scores[i] = objparallelism + intsupport + efficacy;
2578 
2579  /* add small term to prefer global pool cuts */
2580  scores[i] += SCIProwIsInGlobalCutpool(cuts[i]) ? 1e-4 : 0.0;
2581 
2582  if( randnumgen != NULL )
2583  {
2584  scores[i] += SCIPrandomGetReal(randnumgen, 0.0, 1e-6);
2585  }
2586 
2587  goodscore = MAX(goodscore, scores[i]);
2588  }
2589  }
2590 
2591  /* compute values for filtering cuts */
2592  badscore = goodscore * badscorefac;
2593  goodscore *= goodscorefac;
2594 
2595  /* perform cut selection algorithm for the cuts */
2596  {
2597  int nnonforcedcuts;
2598  SCIP_ROW** nonforcedcuts;
2599  SCIP_Real* nonforcedscores;
2600 
2601  /* adjust pointers to the beginning of the non-forced cuts */
2602  nnonforcedcuts = ncuts - nforcedcuts;
2603  nonforcedcuts = cuts + nforcedcuts;
2604  nonforcedscores = scores + nforcedcuts;
2605 
2606  /* select the forced cuts first */
2607  *nselectedcuts = nforcedcuts;
2608  for( i = 0; i < nforcedcuts && nnonforcedcuts > 0; ++i )
2609  {
2610  nnonforcedcuts = filterWithParallelism(cuts[i], nonforcedcuts, nonforcedscores, nnonforcedcuts, goodscore, goodmaxparall, maxparall);
2611  }
2612 
2613  /* if the maximal number of cuts was exceeded after selecting the forced cuts, we can stop here */
2614  if( *nselectedcuts >= maxselectedcuts )
2615  goto TERMINATE;
2616 
2617  /* now greedily select the remaining cuts */
2618  while( nnonforcedcuts > 0 )
2619  {
2620  SCIP_ROW* selectedcut;
2621 
2622  selectBestCut(nonforcedcuts, nonforcedscores, nnonforcedcuts);
2623  selectedcut = nonforcedcuts[0];
2624 
2625  /* if the best cut of the remaining cuts is considered bad, we discard it and all remaining cuts */
2626  if( nonforcedscores[0] < badscore )
2627  goto TERMINATE;
2628 
2629  ++(*nselectedcuts);
2630 
2631  /* if the maximal number of cuts was selected, we can stop here */
2632  if( *nselectedcuts == maxselectedcuts )
2633  goto TERMINATE;
2634 
2635  /* move the pointers to the next position and filter the remaining cuts to enforce the maximum parallelism constraint */
2636  ++nonforcedcuts;
2637  ++nonforcedscores;
2638  --nnonforcedcuts;
2639 
2640  nnonforcedcuts = filterWithParallelism(selectedcut, nonforcedcuts, nonforcedscores, nnonforcedcuts, goodscore, goodmaxparall, maxparall);
2641  }
2642  }
2643 
2644  TERMINATE:
2645  SCIPfreeBufferArray(scip, &scores);
2646 
2647  return SCIP_OKAY;
2648 }
2649 
2650 /* =========================================== c-MIR =========================================== */
2651 
2652 #define MAXCMIRSCALE 1e+6 /**< maximal scaling (scale/(1-f0)) allowed in c-MIR calculations */
2653 
2654 /** finds the best lower bound of the variable to use for MIR transformation */
2655 static
2657  SCIP* scip, /**< SCIP data structure */
2658  SCIP_VAR* var, /**< problem variable */
2659  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2660  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
2661  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2662  SCIP_Real* bestlb, /**< pointer to store best bound value */
2663  int* bestlbtype /**< pointer to store best bound type */
2664  )
2665 {
2666  assert(bestlb != NULL);
2667  assert(bestlbtype != NULL);
2668 
2669  *bestlb = SCIPvarGetLbGlobal(var);
2670  *bestlbtype = -1;
2671 
2672  if( allowlocal )
2673  {
2674  SCIP_Real loclb;
2675 
2676  loclb = SCIPvarGetLbLocal(var);
2677  if( SCIPisGT(scip, loclb, *bestlb) )
2678  {
2679  *bestlb = loclb;
2680  *bestlbtype = -2;
2681  }
2682  }
2683 
2684  if( usevbds && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
2685  {
2686  SCIP_Real bestvlb;
2687  int bestvlbidx;
2688 
2689  SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
2690  if( bestvlbidx >= 0
2691  && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
2692  {
2693  SCIP_VAR** vlbvars;
2694 
2695  /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2696  /**@todo this check is not needed for continuous variables; but allowing all but binary variables
2697  * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
2698  */
2699  vlbvars = SCIPvarGetVlbVars(var);
2700  assert(vlbvars != NULL);
2701  if( SCIPvarGetProbindex(vlbvars[bestvlbidx]) < SCIPvarGetProbindex(var) )
2702  {
2703  *bestlb = bestvlb;
2704  *bestlbtype = bestvlbidx;
2705  }
2706  }
2707  }
2708 
2709  return SCIP_OKAY;
2710 }
2711 
2712 /** finds the best upper bound of the variable to use for MIR transformation */
2713 static
2715  SCIP* scip, /**< SCIP data structure */
2716  SCIP_VAR* var, /**< problem variable */
2717  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2718  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
2719  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2720  SCIP_Real* bestub, /**< pointer to store best bound value */
2721  int* bestubtype /**< pointer to store best bound type */
2722  )
2723 {
2724  assert(bestub != NULL);
2725  assert(bestubtype != NULL);
2726 
2727  *bestub = SCIPvarGetUbGlobal(var);
2728  *bestubtype = -1;
2729 
2730  if( allowlocal )
2731  {
2732  SCIP_Real locub;
2733 
2734  locub = SCIPvarGetUbLocal(var);
2735  if( SCIPisLT(scip, locub, *bestub) )
2736  {
2737  *bestub = locub;
2738  *bestubtype = -2;
2739  }
2740  }
2741 
2742  if( usevbds && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
2743  {
2744  SCIP_Real bestvub;
2745  int bestvubidx;
2746 
2747  SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
2748  if( bestvubidx >= 0
2749  && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
2750  {
2751  SCIP_VAR** vubvars;
2752 
2753  /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2754  /**@todo this check is not needed for continuous variables; but allowing all but binary variables
2755  * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
2756  */
2757  vubvars = SCIPvarGetVubVars(var);
2758  assert(vubvars != NULL);
2759  if( SCIPvarGetProbindex(vubvars[bestvubidx]) < SCIPvarGetProbindex(var) )
2760  {
2761  *bestub = bestvub;
2762  *bestubtype = bestvubidx;
2763  }
2764  }
2765  }
2766 
2767  return SCIP_OKAY;
2768 }
2769 
2770 /** determine the best bounds with respect to the given solution for complementing the given variable */
2771 static
2773  SCIP* scip, /**< SCIP data structure */
2774  SCIP_VAR* var, /**< variable to determine best bound for */
2775  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2776  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
2777  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
2778  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2779  SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
2780  SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
2781  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
2782  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
2783  * NULL for using closest bound for all variables */
2784  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
2785  * NULL for using closest bound for all variables */
2786  SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
2787  SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
2788  int* bestlbtype, /**< pointer to store type of best lower bound of variable */
2789  int* bestubtype, /**< pointer to store type of best upper bound of variable */
2790  SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
2791  SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
2792  )
2793 {
2794  int v;
2795 
2796  v = SCIPvarGetProbindex(var);
2797 
2798  /* check if the user specified a bound to be used */
2799  if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
2800  {
2801  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || ( boundsfortrans[v] == -2 || boundsfortrans[v] == -1 ));
2802 
2803  /* user has explicitly specified a bound to be used */
2804  if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
2805  {
2806  /* user wants to use lower bound */
2807  *bestlbtype = boundsfortrans[v];
2808  if( *bestlbtype == -1 )
2809  *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
2810  else if( *bestlbtype == -2 )
2811  *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
2812  else
2813  {
2814  SCIP_VAR** vlbvars;
2815  SCIP_Real* vlbcoefs;
2816  SCIP_Real* vlbconsts;
2817  int k;
2818 
2819  assert(!ignoresol);
2820 
2821  /* use the given variable lower bound */
2822  vlbvars = SCIPvarGetVlbVars(var);
2823  vlbcoefs = SCIPvarGetVlbCoefs(var);
2824  vlbconsts = SCIPvarGetVlbConstants(var);
2825  k = boundsfortrans[v];
2826  assert(k >= 0 && k < SCIPvarGetNVlbs(var));
2827  assert(vlbvars != NULL);
2828  assert(vlbcoefs != NULL);
2829  assert(vlbconsts != NULL);
2830 
2831  *bestlb = vlbcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[k]) : SCIPgetSolVal(scip, sol, vlbvars[k])) + vlbconsts[k];
2832  }
2833 
2834  assert(!SCIPisInfinity(scip, - *bestlb));
2835  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2836 
2837  /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
2838  SCIP_CALL( findBestUb(scip, var, sol, usevbds && fixintegralrhs, allowlocal && fixintegralrhs, bestub, bestubtype) );
2839  }
2840  else
2841  {
2842  assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
2843 
2844  /* user wants to use upper bound */
2845  *bestubtype = boundsfortrans[v];
2846  if( *bestubtype == -1 )
2847  *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
2848  else if( *bestubtype == -2 )
2849  *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
2850  else
2851  {
2852  SCIP_VAR** vubvars;
2853  SCIP_Real* vubcoefs;
2854  SCIP_Real* vubconsts;
2855  int k;
2856 
2857  assert(!ignoresol);
2858 
2859  /* use the given variable upper bound */
2860  vubvars = SCIPvarGetVubVars(var);
2861  vubcoefs = SCIPvarGetVubCoefs(var);
2862  vubconsts = SCIPvarGetVubConstants(var);
2863  k = boundsfortrans[v];
2864  assert(k >= 0 && k < SCIPvarGetNVubs(var));
2865  assert(vubvars != NULL);
2866  assert(vubcoefs != NULL);
2867  assert(vubconsts != NULL);
2868 
2869  /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2870  *bestub = vubcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vubvars[k]) : SCIPgetSolVal(scip, sol, vubvars[k])) + vubconsts[k];
2871  }
2872 
2873  assert(!SCIPisInfinity(scip, *bestub));
2874  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2875 
2876  /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
2877  SCIP_CALL( findBestLb(scip, var, sol, usevbds && fixintegralrhs, allowlocal && fixintegralrhs, bestlb, bestlbtype) );
2878  }
2879  }
2880  else
2881  {
2882  SCIP_Real varsol;
2883 
2884  /* bound selection should be done automatically */
2885 
2886  /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
2887  SCIP_CALL( findBestLb(scip, var, sol, usevbds, allowlocal, bestlb, bestlbtype) );
2888 
2889  /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
2890  SCIP_CALL( findBestUb(scip, var, sol, usevbds, allowlocal, bestub, bestubtype) );
2891 
2892  /* check, if variable is free variable */
2893  if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
2894  {
2895  /* we found a free variable in the row with non-zero coefficient
2896  * -> MIR row can't be transformed in standard form
2897  */
2898  *freevariable = TRUE;
2899  return SCIP_OKAY;
2900  }
2901 
2902  if( !ignoresol )
2903  {
2904  /* select transformation bound */
2905  varsol = (sol == NULL ? SCIPvarGetLPSol(var) : SCIPgetSolVal(scip, sol, var));
2906 
2907  if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
2908  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2909  else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
2910  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2911  else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2912  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2913  else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2914  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2915  else if( *bestlbtype == -1 ) /* prefer global standard bounds */
2916  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2917  else if( *bestubtype == -1 ) /* prefer global standard bounds */
2918  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2919  else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
2920  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2921  else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
2922  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2923  else /* no decision yet? just use lower bound */
2924  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2925  }
2926  else
2927  {
2928  SCIP_Real glbub = SCIPvarGetUbGlobal(var);
2929  SCIP_Real glblb = SCIPvarGetLbGlobal(var);
2930  SCIP_Real distlb = REALABS(glblb - *bestlb);
2931  SCIP_Real distub = REALABS(glbub - *bestub);
2932 
2933  assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
2934 
2935  if( SCIPisInfinity(scip, - *bestlb) )
2936  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2937  else if( !SCIPisNegative(scip, *bestlb) )
2938  {
2939  if( SCIPisInfinity(scip, *bestub) )
2940  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2941  else if( SCIPisZero(scip, glblb) )
2942  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2943  else if( SCIPisLE(scip, distlb, distub) )
2944  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2945  else
2946  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2947  }
2948  else
2949  {
2950  assert(!SCIPisInfinity(scip, - *bestlb));
2951  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2952  }
2953  }
2954  }
2955 
2956  return SCIP_OKAY;
2957 }
2958 
2959 /** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
2960  * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
2961  *
2962  * Transform variables (lb or ub):
2963  * \f[
2964  * \begin{array}{llll}
2965  * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation}\\
2966  * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation}
2967  * \end{array}
2968  * \f]
2969  * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
2970  *
2971  * Transform variables (vlb or vub):
2972  * \f[
2973  * \begin{array}{llll}
2974  * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
2975  * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
2976  * \end{array}
2977  * \f]
2978  * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
2979  * \f[
2980  * \begin{array}{ll}
2981  * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
2982  * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
2983  * \end{array}
2984  * \f]
2985  */
2986 static
2988  SCIP* scip, /**< SCIP data structure */
2989  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2990  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
2991  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
2992  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2993  SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
2994  SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
2995  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
2996  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
2997  * NULL for using closest bound for all variables */
2998  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
2999  * NULL for using closest bound for all variables */
3000  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
3001  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
3002  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
3003  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
3004  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3005  int* nnz, /**< number of non-zeros in cut */
3006  int* varsign, /**< stores the sign of the transformed variable in summation */
3007  int* boundtype, /**< stores the bound used for transformed variable:
3008  * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
3009  SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
3010  SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
3011  )
3012 {
3013  SCIP_Real QUAD(tmp);
3014  SCIP_Real* bestlbs;
3015  SCIP_Real* bestubs;
3016  int* bestlbtypes;
3017  int* bestubtypes;
3018  SCIP_BOUNDTYPE* selectedbounds;
3019  int i;
3020  int aggrrowintstart;
3021  int nvars;
3022  int firstcontvar;
3023  SCIP_VAR** vars;
3024 
3025  assert(varsign != NULL);
3026  assert(boundtype != NULL);
3027  assert(freevariable != NULL);
3028  assert(localbdsused != NULL);
3029 
3030  *freevariable = FALSE;
3031  *localbdsused = FALSE;
3032 
3033  /* allocate temporary memory to store best bounds and bound types */
3034  SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*(*nnz)) );
3035  SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*(*nnz)) );
3036  SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*(*nnz)) );
3037  SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*(*nnz)) );
3038  SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*(*nnz)) );
3039 
3040  /* start with continuous variables, because using variable bounds can affect the untransformed integral
3041  * variables, and these changes have to be incorporated in the transformation of the integral variables
3042  * (continuous variables have largest problem indices!)
3043  */
3044  SCIPsortDownInt(cutinds, *nnz);
3045 
3046  vars = SCIPgetVars(scip);
3047  nvars = SCIPgetNVars(scip);
3048  firstcontvar = nvars - SCIPgetNContVars(scip);
3049 
3050  /* determine the best bounds for the continous variables */
3051  for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
3052  {
3053  SCIP_CALL( determineBestBounds(scip, vars[cutinds[i]], sol, boundswitch, usevbds, allowlocal, fixintegralrhs,
3054  ignoresol, boundsfortrans, boundtypesfortrans,
3055  bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
3056 
3057  if( *freevariable )
3058  goto TERMINATE;
3059  }
3060 
3061  /* remember start of integer variables in the aggrrow */
3062  aggrrowintstart = i;
3063 
3064  /* perform bound substitution for continuous variables */
3065  for( i = 0; i < aggrrowintstart; ++i )
3066  {
3067  SCIP_Real QUAD(coef);
3068  int v = cutinds[i];
3069  SCIP_VAR* var = vars[v];
3070 
3071  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3072 
3073  if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
3074  {
3075  assert(!SCIPisInfinity(scip, -bestlbs[i]));
3076 
3077  /* use lower bound as transformation bound: x'_j := x_j - lb_j */
3078  boundtype[i] = bestlbtypes[i];
3079  varsign[i] = +1;
3080 
3081  /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
3082  if( bestlbtypes[i] < 0 )
3083  {
3084  SCIPquadprecProdQD(tmp, coef, bestlbs[i]);
3085  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3086  *localbdsused = *localbdsused || (bestlbtypes[i] == -2);
3087  }
3088  else
3089  {
3090  SCIP_VAR** vlbvars;
3091  SCIP_Real* vlbcoefs;
3092  SCIP_Real* vlbconsts;
3093  SCIP_Real QUAD(zcoef);
3094  int zidx;
3095 
3096  vlbvars = SCIPvarGetVlbVars(var);
3097  vlbcoefs = SCIPvarGetVlbCoefs(var);
3098  vlbconsts = SCIPvarGetVlbConstants(var);
3099  assert(vlbvars != NULL);
3100  assert(vlbcoefs != NULL);
3101  assert(vlbconsts != NULL);
3102 
3103  assert(0 <= bestlbtypes[i] && bestlbtypes[i] < SCIPvarGetNVlbs(var));
3104  assert(SCIPvarIsActive(vlbvars[bestlbtypes[i]]));
3105  zidx = SCIPvarGetProbindex(vlbvars[bestlbtypes[i]]);
3106  assert(0 <= zidx && zidx < firstcontvar);
3107 
3108  SCIPquadprecProdQD(tmp, coef, vlbconsts[bestlbtypes[i]]);
3109  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3110 
3111  /* check if integral variable already exists in the row and update sparsity pattern */
3112  QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
3113  if( QUAD_HI(zcoef) == 0.0 )
3114  cutinds[(*nnz)++] = zidx;
3115 
3116  SCIPquadprecProdQD(coef, coef, vlbcoefs[bestlbtypes[i]]);
3117  SCIPquadprecSumQQ(zcoef, zcoef, coef);
3118  QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
3119  QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
3120  assert(QUAD_HI(zcoef) != 0.0);
3121  }
3122  }
3123  else
3124  {
3125  assert(!SCIPisInfinity(scip, bestubs[i]));
3126 
3127  /* use upper bound as transformation bound: x'_j := ub_j - x_j */
3128  boundtype[i] = bestubtypes[i];
3129  varsign[i] = -1;
3130 
3131  /* standard (bestubtype < 0) or variable (bestubtype >= 0) upper bound? */
3132  if( bestubtypes[i] < 0 )
3133  {
3134  SCIPquadprecProdQD(tmp, coef, bestubs[i]);
3135  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3136  *localbdsused = *localbdsused || (bestubtypes[i] == -2);
3137  }
3138  else
3139  {
3140  SCIP_VAR** vubvars;
3141  SCIP_Real* vubcoefs;
3142  SCIP_Real* vubconsts;
3143  SCIP_Real QUAD(zcoef);
3144  int zidx;
3145 
3146  vubvars = SCIPvarGetVubVars(var);
3147  vubcoefs = SCIPvarGetVubCoefs(var);
3148  vubconsts = SCIPvarGetVubConstants(var);
3149  assert(vubvars != NULL);
3150  assert(vubcoefs != NULL);
3151  assert(vubconsts != NULL);
3152 
3153  assert(0 <= bestubtypes[i] && bestubtypes[i] < SCIPvarGetNVubs(var));
3154  assert(SCIPvarIsActive(vubvars[bestubtypes[i]]));
3155  zidx = SCIPvarGetProbindex(vubvars[bestubtypes[i]]);
3156  assert(zidx >= 0);
3157 
3158  SCIPquadprecProdQD(tmp, coef, vubconsts[bestubtypes[i]]);
3159  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3160 
3161  /* check if integral variable already exists in the row and update sparsity pattern */
3162  QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
3163  if( QUAD_HI(zcoef) == 0.0 )
3164  cutinds[(*nnz)++] = zidx;
3165 
3166  SCIPquadprecProdQD(coef, coef, vubcoefs[bestubtypes[i]]);
3167  SCIPquadprecSumQQ(zcoef, zcoef, coef);
3168  QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
3169  QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
3170  assert(QUAD_HI(zcoef) != 0.0);
3171  }
3172  }
3173  }
3174 
3175  /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
3176  * and determine the bound to use for the integer variables that are left
3177  */
3178  while( i < *nnz )
3179  {
3180  SCIP_Real QUAD(coef);
3181  int v = cutinds[i];
3182  assert(cutinds[i] < firstcontvar);
3183 
3184  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3185 
3186  /* due to variable bound usage for the continous variables cancellation may have occurred */
3187  if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
3188  {
3189  QUAD_ASSIGN(coef, 0.0);
3190  QUAD_ARRAY_STORE(cutcoefs, v, coef);
3191  --(*nnz);
3192  cutinds[i] = cutinds[*nnz];
3193  /* do not increase i, since last element is copied to the i-th position */
3194  continue;
3195  }
3196 
3197  /* determine the best bounds for the integral variable, usevbd can be set to FALSE here as vbds are only used for continous variables */
3198  SCIP_CALL( determineBestBounds(scip, vars[v], sol, boundswitch, FALSE, allowlocal, fixintegralrhs,
3199  ignoresol, boundsfortrans, boundtypesfortrans,
3200  bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
3201 
3202  /* increase i */
3203  ++i;
3204 
3205  if( *freevariable )
3206  goto TERMINATE;
3207  }
3208 
3209  /* now perform the bound substitution on the remaining integral variables which only uses standard bounds */
3210  for( i = aggrrowintstart; i < *nnz; ++i )
3211  {
3212  SCIP_Real QUAD(coef);
3213  int v = cutinds[i];
3214 
3215  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3216 
3217  /* perform bound substitution */
3218  if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
3219  {
3220  assert(!SCIPisInfinity(scip, - bestlbs[i]));
3221  assert(bestlbtypes[i] < 0);
3222 
3223  /* use lower bound as transformation bound: x'_j := x_j - lb_j */
3224  boundtype[i] = bestlbtypes[i];
3225  varsign[i] = +1;
3226 
3227  /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
3228  SCIPquadprecProdQD(tmp, coef, bestlbs[i]);
3229  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3230  *localbdsused = *localbdsused || (bestlbtypes[i] == -2);
3231  }
3232  else
3233  {
3234  assert(!SCIPisInfinity(scip, bestubs[i]));
3235  assert(bestubtypes[i] < 0);
3236 
3237  /* use upper bound as transformation bound: x'_j := ub_j - x_j */
3238  boundtype[i] = bestubtypes[i];
3239  varsign[i] = -1;
3240 
3241  /* standard (bestubtype < 0) or variable (bestubtype >= 0) upper bound? */
3242  SCIPquadprecProdQD(tmp, coef, bestubs[i]);
3243  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3244  *localbdsused = *localbdsused || (bestubtypes[i] == -2);
3245  }
3246  }
3247 
3248  if( fixintegralrhs )
3249  {
3250  SCIP_Real f0;
3251 
3252  /* check if rhs is fractional */
3253  f0 = EPSFRAC(QUAD_TO_DBL(*cutrhs), SCIPsumepsilon(scip));
3254  if( f0 < minfrac || f0 > maxfrac )
3255  {
3256  SCIP_Real bestviolgain;
3257  SCIP_Real bestnewf0;
3258  int besti;
3259 
3260  /* choose complementation of one variable differently such that f0 is in correct range */
3261  besti = -1;
3262  bestviolgain = -1e+100;
3263  bestnewf0 = 1.0;
3264  for( i = 0; i < *nnz; i++ )
3265  {
3266  int v;
3267  SCIP_Real QUAD(coef);
3268 
3269  v = cutinds[i];
3270  assert(0 <= v && v < nvars);
3271 
3272  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3273  assert(!EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON));
3274 
3275  if( boundtype[i] < 0
3276  && ((varsign[i] == +1 && !SCIPisInfinity(scip, bestubs[i]) && bestubtypes[i] < 0)
3277  || (varsign[i] == -1 && !SCIPisInfinity(scip, -bestlbs[i]) && bestlbtypes[i] < 0)) )
3278  {
3279  SCIP_Real fj;
3280  SCIP_Real newfj;
3281  SCIP_Real newrhs;
3282  SCIP_Real newf0;
3283  SCIP_Real solval;
3284  SCIP_Real viol;
3285  SCIP_Real newviol;
3286  SCIP_Real violgain;
3287 
3288  /* currently: a'_j = varsign * a_j -> f'_j = a'_j - floor(a'_j)
3289  * after complementation: a''_j = -varsign * a_j -> f''_j = a''_j - floor(a''_j) = 1 - f'_j
3290  * rhs'' = rhs' + varsign * a_j * (lb_j - ub_j)
3291  * cut violation from f0 and fj: f'_0 - f'_j * x'_j
3292  * after complementation: f''_0 - f''_j * x''_j
3293  *
3294  * for continuous variables, we just set f'_j = f''_j = |a'_j|
3295  */
3296  newrhs = QUAD_TO_DBL(*cutrhs) + varsign[i] * QUAD_TO_DBL(coef) * (bestlbs[i] - bestubs[i]);
3297  newf0 = EPSFRAC(newrhs, SCIPsumepsilon(scip));
3298  if( newf0 < minfrac || newf0 > maxfrac )
3299  continue;
3300  if( v >= firstcontvar )
3301  {
3302  fj = REALABS(QUAD_TO_DBL(coef));
3303  newfj = fj;
3304  }
3305  else
3306  {
3307  fj = SCIPfrac(scip, varsign[i] * QUAD_TO_DBL(coef));
3308  newfj = SCIPfrac(scip, -varsign[i] * QUAD_TO_DBL(coef));
3309  }
3310 
3311  if( !ignoresol )
3312  {
3313  solval = (sol == NULL ? SCIPvarGetLPSol(vars[v]) : SCIPgetSolVal(scip, sol, vars[v]));
3314  viol = f0 - fj * (varsign[i] == +1 ? solval - bestlbs[i] : bestubs[i] - solval);
3315  newviol = newf0 - newfj * (varsign[i] == -1 ? solval - bestlbs[i] : bestubs[i] - solval);
3316  violgain = newviol - viol;
3317  }
3318  else
3319  {
3320  /* todo: this should be done, this can improve the dualray significantly */
3321  SCIPerrorMessage("Cannot handle closest bounds with ignoring the LP solution.\n");
3322  return SCIP_INVALIDCALL;
3323  }
3324 
3325  /* prefer larger violations; for equal violations, prefer smaller f0 values since then the possibility that
3326  * we f_j > f_0 is larger and we may improve some coefficients in rounding
3327  */
3328  if( SCIPisGT(scip, violgain, bestviolgain)
3329  || (SCIPisGE(scip, violgain, bestviolgain) && newf0 < bestnewf0) )
3330  {
3331  besti = i;
3332  bestviolgain = violgain;
3333  bestnewf0 = newf0;
3334  }
3335  }
3336  }
3337 
3338  if( besti >= 0 )
3339  {
3340  SCIP_Real QUAD(coef);
3341  assert(besti < *nnz);
3342  assert(boundtype[besti] < 0);
3343  assert(!SCIPisInfinity(scip, -bestlbs[besti]));
3344  assert(!SCIPisInfinity(scip, bestubs[besti]));
3345 
3346  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[besti]);
3347  QUAD_SCALE(coef, varsign[besti]);
3348 
3349  /* switch the complementation of this variable */
3350  SCIPquadprecSumDD(tmp, bestlbs[besti], - bestubs[besti]);
3351  SCIPquadprecProdQQ(tmp, tmp, coef);
3352  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3353 
3354  if( varsign[besti] == +1 )
3355  {
3356  /* switch to upper bound */
3357  assert(bestubtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
3358  boundtype[besti] = bestubtypes[besti];
3359  varsign[besti] = -1;
3360  }
3361  else
3362  {
3363  /* switch to lower bound */
3364  assert(bestlbtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
3365  boundtype[besti] = bestlbtypes[besti];
3366  varsign[besti] = +1;
3367  }
3368  *localbdsused = *localbdsused || (boundtype[besti] == -2);
3369  }
3370  }
3371  }
3372 
3373  TERMINATE:
3374 
3375  /*free temporary memory */
3376  SCIPfreeBufferArray(scip, &selectedbounds);
3377  SCIPfreeBufferArray(scip, &bestubtypes);
3378  SCIPfreeBufferArray(scip, &bestlbtypes);
3379  SCIPfreeBufferArray(scip, &bestubs);
3380  SCIPfreeBufferArray(scip, &bestlbs);
3381 
3382  return SCIP_OKAY;
3383 }
3384 
3385 /** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
3386  * \f[
3387  * \begin{array}{rll}
3388  * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
3389  * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
3390  * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
3391  * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
3392  * \end{array}
3393  * \f]
3394  *
3395  * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
3396  *
3397  * (lb or ub):
3398  * \f[
3399  * \begin{array}{lllll}
3400  * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
3401  * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
3402  * \end{array}
3403  * \f]
3404  * and move the constant terms
3405  * \f[
3406  * \begin{array}{cl}
3407  * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
3408  * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
3409  * \end{array}
3410  * \f]
3411  * to the rhs.
3412  *
3413  * (vlb or vub):
3414  * \f[
3415  * \begin{array}{lllll}
3416  * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
3417  * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
3418  * \end{array}
3419  * \f]
3420  * move the constant terms
3421  * \f[
3422  * \begin{array}{cl}
3423  * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
3424  * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
3425  * \end{array}
3426  * \f]
3427  * to the rhs, and update the VB variable coefficients:
3428  * \f[
3429  * \begin{array}{ll}
3430  * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
3431  * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
3432  * \end{array}
3433  * \f]
3434  */
3435 static
3437  SCIP* scip, /**< SCIP data structure */
3438  SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
3439  QUAD(SCIP_Real*RESTRICT cutrhs), /**< pointer to right hand side of cut */
3440  int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3441  int*RESTRICT nnz, /**< number of non-zeros in cut */
3442  int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
3443  int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
3444  QUAD(SCIP_Real f0) /**< fractional value of rhs */
3445  )
3446 {
3447  SCIP_Real QUAD(tmp);
3448  SCIP_Real QUAD(onedivoneminusf0);
3449  int i;
3450  int firstcontvar;
3451  SCIP_VAR** vars;
3452  int ndelcontvars;
3453 
3454  assert(QUAD_HI(cutrhs) != NULL);
3455  assert(cutcoefs != NULL);
3456  assert(cutinds != NULL);
3457  assert(nnz != NULL);
3458  assert(boundtype != NULL);
3459  assert(varsign != NULL);
3460  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
3461 
3462  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
3463  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
3464 
3465  /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
3466  * without destroying the ordering of the aggrrow's non-zeros.
3467  * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
3468  */
3469 
3470  firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
3471  vars = SCIPgetVars(scip);
3472 #ifndef NDEBUG
3473  /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
3474  i = 0;
3475  while( i < *nnz && cutinds[i] >= firstcontvar )
3476  ++i;
3477 
3478  while( i < *nnz )
3479  {
3480  assert(cutinds[i] < firstcontvar);
3481  ++i;
3482  }
3483 #endif
3484 
3485  for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
3486  {
3487  SCIP_VAR* var;
3488  SCIP_Real QUAD(cutaj);
3489  int v;
3490 
3491  v = cutinds[i];
3492  assert(0 <= v && v < SCIPgetNVars(scip));
3493 
3494  var = vars[v];
3495  assert(var != NULL);
3496  assert(SCIPvarGetProbindex(var) == v);
3497  assert(varsign[i] == +1 || varsign[i] == -1);
3498 
3499  /* calculate the coefficient in the retransformed cut */
3500  {
3501  SCIP_Real QUAD(aj);
3502  SCIP_Real QUAD(downaj);
3503  SCIP_Real QUAD(fj);
3504 
3505  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
3506  QUAD_SCALE(aj, varsign[i]);
3507 
3508  SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
3509  SCIPquadprecSumQQ(fj, aj, -downaj);
3510  assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
3511 
3512  if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
3513  {
3514  QUAD_ASSIGN_Q(cutaj, downaj);
3515  }
3516  else
3517  {
3518  SCIPquadprecSumQQ(tmp, fj, -f0);
3519  SCIPquadprecProdQQ(tmp, tmp, onedivoneminusf0);
3520  SCIPquadprecSumQQ(cutaj, tmp, downaj);
3521  }
3522 
3523  QUAD_SCALE(cutaj, varsign[i]);
3524  }
3525 
3526  /* remove zero cut coefficients from cut */
3527  if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
3528  {
3529  QUAD_ASSIGN(cutaj, 0.0);
3530  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3531  --*nnz;
3532  cutinds[i] = cutinds[*nnz];
3533  continue;
3534  }
3535 
3536  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3537 
3538  /* integral var uses standard bound */
3539  assert(boundtype[i] < 0);
3540 
3541  /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
3542  if( varsign[i] == +1 )
3543  {
3544  /* lower bound was used */
3545  if( boundtype[i] == -1 )
3546  {
3547  assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
3548  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
3549  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetLbGlobal(var) */
3550  }
3551  else
3552  {
3553  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
3554  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
3555  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetLbLocal(var) */
3556  }
3557  }
3558  else
3559  {
3560  /* upper bound was used */
3561  if( boundtype[i] == -1 )
3562  {
3563  assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
3564  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
3565  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetUbGlobal(var) */
3566  }
3567  else
3568  {
3569  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
3570  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
3571  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetUbLocal(var) */
3572  }
3573  }
3574  }
3575 
3576  /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
3577  ndelcontvars = 0;
3578  while( i >= ndelcontvars )
3579  {
3580  SCIP_VAR* var;
3581  SCIP_Real QUAD(cutaj);
3582  int v;
3583 
3584  v = cutinds[i];
3585  assert(0 <= v && v < SCIPgetNVars(scip));
3586 
3587  var = vars[v];
3588  assert(var != NULL);
3589  assert(SCIPvarGetProbindex(var) == v);
3590  assert(varsign[i] == +1 || varsign[i] == -1);
3591  assert( v >= firstcontvar );
3592 
3593  /* calculate the coefficient in the retransformed cut */
3594  {
3595  SCIP_Real QUAD(aj);
3596 
3597  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
3598 
3599  if( QUAD_TO_DBL(aj) * varsign[i] >= 0.0 )
3600  QUAD_ASSIGN(cutaj, 0.0);
3601  else
3602  SCIPquadprecProdQQ(cutaj, onedivoneminusf0, aj); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
3603  }
3604 
3605  /* remove zero cut coefficients from cut; move a continuous var from the beginning
3606  * to the current position, so that all integral variables stay behind the continuous
3607  * variables
3608  */
3609  if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
3610  {
3611  QUAD_ASSIGN(cutaj, 0.0);
3612  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3613  cutinds[i] = cutinds[ndelcontvars];
3614  varsign[i] = varsign[ndelcontvars];
3615  boundtype[i] = boundtype[ndelcontvars];
3616  ++ndelcontvars;
3617  continue;
3618  }
3619 
3620  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3621 
3622  /* check for variable bound use */
3623  if( boundtype[i] < 0 )
3624  {
3625  /* standard bound */
3626 
3627  /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
3628  if( varsign[i] == +1 )
3629  {
3630  /* lower bound was used */
3631  if( boundtype[i] == -1 )
3632  {
3633  assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
3634  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
3635  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3636  }
3637  else
3638  {
3639  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
3640  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
3641  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3642  }
3643  }
3644  else
3645  {
3646  /* upper bound was used */
3647  if( boundtype[i] == -1 )
3648  {
3649  assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
3650  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
3651  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3652  }
3653  else
3654  {
3655  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
3656  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
3657  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3658  }
3659  }
3660  }
3661  else
3662  {
3663  SCIP_VAR** vbz;
3664  SCIP_Real* vbb;
3665  SCIP_Real* vbd;
3666  SCIP_Real QUAD(zcoef);
3667  int vbidx;
3668  int zidx;
3669 
3670  /* variable bound */
3671  vbidx = boundtype[i];
3672 
3673  /* change mirrhs and cutaj of integer variable z_j of variable bound */
3674  if( varsign[i] == +1 )
3675  {
3676  /* variable lower bound was used */
3677  assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
3678  vbz = SCIPvarGetVlbVars(var);
3679  vbb = SCIPvarGetVlbCoefs(var);
3680  vbd = SCIPvarGetVlbConstants(var);
3681  }
3682  else
3683  {
3684  /* variable upper bound was used */
3685  assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
3686  vbz = SCIPvarGetVubVars(var);
3687  vbb = SCIPvarGetVubCoefs(var);
3688  vbd = SCIPvarGetVubConstants(var);
3689  }
3690  assert(SCIPvarIsActive(vbz[vbidx]));
3691  zidx = SCIPvarGetProbindex(vbz[vbidx]);
3692  assert(0 <= zidx && zidx < firstcontvar);
3693 
3694  SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
3695  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3696 
3697  SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
3698  QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
3699 
3700  /* update sparsity pattern */
3701  if( QUAD_HI(zcoef) == 0.0 )
3702  cutinds[(*nnz)++] = zidx;
3703 
3704  SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
3705  QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
3706  QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
3707  assert(QUAD_HI(zcoef) != 0.0);
3708  }
3709 
3710  /* advance to next variable */
3711  --i;
3712  }
3713 
3714  /* fill the empty position due to deleted continuous variables */
3715  if( ndelcontvars > 0 )
3716  {
3717  assert(ndelcontvars <= *nnz);
3718  *nnz -= ndelcontvars;
3719  if( *nnz < ndelcontvars )
3720  {
3721  BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
3722  }
3723  else
3724  {
3725  BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
3726  }
3727  }
3728 
3729  return SCIP_OKAY;
3730 }
3731 
3732 /** substitute aggregated slack variables:
3733  *
3734  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
3735  * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
3736  *
3737  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
3738  * \f[
3739  * \begin{array}{rll}
3740  * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
3741  * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
3742  * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
3743  * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
3744  * \end{array}
3745  * \f]
3746  *
3747  * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
3748  */
3749 static
3751  SCIP* scip, /**< SCIP data structure */
3752  SCIP_Real* weights, /**< row weights in row summation */
3753  int* slacksign, /**< stores the sign of the row's slack variable in summation */
3754  int* rowinds, /**< sparsity pattern of used rows */
3755  int nrowinds, /**< number of used rows */
3756  SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
3757  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
3758  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
3759  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3760  int* nnz, /**< number of non-zeros in cut */
3761  QUAD(SCIP_Real f0) /**< fractional value of rhs */
3762  )
3763 { /*lint --e{715}*/
3764  SCIP_ROW** rows;
3765  SCIP_Real QUAD(onedivoneminusf0);
3766  int i;
3767 
3768  assert(scip != NULL);
3769  assert(weights != NULL || nrowinds == 0);
3770  assert(slacksign != NULL || nrowinds == 0);
3771  assert(rowinds != NULL || nrowinds == 0);
3772  assert(scale > 0.0);
3773  assert(cutcoefs != NULL);
3774  assert(QUAD_HI(cutrhs) != NULL);
3775  assert(cutinds != NULL);
3776  assert(nnz != NULL);
3777  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
3778 
3779  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
3780  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
3781 
3782  rows = SCIPgetLPRows(scip);
3783  for( i = 0; i < nrowinds; i++ )
3784  {
3785  SCIP_ROW* row;
3786  SCIP_Real ar;
3787  SCIP_Real downar;
3788  SCIP_Real QUAD(cutar);
3789  SCIP_Real QUAD(fr);
3790  SCIP_Real QUAD(tmp);
3791  SCIP_Real mul;
3792  int r;
3793 
3794  r = rowinds[i]; /*lint !e613*/
3795  assert(0 <= r && r < SCIPgetNLPRows(scip));
3796  assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
3797  assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
3798 
3799  row = rows[r];
3800  assert(row != NULL);
3801  assert(row->len == 0 || row->cols != NULL);
3802  assert(row->len == 0 || row->cols_index != NULL);
3803  assert(row->len == 0 || row->vals != NULL);
3804 
3805  /* get the slack's coefficient a'_r in the aggregated row */
3806  ar = slacksign[i] * scale * weights[i]; /*lint !e613*/
3807 
3808  /* calculate slack variable's coefficient a^_r in the cut */
3809  if( row->integral
3810  && ((slacksign[i] == +1 && SCIPisFeasIntegral(scip, row->rhs - row->constant))
3811  || (slacksign[i] == -1 && SCIPisFeasIntegral(scip, row->lhs - row->constant))) ) /*lint !e613*/
3812  {
3813  /* slack variable is always integral:
3814  * a^_r = a~_r = down(a'_r) , if f_r <= f0
3815  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
3816  */
3817  downar = EPSFLOOR(ar, QUAD_EPSILON);
3818  SCIPquadprecSumDD(fr, ar, -downar);
3819  if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
3820  QUAD_ASSIGN(cutar, downar);
3821  else
3822  {
3823  SCIPquadprecSumQQ(cutar, fr, -f0);
3824  SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
3825  SCIPquadprecSumQD(cutar, cutar, downar);
3826  }
3827  }
3828  else
3829  {
3830  /* slack variable is continuous:
3831  * a^_r = a~_r = 0 , if a'_r >= 0
3832  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
3833  */
3834  if( ar >= 0.0 )
3835  continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
3836  else
3837  SCIPquadprecProdQD(cutar, onedivoneminusf0, ar);
3838  }
3839 
3840  /* if the coefficient was reduced to zero, ignore the slack variable */
3841  if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
3842  continue;
3843 
3844  /* depending on the slack's sign, we have
3845  * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
3846  * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
3847  */
3848  mul = -slacksign[i] * QUAD_TO_DBL(cutar); /*lint !e613*/
3849 
3850  /* add the slack's definition multiplied with a^_j to the cut */
3851  SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
3852 
3853  /* move slack's constant to the right hand side */
3854  if( slacksign[i] == +1 ) /*lint !e613*/
3855  {
3856  SCIP_Real QUAD(rowrhs);
3857 
3858  /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
3859  assert(!SCIPisInfinity(scip, row->rhs));
3860  SCIPquadprecSumDD(rowrhs, row->rhs, -row->constant);
3861  if( row->integral )
3862  {
3863  /* the right hand side was implicitly rounded down in row aggregation */
3864  QUAD_ASSIGN(rowrhs, SCIPfloor(scip, QUAD_TO_DBL(rowrhs)));
3865  }
3866  SCIPquadprecProdQQ(tmp, cutar, rowrhs);
3867  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3868  }
3869  else
3870  {
3871  SCIP_Real QUAD(rowlhs);
3872 
3873  /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
3874  assert(!SCIPisInfinity(scip, -row->lhs));
3875  SCIPquadprecSumDD(rowlhs, row->lhs, -row->constant);
3876  if( row->integral )
3877  {
3878  /* the left hand side was implicitly rounded up in row aggregation */
3879  QUAD_ASSIGN(rowlhs, SCIPceil(scip, QUAD_TO_DBL(rowlhs)));
3880  }
3881  SCIPquadprecProdQQ(tmp, cutar, rowlhs);
3882  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3883  }
3884  }
3885 
3886  /* relax rhs to zero, if it's very close to */
3887  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= SCIPepsilon(scip) )
3888  QUAD_ASSIGN(*cutrhs, 0.0);
3889 
3890  return SCIP_OKAY;
3891 }
3892 
3893 /** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
3894  * these rows cannot participate in an MIR cut.
3895  *
3896  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3897  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3898  *
3899  * @pre This method can be called if @p scip is in one of the following stages:
3900  * - \ref SCIP_STAGE_SOLVING
3901  *
3902  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
3903  */
3905  SCIP* scip, /**< SCIP data structure */
3906  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
3907  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
3908  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
3909  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
3910  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
3911  SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
3912  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
3913  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
3914  * NULL for using closest bound for all variables */
3915  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
3916  * NULL for using closest bound for all variables */
3917  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
3918  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
3919  SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
3920  SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
3921  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
3922  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
3923  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
3924  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
3925  SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
3926  int* cutrank, /**< pointer to return rank of generated cut */
3927  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
3928  SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut */
3929  )
3930 {
3931  int i;
3932  int nvars;
3933  int* varsign;
3934  int* boundtype;
3935  SCIP_Real* tmpcoefs;
3936 
3937  SCIP_Real QUAD(rhs);
3938  SCIP_Real QUAD(downrhs);
3939  SCIP_Real QUAD(f0);
3940  SCIP_Bool freevariable;
3941  SCIP_Bool localbdsused;
3942 
3943  assert(aggrrow != NULL);
3944  assert(SCIPisPositive(scip, scale));
3945  assert(success != NULL);
3946 
3947  SCIPdebugMessage("calculating MIR cut (scale: %g)\n", scale);
3948 
3949  *success = FALSE;
3950 
3951  /* allocate temporary memory */
3952  nvars = SCIPgetNVars(scip);
3953  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
3954  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
3955  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, QUAD_ARRAY_SIZE(nvars)) );
3956 
3957  /* initialize cut with aggregation */
3958  *cutnnz = aggrrow->nnz;
3959  *cutislocal = aggrrow->local;
3960 
3961  SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
3962 
3963  if( *cutnnz > 0 )
3964  {
3965  BMScopyMemoryArray(cutinds, aggrrow->inds, *cutnnz);
3966 
3967  for( i = 0; i < *cutnnz; ++i )
3968  {
3969  SCIP_Real QUAD(coef);
3970 
3971  int k = aggrrow->inds[i];
3972  QUAD_ARRAY_LOAD(coef, aggrrow->vals, k);
3973 
3974  SCIPquadprecProdQD(coef, coef, scale);
3975 
3976  QUAD_ARRAY_STORE(tmpcoefs, k, coef);
3977 
3978  assert(QUAD_HI(coef) != 0.0);
3979  }
3980 
3981  /* Transform equation a*x == b, lb <= x <= ub into standard form
3982  * a'*x' == b, 0 <= x' <= ub'.
3983  *
3984  * Transform variables (lb or ub):
3985  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
3986  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
3987  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
3988  *
3989  * Transform variables (vlb or vub):
3990  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
3991  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
3992  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
3993  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
3994  * a_{zu_j} := a_{zu_j} + a_j * bu_j
3995  */
3996  SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
3997  boundsfortrans, boundtypesfortrans, minfrac, maxfrac, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, &freevariable, &localbdsused) );
3998  assert(allowlocal || !localbdsused);
3999  *cutislocal = *cutislocal || localbdsused;
4000 
4001  if( freevariable )
4002  goto TERMINATE;
4003  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
4004  }
4005 
4006  /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
4007  * a~*x' <= down(b)
4008  * integers : a~_j = down(a'_j) , if f_j <= f_0
4009  * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
4010  * continuous: a~_j = 0 , if a'_j >= 0
4011  * a~_j = a'_j/(1 - f0) , if a'_j < 0
4012  *
4013  * Transform inequality back to a^*x <= rhs:
4014  *
4015  * (lb or ub):
4016  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
4017  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
4018  * and move the constant terms
4019  * -a~_j * lb_j == -a^_j * lb_j, or
4020  * a~_j * ub_j == -a^_j * ub_j
4021  * to the rhs.
4022  *
4023  * (vlb or vub):
4024  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
4025  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
4026  * move the constant terms
4027  * -a~_j * dl_j == -a^_j * dl_j, or
4028  * a~_j * du_j == -a^_j * du_j
4029  * to the rhs, and update the VB variable coefficients:
4030  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4031  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4032  */
4033  SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
4034 
4035  SCIPquadprecSumQQ(f0, rhs, -downrhs);
4036 
4037  if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
4038  goto TERMINATE;
4039 
4040  /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4041  * If this gives a scalar that is very big, we better do not generate this cut.
4042  */
4043  if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
4044  goto TERMINATE;
4045 
4046  /* renormalize f0 value */
4047  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4048 
4049  QUAD_ASSIGN_Q(rhs, downrhs);
4050 
4051  if( *cutnnz > 0 )
4052  {
4053  SCIP_CALL( cutsRoundMIR(scip, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, QUAD(f0)) );
4054  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
4055  }
4056 
4057  /* substitute aggregated slack variables:
4058  *
4059  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4060  * variable only appears in its own row:
4061  * a'_r = scale * weight[r] * slacksign[r].
4062  *
4063  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4064  * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4065  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4066  * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4067  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4068  *
4069  * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4070  */
4071  SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4072  aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, QUAD(f0)) );
4073  SCIPdebug( printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE) );
4074 
4075  if( postprocess )
4076  {
4077  /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4078  * prevent numerical rounding errors
4079  */
4080  SCIP_CALL( postprocessCutQuad(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, QUAD(&rhs), success) );
4081  }
4082  else
4083  {
4084  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutnnz, cutinds);
4085  }
4086 
4087  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
4088 
4089  if( *success )
4090  {
4091  *cutrhs = QUAD_TO_DBL(rhs);
4092 
4093  /* clean tmpcoefs and go back to double precision */
4094  for( i = 0; i < *cutnnz; ++i )
4095  {
4096  SCIP_Real QUAD(coef);
4097  int j = cutinds[i];
4098 
4099  QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
4100 
4101  cutcoefs[i] = QUAD_TO_DBL(coef);
4102  QUAD_ASSIGN(coef, 0.0);
4103  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
4104  }
4105 
4106  if( cutefficacy != NULL )
4107  *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
4108 
4109  if( cutrank != NULL )
4110  *cutrank = aggrrow->rank + 1;
4111  }
4112 
4113  TERMINATE:
4114  if( !(*success) )
4115  {
4116  SCIP_Real QUAD(tmp);
4117 
4118  QUAD_ASSIGN(tmp, 0.0);
4119  for( i = 0; i < *cutnnz; ++i )
4120  {
4121  QUAD_ARRAY_STORE(tmpcoefs, cutinds[i], tmp);
4122  }
4123  }
4124 
4125  /* free temporary memory */
4126  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
4127  SCIPfreeBufferArray(scip, &boundtype);
4128  SCIPfreeBufferArray(scip, &varsign);
4129 
4130  return SCIP_OKAY;
4131 }
4132 
4133 /** compute the efficacy of the MIR cut for the given values without computing the cut.
4134  * This is used for the CMIR cut generation heuristic.
4135  */
4136 static
4138  SCIP* scip, /**< SCIP datastructure */
4139  SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
4140  SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
4141  SCIP_Real rhs, /**< right hand side of MIR cut */
4142  SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
4143  SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
4144  SCIP_Real delta, /**< delta value to compute the violation for */
4145  int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
4146  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4147  SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
4148  )
4149 {
4150  int i;
4151  SCIP_Real f0pluseps;
4152  SCIP_Real f0;
4153  SCIP_Real onedivoneminusf0;
4154  SCIP_Real scale;
4155  SCIP_Real downrhs;
4156  SCIP_Real norm;
4157  SCIP_Real contscale;
4158 
4159  scale = 1.0 / delta;
4160 
4161  rhs *= scale;
4162 
4163  downrhs = SCIPfloor(scip, rhs);
4164 
4165  f0 = rhs - downrhs;
4166 
4167  if( f0 < minfrac || f0 > maxfrac )
4168  return 0.0;
4169 
4170  onedivoneminusf0 = 1.0 / (1.0 - f0);
4171 
4172  contscale = scale * onedivoneminusf0;
4173 
4174  /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4175  * If this gives a scalar that is very big, we better do not generate this cut.
4176  */
4177  if( contscale > MAXCMIRSCALE )
4178  return 0.0;
4179 
4180  rhs = downrhs;
4181  rhs -= contscale * contactivity;
4182  norm = SQR(contscale) * contsqrnorm;
4183 
4184  assert(!SCIPisFeasZero(scip, f0));
4185  assert(!SCIPisFeasZero(scip, 1.0 - f0));
4186 
4187  f0pluseps = f0 + SCIPepsilon(scip);
4188 
4189  for( i = 0; i < nvars; ++i )
4190  {
4191  SCIP_Real floorai = floor(scale * coefs[i]);
4192  SCIP_Real fi = (scale * coefs[i]) - floorai;
4193 
4194  if( fi > f0pluseps )
4195  floorai += (fi - f0) * onedivoneminusf0;
4196 
4197  rhs -= solvals[i] * floorai;
4198  norm += SQR(floorai);
4199  }
4200 
4201  norm = SQRT(norm);
4202 
4203  return - rhs / MAX(norm, 1e-6);
4204 }
4205 
4206 /** calculates an MIR cut out of an aggregation of LP rows
4207  *
4208  * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
4209  * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
4210  * One of the steps of the MIR is to round the coefficients of the integer variables down,
4211  * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
4212  * mkset.
4213  *
4214  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4215  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4216  *
4217  * @pre This method can be called if @p scip is in one of the following stages:
4218  * - \ref SCIP_STAGE_SOLVING
4219  *
4220  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
4221  */
4223  SCIP* scip, /**< SCIP data structure */
4224  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4225  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
4226  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4227  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
4228  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4229  int maxtestdelta, /**< maximum number of deltas to test */
4230  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4231  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4232  * NULL for using closest bound for all variables */
4233  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4234  * NULL for using closest bound for all variables */
4235  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4236  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
4237  SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
4238  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
4239  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
4240  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
4241  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
4242  SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
4243  * this efficacy on input to this function are returned */
4244  int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
4245  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
4246  SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
4247  )
4248 {
4249  int i;
4250  int firstcontvar;
4251  int nvars;
4252  int intstart;
4253  int ntmpcoefs;
4254  int* varsign;
4255  int* boundtype;
4256  int* mksetinds;
4257  SCIP_Real* mksetcoefs;
4258  SCIP_Real QUAD(mksetrhs);
4259  int mksetnnz;
4260  SCIP_Real* bounddist;
4261  int* bounddistpos;
4262  int nbounddist;
4263  SCIP_Real* tmpcoefs;
4264  SCIP_Real* tmpvalues;
4265  SCIP_Real* deltacands;
4266  int ndeltacands;
4267  SCIP_Real bestdelta;
4268  SCIP_Real bestefficacy;
4269  SCIP_Real maxabsmksetcoef;
4270  SCIP_VAR** vars;
4271  SCIP_Bool freevariable;
4272  SCIP_Bool localbdsused;
4273  SCIP_Real contactivity;
4274  SCIP_Real contsqrnorm;
4275 
4276  assert(aggrrow != NULL);
4277  assert(aggrrow->nrows + aggrrow->nnz >= 1);
4278  assert(success != NULL);
4279 
4280  *success = FALSE;
4281  nvars = SCIPgetNVars(scip);
4282  firstcontvar = nvars - SCIPgetNContVars(scip);
4283  vars = SCIPgetVars(scip);
4284 
4285  /* allocate temporary memory */
4286  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
4287  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
4288  SCIP_CALL( SCIPallocCleanBufferArray(scip, &mksetcoefs, QUAD_ARRAY_SIZE(nvars)) );
4289  SCIP_CALL( SCIPallocBufferArray(scip, &mksetinds, nvars) );
4290  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
4291  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
4292  SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, aggrrow->nnz + 6) );
4293 
4294  /* we only compute bound distance for integer variables; we allocate an array of length aggrrow->nnz to store this, since
4295  * this is the largest number of integer variables. (in contrast to the number of total variables which can be 2 *
4296  * aggrrow->nnz variables: if all are continuous and we use variable bounds to completement, we introduce aggrrow->nnz
4297  * extra vars)
4298  */
4299  SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, aggrrow->nnz) );
4300  SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, aggrrow->nnz) );
4301 
4302  /* initialize mkset with aggregation */
4303  mksetnnz = aggrrow->nnz;
4304  QUAD_ASSIGN_Q(mksetrhs, aggrrow->rhs);
4305 
4306  BMScopyMemoryArray(mksetinds, aggrrow->inds, mksetnnz);
4307 
4308  for( i = 0; i < mksetnnz; ++i )
4309  {
4310  int j = mksetinds[i];
4311  SCIP_Real QUAD(coef);
4312  QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
4313  QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4314  assert(QUAD_HI(coef) != 0.0);
4315  }
4316 
4317  *cutislocal = aggrrow->local;
4318 
4319  /* Transform equation a*x == b, lb <= x <= ub into standard form
4320  * a'*x' == b, 0 <= x' <= ub'.
4321  *
4322  * Transform variables (lb or ub):
4323  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
4324  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
4325  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
4326  *
4327  * Transform variables (vlb or vub):
4328  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
4329  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
4330  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
4331  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
4332  * a_{zu_j} := a_{zu_j} + a_j * bu_j
4333  */
4334  SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, FALSE, FALSE,
4335  boundsfortrans, boundtypesfortrans, minfrac, maxfrac, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, &freevariable, &localbdsused) );
4336 
4337  assert(allowlocal || !localbdsused);
4338 
4339  if( freevariable )
4340  goto TERMINATE;
4341 
4342  SCIPdebugMessage("transformed aggrrow row:\n");
4343  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4344 
4345  /* found positions of integral variables that are strictly between their bounds */
4346  maxabsmksetcoef = -1.0;
4347  nbounddist = 0;
4348 
4349  for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
4350  {
4351  SCIP_VAR* var = vars[mksetinds[i]];
4352  SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
4353  SCIP_Real lb = SCIPvarGetLbLocal(var);
4354  SCIP_Real ub = SCIPvarGetUbLocal(var);
4355  SCIP_Real QUAD(coef);
4356 
4357  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4358 
4359  if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
4360  continue;
4361 
4362  bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
4363  bounddistpos[nbounddist] = i;
4364  deltacands[nbounddist] = QUAD_TO_DBL(coef);
4365  ++nbounddist;
4366  }
4367 
4368  /* no fractional variable; so abort here */
4369  if( nbounddist == 0 )
4370  goto TERMINATE;
4371 
4372  intstart = i + 1;
4373  ndeltacands = nbounddist;
4374 
4375  SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
4376 
4377  {
4378  SCIP_Real intscale;
4379  SCIP_Bool intscalesuccess;
4380 
4381  SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -QUAD_EPSILON, SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
4382 
4383  if( intscalesuccess )
4384  {
4385  SCIP_Real intf0;
4386  SCIP_Real intscalerhs;
4387  SCIP_Real delta;
4388 
4389  intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4390  delta = 1.0 / intscale;
4391  intf0 = intscalerhs - floor(intscalerhs);
4392 
4393  if( ! SCIPisFeasIntegral(scip, intf0) )
4394  {
4395  if( intf0 < minfrac || intf0 > maxfrac )
4396  {
4397  intscale *= ceil(MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
4398  intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4399  delta = 1.0 / intscale;
4400  intf0 = intscalerhs - floor(intscalerhs);
4401  }
4402 
4403  if( intf0 >= minfrac && intf0 <= maxfrac )
4404  {
4405  if( ! SCIPisEQ(scip, delta, 1.0) )
4406  {
4407  deltacands[ndeltacands++] = delta;
4408  }
4409 
4410  if( intf0 < maxfrac )
4411  {
4412  SCIP_Real delta2;
4413 
4414  delta2 = 1.0 / (intscale * floor(maxfrac / intf0));
4415 
4416  if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
4417  {
4418  deltacands[ndeltacands++] = delta2;
4419  }
4420  }
4421  }
4422  }
4423  }
4424  }
4425 
4426  for( i = 0; i < nbounddist; ++i )
4427  {
4428  SCIP_Real absmksetcoef;
4429 
4430  absmksetcoef = REALABS(deltacands[i]);
4431  maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
4432 
4433  deltacands[i] = absmksetcoef;
4434  }
4435 
4436  /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
4437  if( maxabsmksetcoef != -1.0 )
4438  {
4439  deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
4440  }
4441 
4442  deltacands[ndeltacands++] = 1.0;
4443 
4444  maxtestdelta = MIN(ndeltacands, maxtestdelta);
4445 
4446  /* For each delta
4447  * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
4448  * a~*x' <= down(b)
4449  * integers : a~_j = down(a'_j) , if f_j <= f_0
4450  * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
4451  * continuous: a~_j = 0 , if a'_j >= 0
4452  * a~_j = a'_j/(1 - f0) , if a'_j < 0
4453  *
4454  * Transform inequality back to a^*x <= rhs:
4455  *
4456  * (lb or ub):
4457  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
4458  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
4459  * and move the constant terms
4460  * -a~_j * lb_j == -a^_j * lb_j, or
4461  * a~_j * ub_j == -a^_j * ub_j
4462  * to the rhs.
4463  *
4464  * (vlb or vub):
4465  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
4466  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
4467  * move the constant terms
4468  * -a~_j * dl_j == -a^_j * dl_j, or
4469  * a~_j * du_j == -a^_j * du_j
4470  * to the rhs, and update the VB variable coefficients:
4471  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4472  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4473  */
4474 
4475  ntmpcoefs = 0;
4476  for( i = intstart; i < mksetnnz; ++i )
4477  {
4478  SCIP_VAR* var;
4479  SCIP_Real solval;
4480  SCIP_Real QUAD(coef);
4481 
4482  var = vars[mksetinds[i]];
4483 
4484  /* get the soltion value of the continuous variable */
4485  solval = SCIPgetSolVal(scip, sol, var);
4486 
4487  /* now compute the solution value in the transform space considering complementation */
4488  if( boundtype[i] == -1 )
4489  {
4490  /* variable was complemented with global (simple) bound */
4491  if( varsign[i] == -1 )
4492  solval = SCIPvarGetUbGlobal(var) - solval;
4493  else
4494  solval = solval - SCIPvarGetLbGlobal(var);
4495  }
4496  else
4497  {
4498  assert(boundtype[i] == -2);
4499 
4500  /* variable was complemented with local (simple) bound */
4501  if( varsign[i] == -1 )
4502  solval = SCIPvarGetUbLocal(var) - solval;
4503  else
4504  solval = solval - SCIPvarGetLbLocal(var);
4505  }
4506 
4507  tmpvalues[ntmpcoefs] = solval;
4508  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4509  tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
4510  ++ntmpcoefs;
4511  }
4512 
4513  assert(ntmpcoefs == mksetnnz - intstart);
4514 
4515  contactivity = 0.0;
4516  contsqrnorm = 0.0;
4517  for( i = 0; i < intstart; ++i )
4518  {
4519  SCIP_Real solval;
4520  SCIP_Real QUAD(mksetcoef);
4521 
4522  QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
4523 
4524  if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
4525  continue;
4526 
4527  /* get the soltion value of the continuous variable */
4528  solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4529 
4530  /* now compute the solution value in the transform space considering complementation */
4531  switch( boundtype[i] )
4532  {
4533  case -1:
4534  /* variable was complemented with global (simple) bound */
4535  if( varsign[i] == -1 )
4536  solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
4537  else
4538  solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
4539  break;
4540  case -2:
4541  /* variable was complemented with local (simple) bound */
4542  if( varsign[i] == -1 )
4543  solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
4544  else
4545  solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
4546  break;
4547  default:
4548  /* variable was complemented with a variable bound */
4549  if( varsign[i] == -1 )
4550  {
4551  SCIP_Real coef;
4552  SCIP_Real constant;
4553  SCIP_Real vbdsolval;
4554 
4555  coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
4556  constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
4557  vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
4558 
4559  solval = (coef * vbdsolval + constant) - solval;
4560  }
4561  else
4562  {
4563  SCIP_Real coef;
4564  SCIP_Real constant;
4565  SCIP_Real vbdsolval;
4566 
4567  coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
4568  constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
4569  vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
4570 
4571  solval = solval - (coef * vbdsolval + constant);
4572  }
4573  }
4574 
4575  contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
4576  contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
4577  }
4578 
4579  {
4580  SCIP_ROW** rows;
4581 
4582  rows = SCIPgetLPRows(scip);
4583 
4584  for( i = 0; i < aggrrow->nrows; ++i )
4585  {
4586  SCIP_ROW* row;
4587  SCIP_Real slackval;
4588 
4589  row = rows[aggrrow->rowsinds[i]];
4590 
4591  if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
4592  continue;
4593 
4594  /* compute solution value of slack variable */
4595  slackval = SCIPgetRowSolActivity(scip, row, sol);
4596 
4597  if( aggrrow->slacksign[i] == +1 )
4598  {
4599  /* right hand side */
4600  assert(!SCIPisInfinity(scip, row->rhs));
4601 
4602  slackval = row->rhs - slackval;
4603  }
4604  else
4605  {
4606  /* left hand side */
4607  assert(aggrrow->slacksign[i] == -1);
4608  assert(!SCIPisInfinity(scip, -row->lhs));
4609 
4610  slackval = slackval - row->lhs;
4611  }
4612 
4613  if( row->integral )
4614  {
4615  /* if row is integral add variable to tmp arrays */
4616  tmpvalues[ntmpcoefs] = slackval;
4617  tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
4618  ++ntmpcoefs;
4619  }
4620  else
4621  {
4622  SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
4623 
4624  /* otherwise add it to continuous activity */
4625  contactivity += slackval * slackcoeff;
4626  contsqrnorm += SQR(slackcoeff);
4627  }
4628  }
4629  }
4630 
4631  /* try all candidates for delta and remember best */
4632  bestdelta = SCIP_INVALID;
4633  bestefficacy = -SCIPinfinity(scip);
4634 
4635  for( i = 0; i < maxtestdelta; ++i )
4636  {
4637  int j;
4638  SCIP_Real efficacy;
4639 
4640  /* check if we have seen this value of delta before */
4641  SCIP_Bool deltaseenbefore = FALSE;
4642  for( j = 0; j < i; ++j )
4643  {
4644  if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
4645  {
4646  deltaseenbefore = TRUE;
4647  break;
4648  }
4649  }
4650 
4651  /* skip this delta value and allow one more delta value if available */
4652  if( deltaseenbefore )
4653  {
4654  maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
4655  continue;
4656  }
4657 
4658  efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
4659 
4660  if( efficacy > bestefficacy )
4661  {
4662  bestefficacy = efficacy;
4663  bestdelta = deltacands[i];
4664  }
4665  }
4666 
4667  /* no delta was found that yielded any cut */
4668  if( bestdelta == SCIP_INVALID ) /*lint !e777*/
4669  goto TERMINATE;
4670 
4671  /* try bestdelta divided by 2, 4 and 8 */
4672  {
4673  SCIP_Real basedelta = bestdelta;
4674  for( i = 2; i <= 8 ; i *= 2 )
4675  {
4676  SCIP_Real efficacy;
4677  SCIP_Real delta;
4678 
4679  delta = basedelta / i;
4680 
4681  efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
4682 
4683  if( efficacy > bestefficacy )
4684  {
4685  bestefficacy = efficacy;
4686  bestdelta = delta;
4687  }
4688  }
4689  }
4690 
4691  /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
4692  * in order of non-increasing bound distance
4693  */
4694  for( i = 0; i < nbounddist; ++i )
4695  {
4696  int k;
4697  SCIP_Real newefficacy;
4698  SCIP_Real QUAD(newrhs);
4699  SCIP_Real bestlb;
4700  SCIP_Real bestub;
4701  SCIP_Real oldsolval;
4702  int bestlbtype;
4703  int bestubtype;
4704 
4705  k = bounddistpos[i];
4706 
4707  SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, FALSE, allowlocal, &bestlb, &bestlbtype) );
4708 
4709  if( SCIPisInfinity(scip, -bestlb) )
4710  continue;
4711 
4712  SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, FALSE, allowlocal, &bestub, &bestubtype) );
4713 
4714  if( SCIPisInfinity(scip, bestub) )
4715  continue;
4716 
4717  /* switch the complementation of this variable */
4718 #ifndef NDEBUG
4719  {
4720  SCIP_Real QUAD(coef);
4721  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
4722  assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
4723  }
4724 #endif
4725 
4726  /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
4727  SCIPquadprecSumQD(newrhs, mksetrhs, tmpcoefs[k - intstart] * (bestlb - bestub));
4728  tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4729 
4730  oldsolval = tmpvalues[k - intstart];
4731  tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
4732 
4733  /* compute new violation */
4734  newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
4735 
4736  /* check if violaton was increased */
4737  if( newefficacy > bestefficacy )
4738  {
4739  /* keep change of complementation */
4740  bestefficacy = newefficacy;
4741  QUAD_ASSIGN_Q(mksetrhs, newrhs);
4742 
4743  if( varsign[k] == +1 )
4744  {
4745  /* switch to upper bound */
4746  assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4747  boundtype[k] = bestubtype;
4748  varsign[k] = -1;
4749  }
4750  else
4751  {
4752  /* switch to lower bound */
4753  assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4754  boundtype[k] = bestlbtype;
4755  varsign[k] = +1;
4756  }
4757 
4758  localbdsused = localbdsused || (boundtype[k] == -2);
4759  }
4760  else
4761  {
4762  /* undo the change of the complementation */
4763  tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4764  tmpvalues[k - intstart] = oldsolval;
4765  }
4766  }
4767 
4768  if( bestefficacy > 0.0 )
4769  {
4770  SCIP_Real mirefficacy;
4771  SCIP_Real QUAD(downrhs);
4772  SCIP_Real QUAD(f0);
4773  SCIP_Real scale;
4774 
4775  scale = 1.0 / bestdelta;
4776  SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
4777 
4778  SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
4779  SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
4780 
4781  /* renormaliize f0 value */
4782  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4783 
4784  for( i = 0; i < mksetnnz; ++i )
4785  {
4786  SCIP_Real QUAD(coef);
4787 
4788  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4789  SCIPquadprecProdQD(coef, coef, scale);
4790  QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
4791  }
4792  SCIPdebugMessage("applied best scale (=%.13g):\n", scale);
4793  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4794 
4795  QUAD_ASSIGN_Q(mksetrhs, downrhs);
4796 
4797  SCIP_CALL( cutsRoundMIR(scip, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, QUAD(f0)) );
4798 
4799  SCIPdebugMessage("rounded MIR cut:\n");
4800  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4801 
4802  /* substitute aggregated slack variables:
4803  *
4804  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4805  * variable only appears in its own row:
4806  * a'_r = scale * weight[r] * slacksign[r].
4807  *
4808  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4809  * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4810  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4811  * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4812  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4813  *
4814  * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4815  */
4816  SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4817  aggrrow->nrows, scale, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, QUAD(f0)) );
4818 
4819  SCIPdebugMessage("substituted slacks in MIR cut:\n");
4820  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4821 
4822 #ifndef NDEBUG
4823  {
4824  SCIP_Real efficacy = -QUAD_TO_DBL(mksetrhs);
4825  for( i = 0; i < mksetnnz; ++i )
4826  {
4827  SCIP_Real QUAD(coef);
4828  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4829  efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4830  }
4831 
4832  if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
4833  {
4834  SCIPdebugMessage("efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
4835  }
4836  }
4837 #endif
4838 
4839  *cutislocal = *cutislocal || localbdsused;
4840 
4841  /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4842  * prevent numerical rounding errors
4843  */
4844  if( postprocess )
4845  {
4846  SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &mksetnnz, QUAD(&mksetrhs), success) );
4847  }
4848  else
4849  {
4850  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz);
4851  }
4852 
4853  SCIPdebugMessage("post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
4854  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4855 
4856  if( *success )
4857  {
4858  mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(mksetrhs), mksetinds, mksetnnz);
4859 
4860  if( SCIPisEfficacious(scip, mirefficacy) && mirefficacy > *cutefficacy )
4861  {
4862  BMScopyMemoryArray(cutinds, mksetinds, mksetnnz);
4863  for( i = 0; i < mksetnnz; ++i )
4864  {
4865  SCIP_Real QUAD(coef);
4866  int j = cutinds[i];
4867 
4868  QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
4869 
4870  cutcoefs[i] = QUAD_TO_DBL(coef);
4871  QUAD_ASSIGN(coef, 0.0);
4872  QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4873  }
4874  *cutnnz = mksetnnz;
4875  *cutrhs = QUAD_TO_DBL(mksetrhs);
4876  *cutefficacy = mirefficacy;
4877  if( cutrank != NULL )
4878  *cutrank = aggrrow->rank + 1;
4879  *cutislocal = *cutislocal || localbdsused;
4880  }
4881  else
4882  {
4883  *success = FALSE;
4884  }
4885  }
4886  }
4887 
4888  TERMINATE:
4889  /* if we aborted early we need to clean the mksetcoefs */
4890  if( !(*success) )
4891  {
4892  SCIP_Real QUAD(tmp);
4893  QUAD_ASSIGN(tmp, 0.0);
4894 
4895  for( i = 0; i < mksetnnz; ++i )
4896  {
4897  QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
4898  }
4899  }
4900 
4901  /* free temporary memory */
4902  SCIPfreeBufferArray(scip, &bounddistpos);
4903  SCIPfreeBufferArray(scip, &bounddist);
4904  SCIPfreeBufferArray(scip, &deltacands);
4905  SCIPfreeBufferArray(scip, &tmpvalues);
4906  SCIPfreeBufferArray(scip, &tmpcoefs);
4907  SCIPfreeBufferArray(scip, &mksetinds);
4908  SCIPfreeCleanBufferArray(scip, &mksetcoefs);
4909  SCIPfreeBufferArray(scip, &boundtype);
4910  SCIPfreeBufferArray(scip, &varsign);
4911 
4912  return SCIP_OKAY;
4913 }
4914 
4915 /* =========================================== flow cover =========================================== */
4916 
4917 #define NO_EXACT_KNAPSACK
4918 
4919 #ifndef NO_EXACT_KNAPSACK
4920 #define MAXDNOM 1000LL
4921 #define MINDELTA 1e-03
4922 #define MAXDELTA 1e-09
4923 #define MAXSCALE 1000.0
4924 #define MAXDYNPROGSPACE 1000000
4925 #endif
4926 
4927 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
4928 #define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
4929 
4930 /** structure that contains all data required to perform the sequence independent lifting
4931  */
4932 typedef
4933 struct LiftingData
4934 {
4935  SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
4936  SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
4937  * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
4938  * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
4939  * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
4940  * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
4941  */
4942  int r; /**< size of array m */
4943  int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
4944  SCIP_Real d1; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in C^- \f$ */
4945  SCIP_Real d2; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in N^- \f$ */
4946  SCIP_Real lambda; /**< excess of the flowcover */
4947  SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
4948  SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
4949 } LIFTINGDATA;
4950 
4951 /** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
4952 typedef
4953 struct SNF_Relaxation
4954 {
4955  int* transvarcoefs; /**< coefficients of all vars in relaxed set */
4956  SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
4957  SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
4958  SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
4959  int ntransvars; /**< number of vars in relaxed set */
4960  SCIP_Real transrhs; /**< rhs in relaxed set */
4961  int* origbinvars; /**< associated original binary var for all vars in relaxed set */
4962  int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
4963  SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
4964  * continuous variable in the relaxed set */
4965  SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continous var used to define the
4966  * continuous variable in the relaxed set */
4967  SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
4968 } SNF_RELAXATION;
4969 
4970 /** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
4971  * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
4972  * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
4973  * given variable
4974  */
4975 static
4977  SCIP* scip, /**< SCIP data structure */
4978  SCIP_VAR* var, /**< given active problem variable */
4979  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
4980  SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
4981  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
4982  * was not used (0) or was not used but is contained in the row (-1)
4983  */
4984  SCIP_Real bestsub, /**< closest simple upper bound of given variable */
4985  SCIP_Real rowcoef, /**< coefficient of given variable in current row */
4986  SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
4987  int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
4988  )
4989 {
4990  int nvlbs;
4991  int nbinvars;
4992 
4993  assert(scip != NULL);
4994  assert(var != NULL);
4995  assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
4996  assert(!SCIPisInfinity(scip, bestsub));
4997  assert(!EPSZ(rowcoef, QUAD_EPSILON));
4998  assert(rowcoefs != NULL);
4999  assert(binvarused != NULL);
5000  assert(closestvlb != NULL);
5001  assert(closestvlbidx != NULL);
5002 
5003  nvlbs = SCIPvarGetNVlbs(var);
5004  nbinvars = SCIPgetNBinVars(scip);
5005 
5006  *closestvlbidx = -1;
5007  *closestvlb = -SCIPinfinity(scip);
5008  if( nvlbs > 0 )
5009  {
5010  SCIP_VAR** vlbvars;
5011  SCIP_Real* vlbcoefs;
5012  SCIP_Real* vlbconsts;
5013  int i;
5014 
5015  vlbvars = SCIPvarGetVlbVars(var);
5016  vlbcoefs = SCIPvarGetVlbCoefs(var);
5017  vlbconsts = SCIPvarGetVlbConstants(var);
5018 
5019  for( i = 0; i < nvlbs; i++ )
5020  {
5021  SCIP_Real rowcoefbinvar;
5022  SCIP_Real val1;
5023  SCIP_Real val2;
5024  SCIP_Real vlbsol;
5025  SCIP_Real rowcoefsign;
5026  int probidxbinvar;
5027 
5028  if( bestsub > vlbconsts[i] )
5029  continue;
5030 
5031  /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5032  * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5033  */
5034  if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
5035  continue;
5036 
5037  /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
5038  probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
5039 
5040  /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5041  * ensures that the problem index is between 0 and nbinvars - 1
5042  */
5043  if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5044  continue;
5045 
5046  assert(SCIPvarIsBinary(vlbvars[i]));
5047 
5048  /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
5049  * (let a_j = coefficient of y_j in current row,
5050  * u_j = closest simple upper bound imposed on y_j,
5051  * c_i = coefficient of x_i in current row)
5052  * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
5053  * if a_j > 0:
5054  * 1. u_j <= d_i
5055  * 2. a_j ( u_j - d_i ) + c_i <= 0
5056  * 3. a_j l~_i + c_i <= 0
5057  * if a_j < 0:
5058  * 1. u_j <= d_i
5059  * 2. a_j ( u_j - d_i ) + c_i >= 0
5060  * 3. a_j l~_i + c_i >= 0
5061  */
5062 
5063  /* has already been used in the SNF relaxation */
5064  if( binvarused[probidxbinvar] == 1 )
5065  continue;
5066 
5067  /* get the row coefficient */
5068  {
5069  SCIP_Real QUAD(tmp);
5070  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
5071  rowcoefbinvar = QUAD_TO_DBL(tmp);
5072  }
5073  rowcoefsign = COPYSIGN(1.0, rowcoef);
5074 
5075  val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
5076 
5077  /* variable lower bound does not meet criteria */
5078  if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
5079  continue;
5080 
5081  val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
5082 
5083  /* variable lower bound does not meet criteria */
5084  if( val1 > 0.0 )
5085  continue;
5086 
5087  vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
5088  if( vlbsol > *closestvlb )
5089  {
5090  *closestvlb = vlbsol;
5091  *closestvlbidx = i;
5092  }
5093  assert(*closestvlbidx >= 0);
5094  }
5095  }
5096 
5097  return SCIP_OKAY;
5098 }
5099 
5100 /** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
5101  * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
5102  * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
5103  * given variable
5104  */
5105 static
5107  SCIP* scip, /**< SCIP data structure */
5108  SCIP_VAR* var, /**< given active problem variable */
5109  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5110  SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
5111  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5112  * was not used (0) or was not used but is contained in the row (-1)
5113  */
5114  SCIP_Real bestslb, /**< closest simple lower bound of given variable */
5115  SCIP_Real rowcoef, /**< coefficient of given variable in current row */
5116  SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
5117  int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
5118  )
5119 {
5120  int nvubs;
5121  int nbinvars;
5122 
5123  assert(scip != NULL);
5124  assert(var != NULL);
5125  assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
5126  assert(!SCIPisInfinity(scip, - bestslb));
5127  assert(!EPSZ(rowcoef, QUAD_EPSILON));
5128  assert(rowcoefs != NULL);
5129  assert(binvarused != NULL);
5130  assert(closestvub != NULL);
5131  assert(closestvubidx != NULL);
5132 
5133  nvubs = SCIPvarGetNVubs(var);
5134  nbinvars = SCIPgetNBinVars(scip);
5135 
5136  *closestvubidx = -1;
5137  *closestvub = SCIPinfinity(scip);
5138  if( nvubs > 0 )
5139  {
5140  SCIP_VAR** vubvars;
5141  SCIP_Real* vubcoefs;
5142  SCIP_Real* vubconsts;
5143  int i;
5144 
5145  vubvars = SCIPvarGetVubVars(var);
5146  vubcoefs = SCIPvarGetVubCoefs(var);
5147  vubconsts = SCIPvarGetVubConstants(var);
5148 
5149  for( i = 0; i < nvubs; i++ )
5150  {
5151  SCIP_Real rowcoefbinvar;
5152  SCIP_Real val1;
5153  SCIP_Real val2;
5154  SCIP_Real vubsol;
5155  SCIP_Real rowcoefsign;
5156  int probidxbinvar;
5157 
5158  if( bestslb < vubconsts[i] )
5159  continue;
5160 
5161  /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5162  * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5163  */
5164  if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
5165  continue;
5166 
5167  /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
5168  probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
5169 
5170  /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5171  * ensures that the problem index is between 0 and nbinvars - 1
5172  */
5173  if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5174  continue;
5175 
5176  assert(SCIPvarIsBinary(vubvars[i]));
5177 
5178  /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
5179  * (let a_j = coefficient of y_j in current row,
5180  * l_j = closest simple lower bound imposed on y_j,
5181  * c_i = coefficient of x_i in current row)
5182  * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
5183  * if a > 0:
5184  * 1. l_j >= d_i
5185  * 2. a_j ( l_i - d_i ) + c_i >= 0
5186  * 3. a_j u~_i + c_i >= 0
5187  * if a < 0:
5188  * 1. l_j >= d_i
5189  * 2. a_j ( l_j - d_i ) + c_i <= 0
5190  * 3. a_j u~_i + c_i <= 0
5191  */
5192 
5193  /* has already been used in the SNF relaxation */
5194  if( binvarused[probidxbinvar] == 1 )
5195  continue;
5196 
5197  /* get the row coefficient */
5198  {
5199  SCIP_Real QUAD(tmp);
5200  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
5201  rowcoefbinvar = QUAD_TO_DBL(tmp);
5202  }
5203  rowcoefsign = COPYSIGN(1.0, rowcoef);
5204 
5205  val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
5206 
5207  /* variable upper bound does not meet criteria */
5208  if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
5209  continue;
5210 
5211  val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
5212 
5213  /* variable upper bound does not meet criteria */
5214  if( val1 < 0.0 )
5215  continue;
5216 
5217  vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
5218  if( vubsol < *closestvub )
5219  {
5220  *closestvub = vubsol;
5221  *closestvubidx = i;
5222  }
5223  assert(*closestvubidx >= 0);
5224  }
5225  }
5226 
5227  return SCIP_OKAY;
5228 }
5229 
5230 /** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
5231  * the given row.
5232  */
5233 static
5235  SCIP* scip, /**< SCIP data structure */
5236  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5237  SCIP_VAR** vars, /**< array of problem variables */
5238  SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
5239  int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
5240  int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
5241  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5242  * was not used (0) or was not used but is contained in the row (-1)
5243  */
5244  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5245  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5246  SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
5247  SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
5248  SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
5249  SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
5250  int* bestlbtype, /**< pointer to store type of best lower bound */
5251  int* bestubtype, /**< pointer to store type of best upper bound */
5252  int* bestslbtype, /**< pointer to store type of best simple lower bound */
5253  int* bestsubtype, /**< pointer to store type of best simple upper bound */
5254  SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
5255  SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
5256  )
5257 {
5258  SCIP_VAR* var;
5259 
5260  SCIP_Real rowcoef;
5261  SCIP_Real solval;
5262 
5263  int probidx;
5264 
5265  bestlb[varposinrow] = -SCIPinfinity(scip);
5266  bestub[varposinrow] = SCIPinfinity(scip);
5267  bestlbtype[varposinrow] = -3;
5268  bestubtype[varposinrow] = -3;
5269 
5270  probidx = rowinds[varposinrow];
5271  var = vars[probidx];
5272  {
5273  SCIP_Real QUAD(tmp);
5274  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
5275  rowcoef = QUAD_TO_DBL(tmp);
5276  }
5277 
5278  assert(!EPSZ(rowcoef, QUAD_EPSILON));
5279 
5280  /* get closest simple lower bound and closest simple upper bound */
5281  SCIP_CALL( findBestLb(scip, var, sol, FALSE, allowlocal, &bestslb[varposinrow], &bestslbtype[varposinrow]) );
5282  SCIP_CALL( findBestUb(scip, var, sol, FALSE, allowlocal, &bestsub[varposinrow], &bestsubtype[varposinrow]) );
5283 
5284  /* do not use too large bounds */
5285  if( bestslb[varposinrow] <= -MAXBOUND )
5286  bestslb[varposinrow] = -SCIPinfinity(scip);
5287 
5288  if( bestsub[varposinrow] >= MAXBOUND )
5289  bestsub[varposinrow] = SCIPinfinity(scip);
5290 
5291  solval = SCIPgetSolVal(scip, sol, var);
5292 
5293  SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
5294  solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
5295 
5296  /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
5297  * and infinity, respectively
5298  */
5299  if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
5300  {
5301  *freevariable = TRUE;
5302  return SCIP_OKAY;
5303  }
5304 
5305  /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
5306  * relaxation
5307  */
5308  if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
5309  {
5310  bestlb[varposinrow] = bestslb[varposinrow];
5311  bestlbtype[varposinrow] = bestslbtype[varposinrow];
5312 
5314  {
5315  SCIP_Real bestvlb;
5316  int bestvlbidx;
5317 
5318  SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
5319  if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
5320  {
5321  bestlb[varposinrow] = bestvlb;
5322  bestlbtype[varposinrow] = bestvlbidx;
5323  }
5324  }
5325  }
5326 
5327  /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
5328  * relaxation
5329  */
5330  if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
5331  {
5332  bestub[varposinrow] = bestsub[varposinrow];
5333  bestubtype[varposinrow] = bestsubtype[varposinrow];
5334 
5336  {
5337  SCIP_Real bestvub;
5338  int bestvubidx;
5339 
5340  SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
5341  if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
5342  {
5343  bestub[varposinrow] = bestvub;
5344  bestubtype[varposinrow] = bestvubidx;
5345  }
5346  }
5347  }
5348  SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
5349 
5350  /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
5351  * to define the transformed variable y'_j
5352  */
5353  if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
5354  {
5355  *freevariable = TRUE;
5356  return SCIP_OKAY;
5357  }
5358 
5359  *freevariable = FALSE;
5360 
5361  /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
5362  * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
5363  * prefer variable bounds
5364  */
5365  if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
5366  {
5367  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5368  }
5369  else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
5370  && bestubtype[varposinrow] >= 0 )
5371  {
5372  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5373  }
5374  else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
5375  {
5376  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5377  }
5378  else
5379  {
5380  assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
5381  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5382  }
5383 
5384  if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
5385  {
5386  int vlbvarprobidx;
5387  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5388 
5389  /* mark binary variable of vlb so that it is not used for other continuous variables
5390  * by setting it's position in the aggrrow to a negative value
5391  */
5392  vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
5393  binvarused[vlbvarprobidx] = 1;
5394  }
5395  else if ( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
5396  {
5397  int vubvarprobidx;
5398  SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
5399 
5400  /* mark binary variable of vub so that it is not used for other continuous variables
5401  * by setting it's position in the aggrrow to a negative value
5402  */
5403  vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
5404  binvarused[vubvarprobidx] = 1;
5405  }
5406 
5407  return SCIP_OKAY;
5408 }
5409 
5410 /** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
5411  * corresponding to the given aggrrow a * x <= rhs
5412  */
5413 static
5415  SCIP* scip, /**< SCIP data structure */
5416  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5417  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5418  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5419  SCIP_Real* rowcoefs, /**< array of coefficients of row */
5420  QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
5421  int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
5422  int nnz, /**< number of non-zeros in row */
5423  SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
5424  SCIP_Bool* success, /**< stores whether the transformation was valid */
5425  SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5426  )
5427 {
5428  SCIP_VAR** vars;
5429  int i;
5430  int nnonbinvarsrow;
5431  int8_t* binvarused;
5432  int nbinvars;
5433  SCIP_Real QUAD(transrhs);
5434 
5435  /* arrays to store the selected bound for each non-binary variable in the row */
5436  SCIP_Real* bestlb;
5437  SCIP_Real* bestub;
5438  SCIP_Real* bestslb;
5439  SCIP_Real* bestsub;
5440  int* bestlbtype;
5441  int* bestubtype;
5442  int* bestslbtype;
5443  int* bestsubtype;
5444  SCIP_BOUNDTYPE* selectedbounds;
5445 
5446  *success = FALSE;
5447 
5448  SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
5449 
5450  nbinvars = SCIPgetNBinVars(scip);
5451  vars = SCIPgetVars(scip);
5452 
5453  SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
5454  SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
5455  SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
5456  SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
5457  SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
5458  SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
5459  SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
5460  SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
5461  SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
5462 
5463  /* sort descending to have continuous variables first */
5464  SCIPsortDownInt(rowinds, nnz);
5465 
5466  /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
5467  SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
5468 
5469  for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
5470  {
5471  int j = rowinds[i];
5472  binvarused[j] = -1;
5473  }
5474 
5475  nnonbinvarsrow = i + 1;
5476  /* determine the bounds to use for transforming the non-binary variables */
5477  for( i = 0; i < nnonbinvarsrow; ++i )
5478  {
5479  SCIP_Bool freevariable;
5480 
5481  assert(rowinds[i] >= nbinvars);
5482 
5483  SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
5484  bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
5485 
5486  if( freevariable )
5487  {
5488  int j;
5489 
5490  /* clear binvarused at indices of binary variables of row */
5491  for( j = nnz - 1; j >= nnonbinvarsrow; --j )
5492  binvarused[rowinds[j]] = 0;
5493 
5494  /* clear binvarused at indices of selected variable bounds */
5495  for( j = 0; j < i; ++j )
5496  {
5497  if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
5498  {
5499  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
5500  binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
5501  }
5502  else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
5503  {
5504  SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
5505  binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
5506  }
5507  }
5508 
5509  /* terminate */
5510  goto TERMINATE;
5511  }
5512  }
5513 
5514  *localbdsused = FALSE;
5515  QUAD_ASSIGN_Q(transrhs, rowrhs);
5516  snf->ntransvars = 0;
5517 
5518  /* transform non-binary variables */
5519  for( i = 0; i < nnonbinvarsrow; ++i )
5520  {
5521  SCIP_VAR* var;
5522  SCIP_Real QUAD(rowcoef);
5523  SCIP_Real solval;
5524  int probidx;
5525 
5526  probidx = rowinds[i];
5527  var = vars[probidx];
5528  QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5529  solval = SCIPgetSolVal(scip, sol, var);
5530 
5531  assert(probidx >= nbinvars);
5532 
5533  if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5534  {
5535  /* use bestlb to define y'_j */
5536 
5537  assert(!SCIPisInfinity(scip, bestsub[i]));
5538  assert(!SCIPisInfinity(scip, - bestlb[i]));
5539  assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
5540  assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
5541 
5542  /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
5543  * in the relaxed set
5544  */
5545  snf->origcontvars[snf->ntransvars] = probidx;
5546 
5547  if( bestlbtype[i] < 0 )
5548  {
5549  SCIP_Real QUAD(val);
5550  SCIP_Real QUAD(contsolval);
5551  SCIP_Real QUAD(rowcoeftimesbestsub);
5552 
5553  /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
5554  * y'_j = - a_j ( y_j - u_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
5555  * y'_j = a_j ( y_j - u_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
5556  * put j into the set
5557  * N2 if a_j > 0
5558  * N1 if a_j < 0
5559  * and update the right hand side of the constraint in the relaxation
5560  * rhs = rhs - a_j u_j
5561  */
5562  SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
5563  SCIPquadprecProdQQ(val, val, rowcoef);
5564  SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
5565  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5566 
5567  if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
5568  *localbdsused = TRUE;
5569 
5570  SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
5571 
5572  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5573  snf->origbinvars[snf->ntransvars] = -1;
5574  snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5575 
5576  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5577  {
5578  snf->transvarcoefs[snf->ntransvars] = - 1;
5579  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5580  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5581  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5582 
5583  /* aggregation information for y'_j */
5584  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
5585  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5586  }
5587  else
5588  {
5589  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5590  snf->transvarcoefs[snf->ntransvars] = 1;
5591  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5592  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5593  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5594 
5595  /* aggregation information for y'_j */
5596  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestsub);
5597  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5598  }
5599  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
5600 
5601  SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5602  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5603  snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub, QUAD_TO_DBL(transrhs));
5604  }
5605  else
5606  {
5607  SCIP_Real QUAD(rowcoefbinary);
5608  SCIP_Real varsolvalbinary;
5609  SCIP_Real QUAD(val);
5610  SCIP_Real QUAD(contsolval);
5611  SCIP_Real QUAD(rowcoeftimesvlbconst);
5612  int vlbvarprobidx;
5613 
5614  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5615  SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
5616  SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
5617 
5618  /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
5619  * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j l~_j + c_j ) x_j if a_j > 0
5620  * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j l~_j + c_j ) x_j if a_j < 0,
5621  * where c_j is the coefficient of x_j in the row, put j into the set
5622  * N2 if a_j > 0
5623  * N1 if a_j < 0
5624  * and update the right hand side of the constraint in the relaxation
5625  * rhs = rhs - a_j d_j
5626  */
5627 
5628  vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
5629  assert(binvarused[vlbvarprobidx] == 1);
5630  assert(vlbvarprobidx < nbinvars);
5631 
5632  QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
5633  varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
5634 
5635  SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
5636  SCIPquadprecSumQQ(val, val, rowcoefbinary);
5637  {
5638  SCIP_Real QUAD(tmp);
5639 
5640  SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
5641  SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
5642  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5643  SCIPquadprecSumQQ(contsolval, contsolval, tmp);
5644  }
5645 
5646  SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
5647 
5648  /* clear the binvarpos array, since the variable has been processed */
5649  binvarused[vlbvarprobidx] = 0;
5650 
5651  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5652  snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
5653 
5654  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5655  {
5656  snf->transvarcoefs[snf->ntransvars] = - 1;
5657  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5658  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5659  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5660 
5661  /* aggregation information for y'_j */
5662  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5663  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5664  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
5665  }
5666  else
5667  {
5668  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5669  snf->transvarcoefs[snf->ntransvars] = 1;
5670  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5671  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5672  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5673 
5674  /* aggregation information for y'_j */
5675  snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5676  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5677  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
5678  }
5679  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
5680 
5681  SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5682  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5683  snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
5684  vlbconsts[bestlbtype[i]], snf->transrhs );
5685  }
5686  }
5687  else
5688  {
5689  /* use bestub to define y'_j */
5690 
5691  assert(!SCIPisInfinity(scip, bestub[i]));
5692  assert(!SCIPisInfinity(scip, - bestslb[i]));
5693  assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
5694  assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
5695 
5696  /* store for y_j that y'_j is the associated real variable
5697  * in the relaxed set
5698  */
5699  snf->origcontvars[snf->ntransvars] = probidx;
5700 
5701  if( bestubtype[i] < 0 )
5702  {
5703  SCIP_Real QUAD(val);
5704  SCIP_Real QUAD(contsolval);
5705  SCIP_Real QUAD(rowcoeftimesbestslb);
5706 
5707  /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
5708  * y'_j = a_j ( y_j - l_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
5709  * y'_j = - a_j ( y_j - l_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
5710  * put j into the set
5711  * N1 if a_j > 0
5712  * N2 if a_j < 0
5713  * and update the right hand side of the constraint in the relaxation
5714  * rhs = rhs - a_j l_j
5715  */
5716  SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
5717  SCIPquadprecProdQQ(val, val, rowcoef);
5718  SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
5719  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5720 
5721  if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
5722  *localbdsused = TRUE;
5723 
5724  SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
5725 
5726  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5727  snf->origbinvars[snf->ntransvars] = -1;
5728  snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5729 
5730  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5731  {
5732  snf->transvarcoefs[snf->ntransvars] = 1;
5733  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5734  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5735  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5736 
5737  /* aggregation information for y'_j */
5738  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5739  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
5740  }
5741  else
5742  {
5743  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5744  snf->transvarcoefs[snf->ntransvars] = - 1;
5745  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5746  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5747  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5748 
5749  /* aggregation information for y'_j */
5750  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5751  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestslb);
5752  }
5753  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestslb);
5754 
5755  SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., Y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5756  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5757  snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestslb), QUAD_TO_DBL(rowcoef), bestslb[i], QUAD_TO_DBL(transrhs));
5758  }
5759  else
5760  {
5761  SCIP_Real QUAD(rowcoefbinary);
5762  SCIP_Real varsolvalbinary;
5763  SCIP_Real QUAD(val);
5764  SCIP_Real QUAD(contsolval);
5765  SCIP_Real QUAD(rowcoeftimesvubconst);
5766  int vubvarprobidx;
5767 
5768  SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
5769  SCIP_Real* vubconsts = SCIPvarGetVubConstants(var);
5770  SCIP_Real* vubcoefs = SCIPvarGetVubCoefs(var);
5771 
5772  /* use variable upper bound in bestslb = l_j <= y_j <= u~_j x_j + d_j = bestub to define
5773  * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j u~_j + c_j ) x_j if a_j > 0
5774  * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j u~_j + c_j ) x_j if a_j < 0,
5775  * where c_j is the coefficient of x_j in the row, put j into the set
5776  * N1 if a_j > 0
5777  * N2 if a_j < 0
5778  * and update the right hand side of the constraint in the relaxation
5779  * rhs = rhs - a_j d_j
5780  */
5781 
5782  vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[i]]);
5783  assert(binvarused[vubvarprobidx] == 1);
5784  assert(vubvarprobidx < nbinvars);
5785 
5786  QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vubvarprobidx);
5787  varsolvalbinary = SCIPgetSolVal(scip, sol, vubvars[bestubtype[i]]);
5788 
5789  /* clear the binvarpos array, since the variable has been processed */
5790  binvarused[vubvarprobidx] = 0;
5791 
5792  SCIPquadprecProdQD(val, rowcoef, vubcoefs[bestubtype[i]]);
5793  SCIPquadprecSumQQ(val, val, rowcoefbinary);
5794  {
5795  SCIP_Real QUAD(tmp);
5796  SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
5797  SCIPquadprecSumDD(contsolval, solval, - vubconsts[bestubtype[i]]);
5798  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5799  SCIPquadprecSumQQ(contsolval, contsolval, tmp);
5800  }
5801 
5802  SCIPquadprecProdQD(rowcoeftimesvubconst, rowcoef, vubconsts[bestubtype[i]]);
5803  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5804  snf->origbinvars[snf->ntransvars] = vubvarprobidx;
5805 
5806  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5807  {
5808  snf->transvarcoefs[snf->ntransvars] = 1;
5809  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5810  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5811  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5812 
5813  /* aggregation information for y'_j */
5814  snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5815  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5816  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvubconst);
5817  }
5818  else
5819  {
5820  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5821  snf->transvarcoefs[snf->ntransvars] = - 1;
5822  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5823  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5824  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5825 
5826  /* aggregation information for y'_j */
5827  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5828  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5829  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
5830  }
5831  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
5832 
5833  /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
5834 
5835  SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5836  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5837  snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
5838  vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
5839  }
5840  }
5841 
5842  /* make sure the coefficient is not negative due to small numerical rounding errors */
5843  assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
5844  snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
5845 
5846  ++snf->ntransvars;
5847  }
5848 
5849  snf->transrhs = QUAD_TO_DBL(transrhs);
5850 
5851  /* transform remaining binary variables of row */
5852  for( i = nnonbinvarsrow; i < nnz; ++i )
5853  {
5854  SCIP_VAR* var;
5855  SCIP_Real QUAD(rowcoef);
5856  int probidx;
5857  SCIP_Real val;
5858  SCIP_Real contsolval;
5859  SCIP_Real varsolval;
5860 
5861  probidx = rowinds[i];
5862  /* variable should be binary */
5863  assert(probidx < nbinvars);
5864 
5865  /* binary variable was processed together with a non-binary variable */
5866  if( binvarused[probidx] == 0 )
5867  continue;
5868 
5869  /* binary variable was not processed yet, so the binvarused value sould be -1 */
5870  assert(binvarused[probidx] == -1);
5871 
5872  /* set binvarused to zero since it has been processed */
5873  binvarused[probidx] = 0;
5874 
5875  var = vars[probidx];
5876  QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5877 
5878  assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
5879 
5880  varsolval = SCIPgetSolVal(scip, sol, var);
5881  SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
5883 
5884  /* define
5885  * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
5886  * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
5887  * where c_j is the coefficient of x_j in the row and put j into the set
5888  * N1 if c_j > 0
5889  * N2 if c_j < 0.
5890  */
5891  val = QUAD_TO_DBL(rowcoef);
5892  contsolval = QUAD_TO_DBL(rowcoef) * varsolval;
5893 
5894  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5895  snf->origbinvars[snf->ntransvars] = probidx;
5896  snf->origcontvars[snf->ntransvars] = -1;
5897  snf->aggrcoefscont[snf->ntransvars] = 0.0;
5898  snf->aggrconstants[snf->ntransvars] = 0.0;
5899 
5900  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5901  {
5902  snf->transvarcoefs[snf->ntransvars] = 1;
5903  snf->transvarvubcoefs[snf->ntransvars] = val;
5904  snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5905  snf->transcontvarsolvals[snf->ntransvars] = contsolval;
5906 
5907  /* aggregation information for y'_j */
5908  snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5909  }
5910  else
5911  {
5912  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5913  snf->transvarcoefs[snf->ntransvars] = - 1;
5914  snf->transvarvubcoefs[snf->ntransvars] = - val;
5915  snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5916  snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
5917 
5918  /* aggregation information for y'_j */
5919  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5920  }
5921 
5922  assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
5923  assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[snf->ntransvars], 0.0)
5924  && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
5925  assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[snf->ntransvars], 0.0)
5926  && !SCIPisInfinity(scip, snf->transvarvubcoefs[snf->ntransvars]));
5927 
5928  SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
5929  snf->transvarvubcoefs[snf->ntransvars], snf->ntransvars, SCIPvarGetName(var) );
5930 
5931  /* updates number of variables in transformed problem */
5932  snf->ntransvars++;
5933  }
5934 
5935  /* construction was successful */
5936  *success = TRUE;
5937 
5938 #ifdef SCIP_DEBUG
5939  SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
5940  for( i = 0; i < snf->ntransvars; i++ )
5941  {
5942  SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
5943  }
5944  SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
5945 #endif
5946 
5947  TERMINATE:
5948 
5949  SCIPfreeCleanBufferArray(scip, &binvarused);
5950  SCIPfreeBufferArray(scip, &selectedbounds);
5951  SCIPfreeBufferArray(scip, &bestsubtype);
5952  SCIPfreeBufferArray(scip, &bestslbtype);
5953  SCIPfreeBufferArray(scip, &bestubtype);
5954  SCIPfreeBufferArray(scip, &bestlbtype);
5955  SCIPfreeBufferArray(scip, &bestsub);
5956  SCIPfreeBufferArray(scip, &bestslb);
5957  SCIPfreeBufferArray(scip, &bestub);
5958  SCIPfreeBufferArray(scip, &bestlb);
5959 
5960  return SCIP_OKAY;
5961 }
5962 
5963 /** allocate buffer arrays for storing the single-node-flow relaxation */
5964 static
5966  SCIP* scip, /**< SCIP data structure */
5967  SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
5968  int nvars /**< number of active problem variables */
5969  )
5970 {
5971  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transvarcoefs, nvars) );
5972  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transbinvarsolvals, nvars) );
5973  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transcontvarsolvals, nvars) );
5974  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transvarvubcoefs, nvars) );
5975  SCIP_CALL( SCIPallocBufferArray(scip, &snf->origbinvars, nvars) );
5976  SCIP_CALL( SCIPallocBufferArray(scip, &snf->origcontvars, nvars) );
5977  SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrcoefsbin, nvars) );
5978  SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrcoefscont, nvars) );
5979  SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrconstants, nvars) );
5980 
5981  return SCIP_OKAY;
5982 }
5983 
5984 /** free buffer arrays for storing the single-node-flow relaxation */
5985 static
5987  SCIP* scip, /**< SCIP data structure */
5988  SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
5989  )
5990 {
5991  SCIPfreeBufferArray(scip, &snf->aggrconstants);
5992  SCIPfreeBufferArray(scip, &snf->aggrcoefscont);
5993  SCIPfreeBufferArray(scip, &snf->aggrcoefsbin);
5994  SCIPfreeBufferArray(scip, &snf->origcontvars);
5995  SCIPfreeBufferArray(scip, &snf->origbinvars);
5999  SCIPfreeBufferArray(scip, &snf->transvarcoefs);
6000 }
6001 
6002 /** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
6003  * arrays to store all selected items and all not selected items
6004  */
6005 static
6007  SCIP* scip, /**< SCIP data structure */
6008  int nitems, /**< number of available items */
6009  SCIP_Real* weights, /**< item weights */
6010  SCIP_Real* profits, /**< item profits */
6011  SCIP_Real capacity, /**< capacity of knapsack */
6012  int* items, /**< item numbers */
6013  int* solitems, /**< array to store items in solution, or NULL */
6014  int* nonsolitems, /**< array to store items not in solution, or NULL */
6015  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
6016  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
6017  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
6018  )
6019 {
6020  SCIP_Real* tempsort;
6021  SCIP_Real solitemsweight;
6022  SCIP_Real mediancapacity;
6023  int j;
6024  int i;
6025  int criticalitem;
6026 
6027  assert(weights != NULL);
6028  assert(profits != NULL);
6029  assert(SCIPisFeasGE(scip, capacity, 0.0));
6030  assert(!SCIPisInfinity(scip, capacity));
6031  assert(items != NULL);
6032  assert(nitems >= 0);
6033 
6034  if( solitems != NULL )
6035  {
6036  *nsolitems = 0;
6037  *nnonsolitems = 0;
6038  }
6039  if( solval != NULL )
6040  *solval = 0.0;
6041 
6042  /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
6043  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
6044 
6045  /* initialize temporary array */
6046  for( i = nitems - 1; i >= 0; --i )
6047  tempsort[i] = profits[i] / weights[i];
6048 
6049  /* decrease capacity slightly to make it tighter than the original capacity */
6050  mediancapacity = capacity * (1 - SCIPfeastol(scip));
6051 
6052  /* rearrange items around */
6053  SCIPselectWeightedDownRealRealInt(tempsort, profits, items, weights, mediancapacity, nitems, &criticalitem);
6054 
6055  /* free temporary array */
6056  SCIPfreeBufferArray(scip, &tempsort);
6057 
6058  /* select items as long as they fit into the knapsack */
6059  solitemsweight = 0.0;
6060  for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
6061  {
6062  if( solitems != NULL )
6063  {
6064  solitems[*nsolitems] = items[j];
6065  (*nsolitems)++;
6066  }
6067  if( solval != NULL )
6068  (*solval) += profits[j];
6069  solitemsweight += weights[j];
6070  }
6071 
6072  /* continue to put items into the knapsack if they entirely fit */
6073  for( ; j < nitems; j++ )
6074  {
6075  if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
6076  {
6077  if( solitems != NULL )
6078  {
6079  solitems[*nsolitems] = items[j];
6080  (*nsolitems)++;
6081  }
6082  if( solval != NULL )
6083  (*solval) += profits[j];
6084  solitemsweight += weights[j];
6085  }
6086  else if( solitems != NULL )
6087  {
6088  nonsolitems[*nnonsolitems] = items[j];
6089  (*nnonsolitems)++;
6090  }
6091  }
6092 
6093  return SCIP_OKAY;
6094 }
6095 
6096 
6097 /** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
6098  * flow cover contains variables which have been fixed in advance
6099  */
6100 static
6102  SCIP* scip, /**< SCIP data structure */
6103  int* coefs, /**< coefficient of all real variables in N1&N2 */
6104  SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
6105  SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
6106  int* solitems, /**< items in knapsack */
6107  int* nonsolitems, /**< items not in knapsack */
6108  int nsolitems, /**< number of items in knapsack */
6109  int nnonsolitems, /**< number of items not in knapsack */
6110  int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6111  int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6112  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6113  QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
6114  SCIP_Real* lambda /**< pointer to store lambda */
6115  )
6116 {
6117  int j;
6118  SCIP_Real QUAD(tmp);
6119 
6120  assert(scip != NULL);
6121  assert(coefs != NULL);
6122  assert(vubcoefs != NULL);
6123  assert(solitems != NULL);
6124  assert(nonsolitems != NULL);
6125  assert(nsolitems >= 0);
6126  assert(nnonsolitems >= 0);
6127  assert(nflowcovervars != NULL && *nflowcovervars >= 0);
6128  assert(nnonflowcovervars != NULL && *nnonflowcovervars >= 0);
6129  assert(flowcoverstatus != NULL);
6130  assert(QUAD_HI(flowcoverweight) != NULL);
6131  assert(lambda != NULL);
6132 
6133  /* get flowcover status for each item */
6134  for( j = 0; j < nsolitems; j++ )
6135  {
6136  /* j in N1 with z°_j = 1 => j in N1\C1 */
6137  if( coefs[solitems[j]] == 1 )
6138  {
6139  flowcoverstatus[solitems[j]] = -1;
6140  (*nnonflowcovervars)++;
6141  }
6142  /* j in N2 with z_j = 1 => j in C2 */
6143  else
6144  {
6145  assert(coefs[solitems[j]] == -1);
6146  flowcoverstatus[solitems[j]] = 1;
6147  (*nflowcovervars)++;
6148  SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, -vubcoefs[solitems[j]]);
6149  }
6150  }
6151  for( j = 0; j < nnonsolitems; j++ )
6152  {
6153  /* j in N1 with z°_j = 0 => j in C1 */
6154  if( coefs[nonsolitems[j]] == 1 )
6155  {
6156  flowcoverstatus[nonsolitems[j]] = 1;
6157  (*nflowcovervars)++;
6158  SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, vubcoefs[nonsolitems[j]]);
6159  }
6160  /* j in N2 with z_j = 0 => j in N2\C2 */
6161  else
6162  {
6163  assert(coefs[nonsolitems[j]] == -1);
6164  flowcoverstatus[nonsolitems[j]] = -1;
6165  (*nnonflowcovervars)++;
6166  }
6167  }
6168 
6169  /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6170  SCIPquadprecSumQD(tmp, *flowcoverweight, -rhs);
6171  *lambda = QUAD_TO_DBL(tmp);
6172 }
6173 
6174 #ifndef NO_EXACT_KNAPSACK
6175 
6176 /** checks, whether the given scalar scales the given value to an integral number with error in the given bounds */
6177 static
6179  SCIP_Real val, /**< value that should be scaled to an integral value */
6180  SCIP_Real scalar, /**< scalar that should be tried */
6181  SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6182  SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6183  )
6184 {
6185  SCIP_Real sval;
6186  SCIP_Real downval;
6187  SCIP_Real upval;
6188 
6189  assert(mindelta <= 0.0);
6190  assert(maxdelta >= 0.0);
6191 
6192  sval = val * scalar;
6193  downval = floor(sval);
6194  upval = ceil(sval);
6195 
6196  return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
6197 }
6198 
6199 /** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
6200  * should be used in connection with isIntegralScalar()
6201  */
6202 static
6204  SCIP_Real val, /**< value that should be scaled to an integral value */
6205  SCIP_Real scalar, /**< scalar that should be tried */
6206  SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6207  SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6208  )
6209 {
6210  SCIP_Real sval;
6211  SCIP_Real upval;
6212  SCIP_Longint intval;
6213 
6214  assert(mindelta <= 0.0);
6215  assert(maxdelta >= 0.0);
6216 
6217  sval = val * scalar;
6218  upval = ceil(sval);
6219 
6220  if( SCIPrelDiff(sval, upval) >= mindelta )
6221  intval = (SCIP_Longint) upval;
6222  else
6223  intval = (SCIP_Longint) (floor(sval));
6224 
6225  return intval;
6226 }
6227 
6228 /** get a flow cover (C1, C2) for a given 0-1 single node flow set
6229  * {(x,y) in {0,1}^n x R^n : sum_{j in N1} y_j - sum_{j in N2} y_j <= b, 0 <= y_j <= u_j x_j},
6230  * i.e., get sets C1 subset N1 and C2 subset N2 with sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda and lambda > 0
6231  */
6232 static
6234  SCIP* scip, /**< SCIP data structure */
6235  SNF_RELAXATION* snf, /**< the single node flow relaxation */
6236  int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6237  int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6238  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6239  SCIP_Real* lambda, /**< pointer to store lambda */
6240  SCIP_Bool* found /**< pointer to store whether a cover was found */
6241  )
6242 {
6243  SCIP_Real* transprofitsint;
6244  SCIP_Real* transprofitsreal;
6245  SCIP_Real* transweightsreal;
6246  SCIP_Longint* transweightsint;
6247  int* items;
6248  int* itemsint;
6249  int* nonsolitems;
6250  int* solitems;
6251  SCIP_Real QUAD(flowcoverweight);
6252  SCIP_Real QUAD(flowcoverweightafterfix);
6253  SCIP_Real n1itemsweight;
6254  SCIP_Real n2itemsminweight;
6255  SCIP_Real scalar;
6256  SCIP_Real transcapacityreal;
6257 #if !defined(NDEBUG) || defined(SCIP_DEBUG)
6258  SCIP_Bool kpexact;
6259 #endif
6260  SCIP_Bool scalesuccess;
6261  SCIP_Bool transweightsrealintegral;
6262  SCIP_Longint transcapacityint;
6263  int nflowcovervarsafterfix;
6264  int nitems;
6265  int nn1items;
6266  int nnonflowcovervarsafterfix;
6267  int nnonsolitems;
6268  int nsolitems;
6269  int j;
6270 
6271  assert(scip != NULL);
6272  assert(snf->transvarcoefs != NULL);
6273  assert(snf->transbinvarsolvals != NULL);
6274  assert(snf->transvarvubcoefs != NULL);
6275  assert(snf->ntransvars > 0);
6276  assert(nflowcovervars != NULL);
6277  assert(nnonflowcovervars != NULL);
6278  assert(flowcoverstatus != NULL);
6279  assert(lambda != NULL);
6280  assert(found != NULL);
6281 
6282  SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6283 
6284  /* get data structures */
6285  SCIP_CALL( SCIPallocBufferArray(scip, &items, snf->ntransvars) );
6286  SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6287  SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
6288  SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsint, snf->ntransvars) );
6289  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
6290  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
6291  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6292  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
6293 
6294  BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
6295  *found = FALSE;
6296  *nflowcovervars = 0;
6297  *nnonflowcovervars = 0;
6298 
6299  QUAD_ASSIGN(flowcoverweight, 0.0);
6300  nflowcovervarsafterfix = 0;
6301  nnonflowcovervarsafterfix = 0;
6302  QUAD_ASSIGN(flowcoverweightafterfix, 0.0);
6303 #if !defined(NDEBUG) || defined(SCIP_DEBUG)
6304  kpexact = FALSE;
6305 #endif
6306 
6307  /* fix some variables in advance according to the following fixing strategy
6308  * put j into N1\C1, if j in N1 and x*_j = 0,
6309  * put j into C1, if j in N1 and x*_j = 1,
6310  * put j into C2, if j in N2 and x*_j = 1,
6311  * put j into N2\C2, if j in N2 and x*_j = 0
6312  * and get the set of the remaining variables
6313  */
6314  SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6315  nitems = 0;
6316  nn1items = 0;
6317  n1itemsweight = 0.0;
6318  n2itemsminweight = SCIP_REAL_MAX;
6319  for( j = 0; j < snf->ntransvars; j++ )
6320  {
6321  assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6322  assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6323  assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6324 
6325  /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6326  if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6327  {
6328  flowcoverstatus[j] = -1;
6329  (*nnonflowcovervars)++;
6330  continue;
6331  }
6332 
6333  /* x*_j is fractional */
6334  if( !SCIPisFeasIntegral(scip, snf->transbinvarsolvals[j]) )
6335  {
6336  items[nitems] = j;
6337  nitems++;
6338  if( snf->transvarcoefs[j] == 1 )
6339  {
6340  n1itemsweight += snf->transvarvubcoefs[j];
6341  nn1items++;
6342  }
6343  else
6344  n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6345  }
6346  /* j is in N1 and x*_j = 0 */
6347  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6348  {
6349  flowcoverstatus[j] = -1;
6350  (*nnonflowcovervars)++;
6351  SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6352  }
6353  /* j is in N1 and x*_j = 1 */
6354  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6355  {
6356  flowcoverstatus[j] = 1;
6357  (*nflowcovervars)++;
6358  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
6359  SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6360  }
6361  /* j is in N2 and x*_j = 1 */
6362  else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6363  {
6364  flowcoverstatus[j] = 1;
6365  (*nflowcovervars)++;
6366  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6367  SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6368  }
6369  /* j is in N2 and x*_j = 0 */
6370  else
6371  {
6372  assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6373  flowcoverstatus[j] = -1;
6374  (*nnonflowcovervars)++;
6375  SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6376  }
6377  }
6378  assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6379  assert(nn1items >= 0);
6380 
6381  /* to find a flow cover, transform the following knapsack problem
6382  *
6383  * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6384  * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6385  * z_j in {0,1} for all j in N1 & N2
6386  *
6387  * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6388  * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6389  *
6390  * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6391  * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6392  * z°_j in {0,1} for all j in N1
6393  * z_j in {0,1} for all j in N2,
6394  * and solve it approximately under consideration of the fixing,
6395  * or
6396  * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6397  * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6398  * and multiplying the constraint by a suitable scalar C
6399  *
6400  * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6401  * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6402  * z°_j in {0,1} for all j in N1
6403  * z_j in {0,1} for all j in N2,
6404  * where
6405  * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6406  * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6407  * and solve it exactly under consideration of the fixing.
6408  */
6409  SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6410 
6411  /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6412  transweightsrealintegral = TRUE;
6413  for( j = 0; j < nitems; j++ )
6414  {
6415  transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6416 
6417  if( !isIntegralScalar(transweightsreal[j], 1.0, -MINDELTA, MAXDELTA) )
6418  transweightsrealintegral = FALSE;
6419 
6420  if( snf->transvarcoefs[items[j]] == 1 )
6421  {
6422  transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6423  SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6424  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6425  }
6426  else
6427  {
6428  transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6429  SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6430  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6431  }
6432  }
6433  /* get capacity of knapsack constraint in KP^SNF_rat */
6434  transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
6435  SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6436  snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
6437 
6438  /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6439  * is less than or equal to zero
6440  */
6441  if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6442  {
6443  assert(!(*found));
6444  goto TERMINATE;
6445  }
6446 
6447  /* KP^SNF_rat has been solved by fixing some variables in advance */
6448  assert(nitems >= 0);
6449  if( nitems == 0)
6450  {
6451  /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6452  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
6453  *lambda = QUAD_TO_DBL(flowcoverweight);
6454  *found = TRUE;
6455  goto TERMINATE;
6456  }
6457 
6458  /* Use the following strategy
6459  * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
6460  * solve KP^SNF_rat approximately, otherwise
6461  */
6462 
6463  /* find a scaling factor C */
6464  if( transweightsrealintegral )
6465  {
6466  /* weights are already integral */
6467  scalar = 1.0;
6468  scalesuccess = TRUE;
6469  }
6470  else
6471  {
6472  scalesuccess = FALSE;
6473  SCIP_CALL( SCIPcalcIntegralScalar(transweightsreal, nitems, -MINDELTA, MAXDELTA, MAXDNOM, MAXSCALE, &scalar,
6474  &scalesuccess) );
6475  }
6476 
6477  /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6478  nsolitems = -1;
6479  nnonsolitems = -1;
6480 
6481  /* suitable factor C was found*/
6482  if( scalesuccess )
6483  {
6484  SCIP_Real tmp1;
6485  SCIP_Real tmp2;
6486 
6487  /* transform KP^SNF to KP^SNF_int */
6488  for( j = 0; j < nitems; ++j )
6489  {
6490  transweightsint[j] = getIntegralVal(transweightsreal[j], scalar, -MINDELTA, MAXDELTA);
6491  transprofitsint[j] = transprofitsreal[j];
6492  itemsint[j] = items[j];
6493  }
6494  if( isIntegralScalar(transcapacityreal, scalar, -MINDELTA, MAXDELTA) )
6495  {
6496  transcapacityint = getIntegralVal(transcapacityreal, scalar, -MINDELTA, MAXDELTA);
6497  transcapacityint -= 1;
6498  }
6499  else
6500  transcapacityint = (SCIP_Longint) (transcapacityreal * scalar);
6501  nflowcovervarsafterfix = *nflowcovervars;
6502  nnonflowcovervarsafterfix = *nnonflowcovervars;
6503  QUAD_ASSIGN_Q(flowcoverweightafterfix, flowcoverweight);
6504 
6505  tmp1 = (SCIP_Real) (nitems + 1);
6506  tmp2 = (SCIP_Real) ((transcapacityint) + 1);
6507  if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
6508  {
6509  SCIP_Bool success;
6510 
6511  /* solve KP^SNF_int by dynamic programming */
6512  SCIP_CALL(SCIPsolveKnapsackExactly(scip, nitems, transweightsint, transprofitsint, transcapacityint,
6513  itemsint, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL, &success));
6514 
6515  if( !success )
6516  {
6517  /* solve KP^SNF_rat approximately */
6518  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal,
6519  transcapacityreal, items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6520  }
6521 #if !defined(NDEBUG) || defined(SCIP_DEBUG)
6522  else
6523  kpexact = TRUE;
6524 #endif
6525  }
6526  else
6527  {
6528  /* solve KP^SNF_rat approximately */
6529  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6530  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6531  assert(!kpexact);
6532  }
6533  }
6534  else
6535  {
6536  /* solve KP^SNF_rat approximately */
6537  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6538  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6539  assert(!kpexact);
6540  }
6541 
6542  assert(nsolitems != -1);
6543  assert(nnonsolitems != -1);
6544 
6545  /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6546  assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6547  buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6548  nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6549  assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6550 
6551  /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
6552  if( SCIPisFeasLE(scip, *lambda, 0.0) )
6553  {
6554  assert(kpexact);
6555 
6556  /* solve KP^SNF_rat approximately */
6557  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6558  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6559 #ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
6560  kpexact = FALSE;
6561 #endif
6562 
6563  /* build the flow cover from the solution of KP^SNF_rat and the fixing */
6564  *nflowcovervars = nflowcovervarsafterfix;
6565  *nnonflowcovervars = nnonflowcovervarsafterfix;
6566  QUAD_ASSIGN_Q(flowcoverweight, flowcoverweightafterfix);
6567 
6568  assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6569  buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6570  nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6571  assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6572  }
6573  *found = SCIPisFeasGT(scip, *lambda, 0.0);
6574 
6575  TERMINATE:
6576  assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6577 #ifdef SCIP_DEBUG
6578  if( *found )
6579  {
6580  SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
6581  for( j = 0; j < snf->ntransvars; j++ )
6582  {
6583  if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6584  {
6585  SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6586  }
6587  else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6588  {
6589  SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6590  }
6591  }
6592  SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6593  }
6594 #endif
6595 
6596  /* free data structures */
6597  SCIPfreeBufferArray(scip, &nonsolitems);
6598  SCIPfreeBufferArray(scip, &solitems);
6599  SCIPfreeBufferArray(scip, &transweightsint);
6600  SCIPfreeBufferArray(scip, &transweightsreal);
6601  SCIPfreeBufferArray(scip, &transprofitsint);
6602  SCIPfreeBufferArray(scip, &transprofitsreal);
6603  SCIPfreeBufferArray(scip, &itemsint);
6604  SCIPfreeBufferArray(scip, &items);
6605 
6606  return SCIP_OKAY;
6607 }
6608 
6609 #else
6610 
6611 /** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
6612  * \f${(x,y) in {0,1}^n x R^n : sum_{j in N1} y_j - sum_{j in N2} y_j <= b, 0 <= y_j <= u_j x_j}\f$,
6613  * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
6614  * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
6615  */
6616 static
6618  SCIP* scip, /**< SCIP data structure */
6619  SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
6620  int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6621  int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6622  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6623  SCIP_Real* lambda, /**< pointer to store lambda */
6624  SCIP_Bool* found /**< pointer to store whether a cover was found */
6625  )
6626 {
6627  SCIP_Real* transprofitsreal;
6628  SCIP_Real* transweightsreal;
6629  SCIP_Longint* transweightsint;
6630  int* items;
6631  int* itemsint;
6632  int* nonsolitems;
6633  int* solitems;
6634  SCIP_Real QUAD(flowcoverweight);
6635  SCIP_Real n1itemsweight;
6636  SCIP_Real n2itemsminweight;
6637  SCIP_Real transcapacityreal;
6638  int nitems;
6639  int nn1items;
6640  int nnonsolitems;
6641  int nsolitems;
6642  int j;
6643 
6644  assert(scip != NULL);
6645  assert(snf->transvarcoefs != NULL);
6646  assert(snf->transbinvarsolvals != NULL);
6647  assert(snf->transvarvubcoefs != NULL);
6648  assert(snf->ntransvars > 0);
6649  assert(nflowcovervars != NULL);
6650  assert(nnonflowcovervars != NULL);
6651  assert(flowcoverstatus != NULL);
6652  assert(lambda != NULL);
6653  assert(found != NULL);
6654 
6655  SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6656 
6657  /* get data structures */
6658  SCIP_CALL( SCIPallocBufferArray(scip, &items, snf->ntransvars) );
6659  SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6660  SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
6661  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
6662  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
6663  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6664  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
6665 
6666  BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
6667  *found = FALSE;
6668  *nflowcovervars = 0;
6669  *nnonflowcovervars = 0;
6670 
6671  QUAD_ASSIGN(flowcoverweight, 0.0);
6672 
6673  /* fix some variables in advance according to the following fixing strategy
6674  * put j into N1\C1, if j in N1 and x*_j = 0,
6675  * put j into C1, if j in N1 and x*_j = 1,
6676  * put j into C2, if j in N2 and x*_j = 1,
6677  * put j into N2\C2, if j in N2 and x*_j = 0
6678  * and get the set of the remaining variables
6679  */
6680  SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6681  nitems = 0;
6682  nn1items = 0;
6683  n1itemsweight = 0.0;
6684  n2itemsminweight = SCIP_REAL_MAX;
6685  for( j = 0; j < snf->ntransvars; j++ )
6686  {
6687  assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6688  assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6689  assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6690 
6691  /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6692  if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6693  {
6694  flowcoverstatus[j] = -1;
6695  (*nnonflowcovervars)++;
6696  continue;
6697  }
6698 
6699  /* x*_j is fractional */
6700  if( !SCIPisFeasIntegral(scip, snf->transbinvarsolvals[j]) )
6701  {
6702  items[nitems] = j;
6703  nitems++;
6704  if( snf->transvarcoefs[j] == 1 )
6705  {
6706  n1itemsweight += snf->transvarvubcoefs[j];
6707  nn1items++;
6708  }
6709  else
6710  n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6711  }
6712  /* j is in N1 and x*_j = 0 */
6713  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6714  {
6715  flowcoverstatus[j] = -1;
6716  (*nnonflowcovervars)++;
6717  SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6718  }
6719  /* j is in N1 and x*_j = 1 */
6720  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6721  {
6722  flowcoverstatus[j] = 1;
6723  (*nflowcovervars)++;
6724  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
6725  SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6726  }
6727  /* j is in N2 and x*_j = 1 */
6728  else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6729  {
6730  flowcoverstatus[j] = 1;
6731  (*nflowcovervars)++;
6732  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6733  SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6734  }
6735  /* j is in N2 and x*_j = 0 */
6736  else
6737  {
6738  assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6739  flowcoverstatus[j] = -1;
6740  (*nnonflowcovervars)++;
6741  SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6742  }
6743  }
6744  assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6745  assert(nn1items >= 0);
6746 
6747  /* to find a flow cover, transform the following knapsack problem
6748  *
6749  * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6750  * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6751  * z_j in {0,1} for all j in N1 & N2
6752  *
6753  * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6754  * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6755  *
6756  * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6757  * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6758  * z°_j in {0,1} for all j in N1
6759  * z_j in {0,1} for all j in N2,
6760  * and solve it approximately under consideration of the fixing,
6761  * or
6762  * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6763  * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6764  * and multiplying the constraint by a suitable scalar C
6765  *
6766  * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6767  * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6768  * z°_j in {0,1} for all j in N1
6769  * z_j in {0,1} for all j in N2,
6770  * where
6771  * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6772  * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6773  * and solve it exactly under consideration of the fixing.
6774  */
6775  SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6776 
6777  /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6778  for( j = 0; j < nitems; j++ )
6779  {
6780  transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6781 
6782  if( snf->transvarcoefs[items[j]] == 1 )
6783  {
6784  transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6785  SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6786  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6787  }
6788  else
6789  {
6790  transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6791  SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6792  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6793  }
6794  }
6795  /* get capacity of knapsack constraint in KP^SNF_rat */
6796  transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
6797  SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6798  snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
6799 
6800  /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6801  * is less than or equal to zero
6802  */
6803  if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6804  {
6805  assert(!(*found));
6806  goto TERMINATE;
6807  }
6808 
6809  /* KP^SNF_rat has been solved by fixing some variables in advance */
6810  assert(nitems >= 0);
6811  if( nitems == 0 )
6812  {
6813  /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6814  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
6815  *lambda = QUAD_TO_DBL(flowcoverweight);
6816  *found = TRUE;
6817  goto TERMINATE;
6818  }
6819 
6820  /* Solve the KP^SNF_rat approximately */
6821 
6822  /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6823  nsolitems = -1;
6824  nnonsolitems = -1;
6825 
6826  /* suitable factor C was found*/
6827  /* solve KP^SNF_rat approximately */
6828  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6829  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6830 
6831  assert(nsolitems != -1);
6832  assert(nnonsolitems != -1);
6833 
6834  /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6835  assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6836  buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6837  nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6838  assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6839 
6840  *found = SCIPisFeasGT(scip, *lambda, 0.0);
6841 
6842  TERMINATE:
6843  assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6844 #ifdef SCIP_DEBUG
6845  if( *found )
6846  {
6847  SCIPdebugMsg(scip, "2. approximate solution:\n");
6848  for( j = 0; j < snf->ntransvars; j++ )
6849  {
6850  if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6851  {
6852  SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6853  }
6854  else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6855  {
6856  SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6857  }
6858  }
6859  SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6860  }
6861 #endif
6862 
6863  /* free data structures */
6864  SCIPfreeBufferArray(scip, &nonsolitems);
6865  SCIPfreeBufferArray(scip, &solitems);
6866  SCIPfreeBufferArray(scip, &transweightsint);
6867  SCIPfreeBufferArray(scip, &transweightsreal);
6868  SCIPfreeBufferArray(scip, &transprofitsreal);
6869  SCIPfreeBufferArray(scip, &itemsint);
6870  SCIPfreeBufferArray(scip, &items);
6871 
6872  return SCIP_OKAY;
6873 }
6874 
6875 #endif
6876 
6877 /** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
6878  * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
6879  */
6880 static
6882  SCIP* scip, /**< SCIP data structure */
6883  LIFTINGDATA* liftingdata, /**< lifting data to use */
6884  SCIP_Real x /**< value where to evaluate lifting function */
6885  )
6886 {
6887  SCIP_Real QUAD(tmp);
6888  SCIP_Real xpluslambda;
6889  int i;
6890 
6891  xpluslambda = x + liftingdata->lambda;
6892 
6893  i = 0;
6894  while( i < liftingdata->r && SCIPisGT(scip, xpluslambda, liftingdata->M[i+1]) )
6895  ++i;
6896 
6897  if( i < liftingdata->t )
6898  {
6899  if( SCIPisLE(scip, liftingdata->M[i], x) )
6900  {
6901  assert(SCIPisLE(scip, xpluslambda, liftingdata->M[i+1]));
6902  return i * liftingdata->lambda;
6903  }
6904 
6905  assert(i > 0 && SCIPisLE(scip, liftingdata->M[i], xpluslambda) && x <= liftingdata->M[i]);
6906 
6907  /* return x - liftingdata->M[i] + i * liftingdata->lambda */
6908  SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
6909  SCIPquadprecSumQD(tmp, tmp, x);
6910  SCIPquadprecSumQD(tmp, tmp, -liftingdata->M[i]);
6911  return QUAD_TO_DBL(tmp);
6912  }
6913 
6914  if( i < liftingdata->r )
6915  {
6916  assert(!SCIPisInfinity(scip, liftingdata->mp));
6917 
6918  /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
6919  SCIPquadprecSumDD(tmp, liftingdata->m[i], -liftingdata->mp);
6920  SCIPquadprecSumQD(tmp, tmp, -liftingdata->ml);
6921  SCIPquadprecSumQD(tmp, tmp, liftingdata->lambda);
6922 
6923  /* p = MAX(0.0, p); */
6924  if( QUAD_HI(tmp) < 0.0 )
6925  {
6926  QUAD_ASSIGN(tmp, 0.0);
6927  }
6928 
6929  SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
6930  SCIPquadprecSumQD(tmp, tmp, liftingdata->ml);
6931 
6932  if( SCIPisLT(scip, QUAD_TO_DBL(tmp), xpluslambda) )
6933  return i * liftingdata->lambda;
6934 
6935  assert(SCIPisFeasLE(scip, liftingdata->M[i], xpluslambda) &&
6936  SCIPisFeasLE(scip, xpluslambda, liftingdata->M[i] + liftingdata->ml +
6937  MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
6938 
6939  SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
6940  SCIPquadprecSumQD(tmp, tmp, x);
6941  SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[i]);
6942  return QUAD_TO_DBL(tmp);
6943  }
6944 
6945  assert(i == liftingdata->r && SCIPisLE(scip, liftingdata->M[liftingdata->r], xpluslambda));
6946 
6947  SCIPquadprecProdDD(tmp, liftingdata->r, liftingdata->lambda);
6948  SCIPquadprecSumQD(tmp, tmp, x);
6949  SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[liftingdata->r]);
6950  return QUAD_TO_DBL(tmp);
6951 }
6952 
6953 /** computes
6954  * \f[
6955  * (\alpha_j, \beta_j) =
6956  * \begin{cases}
6957  * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
6958  * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
6959  * \end{cases}
6960  * \f]
6961  */
6962 static
6964  SCIP* scip, /**< SCIP data structure */
6965  LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
6966  SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
6967  int* alpha, /**< get alpha coefficient for lifting */
6968  SCIP_Real* beta /**< get beta coefficient for lifting */
6969  )
6970 {
6971  SCIP_Real vubcoefpluslambda;
6972  int i;
6973 
6974  vubcoefpluslambda = vubcoef + liftingdata->lambda;
6975 
6976  i = 0;
6977  while( i < liftingdata->r && SCIPisGT(scip, vubcoefpluslambda, liftingdata->M[i+1]) )
6978  ++i;
6979 
6980  if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
6981  {
6982  SCIP_Real QUAD(tmp);
6983  assert(liftingdata->M[i] < vubcoefpluslambda);
6984  *alpha = 1;
6985  SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
6986  SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
6987  *beta = QUAD_TO_DBL(tmp);
6988  }
6989  else
6990  {
6991  assert(SCIPisSumLE(scip, liftingdata->M[i], vubcoef));
6992  assert(i == liftingdata->r || SCIPisLE(scip, vubcoefpluslambda, liftingdata->M[i+1]));
6993  *alpha = 0;
6994  *beta = 0.0;
6995  }
6996 }
6997 
6998 /** compute relevant data for performing the sequence independent lifting */
6999 static
7001  SCIP* scip, /**< SCIP data structure */
7002  SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
7003  int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
7004  SCIP_Real lambda, /**< lambda */
7005  LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
7006  SCIP_Bool* valid /**< is the lifting data valid */
7007  )
7008 {
7009  int i;
7010  SCIP_Real QUAD(tmp);
7011  SCIP_Real QUAD(sumN2mC2LE);
7012  SCIP_Real QUAD(sumN2mC2GT);
7013  SCIP_Real QUAD(sumC1LE);
7014  SCIP_Real QUAD(sumC2);
7015 
7016  SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
7017 
7018  liftingdata->r = 0;
7019  QUAD_ASSIGN(sumN2mC2LE, 0.0);
7020  QUAD_ASSIGN(sumC1LE, 0.0);
7021  QUAD_ASSIGN(sumN2mC2GT, 0.0);
7022  QUAD_ASSIGN(sumC2, 0.0);
7023 
7024  liftingdata->mp = SCIPinfinity(scip);
7025 
7026  *valid = FALSE;
7027 
7028  for( i = 0; i < snf->ntransvars; ++i )
7029  {
7030  int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
7031 
7032  switch(s)
7033  {
7034  case 0: /* var is in N2 \ C2 */
7035  assert(snf->transvarvubcoefs[i] >= 0.0);
7036  assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
7037 
7038  if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7039  {
7040  SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
7041  liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7042  }
7043  else
7044  {
7045  SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
7046  }
7047  break;
7048  case 1: /* var is in C2 */
7049  assert(snf->transvarvubcoefs[i] > 0.0);
7050  assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
7051 
7052  SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
7053  break;
7054  case 3: /* var is in C1 */
7055  assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
7056  assert(snf->transvarvubcoefs[i] > 0.0);
7057 
7058  if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7059  {
7060  liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7061  liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
7062  }
7063  else
7064  {
7065  SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
7066  }
7067  break;
7068  default:
7069  assert(s == 2);
7070  continue;
7071  }
7072  }
7073 
7074  if( SCIPisInfinity(scip, liftingdata->mp) )
7075  {
7076  SCIPfreeBufferArray(scip, &liftingdata->m);
7077  return SCIP_OKAY;
7078  }
7079 
7080  SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->M, liftingdata->r + 1) );
7081 
7082  *valid = TRUE;
7083 
7084  SCIPquadprecSumQQ(tmp, sumC1LE, sumN2mC2LE);
7085  liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
7086  SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
7087  liftingdata->d1 = QUAD_TO_DBL(tmp);
7088  SCIPquadprecSumQQ(tmp, tmp, sumN2mC2GT);
7089  SCIPquadprecSumQQ(tmp, tmp, sumN2mC2LE);
7090  liftingdata->d2 = QUAD_TO_DBL(tmp);
7091 
7092  SCIPsortDownReal(liftingdata->m, liftingdata->r);
7093 
7094  /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
7095  QUAD_ASSIGN(tmp, 0.0);
7096  for( i = 0; i < liftingdata->r; ++i)
7097  {
7098  liftingdata->M[i] = QUAD_TO_DBL(tmp);
7099  SCIPquadprecSumQD(tmp, tmp, liftingdata->m[i]);
7100  }
7101 
7102  liftingdata->M[liftingdata->r] = QUAD_TO_DBL(tmp);
7103 
7104  SCIP_UNUSED( SCIPsortedvecFindDownReal(liftingdata->m, liftingdata->mp, liftingdata->r, &liftingdata->t) );
7105  assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
7106 
7107  /* compute t largest index sucht that m_t = mp
7108  * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
7109  */
7110  ++liftingdata->t;
7111  while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
7112  ++liftingdata->t;
7113 
7114  liftingdata->lambda = lambda;
7115 
7116  return SCIP_OKAY;
7117 }
7118 
7119 /** destroy data used for the sequence independent lifting */
7120 static
7122  SCIP* scip, /**< SCIP data structure */
7123  LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
7124  )
7125 {
7126  SCIPfreeBufferArray(scip, &liftingdata->M);
7127  SCIPfreeBufferArray(scip, &liftingdata->m);
7128 }
7129 
7130 /** store the simple lifted flowcover cut defined by the given data in the given arrays
7131  * the array for storing the cut coefficients must be all zeros
7132  */
7133 static
7135  SCIP* scip, /**< SCIP data structure */
7136  SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
7137  SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
7138  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
7139  SCIP_Real lambda, /**< lambda */
7140  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7141  SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
7142  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7143  int* nnz, /**< number of non-zeros in cut */
7144  SCIP_Bool* success /**< was the cut successfully generated */
7145  )
7146 {
7147  SCIP_Real QUAD(rhs);
7148  LIFTINGDATA liftingdata;
7149  int i;
7150 
7151  SCIP_CALL( computeLiftingData(scip, snf, flowcoverstatus, lambda, &liftingdata, success) );
7152  if( ! *success )
7153  return SCIP_OKAY;
7154 
7155  QUAD_ASSIGN(rhs, liftingdata.d1);
7156 
7157  *nnz = 0;
7158 
7159  for( i = 0; i < snf->ntransvars; ++i )
7160  {
7161  int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
7162 
7163  switch(s)
7164  {
7165  case 0: /* var is in N2 \ C2 */
7166  if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7167  {
7168  /* var is in L- */
7169  if( snf->origbinvars[i] != -1 )
7170  {
7171  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7172  cutinds[*nnz] = snf->origbinvars[i];
7173  cutcoefs[snf->origbinvars[i]] = -lambda;
7174  ++(*nnz);
7175  }
7176  else
7177  {
7178  SCIPquadprecSumQD(rhs, rhs, lambda);
7179  }
7180  }
7181  else
7182  {
7183  /* var is in L-- */
7184  if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7185  {
7186  assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7187  cutinds[*nnz] = snf->origcontvars[i];
7188  cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
7189  ++(*nnz);
7190  }
7191 
7192  if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
7193  {
7194  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7195  cutinds[*nnz] = snf->origbinvars[i];
7196  cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
7197  ++(*nnz);
7198  }
7199 
7200  SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
7201  }
7202  break;
7203  case 1: /* var is in C2 */
7204  {
7205  assert(snf->transvarvubcoefs[i] > 0.0);
7206  assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
7207 
7208  if( snf->origbinvars[i] != -1 )
7209  {
7210  SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
7211  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7212  if( liftedbincoef != 0.0 )
7213  {
7214  cutinds[*nnz] = snf->origbinvars[i];
7215  cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
7216  ++(*nnz);
7217  SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
7218  }
7219  }
7220  break;
7221  }
7222  case 2: /* var is in N1 \ C1 */
7223  {
7224  int alpha;
7225  SCIP_Real beta;
7226 
7227  assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
7228 
7229  getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
7230  assert(alpha == 0 || alpha == 1);
7231 
7232  if( alpha == 1 )
7233  {
7234  SCIP_Real QUAD(binvarcoef);
7235  assert(beta > 0.0);
7236 
7237  if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7238  {
7239  assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7240  cutinds[*nnz] = snf->origcontvars[i];
7241  cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7242  ++(*nnz);
7243  }
7244 
7245  SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
7246  if( snf->origbinvars[i] != -1 )
7247  {
7248  SCIP_Real tmp;
7249 
7250  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7251 
7252  tmp = QUAD_TO_DBL(binvarcoef);
7253  if( tmp != 0.0 )
7254  {
7255  cutinds[*nnz] = snf->origbinvars[i];
7256  cutcoefs[snf->origbinvars[i]] = tmp;
7257  ++(*nnz);
7258  }
7259  }
7260  else
7261  {
7262  SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
7263  }
7264 
7265  SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
7266  }
7267  break;
7268  }
7269  case 3: /* var is in C1 */
7270  {
7271  SCIP_Real bincoef = snf->aggrcoefsbin[i];
7272  SCIP_Real constant = snf->aggrconstants[i];
7273 
7274  if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7275  {
7276  /* var is in C++ */
7277  SCIP_Real QUAD(tmp);
7278  SCIP_Real QUAD(tmp2);
7279 
7280  SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
7281 
7282  SCIPquadprecSumQD(tmp2, tmp, constant);
7283  constant = QUAD_TO_DBL(tmp2);
7284 
7285  SCIPquadprecSumQD(tmp2, tmp, -bincoef);
7286  bincoef = -QUAD_TO_DBL(tmp2);
7287  }
7288 
7289  if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
7290  {
7291  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7292  cutinds[*nnz] = snf->origbinvars[i];
7293  cutcoefs[snf->origbinvars[i]] = bincoef;
7294  ++(*nnz);
7295  }
7296 
7297  if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7298  {
7299  assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7300  cutinds[*nnz] = snf->origcontvars[i];
7301  cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7302  ++(*nnz);
7303  }
7304 
7305  SCIPquadprecSumQD(rhs, rhs, -constant);
7306  break;
7307  }
7308  default:
7309  SCIPABORT();
7310  }
7311  }
7312 
7313  destroyLiftingData(scip, &liftingdata);
7314 
7315  {
7316  SCIP_ROW** rows = SCIPgetLPRows(scip);
7317  for( i = 0; i < aggrrow->nrows; ++i )
7318  {
7319  SCIP_ROW* row;
7320  SCIP_Real rowlhs;
7321  SCIP_Real rowrhs;
7322  SCIP_Real slackub;
7323  SCIP_Real slackcoef;
7324 
7325  slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
7326  assert(slackcoef != 0.0);
7327 
7328  /* positive slack was implicitly handled in flow cover separation */
7329  if( slackcoef > 0.0 )
7330  continue;
7331 
7332  row = rows[aggrrow->rowsinds[i]];
7333 
7334  /* add the slack's definition multiplied with its coefficient to the cut */
7335  SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
7336 
7337  /* retrieve sides of row */
7338  rowlhs = row->lhs - row->constant;
7339  rowrhs = row->rhs - row->constant;
7340 
7341  if( row->integral )
7342  {
7343  rowrhs = SCIPfloor(scip, rowrhs);
7344  rowlhs = SCIPceil(scip, rowlhs);
7345  }
7346 
7347  slackub = rowrhs - rowlhs;
7348 
7349  /* move slack's constant to the right hand side, and add lambda to the right hand side if the
7350  * upper bound of the slack is larger than lambda, since then an artifical binary variable
7351  * for the slack would get coefficient -lambda
7352  */
7353  if( aggrrow->slacksign[i] == +1 )
7354  {
7355  SCIP_Real rhsslack;
7356  /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7357  assert(!SCIPisInfinity(scip, row->rhs));
7358 
7359  rhsslack = rowrhs - SCIPgetRowMinActivity(scip, row);
7360  slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
7361 
7362  if( SCIPisGE(scip, slackub, lambda) )
7363  SCIPquadprecSumQD(rhs, rhs, lambda);
7364 
7365  SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
7366  }
7367  else
7368  {
7369  SCIP_Real lhsslack;
7370  /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7371  assert(!SCIPisInfinity(scip, -row->lhs));
7372 
7373  lhsslack = SCIPgetRowMaxActivity(scip, row) - rowlhs;
7374  slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
7375 
7376  if( SCIPisGE(scip, slackub, lambda) )
7377  SCIPquadprecSumQD(rhs, rhs, lambda);
7378 
7379  SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
7380  }
7381  }
7382  }
7383 
7384  *cutrhs = QUAD_TO_DBL(rhs);
7385 
7386  /* relax rhs to zero, if it's very close to */
7387  if( *cutrhs < 0.0 && *cutrhs >= SCIPepsilon(scip) )
7388  *cutrhs = 0.0;
7389 
7390  return SCIP_OKAY;
7391 }
7392 
7393 /** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
7394  * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
7395  * participate in the cut.
7396  * For further details we refer to:
7397  *
7398  * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
7399  * Mathematical Programming, 85(3), 439-467.
7400  *
7401  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7402  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7403  *
7404  * @pre This method can be called if @p scip is in one of the following stages:
7405  * - \ref SCIP_STAGE_SOLVING
7406  *
7407  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7408  */
7410  SCIP* scip, /**< SCIP data structure */
7411  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7412  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7413  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7414  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7415  SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
7416  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
7417  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
7418  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
7419  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
7420  SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
7421  int* cutrank, /**< pointer to return rank of generated cut */
7422  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
7423  SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
7424  )
7425 {
7426  int i;
7427  int nvars;
7428  SCIP_Bool localbdsused;
7429  SNF_RELAXATION snf;
7430  SCIP_Real lambda;
7431  SCIP_Real* tmpcoefs;
7432  int *transvarflowcoverstatus;
7433  int nflowcovervars;
7434  int nnonflowcovervars;
7435 
7436  nvars = SCIPgetNVars(scip);
7437 
7438  *success = FALSE;
7439 
7440  /* get data structures */
7441  SCIP_CALL( SCIPallocBufferArray(scip, &transvarflowcoverstatus, nvars) );
7442  SCIP_CALL( allocSNFRelaxation(scip, &snf, nvars) );
7443 
7444  SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
7445 
7446  SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
7447 
7448  if( ! *success )
7449  {
7450  goto TERMINATE;
7451  }
7452 
7453  *cutislocal = aggrrow->local || localbdsused;
7454 
7455  /* initialize lambda because gcc issues a stupid warning */
7456  lambda = 0.0;
7457  SCIP_CALL( getFlowCover(scip, &snf, &nflowcovervars, &nnonflowcovervars, transvarflowcoverstatus, &lambda, success) );
7458 
7459  if( ! *success )
7460  {
7461  goto TERMINATE;
7462  }
7463 
7464  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
7465 
7466  SCIP_CALL( generateLiftedFlowCoverCut(scip, &snf, aggrrow, transvarflowcoverstatus, lambda, tmpcoefs, cutrhs, cutinds, cutnnz, success) );
7467  SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
7468 
7469  /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
7470  if( *success )
7471  {
7472  if( postprocess )
7473  {
7474  SCIP_CALL( postprocessCut(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, cutrhs, success) );
7475  }
7476  else
7477  {
7478  SCIP_Real QUAD(rhs);
7479 
7480  QUAD_ASSIGN(rhs, *cutrhs);
7481  *success = ! removeZeros(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
7482  *cutrhs = QUAD_TO_DBL(rhs);
7483  }
7484 
7485  if( *success )
7486  {
7487  /* store cut sparse and calculate efficacy */
7488  for( i = 0; i < *cutnnz; ++i )
7489  {
7490  int j = cutinds[i];
7491  assert(tmpcoefs[j] != 0.0);
7492  cutcoefs[i] = tmpcoefs[j];
7493  tmpcoefs[j] = 0.0;
7494  }
7495 
7496  if( cutefficacy != NULL )
7497  *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
7498 
7499  if( cutrank != NULL )
7500  *cutrank = aggrrow->rank + 1;
7501  }
7502  else
7503  {
7504  /* clean buffer array */
7505  for( i = 0; i < *cutnnz; ++i )
7506  {
7507  int j = cutinds[i];
7508  assert(tmpcoefs[j] != 0.0);
7509  tmpcoefs[j] = 0.0;
7510  }
7511  }
7512  }
7513 
7514  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
7515 
7516  TERMINATE:
7517  destroySNFRelaxation(scip, &snf);
7518  SCIPfreeBufferArray(scip, &transvarflowcoverstatus);
7519 
7520  return SCIP_OKAY;
7521 }
7522 
7523 
7524 /* =========================================== strongcg =========================================== */
7525 
7526 /** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
7527  * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
7528  *
7529  * Transform variables (lb or ub):
7530  * \f[
7531  * \begin{array}{llll}
7532  * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation}\\
7533  * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation}
7534  * \end{array}
7535  * \f]
7536  * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
7537  *
7538  * Transform variables (vlb or vub):
7539  * \f[
7540  * \begin{array}{llll}
7541  * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
7542  * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
7543  * \end{array}
7544  * \f]
7545  * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
7546  * \f[
7547  * \begin{array}{ll}
7548  * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
7549  * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
7550  * \end{array}
7551  * \f]
7552  */
7553 static
7555  SCIP* scip, /**< SCIP data structure */
7556  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7557  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7558  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
7559  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7560  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7561  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7562  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7563  int* nnz, /**< number of non-zeros in cut */
7564  int* varsign, /**< stores the sign of the transformed variable in summation */
7565  int* boundtype, /**< stores the bound used for transformed variable:
7566  * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
7567  SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
7568  SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
7569  )
7570 {
7571  SCIP_Real* bestbds;
7572  int i;
7573  int aggrrowintstart;
7574  int nvars;
7575  int firstcontvar;
7576  SCIP_VAR** vars;
7577 
7578  assert(varsign != NULL);
7579  assert(boundtype != NULL);
7580  assert(freevariable != NULL);
7581  assert(localbdsused != NULL);
7582 
7583  *freevariable = FALSE;
7584  *localbdsused = FALSE;
7585 
7586  /* allocate temporary memory to store best bounds and bound types */
7587  SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
7588 
7589  /* start with continuous variables, because using variable bounds can affect the untransformed integral
7590  * variables, and these changes have to be incorporated in the transformation of the integral variables
7591  * (continuous variables have largest problem indices!)
7592  */
7593  SCIPsortDownInt(cutinds, *nnz);
7594 
7595  vars = SCIPgetVars(scip);
7596  nvars = SCIPgetNVars(scip);
7597  firstcontvar = nvars - SCIPgetNContVars(scip);
7598 
7599  /* determine best bounds for the continous variables such that they will have a positive coefficient in the transformation */
7600  for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
7601  {
7602  SCIP_Real QUAD(coef);
7603  int v = cutinds[i];
7604 
7605  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7606 
7607  if( QUAD_TO_DBL(coef) > 0.0 )
7608  {
7609  /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
7610  SCIP_CALL( findBestLb(scip, vars[v], sol, usevbds, allowlocal, bestbds + i, boundtype + i) );
7611 
7612  /* cannot create transformation for strongcg cut */
7613  if( SCIPisInfinity(scip, -bestbds[i]) )
7614  {
7615  *freevariable = TRUE;
7616  goto TERMINATE;
7617  }
7618 
7619  varsign[i] = +1;
7620  }
7621  else if( QUAD_TO_DBL(coef) < 0.0 )
7622  {
7623  /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
7624  SCIP_CALL( findBestUb(scip, vars[cutinds[i]], sol, usevbds, allowlocal, bestbds + i, boundtype + i) );
7625 
7626  /* cannot create transformation for strongcg cut */
7627  if( SCIPisInfinity(scip, bestbds[i]) )
7628  {
7629  *freevariable = TRUE;
7630  goto TERMINATE;
7631  }
7632 
7633  varsign[i] = -1;
7634  }
7635  }
7636 
7637  /* remember start of integer variables in the aggrrow */
7638  aggrrowintstart = i;
7639 
7640  /* perform bound substitution for continuous variables */
7641  for( i = 0; i < aggrrowintstart; ++i )
7642  {
7643  SCIP_Real QUAD(coef);
7644  SCIP_Real QUAD(tmp);
7645  int v = cutinds[i];
7646  SCIP_VAR* var = vars[v];
7647  assert(!SCIPisInfinity(scip, -varsign[i] * bestbds[i]));
7648 
7649  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7650 
7651  /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
7652  if( boundtype[i] < 0 )
7653  {
7654  SCIPquadprecProdQD(tmp, coef, bestbds[i]);
7655  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
7656  *localbdsused = *localbdsused || (boundtype[i] == -2);
7657  }
7658  else
7659  {
7660  SCIP_VAR** vbdvars;
7661  SCIP_Real* vbdcoefs;
7662  SCIP_Real* vbdconsts;
7663  SCIP_Real QUAD(zcoef);
7664  int zidx;
7665 
7666  if( varsign[i] == +1 )
7667  {
7668  vbdvars = SCIPvarGetVlbVars(var);
7669  vbdcoefs = SCIPvarGetVlbCoefs(var);
7670  vbdconsts = SCIPvarGetVlbConstants(var);
7671  assert(0 <= boundtype[i] && boundtype[i] < SCIPvarGetNVlbs(var));
7672  }
7673  else
7674  {
7675  vbdvars = SCIPvarGetVubVars(var);
7676  vbdcoefs = SCIPvarGetVubCoefs(var);
7677  vbdconsts = SCIPvarGetVubConstants(var);
7678  assert(0 <= boundtype[i] && boundtype[i] < SCIPvarGetNVubs(var));
7679  }
7680 
7681  assert(vbdvars != NULL);
7682  assert(vbdcoefs != NULL);
7683  assert(vbdconsts != NULL);
7684  assert(SCIPvarIsActive(vbdvars[boundtype[i]]));
7685 
7686  zidx = SCIPvarGetProbindex(vbdvars[boundtype[i]]);
7687  assert(0 <= zidx && zidx < firstcontvar);
7688 
7689  SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype[i]]);
7690  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
7691 
7692  /* check if integral variable already exists in the row */
7693  QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
7694 
7695  if( QUAD_HI(zcoef) == 0.0 )
7696  cutinds[(*nnz)++] = zidx;
7697 
7698  SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype[i]]);
7699  SCIPquadprecSumQQ(zcoef, zcoef, tmp);
7700 
7701  QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
7702  assert(QUAD_HI(zcoef) != 0.0);
7703 
7704  QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
7705  }
7706  }
7707 
7708  assert(i == aggrrowintstart);
7709 
7710  /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
7711  * and perform the bound substitution for the integer variables that are left using simple bounds
7712  */
7713  while( i < *nnz )
7714  {
7715  SCIP_Real QUAD(coef);
7716  SCIP_Real QUAD(tmp);
7717  SCIP_Real bestlb;
7718  SCIP_Real bestub;
7719  int bestlbtype;
7720  int bestubtype;
7721  SCIP_BOUNDTYPE selectedbound;
7722  int v = cutinds[i];
7723 
7724  assert(v < firstcontvar);
7725  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7726 
7727  /* due to variable bound usage for the continous variables cancellation may have occurred */
7728  if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
7729  {
7730  QUAD_ASSIGN(coef, 0.0);
7731  QUAD_ARRAY_STORE(cutcoefs, v, coef);
7732  --(*nnz);
7733  cutinds[i] = cutinds[*nnz];
7734 
7735  /* do not increase i, since last element is copied to the i-th position */
7736  continue;
7737  }
7738 
7739  /* determine the best bounds for the integral variable, usevbd can be set to FALSE here as vbds are only used for continous variables */
7740  SCIP_CALL( determineBestBounds(scip, vars[v], sol, boundswitch, FALSE, allowlocal, FALSE, FALSE, NULL, NULL,
7741  &bestlb, &bestub, &bestlbtype, &bestubtype, &selectedbound, freevariable) );
7742 
7743  /* check if we have an unbounded integral variable */
7744  if( *freevariable )
7745  {
7746  goto TERMINATE;
7747  }
7748 
7749  /* perform bound substitution */
7750  if( selectedbound == SCIP_BOUNDTYPE_LOWER )
7751  {
7752  boundtype[i] = bestlbtype;
7753  varsign[i] = +1;
7754  SCIPquadprecProdQD(tmp, coef, bestlb);
7755  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
7756  }
7757  else
7758  {
7759  assert(selectedbound == SCIP_BOUNDTYPE_UPPER);
7760  boundtype[i] = bestubtype;
7761  varsign[i] = -1;
7762  SCIPquadprecProdQD(tmp, coef, bestub);
7763  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
7764  }
7765 
7766  assert(boundtype[i] == -1 || boundtype[i] == -2);
7767  *localbdsused = *localbdsused || (boundtype[i] == -2);
7768 
7769  /* increase i */
7770  ++i;
7771  }
7772 
7773  /* relax rhs to zero if it is close to */
7774  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7775  QUAD_ASSIGN(*cutrhs, 0.0);
7776 
7777  TERMINATE:
7778  /*free temporary memory */
7779  SCIPfreeBufferArray(scip, &bestbds);
7780 
7781  return SCIP_OKAY;
7782 }
7783 
7784 /** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$ and
7785  * integer \f$ k >= 1 \f$ with \f$ 1/(k + 1) <= f_0 < 1/k \f$ and \f$ (=> k = up(1/f_0) + 1) \f$
7786  * integer \f$ 1 <= p_j <= k \f$ with \f$ f_0 + ((p_j - 1) * (1 - f_0)/k) < f_j <= f_0 + (p_j * (1 - f_0)/k)\f$ \f$ (=> p_j = up( k*(f_j - f_0)/(1 - f_0) )) \f$
7787  * and derive strong CG cut \f$ \tilde{a}*x^\prime <= down(b) \f$
7788  * \f[
7789  * \begin{array}{rll}
7790  * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j <= f_0 \\
7791  * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
7792  * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j >= 0 \\
7793  * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
7794  * \end{array}
7795  * \f]
7796  *
7797  * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
7798  *
7799  * (lb or ub):
7800  * \f[
7801  * \begin{array}{lllll}
7802  * x^\prime_j := x_j - lb_j,& x_j == x^\prime_j + lb_j,& a^\prime_j == a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
7803  * x^\prime_j := ub_j - x_j,& x_j == ub_j - x^\prime_j,& a^\prime_j == -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
7804  * \end{array}
7805  * \f]
7806  * \f[
7807  * and move the constant terms
7808  * \begin{array}{rl}
7809  * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
7810  * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
7811  * \end{array}
7812  * \f]
7813  * to the rhs.
7814  *
7815  * (vlb or vub):
7816  * \f[
7817  * \begin{array}{lllll}
7818  * x^\prime_j := x_j - (bl_j * zl_j + dl_j),& x_j == x^\prime_j + (bl_j * zl_j + dl_j),& a^\prime_j == a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
7819  * x^\prime_j := (bu_j * zu_j + du_j) - x_j,& x_j == (bu_j * zu_j + du_j) - x^\prime_j,& a^\prime_j == -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
7820  * \end{array}
7821  * \f]
7822  * move the constant terms
7823  * \f[
7824  * \begin{array}{rl}
7825  * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
7826  * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
7827  * \end{array}
7828  * \f]
7829  * to the rhs, and update the VB variable coefficients:
7830  * \f[
7831  * \begin{array}{ll}
7832  * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
7833  * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
7834  * \end{array}
7835  * \f]
7836  */
7837 static
7839  SCIP* scip, /**< SCIP data structure */
7840  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7841  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7842  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7843  int* nnz, /**< number of non-zeros in cut */
7844  int* varsign, /**< stores the sign of the transformed variable in summation */
7845  int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
7846  QUAD(SCIP_Real f0), /**< fractional value of rhs */
7847  SCIP_Real k /**< factor to strengthen strongcg cut */
7848  )
7849 {
7850  SCIP_Real QUAD(onedivoneminusf0);
7851  int i;
7852  int firstcontvar;
7853  SCIP_VAR** vars;
7854  int aggrrowintstart;
7855 
7856  assert(QUAD_HI(cutrhs) != NULL);
7857  assert(cutcoefs != NULL);
7858  assert(cutinds != NULL);
7859  assert(nnz != NULL);
7860  assert(boundtype != NULL);
7861  assert(varsign != NULL);
7862  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
7863 
7864  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
7865  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
7866 
7867  /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
7868  * without destroying the ordering of the aggrrow's non-zeros.
7869  * (due to sorting in cutsTransformStrongCG the ordering is continuous before integral)
7870  */
7871 
7872  firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
7873  vars = SCIPgetVars(scip);
7874 #ifndef NDEBUG
7875  /*in debug mode check, that all continuous variables of the aggrrow come before the integral variables */
7876  i = 0;
7877  while( i < *nnz && cutinds[i] >= firstcontvar )
7878  ++i;
7879 
7880  while( i < *nnz )
7881  {
7882  assert(cutinds[i] < firstcontvar);
7883  ++i;
7884  }
7885 #endif
7886 
7887  /* integer variables */
7888  for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
7889  {
7890  SCIP_VAR* var;
7891  SCIP_Real QUAD(aj);
7892  SCIP_Real QUAD(downaj);
7893  SCIP_Real QUAD(cutaj);
7894  SCIP_Real QUAD(fj);
7895  int v;
7896 
7897  v = cutinds[i];
7898  assert(0 <= v && v < SCIPgetNVars(scip));
7899 
7900  var = vars[v];
7901  assert(var != NULL);
7902  assert(SCIPvarGetProbindex(var) == v);
7903  assert(boundtype[i] == -1 || boundtype[i] == -2);
7904  assert(varsign[i] == +1 || varsign[i] == -1);
7905 
7906  /* calculate the coefficient in the retransformed cut */
7907  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
7908  QUAD_SCALE(aj, varsign[i]);
7909 
7910  SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
7911  SCIPquadprecSumQQ(fj, aj, -downaj);
7912 
7913  if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
7914  QUAD_ASSIGN_Q(cutaj, downaj); /* a^_j */
7915  else
7916  {
7917  SCIP_Real pj;
7918 
7919  SCIPquadprecSumQQ(cutaj, fj, -f0);
7920  SCIPquadprecProdQD(cutaj, cutaj, k);
7921  SCIPquadprecProdQQ(cutaj, cutaj, onedivoneminusf0);
7922  pj = SCIPceil(scip, QUAD_TO_DBL(cutaj));
7923  assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj almost equal to f0 */
7924  assert(pj <= k);
7925  SCIPquadprecDivDD(cutaj, pj, k + 1.0);
7926  SCIPquadprecSumQQ(cutaj, cutaj, downaj);
7927  }
7928 
7929  QUAD_SCALE(cutaj, varsign[i]);
7930 
7931  /* remove zero cut coefficients from cut */
7932  if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
7933  {
7934  QUAD_ASSIGN(cutaj, 0.0);
7935  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
7936  --*nnz;
7937  cutinds[i] = cutinds[*nnz];
7938  continue;
7939  }
7940 
7941  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
7942 
7943  /* integral var uses standard bound */
7944  assert(boundtype[i] < 0);
7945 
7946  /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
7947  if( varsign[i] == +1 )
7948  {
7949  SCIP_Real QUAD(tmp);
7950 
7951  /* lower bound was used */
7952  if( boundtype[i] == -1 )
7953  {
7954  assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
7955  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
7956  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7957  }
7958  else
7959  {
7960  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
7961  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
7962  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7963  }
7964  }
7965  else
7966  {
7967  SCIP_Real QUAD(tmp);
7968 
7969  /* upper bound was used */
7970  if( boundtype[i] == -1 )
7971  {
7972  assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
7973  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
7974  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7975  }
7976  else
7977  {
7978  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
7979  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
7980  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
7981  }
7982  }
7983  }
7984 
7985  /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
7986  aggrrowintstart = i + 1;
7987 
7988 #ifndef NDEBUG
7989  /* in a strong CG cut, cut coefficients of continuous variables are always zero; check this in debug mode */
7990  for( i = 0; i < aggrrowintstart; ++i )
7991  {
7992  int v;
7993 
7994  v = cutinds[i];
7995  assert(firstcontvar <= v && v < SCIPgetNVars(scip));
7996 
7997  {
7998  SCIP_VAR* var;
7999  SCIP_Real QUAD(aj);
8000 
8001  var = vars[v];
8002  assert(var != NULL);
8003  assert(!SCIPvarIsIntegral(var));
8004  assert(SCIPvarGetProbindex(var) == v);
8005  assert(varsign[i] == +1 || varsign[i] == -1);
8006 
8007  /* calculate the coefficient in the retransformed cut */
8008  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
8009  QUAD_SCALE(aj, varsign[i]);
8010 
8011  assert(QUAD_TO_DBL(aj) >= 0.0);
8012  }
8013  }
8014 #endif
8015 
8016  /* move integer variables to the empty position of the continuous variables */
8017  if( aggrrowintstart > 0 )
8018  {
8019  SCIP_Real QUAD(tmp);
8020  assert(aggrrowintstart <= *nnz);
8021 
8022  QUAD_ASSIGN(tmp, 0.0);
8023 
8024  for( i = 0; i < aggrrowintstart; ++i )
8025  {
8026  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], tmp);
8027  }
8028 
8029  *nnz -= aggrrowintstart;
8030  if( *nnz < aggrrowintstart )
8031  {
8032  BMScopyMemoryArray(cutinds, cutinds + aggrrowintstart, *nnz);
8033  }
8034  else
8035  {
8036  BMScopyMemoryArray(cutinds, cutinds + *nnz, aggrrowintstart);
8037  }
8038  }
8039 
8040  return SCIP_OKAY;
8041 }
8042 
8043 /** substitute aggregated slack variables:
8044  *
8045  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
8046  * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r] \f$.
8047  *
8048  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
8049  * \f[
8050  * \begin{array}{rll}
8051  * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) &, if \qquad f_r <= f0 \\
8052  * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1) &, if \qquad f_r > f0 \\
8053  * continuous:& \hat{a}_r = \tilde{a}_r = 0 &, if \qquad a^\prime_r >= 0 \\
8054  * & \mbox{no strong CG cut found} &, if \qquad a^\prime_r < 0
8055  * \end{array}
8056  * \f]
8057  *
8058  * Substitute \f$ \hat{a}_r * s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
8059  */
8060 static
8062  SCIP* scip, /**< SCIP datastructure */
8063  SCIP_Real* weights, /**< row weights in row summation */
8064  int* slacksign, /**< stores the sign of the row's slack variable in summation */
8065  int* rowinds, /**< sparsity pattern of used rows */
8066  int nrowinds, /**< number of used rows */
8067  SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8068  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8069  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8070  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8071  int* nnz, /**< number of non-zeros in cut */
8072  QUAD(SCIP_Real f0), /**< fractional value of rhs */
8073  SCIP_Real k /**< factor to strengthen strongcg cut */
8074  )
8075 { /*lint --e{715}*/
8076  SCIP_ROW** rows;
8077  SCIP_Real QUAD(onedivoneminusf0);
8078  int i;
8079 
8080  assert(scip != NULL);
8081  assert(weights != NULL);
8082  assert(slacksign != NULL);
8083  assert(rowinds != NULL);
8084  assert(SCIPisPositive(scip, scale));
8085  assert(cutcoefs != NULL);
8086  assert(QUAD_HI(cutrhs) != NULL);
8087  assert(cutinds != NULL);
8088  assert(nnz != NULL);
8089  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
8090 
8091  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
8092  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
8093 
8094  rows = SCIPgetLPRows(scip);
8095  for( i = 0; i < nrowinds; i++ )
8096  {
8097  SCIP_ROW* row;
8098  SCIP_Real pr;
8099  SCIP_Real QUAD(ar);
8100  SCIP_Real downar;
8101  SCIP_Real QUAD(cutar);
8102  SCIP_Real QUAD(fr);
8103  SCIP_Real mul;
8104  int r;
8105 
8106  r = rowinds[i];
8107  assert(0 <= r && r < SCIPgetNLPRows(scip));
8108  assert(slacksign[i] == -1 || slacksign[i] == +1);
8109  assert(!SCIPisZero(scip, weights[i]));
8110 
8111  row = rows[r];
8112  assert(row != NULL);
8113  assert(row->len == 0 || row->cols != NULL);
8114  assert(row->len == 0 || row->cols_index != NULL);
8115  assert(row->len == 0 || row->vals != NULL);
8116 
8117  /* get the slack's coefficient a'_r in the aggregated row */
8118  SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
8119 
8120  /* calculate slack variable's coefficient a^_r in the cut */
8121  if( row->integral )
8122  {
8123  /* slack variable is always integral: */
8124  downar = EPSFLOOR(QUAD_TO_DBL(ar), QUAD_EPSILON);
8125  SCIPquadprecSumQD(fr, ar, -downar);
8126 
8127  if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
8128  QUAD_ASSIGN(cutar, downar);
8129  else
8130  {
8131  SCIPquadprecSumQQ(cutar, fr, -f0);
8132  SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
8133  SCIPquadprecProdQD(cutar, cutar, k);
8134  pr = SCIPceil(scip, QUAD_TO_DBL(cutar));
8135  assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr almost equal to f0 */
8136  assert(pr <= k);
8137  SCIPquadprecDivDD(cutar, pr, k + 1.0);
8138  SCIPquadprecSumQD(cutar, cutar, downar);
8139  }
8140  }
8141  else
8142  {
8143  /* slack variable is continuous: */
8144  assert(QUAD_TO_DBL(ar) >= 0.0);
8145  continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
8146  }
8147 
8148  /* if the coefficient was reduced to zero, ignore the slack variable */
8149  if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
8150  continue;
8151 
8152  /* depending on the slack's sign, we have
8153  * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
8154  * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
8155  */
8156  mul = -slacksign[i] * QUAD_TO_DBL(cutar);
8157 
8158  /* add the slack's definition multiplied with a^_j to the cut */
8159  SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
8160 
8161  /* move slack's constant to the right hand side */
8162  if( slacksign[i] == +1 )
8163  {
8164  SCIP_Real rhs;
8165 
8166  /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
8167  assert(!SCIPisInfinity(scip, row->rhs));
8168  rhs = row->rhs - row->constant;
8169  if( row->integral )
8170  {
8171  /* the right hand side was implicitly rounded down in row aggregation */
8172  rhs = SCIPfloor(scip, rhs);
8173  }
8174 
8175  SCIPquadprecProdQD(cutar, cutar, rhs);
8176  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -cutar);
8177  }
8178  else
8179  {
8180  SCIP_Real lhs;
8181 
8182  /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
8183  assert(!SCIPisInfinity(scip, -row->lhs));
8184  lhs = row->lhs - row->constant;
8185  if( row->integral )
8186  {
8187  /* the left hand side was implicitly rounded up in row aggregation */
8188  lhs = SCIPceil(scip, lhs);
8189  }
8190 
8191  SCIPquadprecProdQD(cutar, cutar, lhs);
8192  SCIPquadprecSumQQ(*cutrhs, *cutrhs, cutar);
8193  }
8194  }
8195 
8196  /* relax rhs to zero, if it's very close to */
8197  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= SCIPepsilon(scip) )
8198  QUAD_ASSIGN(*cutrhs, 0.0);
8199 
8200  return SCIP_OKAY;
8201 }
8202 
8203 
8204 /** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
8205  * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
8206  * participate in a strongcg cut
8207  *
8208  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8209  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8210  *
8211  * @pre This method can be called if @p scip is in one of the following stages:
8212  * - \ref SCIP_STAGE_SOLVING
8213  *
8214  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8215  */
8217  SCIP* scip, /**< SCIP data structure */
8218  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8219  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
8220  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8221  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
8222  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8223  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
8224  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
8225  SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8226  SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
8227  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8228  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8229  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8230  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8231  SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
8232  int* cutrank, /**< pointer to return rank of generated cut */
8233  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8234  SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
8235  )
8236 {
8237  int i;
8238  int nvars;
8239  int* varsign;
8240  int* boundtype;
8241  SCIP_Real* tmpcoefs;
8242  SCIP_Real QUAD(downrhs);
8243  SCIP_Real QUAD(f0);
8244  SCIP_Real QUAD(tmp);
8245  SCIP_Real QUAD(rhs);
8246  SCIP_Real k;
8247  SCIP_Bool freevariable;
8248  SCIP_Bool localbdsused;
8249 
8250  assert(scip != NULL);
8251  assert(aggrrow != NULL);
8252  assert(SCIPisPositive(scip, scale));
8253  assert(cutcoefs != NULL);
8254  assert(cutrhs != NULL);
8255  assert(cutinds != NULL);
8256  assert(success != NULL);
8257  assert(cutislocal != NULL);
8258 
8259  SCIPdebugMessage("calculating strong CG cut (scale: %g)\n", scale);
8260 
8261  *success = FALSE;
8262 
8263  /* allocate temporary memory */
8264  nvars = SCIPgetNVars(scip);
8265  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
8266  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
8267  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, QUAD_ARRAY_SIZE(nvars)) );
8268 
8269  /* initialize cut with aggregation */
8270  *cutnnz = aggrrow->nnz;
8271  *cutislocal = aggrrow->local;
8272  SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
8273 
8274  if( *cutnnz > 0 )
8275  {
8276  BMScopyMemoryArray(cutinds, aggrrow->inds, *cutnnz);
8277 
8278  for( i = 0; i < *cutnnz; ++i )
8279  {
8280  SCIP_Real QUAD(coef);
8281  int j = cutinds[i];
8282 
8283  QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
8284  SCIPquadprecProdQD(coef, coef, scale);
8285 
8286  QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
8287  assert(QUAD_HI(coef) != 0.0);
8288 
8289  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8290  }
8291 
8292  /* Transform equation a*x == b, lb <= x <= ub into standard form
8293  * a'*x' == b, 0 <= x' <= ub'.
8294  *
8295  * Transform variables (lb or ub):
8296  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
8297  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
8298  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
8299  *
8300  * Transform variables (vlb or vub):
8301  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
8302  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
8303  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
8304  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
8305  * a_{zu_j} := a_{zu_j} + a_j * bu_j
8306  */
8307  SCIP_CALL( cutsTransformStrongCG(scip, sol, boundswitch, usevbds, allowlocal,
8308  tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, &freevariable, &localbdsused) );
8309 
8310  assert(allowlocal || !localbdsused);
8311  *cutislocal = *cutislocal || localbdsused;
8312 
8313  if( freevariable )
8314  goto TERMINATE;
8315 
8316  SCIPdebug(printCutQuad(scip, NULL, cutcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
8317  }
8318 
8319  /* Calculate
8320  * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
8321  * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
8322  * (=> k = up(1/f_0) + 1)
8323  * - integer 1 <= p_j <= k with f_0 + ((p_j - 1) * (1 - f_0)/k) < f_j <= f_0 + (p_j * (1 - f_0)/k)
8324  * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
8325  * and derive strong CG cut
8326  * a~*x' <= (k+1) * down(b)
8327  * integers : a~_j = down(a'_j) , if f_j <= f_0
8328  * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
8329  * continuous: a~_j = 0 , if a'_j >= 0
8330  * no strong CG cut found , if a'_j < 0
8331  *
8332  * Transform inequality back to a^*x <= rhs:
8333  *
8334  * (lb or ub):
8335  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
8336  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
8337  * and move the constant terms
8338  * -a~_j * lb_j == -a^_j * lb_j, or
8339  * a~_j * ub_j == -a^_j * ub_j
8340  * to the rhs.
8341  *
8342  * (vlb or vub):
8343  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
8344  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
8345  * move the constant terms
8346  * -a~_j * dl_j == -a^_j * dl_j, or
8347  * a~_j * du_j == -a^_j * du_j
8348  * to the rhs, and update the VB variable coefficients:
8349  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
8350  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
8351  */
8352  SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
8353 
8354  SCIPquadprecSumQQ(f0, rhs, -downrhs);
8355  if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
8356  goto TERMINATE;
8357 
8358  /* renormalize the f0 value */
8359  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
8360 
8361  SCIPquadprecDivDQ(tmp, 1.0, f0);
8362  k = SCIPround(scip, ceil(QUAD_TO_DBL(tmp)) - 1.0);
8363 
8364  QUAD_ASSIGN_Q(rhs, downrhs);
8365 
8366  if( *cutnnz > 0 )
8367  {
8368  SCIP_CALL( cutsRoundStrongCG(scip, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, QUAD(f0), k) );
8369  SCIPdebug(printCutQuad(scip, sol, cutcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
8370  }
8371 
8372  /* substitute aggregated slack variables:
8373  *
8374  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
8375  * variable only appears in its own row:
8376  * a'_r = scale * weight[r] * slacksign[r].
8377  *
8378  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
8379  * integers : a^_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
8380  * a^_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
8381  * continuous: a^_r = a~_r = 0 , if a'_r >= 0
8382  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
8383  *
8384  * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
8385  */
8386  SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
8387  aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, QUAD(f0), k) );
8388  SCIPdebug(printCutQuad(scip, sol, cutcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
8389 
8390  /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
8391  * prevent numerical rounding errors
8392  */
8393  if( postprocess )
8394  {
8395  SCIP_CALL( postprocessCutQuad(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, QUAD(&rhs), success) );
8396  }
8397  else
8398  {
8399  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
8400  }
8401  SCIPdebug(printCutQuad(scip, sol, cutcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
8402 
8403  if( *success )
8404  {
8405  *cutrhs = QUAD_TO_DBL(rhs);
8406 
8407  /* store cut in given array in sparse representation and clean buffer array */
8408  for( i = 0; i < *cutnnz; ++i )
8409  {
8410  SCIP_Real QUAD(coef);
8411  int j = cutinds[i];
8412 
8413  QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
8414  assert(QUAD_HI(coef) != 0.0);
8415 
8416  cutcoefs[i] = QUAD_TO_DBL(coef);
8417  QUAD_ASSIGN(coef, 0.0);
8418  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8419  }
8420 
8421  if( cutefficacy != NULL )
8422  *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
8423 
8424  if( cutrank != NULL )
8425  *cutrank = aggrrow->rank + 1;
8426  }
8427 
8428  TERMINATE:
8429 
8430  /* if we aborted early the tmpcoefs array needs to be cleaned */
8431  if( !(*success) )
8432  {
8433  QUAD_ASSIGN(tmp, 0.0);
8434 
8435  for( i = 0; i < *cutnnz; ++i )
8436  {
8437  QUAD_ARRAY_STORE(tmpcoefs, cutinds[i], tmp);
8438  }
8439  }
8440 
8441  /* free temporary memory */
8442  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
8443  SCIPfreeBufferArray(scip, &boundtype);
8444  SCIPfreeBufferArray(scip, &varsign);
8445 
8446  return SCIP_OKAY;
8447 }
void SCIPsortDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, int len)
SCIP_Real * transbinvarsolvals
Definition: cuts.c:4956
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:116
SCIP_STAT * stat
Definition: struct_scip.h:69
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:608
static SCIP_RETCODE postprocessCutQuad(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, QUAD(SCIP_Real *cutrhs), SCIP_Bool *success)
Definition: cuts.c:2223
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:105
SCIP_RETCODE SCIPcalcStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:8216
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1581
static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
Definition: cuts.c:7000
int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2295
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17558
#define NULL
Definition: def.h:246
SCIP_Real lambda
Definition: cuts.c:4946
SCIP_Real SCIPfeastol(SCIP *scip)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:99
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_Real d1
Definition: cuts.c:4944
int ntransvars
Definition: cuts.c:4959
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int * origcontvars
Definition: cuts.c:4962
SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
Definition: cuts.c:1684
#define SCIPquadprecDivDQ(r, a, b)
Definition: dbldblarith.h:55
#define SCIPquadprecSumQD(r, a, b)
Definition: dbldblarith.h:53
static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:156
int * cols_index
Definition: struct_lp.h:219
SCIP_Real * aggrcoefscont
Definition: cuts.c:4965
public methods for memory management
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17536
enum SCIP_BaseStat SCIP_BASESTAT
Definition: type_lpi.h:86
static SCIP_RETCODE cutTightenCoefsQuad(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition: cuts.c:594
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17344
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:210
void SCIPaggrRowCancelVarWithBound(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_VAR *var, int pos, SCIP_Bool *valid)
Definition: cuts.c:1771
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16880
#define SQR(x)
Definition: def.h:198
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17400
#define QUAD_ARRAY_STORE(a, idx, x)
Definition: dbldblarith.h:46
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real transrhs
Definition: cuts.c:4960
static SCIP_RETCODE SCIPsolveKnapsackApproximatelyLT(SCIP *scip, int nitems, SCIP_Real *weights, SCIP_Real *profits, SCIP_Real capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
Definition: cuts.c:6006
int rank
Definition: struct_lp.h:239
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16910
#define MAXABSVBCOEF
Definition: cuts.c:4927
#define RESTRICT
Definition: def.h:258
static SCIP_Real computeMIREfficacy(SCIP *scip, SCIP_Real *RESTRICT coefs, SCIP_Real *RESTRICT solvals, SCIP_Real rhs, SCIP_Real contactivity, SCIP_Real contsqrnorm, SCIP_Real delta, int nvars, SCIP_Real minfrac, SCIP_Real maxfrac)
Definition: cuts.c:4137
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPquadprecProdQQ(r, a, b)
Definition: dbldblarith.h:57
SCIP_Real * M
Definition: cuts.c:4935
static SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
Definition: cuts.c:465
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:9881
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1918
static SCIP_RETCODE generateLiftedFlowCoverCut(SCIP *scip, SNF_RELAXATION *snf, SCIP_AGGRROW *aggrrow, int *flowcoverstatus, SCIP_Real lambda, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, SCIP_Bool *success)
Definition: cuts.c:7134
struct LiftingData LIFTINGDATA
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16959
#define FALSE
Definition: def.h:72
#define EPSISINT(x, eps)
Definition: def.h:194
methods for the aggregation rows
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10561
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:17007
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:71
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2380
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_RETCODE cutsTransformStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:7554
SCIP_RETCODE SCIPcutGenerationHeuristicCMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, int maxtestdelta, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:4222
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17578
SCIP_Real SCIProwGetLPEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp)
Definition: lp.c:6715
#define MAXCMIRSCALE
Definition: cuts.c:2652
static SCIP_RETCODE cutsSubstituteMIR(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0))
Definition: cuts.c:3750
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17037
#define SCIP_UNUSED(x)
Definition: def.h:412
SCIP_Real SCIPgetVectorEfficacyNorm(SCIP *scip, SCIP_Real *vals, int nvals)
Definition: scip_cut.c:193
static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
Definition: cuts.c:6881
public methods for problem variables
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:9868
int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2360
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:114
SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2390
#define QUAD_SCALE(x, a)
Definition: dbldblarith.h:41
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17548
SCIP_Real SCIProwGetLPSolCutoffDistance(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_SOL *sol, SCIP_LP *lp)
Definition: lp.c:6658
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:171
unsigned int integral
Definition: struct_lp.h:248
#define EPSFRAC(x, eps)
Definition: def.h:193
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
Definition: cuts.c:1601
int * slacksign
Definition: struct_cuts.h:36
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:142
#define QUAD_ASSIGN(a, constant)
Definition: dbldblarith.h:42
defines macros for basic operations in double-double arithmetic giving roughly twice the precision of...
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:97
public methods for SCIP variables
int * rowsinds
Definition: struct_cuts.h:35
#define SCIPdebugMsgPrint
Definition: scip_message.h:89
#define SCIPdebugMsg
Definition: scip_message.h:88
static SCIP_RETCODE determineBestBounds(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *bestlb, SCIP_Real *bestub, int *bestlbtype, int *bestubtype, SCIP_BOUNDTYPE *selectedbound, SCIP_Bool *freevariable)
Definition: cuts.c:2772
internal methods for LP management
SCIP_VAR ** x
Definition: circlepacking.c:54
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2224
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: scip_var.c:6519
#define QUAD_TO_DBL(x)
Definition: dbldblarith.h:40
SCIP_Real SCIPgetRowMaxActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1862
static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
Definition: cuts.c:6963
public methods for numerical tolerances
SCIP_RETCODE SCIPselectCuts(SCIP *scip, SCIP_ROW **cuts, SCIP_RANDNUMGEN *randnumgen, SCIP_Real goodscorefac, SCIP_Real badscorefac, SCIP_Real goodmaxparall, SCIP_Real maxparall, SCIP_Real dircutoffdistweight, SCIP_Real efficacyweight, SCIP_Real objparalweight, SCIP_Real intsupportweight, int ncuts, int nforcedcuts, int maxselectedcuts, int *nselectedcuts)
Definition: cuts.c:2472
SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
Definition: cuts.c:2327
static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
Definition: cuts.c:7121
static int filterWithParallelism(SCIP_ROW *cut, SCIP_ROW **cuts, SCIP_Real *scores, int ncuts, SCIP_Real goodscore, SCIP_Real goodmaxparall, SCIP_Real maxparall)
Definition: cuts.c:2402
public methods for querying solving statistics
SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
Definition: cuts.c:1828
static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
Definition: cuts.c:227
static SCIP_RETCODE cutTightenCoefs(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition: cuts.c:982
SCIP_Real * vals
Definition: struct_lp.h:220
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:148
SCIP_Real * rowweights
Definition: struct_cuts.h:37
static SCIP_Bool removeZerosQuad(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition: cuts.c:324
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17354
int lppos
Definition: struct_lp.h:230
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:111
void SCIPsortDownInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
static SCIP_Longint getIntegralVal(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta)
static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:113
#define QUAD_HI(x)
Definition: dbldblarith.h:36
int * transvarcoefs
Definition: cuts.c:4955
SCIP_Bool SCIPsortedvecFindDownReal(SCIP_Real *realarray, SCIP_Real val, int len, int *pos)
int t
Definition: cuts.c:4943
int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2305
static SCIP_Bool isIntegralScalar(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Real *intval)
Definition: lp.c:4823
#define SCIPerrorMessage
Definition: pub_message.h:45
static SCIP_RETCODE findBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, int *bestlbtype)
Definition: cuts.c:2656
#define SCIPdebugPrintf
Definition: pub_message.h:80
#define QUAD_EPSILON
Definition: dbldblarith.h:33
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_COL ** cols
Definition: struct_lp.h:218
#define SCIPquadprecEpsFloorQ(r, a, eps)
Definition: dbldblarith.h:66
#define COPYSIGN
Definition: def.h:237
#define MAXSCALE
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17068
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:143
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:179
#define QUAD(x)
Definition: dbldblarith.h:38
SCIP_Real lhs
Definition: struct_lp.h:195
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17610
SCIP_Real sepa_maxcoefratio
Definition: struct_set.h:495
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16730
static SCIP_Bool chgCoeffWithBound(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:509
int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2370
static SCIP_RETCODE cutsTransformMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:2987
static SCIP_RETCODE findBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, int *bestubtype)
Definition: cuts.c:2714
int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2350
#define REALABS(x)
Definition: def.h:181
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:17718
void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool *valid)
Definition: cuts.c:2282
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:629
#define QUAD_ARRAY_LOAD(r, a, idx)
Definition: dbldblarith.h:45
#define SCIP_CALL(x)
Definition: def.h:358
SCIP main data structure.
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17568
SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
Definition: scip_var.c:6542
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16969
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17600
SCIP_RETCODE SCIPaggrRowAddCustomCons(SCIP *scip, SCIP_AGGRROW *aggrrow, int *inds, SCIP_Real *vals, int len, SCIP_Real rhs, SCIP_Real weight, int rank, SCIP_Bool local)
Definition: cuts.c:1899
#define MINDELTA
static SCIP_RETCODE getClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestsub, SCIP_Real rowcoef, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: cuts.c:4976
#define SCIPquadprecProdDD(r, a, b)
Definition: dbldblarith.h:49
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17078
#define MAXBOUND
Definition: cuts.c:4928
static SCIP_Bool chgQuadCoeffWithBound(SCIP *scip, SCIP_VAR *var, QUAD(SCIP_Real oldcoeff), SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:551
int SCIProwGetNumIntCols(SCIP_ROW *row, SCIP_SET *set)
Definition: lp.c:6642
static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
Definition: cuts.c:5965
int var_probindex
Definition: struct_lp.h:169
SCIP_Real * aggrcoefsbin
Definition: cuts.c:4963
SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:3904
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:130
public data structures and miscellaneous methods
#define SCIP_Bool
Definition: def.h:69
static SCIP_RETCODE cutsSubstituteStrongCG(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:8061
SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
Definition: cuts.c:1974
#define QUAD_LO(x)
Definition: dbldblarith.h:37
#define QUAD_ARRAY_SIZE(size)
Definition: dbldblarith.h:44
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition: cuts.c:1348
SCIP_Bool SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7409
#define MIN(x, y)
Definition: def.h:216
static SCIP_RETCODE determineBoundForSNF(SCIP *scip, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *rowcoefs, int *rowinds, int varposinrow, int8_t *binvarused, SCIP_Bool allowlocal, SCIP_Real boundswitch, SCIP_Real *bestlb, SCIP_Real *bestub, SCIP_Real *bestslb, SCIP_Real *bestsub, int *bestlbtype, int *bestubtype, int *bestslbtype, int *bestsubtype, SCIP_BOUNDTYPE *selectedbounds, SCIP_Bool *freevariable)
Definition: cuts.c:5234
public methods for LP management
public methods for cuts and aggregation rows
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17192
static SCIP_RETCODE constructSNFRelaxation(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_Real *rowcoefs, QUAD(SCIP_Real rowrhs), int *rowinds, int nnz, SNF_RELAXATION *snf, SCIP_Bool *success, SCIP_Bool *localbdsused)
Definition: cuts.c:5414
int * origbinvars
Definition: cuts.c:4961
#define SCIPquadprecProdQD(r, a, b)
Definition: dbldblarith.h:54
SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2316
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:123
static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:7838
static SCIP_RETCODE addOneRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *rowtoolong)
Definition: cuts.c:1986
#define MAXDNOM
Definition: cons_linear.c:172
static SCIP_RETCODE getClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestslb, SCIP_Real rowcoef, SCIP_Real *closestvub, int *closestvubidx)
Definition: cuts.c:5106
char sepa_efficacynorm
Definition: struct_set.h:507
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2050
SCIP_Real * transvarvubcoefs
Definition: cuts.c:4958
SCIP_Real * vals
Definition: struct_cuts.h:33
struct SNF_Relaxation SNF_RELAXATION
#define SCIPquadprecSumQQ(r, a, b)
Definition: dbldblarith.h:58
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2089
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:9630
public methods for the LP relaxation, rows and columns
#define QUAD_ASSIGN_Q(a, b)
Definition: dbldblarith.h:43
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2044
#define SCIP_REAL_MAX
Definition: def.h:158
SCIP_Real rhs
Definition: struct_lp.h:196
SCIP_Real constant
Definition: struct_lp.h:194
SCIP_Real SCIProwGetParallelism(SCIP_ROW *row1, SCIP_ROW *row2, char orthofunc)
Definition: lp.c:7631
SCIP_Real * r
Definition: circlepacking.c:50
methods for sorting joint arrays of various types
static SCIP_RETCODE cutsRoundMIR(SCIP *scip, SCIP_Real *RESTRICT cutcoefs, QUAD(SCIP_Real *RESTRICT cutrhs), int *RESTRICT cutinds, int *RESTRICT nnz, int *RESTRICT varsign, int *RESTRICT boundtype, QUAD(SCIP_Real f0))
Definition: cuts.c:3436
#define SQRT(x)
Definition: def.h:199
SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
Definition: cuts.c:1638
#define SCIPquadprecDivDD(r, a, b)
Definition: dbldblarith.h:52
int r
Definition: cuts.c:4942
#define MAX(x, y)
Definition: def.h:215
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2362
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPaggrRowSumRows(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real *weights, int *rowinds, int nrowinds, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *valid)
Definition: cuts.c:2093
void SCIPselectWeightedDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
public methods for solutions
static SCIP_Bool removeZeros(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition: cuts.c:395
static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
Definition: cuts.c:5986
SCIP_SET * set
Definition: struct_scip.h:62
int SCIPgetNCuts(SCIP *scip)
Definition: scip_cut.c:830
static void buildFlowCover(SCIP *scip, int *coefs, SCIP_Real *vubcoefs, SCIP_Real rhs, int *solitems, int *nonsolitems, int nsolitems, int nnonsolitems, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, QUAD(SCIP_Real *flowcoverweight), SCIP_Real *lambda)
Definition: cuts.c:6101
public methods for message output
data structures for LP management
SCIP_Real * aggrconstants
Definition: cuts.c:4967
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:608
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1999
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17148
void SCIPsortDownInt(int *intarray, int len)
static SCIP_RETCODE postprocessCut(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, SCIP_Real *cutrhs, SCIP_Bool *success)
Definition: cuts.c:2154
#define SCIP_Real
Definition: def.h:157
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:152
SCIP_Real SCIProwGetObjParallelism(SCIP_ROW *row, SCIP_SET *set, SCIP_LP *lp)
Definition: lp.c:7707
SCIP_Real SCIPgetRowMinActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1845
public methods for message handling
#define SCIP_INVALID
Definition: def.h:177
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1549
#define SCIPquadprecSumDD(r, a, b)
Definition: dbldblarith.h:51
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17590
#define SCIP_Longint
Definition: def.h:142
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition: misc.c:9123
SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16895
#define NONZERO(x)
Definition: cuts.c:107
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real d2
Definition: cuts.c:4945
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17410
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:117
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Real ml
Definition: cuts.c:4948
#define EPSFLOOR(x, eps)
Definition: def.h:190
static void selectBestCut(SCIP_ROW **cuts, SCIP_Real *scores, int ncuts)
Definition: cuts.c:2439
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:119
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:573
static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
Definition: cuts.c:6617
void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:1949
#define SCIP_CALL_ABORT(x)
Definition: def.h:337
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_LP * lp
Definition: struct_scip.h:80
SCIP_Longint SCIPgetNLPs(SCIP *scip)
#define SCIPABORT()
Definition: def.h:330
SCIP_Real * m
Definition: cuts.c:4936
public methods for global and local (sub)problems
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16921
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1410
datastructures for global SCIP settings
static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:289
void SCIPsortDownReal(SCIP_Real *realarray, int len)
SCIP_Real * transcontvarsolvals
Definition: cuts.c:4957
#define MAXDELTA
unsigned int local
Definition: struct_lp.h:249
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
#define EPSZ(x, eps)
Definition: def.h:187
SCIP_Real mp
Definition: cuts.c:4947
int len
Definition: struct_lp.h:226
static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:197
SCIP_Bool local
Definition: struct_cuts.h:43
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17017
methods for selecting (weighted) k-medians
SCIP_Bool SCIProwIsInGlobalCutpool(SCIP_ROW *row)
Definition: lp.c:17138
memory allocation routines