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