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