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