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