Scippy

SCIP

Solving Constraint Integer Programs

cuts.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2024 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
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
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
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
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
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
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
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
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
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
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
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), SCIPsumepsilon(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
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), SCIPsumepsilon(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  */
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 = SCIPfloor(scip, 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 = SCIPceil(scip, 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 */
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 */
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 */
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 */
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 */
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  */
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 */
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 */
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 */
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  */
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
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  {
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  */
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
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
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. */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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
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
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
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
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
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
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); /* a^_j */
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
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 QUAD(ar);
3764  SCIP_Real QUAD(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  SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
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  SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
3793  SCIPquadprecSumQQ(fr, ar, -downar);
3794  assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
3795 
3796  if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
3797  QUAD_ASSIGN_Q(cutar, downar); /* a^_r */
3798  else
3799  {
3800  SCIPquadprecSumQQ(cutar, fr, -f0);
3801  SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
3802  SCIPquadprecSumQQ(cutar, cutar, downar);
3803  }
3804  }
3805  else
3806  {
3807  /* slack variable is continuous:
3808  * a^_r = a~_r = 0 , if a'_r >= 0
3809  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
3810  */
3811  if( QUAD_TO_DBL(ar) >= 0.0 )
3812  continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
3813  else
3814  SCIPquadprecProdQQ(cutar, onedivoneminusf0, ar);
3815  }
3816 
3817  /* if the coefficient was reduced to zero, ignore the slack variable */
3818  if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
3819  continue;
3820 
3821  /* depending on the slack's sign, we have
3822  * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
3823  * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
3824  */
3825  SCIPquadprecProdQD(myprod, cutar, -slacksign[i]);
3826 
3827  /* add the slack's definition multiplied with a^_j to the cut */
3828  SCIP_CALL( varVecAddScaledRowCoefsQuadScale(cutinds, cutcoefs, nnz, row, QUAD(myprod)) );
3829 
3830  /* move slack's constant to the right hand side */
3831  if( slacksign[i] == +1 ) /*lint !e613*/
3832  {
3833  SCIP_Real QUAD(rowrhs);
3834 
3835  /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
3836  assert(!SCIPisInfinity(scip, row->rhs));
3837  QUAD_ASSIGN(rowrhs, row->rhs - row->constant);
3838  if( row->integral )
3839  {
3840  /* the right hand side was implicitly rounded down in row aggregation */
3841  SCIPquadprecEpsFloorQ(rowrhs, rowrhs, SCIPepsilon(scip)); /*lint !e666*/
3842  }
3843  SCIPquadprecProdQQ(tmp, myprod, rowrhs);
3844  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3845  }
3846  else
3847  {
3848  SCIP_Real QUAD(rowlhs);
3849 
3850  /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
3851  assert(!SCIPisInfinity(scip, -row->lhs));
3852  QUAD_ASSIGN(rowlhs, row->lhs - row->constant);
3853  if( row->integral )
3854  {
3855  /* the left hand side was implicitly rounded up in row aggregation */
3856  SCIPquadprecEpsCeilQ(rowlhs, rowlhs, SCIPepsilon(scip)); /*lint !e666*/
3857  }
3858  SCIPquadprecProdQQ(tmp, myprod, rowlhs);
3859  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3860  }
3861  }
3862 
3863  /* relax rhs to zero, if it's very close to 0 */
3864  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
3865  QUAD_ASSIGN(*cutrhs, 0.0);
3866 
3867  return SCIP_OKAY;
3868 }
3869 
3870 /** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
3871  * these rows cannot participate in an MIR cut.
3872  *
3873  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3874  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3875  *
3876  * @pre This method can be called if @p scip is in one of the following stages:
3877  * - \ref SCIP_STAGE_SOLVING
3878  *
3879  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
3880  */
3882  SCIP* scip, /**< SCIP data structure */
3883  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
3884  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
3885  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
3886  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
3887  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
3888  SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
3889  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
3890  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
3891  * NULL for using closest bound for all variables */
3892  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
3893  * NULL for using closest bound for all variables */
3894  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
3895  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
3896  SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
3897  SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
3898  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
3899  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
3900  int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
3901  int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
3902  SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
3903  int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
3904  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
3905  SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
3906  )
3907 {
3908  int i;
3909  int nvars;
3910  int tmpnnz;
3911  int* varsign;
3912  int* boundtype;
3913  int* tmpinds;
3914  SCIP_Real* tmpcoefs;
3915 
3916  SCIP_Real QUAD(rhs);
3917  SCIP_Real QUAD(downrhs);
3918  SCIP_Real QUAD(f0);
3919  SCIP_Bool freevariable;
3920  SCIP_Bool localbdsused;
3921  SCIP_Bool tmpislocal;
3922 
3923  assert(aggrrow != NULL);
3924  assert(SCIPisPositive(scip, scale));
3925  assert(success != NULL);
3926 
3927  SCIPdebugMsg(scip, "calculating MIR cut (scale: %g)\n", scale);
3928 
3929  *success = FALSE;
3930 
3931  /* allocate temporary memory */
3932  nvars = SCIPgetNVars(scip);
3933  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
3934  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
3935  SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
3936  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, QUAD_ARRAY_SIZE(nvars)) );
3937 
3938  /* initialize cut with aggregation */
3939  tmpnnz = aggrrow->nnz;
3940  tmpislocal = aggrrow->local;
3941 
3942  SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
3943 
3944  if( tmpnnz > 0 )
3945  {
3946  BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
3947 
3948  for( i = 0; i < tmpnnz; ++i )
3949  {
3950  SCIP_Real QUAD(coef);
3951  int k = aggrrow->inds[i];
3952 
3953  QUAD_ARRAY_LOAD(coef, aggrrow->vals, k);
3954 
3955  SCIPquadprecProdQD(coef, coef, scale);
3956 
3957  QUAD_ARRAY_STORE(tmpcoefs, k, coef);
3958 
3959  assert(QUAD_HI(coef) != 0.0);
3960  }
3961 
3962  /* Transform equation a*x == b, lb <= x <= ub into standard form
3963  * a'*x' == b, 0 <= x' <= ub'.
3964  *
3965  * Transform variables (lb or ub):
3966  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
3967  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
3968  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
3969  *
3970  * Transform variables (vlb or vub):
3971  * 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.
3972  * 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.
3973  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
3974  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
3975  * a_{zu_j} := a_{zu_j} + a_j * bu_j
3976  */
3977  SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
3978  boundsfortrans, boundtypesfortrans, minfrac, maxfrac, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, varsign, boundtype, &freevariable, &localbdsused) );
3979  assert(allowlocal || !localbdsused);
3980  tmpislocal = tmpislocal || localbdsused;
3981 
3982  if( freevariable )
3983  goto TERMINATE;
3984 
3985  SCIPdebugMsg(scip, "Aggregated and transformed:\n");
3986  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE));
3987  }
3988 
3989  /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
3990  * a~*x' <= down(b)
3991  * integers : a~_j = down(a'_j) , if f_j <= f_0
3992  * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
3993  * continuous: a~_j = 0 , if a'_j >= 0
3994  * a~_j = a'_j/(1 - f0) , if a'_j < 0
3995  *
3996  * Transform inequality back to a^*x <= rhs:
3997  *
3998  * (lb or ub):
3999  * 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
4000  * 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
4001  * and move the constant terms
4002  * -a~_j * lb_j == -a^_j * lb_j, or
4003  * a~_j * ub_j == -a^_j * ub_j
4004  * to the rhs.
4005  *
4006  * (vlb or vub):
4007  * 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)
4008  * 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)
4009  * move the constant terms
4010  * -a~_j * dl_j == -a^_j * dl_j, or
4011  * a~_j * du_j == -a^_j * du_j
4012  * to the rhs, and update the VB variable coefficients:
4013  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4014  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4015  */
4016  SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
4017  SCIPquadprecSumQQ(f0, rhs, -downrhs);
4018  assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
4019 
4020  if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
4021  goto TERMINATE;
4022 
4023  /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4024  * If this gives a scalar that is very big, we better do not generate this cut.
4025  */
4026  if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
4027  goto TERMINATE;
4028 
4029  /* renormalize f0 value */
4030  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4031 
4032  QUAD_ASSIGN_Q(rhs, downrhs);
4033 
4034  if( tmpnnz > 0 )
4035  {
4036  SCIP_CALL( cutsRoundMIR(scip, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, varsign, boundtype, QUAD(f0)) );
4037 
4038  SCIPdebugMsg(scip, "After MIR rounding:\n");
4039  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE));
4040  }
4041 
4042  /* substitute aggregated slack variables:
4043  *
4044  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4045  * variable only appears in its own row:
4046  * a'_r = scale * weight[r] * slacksign[r].
4047  *
4048  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4049  * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4050  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4051  * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4052  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4053  *
4054  * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4055  */
4056  SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4057  aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, QUAD(f0)) );
4058 
4059  SCIPdebugMsg(scip, "After slack substitution:\n");
4060  SCIPdebug( printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE) );
4061 
4062  if( postprocess )
4063  {
4064  /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4065  * prevent numerical rounding errors
4066  */
4067  SCIP_CALL( postprocessCutQuad(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, QUAD(&rhs), success) );
4068  }
4069  else
4070  {
4071  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), tmpislocal, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz);
4072  }
4073 
4074  SCIPdebugMsg(scip, "After post processing:\n");
4075  SCIPdebug( printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE) );
4076 
4077  if( *success )
4078  {
4079  SCIP_Real mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, tmpnnz);
4080 
4081  if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
4082  {
4083  BMScopyMemoryArray(cutinds, tmpinds, tmpnnz);
4084  *cutnnz = tmpnnz;
4085  *cutrhs = QUAD_TO_DBL(rhs);
4086  *cutislocal = tmpislocal;
4087 
4088  /* clean tmpcoefs and go back to double precision */
4089  for( i = 0; i < *cutnnz; ++i )
4090  {
4091  SCIP_Real QUAD(coef);
4092  int j = cutinds[i];
4093 
4094  QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
4095 
4096  cutcoefs[i] = QUAD_TO_DBL(coef);
4097  QUAD_ASSIGN(coef, 0.0);
4098  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
4099  }
4100 
4101  if( cutefficacy != NULL )
4102  *cutefficacy = mirefficacy;
4103 
4104  if( cutrank != NULL )
4105  *cutrank = aggrrow->rank + 1;
4106  }
4107  else
4108  {
4109  *success = FALSE;
4110  }
4111  }
4112 
4113  TERMINATE:
4114  if( !(*success) )
4115  {
4116  SCIP_Real QUAD(tmp);
4117 
4118  QUAD_ASSIGN(tmp, 0.0);
4119  for( i = 0; i < tmpnnz; ++i )
4120  {
4121  QUAD_ARRAY_STORE(tmpcoefs, tmpinds[i], tmp);
4122  }
4123  }
4124 
4125  /* free temporary memory */
4126  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
4127  SCIPfreeBufferArray(scip, &tmpinds);
4128  SCIPfreeBufferArray(scip, &boundtype);
4129  SCIPfreeBufferArray(scip, &varsign);
4130 
4131  return SCIP_OKAY;
4132 }
4133 
4134 /** compute the efficacy of the MIR cut for the given values without computing the cut.
4135  * This is used for the CMIR cut generation heuristic.
4136  */
4137 static
4139  SCIP* scip, /**< SCIP datastructure */
4140  SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
4141  SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
4142  SCIP_Real rhs, /**< right hand side of MIR cut */
4143  SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
4144  SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
4145  SCIP_Real delta, /**< delta value to compute the violation for */
4146  int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
4147  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4148  SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
4149  )
4150 {
4151  int i;
4152  SCIP_Real f0pluseps;
4153  SCIP_Real f0;
4154  SCIP_Real onedivoneminusf0;
4155  SCIP_Real scale;
4156  SCIP_Real downrhs;
4157  SCIP_Real norm;
4158  SCIP_Real contscale;
4159 
4160  scale = 1.0 / delta;
4161  rhs *= scale;
4162  downrhs = SCIPfloor(scip, rhs);
4163  f0 = rhs - downrhs;
4164 
4165  if( f0 < minfrac || f0 > maxfrac )
4166  return 0.0;
4167 
4168  onedivoneminusf0 = 1.0 / (1.0 - f0);
4169 
4170  contscale = scale * onedivoneminusf0;
4171 
4172  /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4173  * If this gives a scalar that is very big, we better do not generate this cut.
4174  */
4175  if( contscale > MAXCMIRSCALE )
4176  return 0.0;
4177 
4178  rhs = downrhs;
4179  rhs -= contscale * contactivity;
4180  norm = SQR(contscale) * contsqrnorm;
4181 
4182  assert(!SCIPisFeasZero(scip, f0));
4183  assert(!SCIPisFeasZero(scip, 1.0 - f0));
4184 
4185  f0pluseps = f0 + SCIPepsilon(scip);
4186 
4187  for( i = 0; i < nvars; ++i )
4188  {
4189  SCIP_Real floorai = SCIPfloor(scip, scale * coefs[i]);
4190  SCIP_Real fi = (scale * coefs[i]) - floorai;
4191 
4192  if( fi > f0pluseps )
4193  floorai += (fi - f0) * onedivoneminusf0;
4194 
4195  rhs -= solvals[i] * floorai;
4196  norm += SQR(floorai);
4197  }
4198 
4199  norm = sqrt(norm);
4200 
4201  return - rhs / MAX(norm, 1e-6);
4202 }
4203 
4204 /** calculates an MIR cut out of an aggregation of LP rows
4205  *
4206  * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
4207  * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
4208  * One of the steps of the MIR is to round the coefficients of the integer variables down,
4209  * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
4210  * mkset.
4211  *
4212  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4213  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4214  *
4215  * @pre This method can be called if @p scip is in one of the following stages:
4216  * - \ref SCIP_STAGE_SOLVING
4217  *
4218  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
4219  */
4221  SCIP* scip, /**< SCIP data structure */
4222  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4223  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
4224  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4225  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
4226  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4227  int maxtestdelta, /**< maximum number of deltas to test */
4228  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4229  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4230  * NULL for using closest bound for all variables */
4231  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4232  * NULL for using closest bound for all variables */
4233  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4234  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
4235  SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
4236  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
4237  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
4238  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
4239  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
4240  SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
4241  * this efficacy on input to this function are returned */
4242  int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
4243  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
4244  SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
4245  )
4246 {
4247  int i;
4248  int firstcontvar;
4249  int nvars;
4250  int intstart;
4251  int ntmpcoefs;
4252  int* varsign;
4253  int* boundtype;
4254  int* mksetinds;
4255  SCIP_Real* mksetcoefs;
4256  SCIP_Real QUAD(mksetrhs);
4257  int mksetnnz;
4258  SCIP_Real* bounddist;
4259  int* bounddistpos;
4260  int nbounddist;
4261  SCIP_Real* tmpcoefs;
4262  SCIP_Real* tmpvalues;
4263  SCIP_Real* deltacands;
4264  int ndeltacands;
4265  SCIP_Real bestdelta;
4266  SCIP_Real bestefficacy;
4267  SCIP_Real maxabsmksetcoef;
4268  SCIP_VAR** vars;
4269  SCIP_Bool freevariable;
4270  SCIP_Bool localbdsused;
4271  SCIP_Real contactivity;
4272  SCIP_Real contsqrnorm;
4273 
4274  assert(aggrrow != NULL);
4275  assert(aggrrow->nrows + aggrrow->nnz >= 1);
4276  assert(success != NULL);
4277 
4278  *success = FALSE;
4279  nvars = SCIPgetNVars(scip);
4280  firstcontvar = nvars - SCIPgetNContVars(scip);
4281  vars = SCIPgetVars(scip);
4282 
4283  /* allocate temporary memory */
4284  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
4285  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
4286  SCIP_CALL( SCIPallocCleanBufferArray(scip, &mksetcoefs, QUAD_ARRAY_SIZE(nvars)) );
4287  SCIP_CALL( SCIPallocBufferArray(scip, &mksetinds, nvars) );
4288  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
4289  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
4290  SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, aggrrow->nnz + 6) );
4291 
4292  /* we only compute bound distance for integer variables; we allocate an array of length aggrrow->nnz to store this, since
4293  * this is the largest number of integer variables. (in contrast to the number of total variables which can be 2 *
4294  * aggrrow->nnz variables: if all are continuous and we use variable bounds to completement, we introduce aggrrow->nnz
4295  * extra vars)
4296  */
4297  SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, aggrrow->nnz) );
4298  SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, aggrrow->nnz) );
4299 
4300  /* initialize mkset with aggregation */
4301  mksetnnz = aggrrow->nnz;
4302  QUAD_ASSIGN_Q(mksetrhs, aggrrow->rhs);
4303 
4304  BMScopyMemoryArray(mksetinds, aggrrow->inds, mksetnnz);
4305 
4306  for( i = 0; i < mksetnnz; ++i )
4307  {
4308  int j = mksetinds[i];
4309  SCIP_Real QUAD(coef);
4310  QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
4311  QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4312  assert(QUAD_HI(coef) != 0.0);
4313  }
4314 
4315  *cutislocal = aggrrow->local;
4316 
4317  /* Transform equation a*x == b, lb <= x <= ub into standard form
4318  * a'*x' == b, 0 <= x' <= ub'.
4319  *
4320  * Transform variables (lb or ub):
4321  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
4322  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
4323  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
4324  *
4325  * Transform variables (vlb or vub):
4326  * 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.
4327  * 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.
4328  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
4329  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
4330  * a_{zu_j} := a_{zu_j} + a_j * bu_j
4331  */
4332  SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, FALSE, FALSE,
4333  boundsfortrans, boundtypesfortrans, minfrac, maxfrac, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, &freevariable, &localbdsused) );
4334 
4335  assert(allowlocal || !localbdsused);
4336 
4337  if( freevariable )
4338  goto TERMINATE;
4339 
4340  SCIPdebugMsg(scip, "transformed aggrrow row:\n");
4341  SCIPdebug( printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE) );
4342 
4343  /* found positions of integral variables that are strictly between their bounds */
4344  maxabsmksetcoef = -1.0;
4345  nbounddist = 0;
4346 
4347  for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
4348  {
4349  SCIP_VAR* var = vars[mksetinds[i]];
4350  SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
4351  SCIP_Real lb = SCIPvarGetLbLocal(var);
4352  SCIP_Real ub = SCIPvarGetUbLocal(var);
4353  SCIP_Real QUAD(coef);
4354 
4355  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4356 
4357  if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
4358  continue;
4359 
4360  bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
4361  bounddistpos[nbounddist] = i;
4362  deltacands[nbounddist] = QUAD_TO_DBL(coef);
4363  ++nbounddist;
4364  }
4365 
4366  /* no fractional variable; so abort here */
4367  if( nbounddist == 0 )
4368  goto TERMINATE;
4369 
4370  intstart = i + 1;
4371  ndeltacands = nbounddist;
4372 
4373  SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
4374 
4375  {
4376  SCIP_Real intscale;
4377  SCIP_Bool intscalesuccess;
4378 
4379  SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -SCIPepsilon(scip), SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
4380 
4381  if( intscalesuccess )
4382  {
4383  SCIP_Real intf0;
4384  SCIP_Real intscalerhs;
4385  SCIP_Real delta;
4386 
4387  intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4388  delta = 1.0 / intscale;
4389  intf0 = intscalerhs - floor(intscalerhs);
4390 
4391  if( ! SCIPisFeasIntegral(scip, intf0) )
4392  {
4393  if( intf0 < minfrac || intf0 > maxfrac )
4394  {
4395  intscale *= SCIPceil(scip, MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
4396  intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4397  delta = 1.0 / intscale;
4398  intf0 = intscalerhs - floor(intscalerhs);
4399  }
4400 
4401  if( intf0 >= minfrac && intf0 <= maxfrac )
4402  {
4403  if( ! SCIPisEQ(scip, delta, 1.0) )
4404  deltacands[ndeltacands++] = delta;
4405 
4406  if( intf0 < maxfrac )
4407  {
4408  SCIP_Real delta2;
4409 
4410  delta2 = 1.0 / (intscale * SCIPfloor(scip, maxfrac / intf0));
4411 
4412  if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
4413  deltacands[ndeltacands++] = delta2;
4414  }
4415  }
4416  }
4417  }
4418  }
4419 
4420  for( i = 0; i < nbounddist; ++i )
4421  {
4422  SCIP_Real absmksetcoef;
4423 
4424  absmksetcoef = REALABS(deltacands[i]);
4425  maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
4426 
4427  deltacands[i] = absmksetcoef;
4428  }
4429 
4430  /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
4431  if( maxabsmksetcoef != -1.0 )
4432  deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
4433 
4434  deltacands[ndeltacands++] = 1.0;
4435 
4436  maxtestdelta = MIN(ndeltacands, maxtestdelta);
4437 
4438  /* For each delta
4439  * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
4440  * a~*x' <= down(b)
4441  * integers : a~_j = down(a'_j) , if f_j <= f_0
4442  * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
4443  * continuous: a~_j = 0 , if a'_j >= 0
4444  * a~_j = a'_j/(1 - f0) , if a'_j < 0
4445  *
4446  * Transform inequality back to a^*x <= rhs:
4447  *
4448  * (lb or ub):
4449  * 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
4450  * 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
4451  * and move the constant terms
4452  * -a~_j * lb_j == -a^_j * lb_j, or
4453  * a~_j * ub_j == -a^_j * ub_j
4454  * to the rhs.
4455  *
4456  * (vlb or vub):
4457  * 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)
4458  * 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)
4459  * move the constant terms
4460  * -a~_j * dl_j == -a^_j * dl_j, or
4461  * a~_j * du_j == -a^_j * du_j
4462  * to the rhs, and update the VB variable coefficients:
4463  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4464  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4465  */
4466 
4467  ntmpcoefs = 0;
4468  for( i = intstart; i < mksetnnz; ++i )
4469  {
4470  SCIP_VAR* var;
4471  SCIP_Real solval;
4472  SCIP_Real QUAD(coef);
4473 
4474  var = vars[mksetinds[i]];
4475 
4476  /* get the soltion value of the continuous variable */
4477  solval = SCIPgetSolVal(scip, sol, var);
4478 
4479  /* now compute the solution value in the transform space considering complementation */
4480  if( boundtype[i] == -1 )
4481  {
4482  /* variable was complemented with global (simple) bound */
4483  if( varsign[i] == -1 )
4484  solval = SCIPvarGetUbGlobal(var) - solval;
4485  else
4486  solval = solval - SCIPvarGetLbGlobal(var);
4487  }
4488  else
4489  {
4490  assert(boundtype[i] == -2);
4491 
4492  /* variable was complemented with local (simple) bound */
4493  if( varsign[i] == -1 )
4494  solval = SCIPvarGetUbLocal(var) - solval;
4495  else
4496  solval = solval - SCIPvarGetLbLocal(var);
4497  }
4498 
4499  tmpvalues[ntmpcoefs] = solval;
4500  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4501  tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
4502  ++ntmpcoefs;
4503  }
4504 
4505  assert(ntmpcoefs == mksetnnz - intstart);
4506 
4507  contactivity = 0.0;
4508  contsqrnorm = 0.0;
4509  for( i = 0; i < intstart; ++i )
4510  {
4511  SCIP_Real solval;
4512  SCIP_Real QUAD(mksetcoef);
4513 
4514  QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
4515 
4516  if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
4517  continue;
4518 
4519  /* get the soltion value of the continuous variable */
4520  solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4521 
4522  /* now compute the solution value in the transform space considering complementation */
4523  switch( boundtype[i] )
4524  {
4525  case -1:
4526  /* variable was complemented with global (simple) bound */
4527  if( varsign[i] == -1 )
4528  solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
4529  else
4530  solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
4531  break;
4532  case -2:
4533  /* variable was complemented with local (simple) bound */
4534  if( varsign[i] == -1 )
4535  solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
4536  else
4537  solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
4538  break;
4539  default:
4540  /* variable was complemented with a variable bound */
4541  if( varsign[i] == -1 )
4542  {
4543  SCIP_Real coef;
4544  SCIP_Real constant;
4545  SCIP_Real vbdsolval;
4546 
4547  coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
4548  constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
4549  vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
4550 
4551  solval = (coef * vbdsolval + constant) - solval;
4552  }
4553  else
4554  {
4555  SCIP_Real coef;
4556  SCIP_Real constant;
4557  SCIP_Real vbdsolval;
4558 
4559  coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
4560  constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
4561  vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
4562 
4563  solval = solval - (coef * vbdsolval + constant);
4564  }
4565  }
4566 
4567  contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
4568  contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
4569  }
4570 
4571  {
4572  SCIP_ROW** rows;
4573 
4574  rows = SCIPgetLPRows(scip);
4575 
4576  for( i = 0; i < aggrrow->nrows; ++i )
4577  {
4578  SCIP_ROW* row;
4579  SCIP_Real slackval;
4580 
4581  row = rows[aggrrow->rowsinds[i]];
4582 
4583  if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
4584  continue;
4585 
4586  /* compute solution value of slack variable */
4587  slackval = SCIPgetRowSolActivity(scip, row, sol);
4588 
4589  if( aggrrow->slacksign[i] == +1 )
4590  {
4591  /* right hand side */
4592  assert(!SCIPisInfinity(scip, row->rhs));
4593 
4594  slackval = row->rhs - slackval;
4595  }
4596  else
4597  {
4598  /* left hand side */
4599  assert(aggrrow->slacksign[i] == -1);
4600  assert(!SCIPisInfinity(scip, -row->lhs));
4601 
4602  slackval = slackval - row->lhs;
4603  }
4604 
4605  if( row->integral )
4606  {
4607  /* if row is integral add variable to tmp arrays */
4608  tmpvalues[ntmpcoefs] = slackval;
4609  tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
4610  ++ntmpcoefs;
4611  }
4612  else
4613  {
4614  SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
4615 
4616  /* otherwise add it to continuous activity */
4617  contactivity += slackval * slackcoeff;
4618  contsqrnorm += SQR(slackcoeff);
4619  }
4620  }
4621  }
4622 
4623  /* try all candidates for delta and remember best */
4624  bestdelta = SCIP_INVALID;
4625  bestefficacy = -SCIPinfinity(scip);
4626 
4627  for( i = 0; i < maxtestdelta; ++i )
4628  {
4629  int j;
4630  SCIP_Real efficacy;
4631 
4632  /* check if we have seen this value of delta before */
4633  SCIP_Bool deltaseenbefore = FALSE;
4634  for( j = 0; j < i; ++j )
4635  {
4636  if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
4637  {
4638  deltaseenbefore = TRUE;
4639  break;
4640  }
4641  }
4642 
4643  /* skip this delta value and allow one more delta value if available */
4644  if( deltaseenbefore )
4645  {
4646  maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
4647  continue;
4648  }
4649 
4650  efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
4651 
4652  if( efficacy > bestefficacy )
4653  {
4654  bestefficacy = efficacy;
4655  bestdelta = deltacands[i];
4656  }
4657  }
4658 
4659  /* no delta was found that yielded any cut */
4660  if( bestdelta == SCIP_INVALID ) /*lint !e777*/
4661  goto TERMINATE;
4662 
4663  /* try bestdelta divided by 2, 4 and 8 */
4664  {
4665  SCIP_Real basedelta = bestdelta;
4666  for( i = 2; i <= 8 ; i *= 2 )
4667  {
4668  SCIP_Real efficacy;
4669  SCIP_Real delta;
4670 
4671  delta = basedelta / i;
4672 
4673  efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
4674 
4675  if( efficacy > bestefficacy )
4676  {
4677  bestefficacy = efficacy;
4678  bestdelta = delta;
4679  }
4680  }
4681  }
4682 
4683  /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
4684  * in order of non-increasing bound distance
4685  */
4686  for( i = 0; i < nbounddist; ++i )
4687  {
4688  int k;
4689  SCIP_Real newefficacy;
4690  SCIP_Real QUAD(newrhs);
4691  SCIP_Real QUAD(quadprod);
4692  SCIP_Real bestlb;
4693  SCIP_Real bestub;
4694  SCIP_Real oldsolval;
4695  SCIP_Real simplebnd;
4696  int bestlbtype;
4697  int bestubtype;
4698 
4699  k = bounddistpos[i];
4700 
4701  SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &simplebnd, &bestlbtype) );
4702 
4703  if( SCIPisInfinity(scip, -bestlb) )
4704  continue;
4705 
4706  SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &simplebnd, &bestubtype) );
4707 
4708  if( SCIPisInfinity(scip, bestub) )
4709  continue;
4710 
4711  /* switch the complementation of this variable */
4712 #ifndef NDEBUG
4713  {
4714  SCIP_Real QUAD(coef);
4715  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
4716  assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
4717  }
4718 #endif
4719 
4720  /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
4721  SCIPquadprecProdDD(quadprod, tmpcoefs[k - intstart], bestlb - bestub);
4722  SCIPquadprecSumQQ(newrhs, mksetrhs, quadprod);
4723  tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4724 
4725  oldsolval = tmpvalues[k - intstart];
4726  tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
4727 
4728  /* compute new violation */
4729  newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
4730 
4731  /* check if violaton was increased */
4732  if( newefficacy > bestefficacy )
4733  {
4734  /* keep change of complementation */
4735  bestefficacy = newefficacy;
4736  QUAD_ASSIGN_Q(mksetrhs, newrhs);
4737 
4738  if( varsign[k] == +1 )
4739  {
4740  /* switch to upper bound */
4741  assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4742  boundtype[k] = bestubtype;
4743  varsign[k] = -1;
4744  }
4745  else
4746  {
4747  /* switch to lower bound */
4748  assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4749  boundtype[k] = bestlbtype;
4750  varsign[k] = +1;
4751  }
4752 
4753  localbdsused = localbdsused || (boundtype[k] == -2);
4754  }
4755  else
4756  {
4757  /* undo the change of the complementation */
4758  tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4759  tmpvalues[k - intstart] = oldsolval;
4760  }
4761  } /*lint !e438*/
4762 
4763  if( bestefficacy > 0.0 )
4764  {
4765  SCIP_Real mirefficacy;
4766  SCIP_Real QUAD(downrhs);
4767  SCIP_Real QUAD(f0);
4768  SCIP_Real scale;
4769 
4770  scale = 1.0 / bestdelta;
4771  SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
4772  SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
4773  SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
4774  assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
4775 
4776  /* renormaliize f0 value */
4777  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4778 
4779  for( i = 0; i < mksetnnz; ++i )
4780  {
4781  SCIP_Real QUAD(coef);
4782 
4783  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4784  SCIPquadprecProdQD(coef, coef, scale);
4785  QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
4786  }
4787  SCIPdebugMsg(scip, "applied best scale (=%.13g):\n", scale);
4788  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4789 
4790  QUAD_ASSIGN_Q(mksetrhs, downrhs);
4791 
4792  SCIP_CALL( cutsRoundMIR(scip, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, QUAD(f0)) );
4793 
4794  SCIPdebugMsg(scip, "rounded MIR cut:\n");
4795  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4796 
4797  /* substitute aggregated slack variables:
4798  *
4799  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4800  * variable only appears in its own row:
4801  * a'_r = scale * weight[r] * slacksign[r].
4802  *
4803  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4804  * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4805  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4806  * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4807  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4808  *
4809  * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4810  */
4811  SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4812  aggrrow->nrows, scale, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, QUAD(f0)) );
4813 
4814  SCIPdebugMsg(scip, "substituted slacks in MIR cut:\n");
4815  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4816 
4817 #ifndef NDEBUG
4818  {
4819  SCIP_Real efficacy = -QUAD_TO_DBL(mksetrhs);
4820  for( i = 0; i < mksetnnz; ++i )
4821  {
4822  SCIP_Real QUAD(coef);
4823  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4824  efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4825  }
4826 
4827  if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
4828  {
4829  SCIPdebugMsg(scip, "efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
4830  }
4831  }
4832 #endif
4833 
4834  *cutislocal = *cutislocal || localbdsused;
4835 
4836  /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4837  * prevent numerical rounding errors
4838  */
4839  if( postprocess )
4840  {
4841  SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &mksetnnz, QUAD(&mksetrhs), success) );
4842  }
4843  else
4844  {
4845  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz);
4846  }
4847 
4848  SCIPdebugMsg(scip, "post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
4849  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4850 
4851  if( *success )
4852  {
4853  mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(mksetrhs), mksetinds, mksetnnz);
4854 
4855  if( SCIPisEfficacious(scip, mirefficacy) && mirefficacy > *cutefficacy )
4856  {
4857  BMScopyMemoryArray(cutinds, mksetinds, mksetnnz);
4858  for( i = 0; i < mksetnnz; ++i )
4859  {
4860  SCIP_Real QUAD(coef);
4861  int j = cutinds[i];
4862 
4863  QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
4864 
4865  cutcoefs[i] = QUAD_TO_DBL(coef);
4866  QUAD_ASSIGN(coef, 0.0);
4867  QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4868  }
4869  *cutnnz = mksetnnz;
4870  *cutrhs = QUAD_TO_DBL(mksetrhs);
4871  *cutefficacy = mirefficacy;
4872  if( cutrank != NULL )
4873  *cutrank = aggrrow->rank + 1;
4874  *cutislocal = *cutislocal || localbdsused;
4875  }
4876  else
4877  *success = FALSE;
4878  }
4879  }
4880 
4881  TERMINATE:
4882  /* if we aborted early we need to clean the mksetcoefs */
4883  if( !(*success) )
4884  {
4885  SCIP_Real QUAD(tmp);
4886  QUAD_ASSIGN(tmp, 0.0);
4887 
4888  for( i = 0; i < mksetnnz; ++i )
4889  {
4890  QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
4891  }
4892  }
4893 
4894  /* free temporary memory */
4895  SCIPfreeBufferArray(scip, &bounddistpos);
4896  SCIPfreeBufferArray(scip, &bounddist);
4897  SCIPfreeBufferArray(scip, &deltacands);
4898  SCIPfreeBufferArray(scip, &tmpvalues);
4899  SCIPfreeBufferArray(scip, &tmpcoefs);
4900  SCIPfreeBufferArray(scip, &mksetinds);
4901  SCIPfreeCleanBufferArray(scip, &mksetcoefs);
4902  SCIPfreeBufferArray(scip, &boundtype);
4903  SCIPfreeBufferArray(scip, &varsign);
4904 
4905  return SCIP_OKAY;
4906 }
4907 
4908 /* =========================================== flow cover =========================================== */
4909 
4910 #define NO_EXACT_KNAPSACK
4911 
4912 #ifndef NO_EXACT_KNAPSACK
4913 #define MAXDNOM 1000LL
4914 #define MINDELTA 1e-03
4915 #define MAXDELTA 1e-09
4916 #define MAXSCALE 1000.0
4917 #define MAXDYNPROGSPACE 1000000
4918 #endif
4919 
4920 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
4921 #define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
4922 
4923 /** structure that contains all data required to perform the sequence independent lifting
4924  */
4925 typedef
4926 struct LiftingData
4927 {
4928  SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
4929  SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
4930  * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
4931  * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
4932  * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
4933  * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
4934  */
4935  int r; /**< size of array m */
4936  int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
4937  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$ */
4938  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$ */
4939  SCIP_Real lambda; /**< excess of the flowcover */
4940  SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
4941  SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
4942 } LIFTINGDATA;
4943 
4944 /** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
4945 typedef
4946 struct SNF_Relaxation
4947 {
4948  int* transvarcoefs; /**< coefficients of all vars in relaxed set */
4949  SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
4950  SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
4951  SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
4952  int ntransvars; /**< number of vars in relaxed set */
4953  SCIP_Real transrhs; /**< rhs in relaxed set */
4954  int* origbinvars; /**< associated original binary var for all vars in relaxed set */
4955  int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
4956  SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
4957  * continuous variable in the relaxed set */
4958  SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
4959  * continuous variable in the relaxed set */
4960  SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
4961 } SNF_RELAXATION;
4962 
4963 /** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
4964  * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
4965  * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
4966  * given variable
4967  */
4968 static
4970  SCIP* scip, /**< SCIP data structure */
4971  SCIP_VAR* var, /**< given active problem variable */
4972  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
4973  SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
4974  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
4975  * was not used (0) or was not used but is contained in the row (-1)
4976  */
4977  SCIP_Real bestsub, /**< closest simple upper bound of given variable */
4978  SCIP_Real rowcoef, /**< coefficient of given variable in current row */
4979  SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
4980  int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
4981  )
4982 {
4983  int nvlbs;
4984  int nbinvars;
4985 
4986  assert(scip != NULL);
4987  assert(var != NULL);
4988  assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
4989  assert(!SCIPisInfinity(scip, bestsub));
4990  assert(!EPSZ(rowcoef, QUAD_EPSILON));
4991  assert(rowcoefs != NULL);
4992  assert(binvarused != NULL);
4993  assert(closestvlb != NULL);
4994  assert(closestvlbidx != NULL);
4995 
4996  nvlbs = SCIPvarGetNVlbs(var);
4997  nbinvars = SCIPgetNBinVars(scip);
4998 
4999  *closestvlbidx = -1;
5000  *closestvlb = -SCIPinfinity(scip);
5001  if( nvlbs > 0 )
5002  {
5003  SCIP_VAR** vlbvars;
5004  SCIP_Real* vlbcoefs;
5005  SCIP_Real* vlbconsts;
5006  int i;
5007 
5008  vlbvars = SCIPvarGetVlbVars(var);
5009  vlbcoefs = SCIPvarGetVlbCoefs(var);
5010  vlbconsts = SCIPvarGetVlbConstants(var);
5011 
5012  for( i = 0; i < nvlbs; i++ )
5013  {
5014  SCIP_Real rowcoefbinvar;
5015  SCIP_Real val1;
5016  SCIP_Real val2;
5017  SCIP_Real vlbsol;
5018  SCIP_Real rowcoefsign;
5019  int probidxbinvar;
5020 
5021  if( bestsub > vlbconsts[i] )
5022  continue;
5023 
5024  /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5025  * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5026  */
5027  if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
5028  continue;
5029 
5030  /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
5031  probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
5032 
5033  /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5034  * ensures that the problem index is between 0 and nbinvars - 1
5035  */
5036  if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5037  continue;
5038 
5039  assert(SCIPvarIsBinary(vlbvars[i]));
5040 
5041  /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
5042  * (let a_j = coefficient of y_j in current row,
5043  * u_j = closest simple upper bound imposed on y_j,
5044  * c_i = coefficient of x_i in current row)
5045  * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
5046  * if a_j > 0:
5047  * 1. u_j <= d_i
5048  * 2. a_j ( u_j - d_i ) + c_i <= 0
5049  * 3. a_j l~_i + c_i <= 0
5050  * if a_j < 0:
5051  * 1. u_j <= d_i
5052  * 2. a_j ( u_j - d_i ) + c_i >= 0
5053  * 3. a_j l~_i + c_i >= 0
5054  */
5055 
5056  /* has already been used in the SNF relaxation */
5057  if( binvarused[probidxbinvar] == 1 )
5058  continue;
5059 
5060  /* get the row coefficient */
5061  {
5062  SCIP_Real QUAD(tmp);
5063  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
5064  rowcoefbinvar = QUAD_TO_DBL(tmp);
5065  }
5066  rowcoefsign = COPYSIGN(1.0, rowcoef);
5067 
5068  val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
5069 
5070  /* variable lower bound does not meet criteria */
5071  if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
5072  continue;
5073 
5074  val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
5075 
5076  /* variable lower bound does not meet criteria */
5077  if( val1 > 0.0 )
5078  continue;
5079 
5080  vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
5081  if( vlbsol > *closestvlb )
5082  {
5083  *closestvlb = vlbsol;
5084  *closestvlbidx = i;
5085  }
5086  assert(*closestvlbidx >= 0);
5087  }
5088  }
5089 
5090  return SCIP_OKAY;
5091 }
5092 
5093 /** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
5094  * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
5095  * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
5096  * given variable
5097  */
5098 static
5100  SCIP* scip, /**< SCIP data structure */
5101  SCIP_VAR* var, /**< given active problem variable */
5102  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5103  SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
5104  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5105  * was not used (0) or was not used but is contained in the row (-1)
5106  */
5107  SCIP_Real bestslb, /**< closest simple lower bound of given variable */
5108  SCIP_Real rowcoef, /**< coefficient of given variable in current row */
5109  SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
5110  int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
5111  )
5112 {
5113  int nvubs;
5114  int nbinvars;
5115 
5116  assert(scip != NULL);
5117  assert(var != NULL);
5118  assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
5119  assert(!SCIPisInfinity(scip, - bestslb));
5120  assert(!EPSZ(rowcoef, QUAD_EPSILON));
5121  assert(rowcoefs != NULL);
5122  assert(binvarused != NULL);
5123  assert(closestvub != NULL);
5124  assert(closestvubidx != NULL);
5125 
5126  nvubs = SCIPvarGetNVubs(var);
5127  nbinvars = SCIPgetNBinVars(scip);
5128 
5129  *closestvubidx = -1;
5130  *closestvub = SCIPinfinity(scip);
5131  if( nvubs > 0 )
5132  {
5133  SCIP_VAR** vubvars;
5134  SCIP_Real* vubcoefs;
5135  SCIP_Real* vubconsts;
5136  int i;
5137 
5138  vubvars = SCIPvarGetVubVars(var);
5139  vubcoefs = SCIPvarGetVubCoefs(var);
5140  vubconsts = SCIPvarGetVubConstants(var);
5141 
5142  for( i = 0; i < nvubs; i++ )
5143  {
5144  SCIP_Real rowcoefbinvar;
5145  SCIP_Real val1;
5146  SCIP_Real val2;
5147  SCIP_Real vubsol;
5148  SCIP_Real rowcoefsign;
5149  int probidxbinvar;
5150 
5151  if( bestslb < vubconsts[i] )
5152  continue;
5153 
5154  /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5155  * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5156  */
5157  if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
5158  continue;
5159 
5160  /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
5161  probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
5162 
5163  /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5164  * ensures that the problem index is between 0 and nbinvars - 1
5165  */
5166  if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5167  continue;
5168 
5169  assert(SCIPvarIsBinary(vubvars[i]));
5170 
5171  /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
5172  * (let a_j = coefficient of y_j in current row,
5173  * l_j = closest simple lower bound imposed on y_j,
5174  * c_i = coefficient of x_i in current row)
5175  * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
5176  * if a > 0:
5177  * 1. l_j >= d_i
5178  * 2. a_j ( l_i - d_i ) + c_i >= 0
5179  * 3. a_j u~_i + c_i >= 0
5180  * if a < 0:
5181  * 1. l_j >= d_i
5182  * 2. a_j ( l_j - d_i ) + c_i <= 0
5183  * 3. a_j u~_i + c_i <= 0
5184  */
5185 
5186  /* has already been used in the SNF relaxation */
5187  if( binvarused[probidxbinvar] == 1 )
5188  continue;
5189 
5190  /* get the row coefficient */
5191  {
5192  SCIP_Real QUAD(tmp);
5193  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
5194  rowcoefbinvar = QUAD_TO_DBL(tmp);
5195  }
5196  rowcoefsign = COPYSIGN(1.0, rowcoef);
5197 
5198  val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
5199 
5200  /* variable upper bound does not meet criteria */
5201  if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
5202  continue;
5203 
5204  val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
5205 
5206  /* variable upper bound does not meet criteria */
5207  if( val1 < 0.0 )
5208  continue;
5209 
5210  vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
5211  if( vubsol < *closestvub )
5212  {
5213  *closestvub = vubsol;
5214  *closestvubidx = i;
5215  }
5216  assert(*closestvubidx >= 0);
5217  }
5218  }
5219 
5220  return SCIP_OKAY;
5221 }
5222 
5223 /** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
5224  * the given row.
5225  */
5226 static
5228  SCIP* scip, /**< SCIP data structure */
5229  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5230  SCIP_VAR** vars, /**< array of problem variables */
5231  SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
5232  int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
5233  int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
5234  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5235  * was not used (0) or was not used but is contained in the row (-1)
5236  */
5237  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5238  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5239  SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
5240  SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
5241  SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
5242  SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
5243  int* bestlbtype, /**< pointer to store type of best lower bound */
5244  int* bestubtype, /**< pointer to store type of best upper bound */
5245  int* bestslbtype, /**< pointer to store type of best simple lower bound */
5246  int* bestsubtype, /**< pointer to store type of best simple upper bound */
5247  SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
5248  SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
5249  )
5250 {
5251  SCIP_VAR* var;
5252 
5253  SCIP_Real rowcoef;
5254  SCIP_Real solval;
5255  SCIP_Real simplebound;
5256 
5257  int probidx;
5258 
5259  bestlb[varposinrow] = -SCIPinfinity(scip);
5260  bestub[varposinrow] = SCIPinfinity(scip);
5261  bestlbtype[varposinrow] = -3;
5262  bestubtype[varposinrow] = -3;
5263 
5264  probidx = rowinds[varposinrow];
5265  var = vars[probidx];
5266  {
5267  SCIP_Real QUAD(tmp);
5268  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
5269  rowcoef = QUAD_TO_DBL(tmp);
5270  }
5271 
5272  assert(!EPSZ(rowcoef, QUAD_EPSILON));
5273 
5274  /* get closest simple lower bound and closest simple upper bound */
5275  SCIP_CALL( findBestLb(scip, var, sol, 0, allowlocal, &bestslb[varposinrow], &simplebound, &bestslbtype[varposinrow]) );
5276  SCIP_CALL( findBestUb(scip, var, sol, 0, allowlocal, &bestsub[varposinrow], &simplebound, &bestsubtype[varposinrow]) );
5277 
5278  /* do not use too large bounds */
5279  if( bestslb[varposinrow] <= -MAXBOUND )
5280  bestslb[varposinrow] = -SCIPinfinity(scip);
5281 
5282  if( bestsub[varposinrow] >= MAXBOUND )
5283  bestsub[varposinrow] = SCIPinfinity(scip);
5284 
5285  solval = SCIPgetSolVal(scip, sol, var);
5286 
5287  SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
5288  solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
5289 
5290  /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
5291  * and infinity, respectively
5292  */
5293  if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
5294  {
5295  *freevariable = TRUE;
5296  return SCIP_OKAY;
5297  }
5298 
5299  /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
5300  * relaxation
5301  */
5302  if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
5303  {
5304  bestlb[varposinrow] = bestslb[varposinrow];
5305  bestlbtype[varposinrow] = bestslbtype[varposinrow];
5306 
5308  {
5309  SCIP_Real bestvlb;
5310  int bestvlbidx;
5311 
5312  SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
5313  if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
5314  {
5315  bestlb[varposinrow] = bestvlb;
5316  bestlbtype[varposinrow] = bestvlbidx;
5317  }
5318  }
5319  }
5320 
5321  /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
5322  * relaxation
5323  */
5324  if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
5325  {
5326  bestub[varposinrow] = bestsub[varposinrow];
5327  bestubtype[varposinrow] = bestsubtype[varposinrow];
5328 
5330  {
5331  SCIP_Real bestvub;
5332  int bestvubidx;
5333 
5334  SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
5335  if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
5336  {
5337  bestub[varposinrow] = bestvub;
5338  bestubtype[varposinrow] = bestvubidx;
5339  }
5340  }
5341  }
5342  SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
5343 
5344  /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
5345  * to define the transformed variable y'_j
5346  */
5347  if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
5348  {
5349  *freevariable = TRUE;
5350  return SCIP_OKAY;
5351  }
5352 
5353  *freevariable = FALSE;
5354 
5355  /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
5356  * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
5357  * prefer variable bounds
5358  */
5359  if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
5360  {
5361  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5362  }
5363  else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
5364  && bestubtype[varposinrow] >= 0 )
5365  {
5366  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5367  }
5368  else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
5369  {
5370  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5371  }
5372  else
5373  {
5374  assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
5375  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5376  }
5377 
5378  if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
5379  {
5380  int vlbvarprobidx;
5381  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5382 
5383  /* mark binary variable of vlb so that it is not used for other continuous variables
5384  * by setting it's position in the aggrrow to a negative value
5385  */
5386  vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
5387  binvarused[vlbvarprobidx] = 1;
5388  }
5389  else if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
5390  {
5391  int vubvarprobidx;
5392  SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
5393 
5394  /* mark binary variable of vub so that it is not used for other continuous variables
5395  * by setting it's position in the aggrrow to a negative value
5396  */
5397  vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
5398  binvarused[vubvarprobidx] = 1;
5399  }
5400 
5401  return SCIP_OKAY; /*lint !e438*/
5402 }
5403 
5404 /** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
5405  * corresponding to the given aggrrow a * x <= rhs
5406  */
5407 static
5409  SCIP* scip, /**< SCIP data structure */
5410  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5411  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5412  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5413  SCIP_Real* rowcoefs, /**< array of coefficients of row */
5414  QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
5415  int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
5416  int nnz, /**< number of non-zeros in row */
5417  SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
5418  SCIP_Bool* success, /**< stores whether the transformation was valid */
5419  SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5420  )
5421 {
5422  SCIP_VAR** vars;
5423  int i;
5424  int nnonbinvarsrow;
5425  int8_t* binvarused;
5426  int nbinvars;
5427  SCIP_Real QUAD(transrhs);
5428 
5429  /* arrays to store the selected bound for each non-binary variable in the row */
5430  SCIP_Real* bestlb;
5431  SCIP_Real* bestub;
5432  SCIP_Real* bestslb;
5433  SCIP_Real* bestsub;
5434  int* bestlbtype;
5435  int* bestubtype;
5436  int* bestslbtype;
5437  int* bestsubtype;
5438  SCIP_BOUNDTYPE* selectedbounds;
5439 
5440  *success = FALSE;
5441 
5442  SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
5443 
5444  nbinvars = SCIPgetNBinVars(scip);
5445  vars = SCIPgetVars(scip);
5446 
5447  SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
5448  SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
5449  SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
5450  SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
5451  SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
5452  SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
5453  SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
5454  SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
5455  SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
5456 
5457  /* sort descending to have continuous variables first */
5458  SCIPsortDownInt(rowinds, nnz);
5459 
5460  /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
5461  SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
5462 
5463  for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
5464  binvarused[rowinds[i]] = -1;
5465 
5466  nnonbinvarsrow = i + 1;
5467  /* determine the bounds to use for transforming the non-binary variables */
5468  for( i = 0; i < nnonbinvarsrow; ++i )
5469  {
5470  SCIP_Bool freevariable;
5471 
5472  assert(rowinds[i] >= nbinvars);
5473 
5474  SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
5475  bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
5476 
5477  if( freevariable )
5478  {
5479  int j;
5480 
5481  /* clear binvarused at indices of binary variables of row */
5482  for( j = nnz - 1; j >= nnonbinvarsrow; --j )
5483  binvarused[rowinds[j]] = 0;
5484 
5485  /* clear binvarused at indices of selected variable bounds */
5486  for( j = 0; j < i; ++j )
5487  {
5488  if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
5489  {
5490  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
5491  binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
5492  }
5493  else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
5494  {
5495  SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
5496  binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
5497  }
5498  }
5499 
5500  /* terminate */
5501  goto TERMINATE;
5502  }
5503  }
5504 
5505  *localbdsused = FALSE;
5506  QUAD_ASSIGN_Q(transrhs, rowrhs);
5507  snf->ntransvars = 0;
5508 
5509  assert(snf->transvarcoefs != NULL); /* for lint */
5510  assert(snf->transvarvubcoefs != NULL);
5511  assert(snf->transbinvarsolvals != NULL);
5512  assert(snf->transcontvarsolvals != NULL);
5513  assert(snf->aggrconstants != NULL);
5514  assert(snf->aggrcoefscont != NULL);
5515  assert(snf->origcontvars != NULL);
5516  assert(snf->origbinvars != NULL);
5517  assert(snf->aggrcoefsbin != NULL);
5518 
5519  /* transform non-binary variables */
5520  for( i = 0; i < nnonbinvarsrow; ++i )
5521  {
5522  SCIP_VAR* var;
5523  SCIP_Real QUAD(rowcoef);
5524  SCIP_Real solval;
5525  int probidx;
5526 
5527  probidx = rowinds[i];
5528  var = vars[probidx];
5529  QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5530  assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
5531  solval = SCIPgetSolVal(scip, sol, var);
5532 
5533  assert(probidx >= nbinvars);
5534 
5535  if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5536  {
5537  /* use bestlb to define y'_j */
5538 
5539  assert(!SCIPisInfinity(scip, bestsub[i]));
5540  assert(!SCIPisInfinity(scip, - bestlb[i]));
5541  assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
5542  assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
5543 
5544  /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
5545  * in the relaxed set
5546  */
5547  snf->origcontvars[snf->ntransvars] = probidx;
5548 
5549  if( bestlbtype[i] < 0 )
5550  {
5551  SCIP_Real QUAD(val);
5552  SCIP_Real QUAD(contsolval);
5553  SCIP_Real QUAD(rowcoeftimesbestsub);
5554 
5555  /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
5556  * 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
5557  * 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,
5558  * put j into the set
5559  * N2 if a_j > 0
5560  * N1 if a_j < 0
5561  * and update the right hand side of the constraint in the relaxation
5562  * rhs = rhs - a_j u_j
5563  */
5564  SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
5565  SCIPquadprecProdQQ(val, val, rowcoef);
5566  SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
5567  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5568 
5569  if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
5570  *localbdsused = TRUE;
5571 
5572  SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
5573 
5574  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5575  snf->origbinvars[snf->ntransvars] = -1;
5576  snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5577 
5578  if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5579  {
5580  snf->transvarcoefs[snf->ntransvars] = - 1;
5581  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5582  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5583  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5584 
5585  /* aggregation information for y'_j */
5586  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
5587  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5588  }
5589  else
5590  {
5591  snf->transvarcoefs[snf->ntransvars] = 1;
5592  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5593  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5594  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5595 
5596  /* aggregation information for y'_j */
5597  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestsub);
5598  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5599  }
5600  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
5601 
5602  SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5603  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5604  snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
5605  }
5606  else
5607  {
5608  SCIP_Real QUAD(rowcoefbinary);
5609  SCIP_Real varsolvalbinary;
5610  SCIP_Real QUAD(val);
5611  SCIP_Real QUAD(contsolval);
5612  SCIP_Real QUAD(rowcoeftimesvlbconst);
5613  int vlbvarprobidx;
5614 
5615  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5616  SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
5617  SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
5618 
5619  /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
5620  * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j l~_j + c_j ) x_j if a_j > 0
5621  * 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,
5622  * where c_j is the coefficient of x_j in the row, put j into the set
5623  * N2 if a_j > 0
5624  * N1 if a_j < 0
5625  * and update the right hand side of the constraint in the relaxation
5626  * rhs = rhs - a_j d_j
5627  */
5628 
5629  vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
5630  assert(binvarused[vlbvarprobidx] == 1);
5631  assert(vlbvarprobidx < nbinvars);
5632 
5633  QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
5634  varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
5635 
5636  SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
5637  SCIPquadprecSumQQ(val, val, rowcoefbinary);
5638  {
5639  SCIP_Real QUAD(tmp);
5640 
5641  SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
5642  SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
5643  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5644  SCIPquadprecSumQQ(contsolval, contsolval, tmp);
5645  }
5646 
5647  SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
5648 
5649  /* clear the binvarpos array, since the variable has been processed */
5650  binvarused[vlbvarprobidx] = 0;
5651 
5652  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5653  snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
5654 
5655  if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5656  {
5657  snf->transvarcoefs[snf->ntransvars] = - 1;
5658  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5659  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5660  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5661 
5662  /* aggregation information for y'_j */
5663  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5664  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5665  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
5666  }
5667  else
5668  {
5669  snf->transvarcoefs[snf->ntransvars] = 1;
5670  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5671  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5672  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5673 
5674  /* aggregation information for y'_j */
5675  snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5676  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5677  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
5678  }
5679  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
5680 
5681  SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5682  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5683  snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
5684  vlbconsts[bestlbtype[i]], snf->transrhs );
5685  }
5686  }
5687  else
5688  {
5689  /* use bestub to define y'_j */
5690 
5691  assert(!SCIPisInfinity(scip, bestub[i]));
5692  assert(!SCIPisInfinity(scip, - bestslb[i]));
5693  assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
5694  assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
5695 
5696  /* store for y_j that y'_j is the associated real variable
5697  * in the relaxed set
5698  */
5699  snf->origcontvars[snf->ntransvars] = probidx;
5700 
5701  if( bestubtype[i] < 0 )
5702  {
5703  SCIP_Real QUAD(val);
5704  SCIP_Real QUAD(contsolval);
5705  SCIP_Real QUAD(rowcoeftimesbestslb);
5706 
5707  /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
5708  * y'_j = a_j ( y_j - l_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
5709  * y'_j = - a_j ( y_j - l_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
5710  * put j into the set
5711  * N1 if a_j > 0
5712  * N2 if a_j < 0
5713  * and update the right hand side of the constraint in the relaxation
5714  * rhs = rhs - a_j l_j
5715  */
5716  SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
5717  SCIPquadprecProdQQ(val, val, rowcoef);
5718  SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
5719  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5720 
5721  if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
5722  *localbdsused = TRUE;
5723 
5724  SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
5725 
5726  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5727  snf->origbinvars[snf->ntransvars] = -1;
5728  snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5729 
5730  if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5731  {
5732  snf->transvarcoefs[snf->ntransvars] = 1;
5733  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5734  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5735  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5736 
5737  /* aggregation information for y'_j */
5738  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5739  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
5740  }
5741  else
5742  {
5743  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) >= 0.0 )
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  snf->transvarcoefs[snf->ntransvars] = - 1;
5820  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5821  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5822  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5823 
5824  /* aggregation information for y'_j */
5825  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5826  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5827  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
5828  }
5829  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
5830 
5831  /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
5832 
5833  SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5834  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5835  snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
5836  vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
5837  }
5838  }
5839 
5840  /* make sure the coefficient is not negative due to small numerical rounding errors */
5841  assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
5842  snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
5843 
5844  ++snf->ntransvars;
5845  }
5846 
5847  snf->transrhs = QUAD_TO_DBL(transrhs);
5848 
5849  /* transform remaining binary variables of row */
5850  for( i = nnonbinvarsrow; i < nnz; ++i )
5851  {
5852  SCIP_VAR* var;
5853  SCIP_Real QUAD(rowcoef);
5854  int probidx;
5855  SCIP_Real val;
5856  SCIP_Real contsolval;
5857  SCIP_Real varsolval;
5858 
5859  probidx = rowinds[i];
5860  /* variable should be binary */
5861  assert(probidx < nbinvars);
5862 
5863  /* binary variable was processed together with a non-binary variable */
5864  if( binvarused[probidx] == 0 )
5865  continue;
5866 
5867  /* binary variable was not processed yet, so the binvarused value sould be -1 */
5868  assert(binvarused[probidx] == -1);
5869 
5870  /* set binvarused to zero since it has been processed */
5871  binvarused[probidx] = 0;
5872 
5873  var = vars[probidx];
5874  QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5875  assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
5876 
5877  varsolval = SCIPgetSolVal(scip, sol, var);
5878  SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,
5880 
5881  /* define
5882  * y'_j = c_j x_j with 0 <= y'_j <= c_j x_j if c_j > 0
5883  * y'_j = - c_j x_j with 0 <= y'_j <= - c_j x_j if c_j < 0,
5884  * where c_j is the coefficient of x_j in the row and put j into the set
5885  * N1 if c_j > 0
5886  * N2 if c_j < 0.
5887  */
5888  val = QUAD_TO_DBL(rowcoef);
5889  contsolval = QUAD_TO_DBL(rowcoef) * varsolval;
5890 
5891  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5892  snf->origbinvars[snf->ntransvars] = probidx;
5893  snf->origcontvars[snf->ntransvars] = -1;
5894  snf->aggrcoefscont[snf->ntransvars] = 0.0;
5895  snf->aggrconstants[snf->ntransvars] = 0.0;
5896 
5897  if( QUAD_TO_DBL(rowcoef) >= 0.0 )
5898  {
5899  snf->transvarcoefs[snf->ntransvars] = 1;
5900  snf->transvarvubcoefs[snf->ntransvars] = val;
5901  snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5902  snf->transcontvarsolvals[snf->ntransvars] = contsolval;
5903 
5904  /* aggregation information for y'_j */
5905  snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5906  }
5907  else
5908  {
5909  snf->transvarcoefs[snf->ntransvars] = - 1;
5910  snf->transvarvubcoefs[snf->ntransvars] = - val;
5911  snf->transbinvarsolvals[snf->ntransvars] = varsolval;
5912  snf->transcontvarsolvals[snf->ntransvars] = - contsolval;
5913 
5914  /* aggregation information for y'_j */
5915  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5916  }
5917 
5918  assert(snf->transvarcoefs[snf->ntransvars] == 1 || snf->transvarcoefs[snf->ntransvars] == - 1 );
5919  assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[snf->ntransvars], 0.0)
5920  && SCIPisFeasLE(scip, snf->transbinvarsolvals[snf->ntransvars], 1.0));
5921  assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[snf->ntransvars], 0.0)
5922  && !SCIPisInfinity(scip, snf->transvarvubcoefs[snf->ntransvars]));
5923 
5924  SCIPdebugMsg(scip, " --> ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s))\n", snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars,
5925  snf->transvarvubcoefs[snf->ntransvars], snf->ntransvars, SCIPvarGetName(var) );
5926 
5927  /* updates number of variables in transformed problem */
5928  snf->ntransvars++;
5929  }
5930 
5931  /* construction was successful */
5932  *success = TRUE;
5933 
5934 #ifdef SCIP_DEBUG
5935  SCIPdebugMsg(scip, "constraint in constructed 0-1 single node flow relaxation: ");
5936  for( i = 0; i < snf->ntransvars; i++ )
5937  {
5938  SCIPdebugMsgPrint(scip, "%s y'_%d ", snf->transvarcoefs[i] == 1 ? "+" : "-", i);
5939  }
5940  SCIPdebugMsgPrint(scip, "<= %g\n", snf->transrhs);
5941 #endif
5942 
5943  TERMINATE:
5944 
5945  SCIPfreeCleanBufferArray(scip, &binvarused);
5946  SCIPfreeBufferArray(scip, &selectedbounds);
5947  SCIPfreeBufferArray(scip, &bestsubtype);
5948  SCIPfreeBufferArray(scip, &bestslbtype);
5949  SCIPfreeBufferArray(scip, &bestubtype);
5950  SCIPfreeBufferArray(scip, &bestlbtype);
5951  SCIPfreeBufferArray(scip, &bestsub);
5952  SCIPfreeBufferArray(scip, &bestslb);
5953  SCIPfreeBufferArray(scip, &bestub);
5954  SCIPfreeBufferArray(scip, &bestlb);
5955 
5956  return SCIP_OKAY;
5957 }
5958 
5959 /** allocate buffer arrays for storing the single-node-flow relaxation */
5960 static
5962  SCIP* scip, /**< SCIP data structure */
5963  SNF_RELAXATION* snf, /**< pointer to snf relaxation to be destroyed */
5964  int nvars /**< number of active problem variables */
5965  )
5966 {
5967  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transvarcoefs, nvars) );
5968  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transbinvarsolvals, nvars) );
5969  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transcontvarsolvals, nvars) );
5970  SCIP_CALL( SCIPallocBufferArray(scip, &snf->transvarvubcoefs, nvars) );
5971  SCIP_CALL( SCIPallocBufferArray(scip, &snf->origbinvars, nvars) );
5972  SCIP_CALL( SCIPallocBufferArray(scip, &snf->origcontvars, nvars) );
5973  SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrcoefsbin, nvars) );
5974  SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrcoefscont, nvars) );
5975  SCIP_CALL( SCIPallocBufferArray(scip, &snf->aggrconstants, nvars) );
5976 
5977  return SCIP_OKAY;
5978 }
5979 
5980 /** free buffer arrays for storing the single-node-flow relaxation */
5981 static
5983  SCIP* scip, /**< SCIP data structure */
5984  SNF_RELAXATION* snf /**< pointer to snf relaxation to be destroyed */
5985  )
5986 {
5987  SCIPfreeBufferArray(scip, &snf->aggrconstants);
5988  SCIPfreeBufferArray(scip, &snf->aggrcoefscont);
5989  SCIPfreeBufferArray(scip, &snf->aggrcoefsbin);
5990  SCIPfreeBufferArray(scip, &snf->origcontvars);
5991  SCIPfreeBufferArray(scip, &snf->origbinvars);
5995  SCIPfreeBufferArray(scip, &snf->transvarcoefs);
5996 }
5997 
5998 /** solve knapsack problem in maximization form with "<" constraint approximately by greedy; if needed, one can provide
5999  * arrays to store all selected items and all not selected items
6000  */
6001 static
6003  SCIP* scip, /**< SCIP data structure */
6004  int nitems, /**< number of available items */
6005  SCIP_Real* weights, /**< item weights */
6006  SCIP_Real* profits, /**< item profits */
6007  SCIP_Real capacity, /**< capacity of knapsack */
6008  int* items, /**< item numbers */
6009  int* solitems, /**< array to store items in solution, or NULL */
6010  int* nonsolitems, /**< array to store items not in solution, or NULL */
6011  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
6012  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
6013  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
6014  )
6015 {
6016  SCIP_Real* tempsort;
6017  SCIP_Real solitemsweight;
6018  SCIP_Real mediancapacity;
6019  int j;
6020  int i;
6021  int criticalitem;
6022 
6023  assert(weights != NULL);
6024  assert(profits != NULL);
6025  assert(SCIPisFeasGE(scip, capacity, 0.0));
6026  assert(!SCIPisInfinity(scip, capacity));
6027  assert(items != NULL);
6028  assert(nitems >= 0);
6029 
6030  if( solitems != NULL )
6031  {
6032  *nsolitems = 0;
6033  *nnonsolitems = 0;
6034  }
6035  if( solval != NULL )
6036  *solval = 0.0;
6037 
6038  /* allocate memory for temporary array used for sorting; array should contain profits divided by corresponding weights (p_1 / w_1 ... p_n / w_n )*/
6039  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
6040 
6041  /* initialize temporary array */
6042  for( i = nitems - 1; i >= 0; --i )
6043  tempsort[i] = profits[i] / weights[i];
6044 
6045  /* decrease capacity slightly to make it tighter than the original capacity */
6046  mediancapacity = capacity * (1 - SCIPfeastol(scip));
6047 
6048  /* rearrange items around */
6049  SCIPselectWeightedDownRealRealInt(tempsort, profits, items, weights, mediancapacity, nitems, &criticalitem);
6050 
6051  /* free temporary array */
6052  SCIPfreeBufferArray(scip, &tempsort);
6053 
6054  /* select items as long as they fit into the knapsack */
6055  solitemsweight = 0.0;
6056  for( j = 0; j < nitems && SCIPisFeasLT(scip, solitemsweight + weights[j], capacity); j++ )
6057  {
6058  if( solitems != NULL )
6059  {
6060  solitems[*nsolitems] = items[j];
6061  (*nsolitems)++;
6062  }
6063  if( solval != NULL )
6064  (*solval) += profits[j];
6065  solitemsweight += weights[j];
6066  }
6067 
6068  /* continue to put items into the knapsack if they entirely fit */
6069  for( ; j < nitems; j++ )
6070  {
6071  if( SCIPisFeasLT(scip, solitemsweight + weights[j], capacity) )
6072  {
6073  if( solitems != NULL )
6074  {
6075  solitems[*nsolitems] = items[j];
6076  (*nsolitems)++;
6077  }
6078  if( solval != NULL )
6079  (*solval) += profits[j];
6080  solitemsweight += weights[j];
6081  }
6082  else if( solitems != NULL )
6083  {
6084  nonsolitems[*nnonsolitems] = items[j];
6085  (*nnonsolitems)++;
6086  }
6087  }
6088 
6089  return SCIP_OKAY;
6090 }
6091 
6092 
6093 /** build the flow cover which corresponds to the given exact or approximate solution of KP^SNF; given unfinished
6094  * flow cover contains variables which have been fixed in advance
6095  */
6096 static
6098  SCIP* scip, /**< SCIP data structure */
6099  int* coefs, /**< coefficient of all real variables in N1&N2 */
6100  SCIP_Real* vubcoefs, /**< coefficient in vub of all real variables in N1&N2 */
6101  SCIP_Real rhs, /**< right hand side of 0-1 single node flow constraint */
6102  int* solitems, /**< items in knapsack */
6103  int* nonsolitems, /**< items not in knapsack */
6104  int nsolitems, /**< number of items in knapsack */
6105  int nnonsolitems, /**< number of items not in knapsack */
6106  int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6107  int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6108  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6109  QUAD(SCIP_Real* flowcoverweight), /**< pointer to store weight of flow cover */
6110  SCIP_Real* lambda /**< pointer to store lambda */
6111  )
6112 {
6113  int j;
6114  SCIP_Real QUAD(tmp);
6115 
6116  assert(scip != NULL);
6117  assert(coefs != NULL);
6118  assert(vubcoefs != NULL);
6119  assert(solitems != NULL);
6120  assert(nonsolitems != NULL);
6121  assert(nsolitems >= 0);
6122  assert(nnonsolitems >= 0);
6123  assert(nflowcovervars != NULL && *nflowcovervars >= 0);
6124  assert(nnonflowcovervars != NULL && *nnonflowcovervars >= 0);
6125  assert(flowcoverstatus != NULL);
6126  assert(QUAD_HI(flowcoverweight) != NULL);
6127  assert(lambda != NULL);
6128 
6129  /* get flowcover status for each item */
6130  for( j = 0; j < nsolitems; j++ )
6131  {
6132  /* j in N1 with z°_j = 1 => j in N1\C1 */
6133  if( coefs[solitems[j]] == 1 )
6134  {
6135  flowcoverstatus[solitems[j]] = -1;
6136  (*nnonflowcovervars)++;
6137  }
6138  /* j in N2 with z_j = 1 => j in C2 */
6139  else
6140  {
6141  assert(coefs[solitems[j]] == -1);
6142  flowcoverstatus[solitems[j]] = 1;
6143  (*nflowcovervars)++;
6144  SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, -vubcoefs[solitems[j]]);
6145  }
6146  }
6147  for( j = 0; j < nnonsolitems; j++ )
6148  {
6149  /* j in N1 with z°_j = 0 => j in C1 */
6150  if( coefs[nonsolitems[j]] == 1 )
6151  {
6152  flowcoverstatus[nonsolitems[j]] = 1;
6153  (*nflowcovervars)++;
6154  SCIPquadprecSumQD(*flowcoverweight, *flowcoverweight, vubcoefs[nonsolitems[j]]);
6155  }
6156  /* j in N2 with z_j = 0 => j in N2\C2 */
6157  else
6158  {
6159  assert(coefs[nonsolitems[j]] == -1);
6160  flowcoverstatus[nonsolitems[j]] = -1;
6161  (*nnonflowcovervars)++;
6162  }
6163  }
6164 
6165  /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6166  SCIPquadprecSumQD(tmp, *flowcoverweight, -rhs);
6167  *lambda = QUAD_TO_DBL(tmp);
6168 }
6169 
6170 #ifndef NO_EXACT_KNAPSACK
6171 
6172 /** checks, whether the given scalar scales the given value to an integral number with error in the given bounds */
6173 static
6175  SCIP_Real val, /**< value that should be scaled to an integral value */
6176  SCIP_Real scalar, /**< scalar that should be tried */
6177  SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6178  SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6179  )
6180 {
6181  SCIP_Real sval;
6182  SCIP_Real downval;
6183  SCIP_Real upval;
6184 
6185  assert(mindelta <= 0.0);
6186  assert(maxdelta >= 0.0);
6187 
6188  sval = val * scalar;
6189  downval = floor(sval);
6190  upval = ceil(sval);
6191 
6192  return (SCIPrelDiff(sval, downval) <= maxdelta || SCIPrelDiff(sval, upval) >= mindelta);
6193 }
6194 
6195 /** get integral number with error in the bounds which corresponds to given value scaled by a given scalar;
6196  * should be used in connection with isIntegralScalar()
6197  */
6198 static
6199 SCIP_Longint getIntegralVal(
6200  SCIP_Real val, /**< value that should be scaled to an integral value */
6201  SCIP_Real scalar, /**< scalar that should be tried */
6202  SCIP_Real mindelta, /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
6203  SCIP_Real maxdelta /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
6204  )
6205 {
6206  SCIP_Real sval;
6207  SCIP_Real upval;
6208  SCIP_Longint intval;
6209 
6210  assert(mindelta <= 0.0);
6211  assert(maxdelta >= 0.0);
6212 
6213  sval = val * scalar;
6214  upval = ceil(sval);
6215 
6216  if( SCIPrelDiff(sval, upval) >= mindelta )
6217  intval = (SCIP_Longint) upval;
6218  else
6219  intval = (SCIP_Longint) (floor(sval));
6220 
6221  return intval;
6222 }
6223 
6224 /** get a flow cover (C1, C2) for a given 0-1 single node flow set
6225  * {(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},
6226  * 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
6227  */
6228 static
6230  SCIP* scip, /**< SCIP data structure */
6231  SNF_RELAXATION* snf, /**< the single node flow relaxation */
6232  int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6233  int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6234  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6235  SCIP_Real* lambda, /**< pointer to store lambda */
6236  SCIP_Bool* found /**< pointer to store whether a cover was found */
6237  )
6238 {
6239  SCIP_Real* transprofitsint;
6240  SCIP_Real* transprofitsreal;
6241  SCIP_Real* transweightsreal;
6242  SCIP_Longint* transweightsint;
6243  int* items;
6244  int* itemsint;
6245  int* nonsolitems;
6246  int* solitems;
6247  SCIP_Real QUAD(flowcoverweight);
6248  SCIP_Real QUAD(flowcoverweightafterfix);
6249  SCIP_Real n1itemsweight;
6250  SCIP_Real n2itemsminweight;
6251  SCIP_Real scalar;
6252  SCIP_Real transcapacityreal;
6253 #if !defined(NDEBUG) || defined(SCIP_DEBUG)
6254  SCIP_Bool kpexact;
6255 #endif
6256  SCIP_Bool scalesuccess;
6257  SCIP_Bool transweightsrealintegral;
6258  SCIP_Longint transcapacityint;
6259  int nflowcovervarsafterfix;
6260  int nitems;
6261  int nn1items;
6262  int nnonflowcovervarsafterfix;
6263  int nnonsolitems;
6264  int nsolitems;
6265  int j;
6266 
6267  assert(scip != NULL);
6268  assert(snf->transvarcoefs != NULL);
6269  assert(snf->transbinvarsolvals != NULL);
6270  assert(snf->transvarvubcoefs != NULL);
6271  assert(snf->ntransvars > 0);
6272  assert(nflowcovervars != NULL);
6273  assert(nnonflowcovervars != NULL);
6274  assert(flowcoverstatus != NULL);
6275  assert(lambda != NULL);
6276  assert(found != NULL);
6277 
6278  SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6279 
6280  /* get data structures */
6281  SCIP_CALL( SCIPallocBufferArray(scip, &items, snf->ntransvars) );
6282  SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6283  SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
6284  SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsint, snf->ntransvars) );
6285  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
6286  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
6287  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6288  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
6289 
6290  BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
6291  *found = FALSE;
6292  *nflowcovervars = 0;
6293  *nnonflowcovervars = 0;
6294 
6295  QUAD_ASSIGN(flowcoverweight, 0.0);
6296  nflowcovervarsafterfix = 0;
6297  nnonflowcovervarsafterfix = 0;
6298  QUAD_ASSIGN(flowcoverweightafterfix, 0.0);
6299 #if !defined(NDEBUG) || defined(SCIP_DEBUG)
6300  kpexact = FALSE;
6301 #endif
6302 
6303  /* fix some variables in advance according to the following fixing strategy
6304  * put j into N1\C1, if j in N1 and x*_j = 0,
6305  * put j into C1, if j in N1 and x*_j = 1,
6306  * put j into C2, if j in N2 and x*_j = 1,
6307  * put j into N2\C2, if j in N2 and x*_j = 0
6308  * and get the set of the remaining variables
6309  */
6310  SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6311  nitems = 0;
6312  nn1items = 0;
6313  n1itemsweight = 0.0;
6314  n2itemsminweight = SCIP_REAL_MAX;
6315  for( j = 0; j < snf->ntransvars; j++ )
6316  {
6317  assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6318  assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6319  assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6320 
6321  /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6322  if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6323  {
6324  flowcoverstatus[j] = -1;
6325  (*nnonflowcovervars)++;
6326  continue;
6327  }
6328 
6329  /* x*_j is fractional */
6330  if( !SCIPisFeasIntegral(scip, snf->transbinvarsolvals[j]) )
6331  {
6332  items[nitems] = j;
6333  nitems++;
6334  if( snf->transvarcoefs[j] == 1 )
6335  {
6336  n1itemsweight += snf->transvarvubcoefs[j];
6337  nn1items++;
6338  }
6339  else
6340  n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6341  }
6342  /* j is in N1 and x*_j = 0 */
6343  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6344  {
6345  flowcoverstatus[j] = -1;
6346  (*nnonflowcovervars)++;
6347  SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6348  }
6349  /* j is in N1 and x*_j = 1 */
6350  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6351  {
6352  flowcoverstatus[j] = 1;
6353  (*nflowcovervars)++;
6354  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
6355  SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6356  }
6357  /* j is in N2 and x*_j = 1 */
6358  else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6359  {
6360  flowcoverstatus[j] = 1;
6361  (*nflowcovervars)++;
6362  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6363  SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6364  }
6365  /* j is in N2 and x*_j = 0 */
6366  else
6367  {
6368  assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6369  flowcoverstatus[j] = -1;
6370  (*nnonflowcovervars)++;
6371  SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6372  }
6373  }
6374  assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6375  assert(nn1items >= 0);
6376 
6377  /* to find a flow cover, transform the following knapsack problem
6378  *
6379  * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6380  * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6381  * z_j in {0,1} for all j in N1 & N2
6382  *
6383  * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6384  * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6385  *
6386  * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6387  * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6388  * z°_j in {0,1} for all j in N1
6389  * z_j in {0,1} for all j in N2,
6390  * and solve it approximately under consideration of the fixing,
6391  * or
6392  * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6393  * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6394  * and multiplying the constraint by a suitable scalar C
6395  *
6396  * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6397  * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6398  * z°_j in {0,1} for all j in N1
6399  * z_j in {0,1} for all j in N2,
6400  * where
6401  * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6402  * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6403  * and solve it exactly under consideration of the fixing.
6404  */
6405  SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6406 
6407  /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6408  transweightsrealintegral = TRUE;
6409  for( j = 0; j < nitems; j++ )
6410  {
6411  transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6412 
6413  if( !isIntegralScalar(transweightsreal[j], 1.0, -MINDELTA, MAXDELTA) )
6414  transweightsrealintegral = FALSE;
6415 
6416  if( snf->transvarcoefs[items[j]] == 1 )
6417  {
6418  transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6419  SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6420  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6421  }
6422  else
6423  {
6424  transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6425  SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6426  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6427  }
6428  }
6429  /* get capacity of knapsack constraint in KP^SNF_rat */
6430  transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight;
6431  SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6432  snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
6433 
6434  /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6435  * is less than or equal to zero
6436  */
6437  if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6438  {
6439  assert(!(*found));
6440  goto TERMINATE;
6441  }
6442 
6443  /* KP^SNF_rat has been solved by fixing some variables in advance */
6444  assert(nitems >= 0);
6445  if( nitems == 0)
6446  {
6447  /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6448  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
6449  *lambda = QUAD_TO_DBL(flowcoverweight);
6450  *found = TRUE;
6451  goto TERMINATE;
6452  }
6453 
6454  /* Use the following strategy
6455  * solve KP^SNF_int exactly, if a suitable factor C is found and (nitems*capacity) <= MAXDYNPROGSPACE,
6456  * solve KP^SNF_rat approximately, otherwise
6457  */
6458 
6459  /* find a scaling factor C */
6460  if( transweightsrealintegral )
6461  {
6462  /* weights are already integral */
6463  scalar = 1.0;
6464  scalesuccess = TRUE;
6465  }
6466  else
6467  {
6468  scalesuccess = FALSE;
6469  SCIP_CALL( SCIPcalcIntegralScalar(transweightsreal, nitems, -MINDELTA, MAXDELTA, MAXDNOM, MAXSCALE, &scalar,
6470  &scalesuccess) );
6471  }
6472 
6473  /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6474  nsolitems = -1;
6475  nnonsolitems = -1;
6476 
6477  /* suitable factor C was found*/
6478  if( scalesuccess )
6479  {
6480  SCIP_Real tmp1;
6481  SCIP_Real tmp2;
6482 
6483  /* transform KP^SNF to KP^SNF_int */
6484  for( j = 0; j < nitems; ++j )
6485  {
6486  transweightsint[j] = getIntegralVal(transweightsreal[j], scalar, -MINDELTA, MAXDELTA);
6487  transprofitsint[j] = transprofitsreal[j];
6488  itemsint[j] = items[j];
6489  }
6490  if( isIntegralScalar(transcapacityreal, scalar, -MINDELTA, MAXDELTA) )
6491  {
6492  transcapacityint = getIntegralVal(transcapacityreal, scalar, -MINDELTA, MAXDELTA);
6493  transcapacityint -= 1;
6494  }
6495  else
6496  transcapacityint = (SCIP_Longint) (transcapacityreal * scalar);
6497  nflowcovervarsafterfix = *nflowcovervars;
6498  nnonflowcovervarsafterfix = *nnonflowcovervars;
6499  QUAD_ASSIGN_Q(flowcoverweightafterfix, flowcoverweight);
6500 
6501  tmp1 = (SCIP_Real) (nitems + 1);
6502  tmp2 = (SCIP_Real) ((transcapacityint) + 1);
6503  if( transcapacityint * nitems <= MAXDYNPROGSPACE && tmp1 * tmp2 <= INT_MAX / 8.0)
6504  {
6505  SCIP_Bool success;
6506 
6507  /* solve KP^SNF_int by dynamic programming */
6508  SCIP_CALL(SCIPsolveKnapsackExactly(scip, nitems, transweightsint, transprofitsint, transcapacityint,
6509  itemsint, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL, &success));
6510 
6511  if( !success )
6512  {
6513  /* solve KP^SNF_rat approximately */
6514  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal,
6515  transcapacityreal, items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6516  }
6517 #if !defined(NDEBUG) || defined(SCIP_DEBUG)
6518  else
6519  kpexact = TRUE;
6520 #endif
6521  }
6522  else
6523  {
6524  /* solve KP^SNF_rat approximately */
6525  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6526  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6527  assert(!kpexact);
6528  }
6529  }
6530  else
6531  {
6532  /* solve KP^SNF_rat approximately */
6533  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6534  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6535  assert(!kpexact);
6536  }
6537 
6538  assert(nsolitems != -1);
6539  assert(nnonsolitems != -1);
6540 
6541  /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6542  assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6543  buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6544  nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6545  assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6546 
6547  /* if the found structure is not a flow cover, because of scaling, solve KP^SNF_rat approximately */
6548  if( SCIPisFeasLE(scip, *lambda, 0.0) )
6549  {
6550  assert(kpexact);
6551 
6552  /* solve KP^SNF_rat approximately */
6553  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6554  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6555 #ifdef SCIP_DEBUG /* this time only for SCIP_DEBUG, because only then, the variable is used again */
6556  kpexact = FALSE;
6557 #endif
6558 
6559  /* build the flow cover from the solution of KP^SNF_rat and the fixing */
6560  *nflowcovervars = nflowcovervarsafterfix;
6561  *nnonflowcovervars = nnonflowcovervarsafterfix;
6562  QUAD_ASSIGN_Q(flowcoverweight, flowcoverweightafterfix);
6563 
6564  assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6565  buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6566  nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6567  assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6568  }
6569  *found = SCIPisFeasGT(scip, *lambda, 0.0);
6570 
6571  TERMINATE:
6572  assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6573 #ifdef SCIP_DEBUG
6574  if( *found )
6575  {
6576  SCIPdebugMsg(scip, "2. %s solution:\n", kpexact ? "exact" : "approximate");
6577  for( j = 0; j < snf->ntransvars; j++ )
6578  {
6579  if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6580  {
6581  SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6582  }
6583  else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6584  {
6585  SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6586  }
6587  }
6588  SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6589  }
6590 #endif
6591 
6592  /* free data structures */
6593  SCIPfreeBufferArray(scip, &nonsolitems);
6594  SCIPfreeBufferArray(scip, &solitems);
6595  SCIPfreeBufferArray(scip, &transweightsint);
6596  SCIPfreeBufferArray(scip, &transweightsreal);
6597  SCIPfreeBufferArray(scip, &transprofitsint);
6598  SCIPfreeBufferArray(scip, &transprofitsreal);
6599  SCIPfreeBufferArray(scip, &itemsint);
6600  SCIPfreeBufferArray(scip, &items);
6601 
6602  return SCIP_OKAY;
6603 }
6604 
6605 #else
6606 
6607 /** get a flow cover \f$(C1, C2)\f$ for a given 0-1 single node flow set
6608  * \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$,
6609  * i.e., get sets \f$ C1 \subset N1 \f$ and \f$ C2 \subset N2 \f$ with
6610  * \f$ \sum_{j in C1} u_j - sum_{j in C2} u_j = b + lambda \f$ and \f$ lambda > 0 \f$
6611  */
6612 static
6614  SCIP* scip, /**< SCIP data structure */
6615  SNF_RELAXATION* snf, /**< the 0-1 single node flow relaxation */
6616  int* nflowcovervars, /**< pointer to store number of variables in flow cover */
6617  int* nnonflowcovervars, /**< pointer to store number of variables not in flow cover */
6618  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
6619  SCIP_Real* lambda, /**< pointer to store lambda */
6620  SCIP_Bool* found /**< pointer to store whether a cover was found */
6621  )
6622 {
6623  SCIP_Real* transprofitsreal;
6624  SCIP_Real* transweightsreal;
6625  SCIP_Longint* transweightsint;
6626  int* items;
6627  int* itemsint;
6628  int* nonsolitems;
6629  int* solitems;
6630  SCIP_Real QUAD(flowcoverweight);
6631  SCIP_Real n1itemsweight;
6632  SCIP_Real n2itemsminweight;
6633  SCIP_Real transcapacityreal;
6634  int nitems;
6635 #ifndef NDEBUG
6636  int nn1items = 0;
6637 #endif
6638  int nnonsolitems;
6639  int nsolitems;
6640  int j;
6641 
6642  assert(scip != NULL);
6643  assert(snf->transvarcoefs != NULL);
6644  assert(snf->transbinvarsolvals != NULL);
6645  assert(snf->transvarvubcoefs != NULL);
6646  assert(snf->ntransvars > 0);
6647  assert(nflowcovervars != NULL);
6648  assert(nnonflowcovervars != NULL);
6649  assert(flowcoverstatus != NULL);
6650  assert(lambda != NULL);
6651  assert(found != NULL);
6652 
6653  SCIPdebugMsg(scip, "--------------------- get flow cover ----------------------------------------------------\n");
6654 
6655  /* get data structures */
6656  SCIP_CALL( SCIPallocBufferArray(scip, &items, snf->ntransvars) );
6657  SCIP_CALL( SCIPallocBufferArray(scip, &itemsint, snf->ntransvars) );
6658  SCIP_CALL( SCIPallocBufferArray(scip, &transprofitsreal, snf->ntransvars) );
6659  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsreal, snf->ntransvars) );
6660  SCIP_CALL( SCIPallocBufferArray(scip, &transweightsint, snf->ntransvars) );
6661  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, snf->ntransvars) );
6662  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, snf->ntransvars) );
6663 
6664  BMSclearMemoryArray(flowcoverstatus, snf->ntransvars);
6665  *found = FALSE;
6666  *nflowcovervars = 0;
6667  *nnonflowcovervars = 0;
6668 
6669  QUAD_ASSIGN(flowcoverweight, 0.0);
6670 
6671  /* fix some variables in advance according to the following fixing strategy
6672  * put j into N1\C1, if j in N1 and x*_j = 0,
6673  * put j into C1, if j in N1 and x*_j = 1,
6674  * put j into C2, if j in N2 and x*_j = 1,
6675  * put j into N2\C2, if j in N2 and x*_j = 0
6676  * and get the set of the remaining variables
6677  */
6678  SCIPdebugMsg(scip, "0. Fix some variables in advance:\n");
6679  nitems = 0;
6680  n1itemsweight = 0.0;
6681  n2itemsminweight = SCIP_REAL_MAX;
6682  for( j = 0; j < snf->ntransvars; j++ )
6683  {
6684  assert(snf->transvarcoefs[j] == 1 || snf->transvarcoefs[j] == -1);
6685  assert(SCIPisFeasGE(scip, snf->transbinvarsolvals[j], 0.0) && SCIPisFeasLE(scip, snf->transbinvarsolvals[j], 1.0));
6686  assert(SCIPisFeasGE(scip, snf->transvarvubcoefs[j], 0.0));
6687 
6688  /* if u_j = 0, put j into N1\C1 and N2\C2, respectively */
6689  if( SCIPisFeasZero(scip, snf->transvarvubcoefs[j]) )
6690  {
6691  flowcoverstatus[j] = -1;
6692  (*nnonflowcovervars)++;
6693  continue;
6694  }
6695 
6696  /* x*_j is fractional */
6697  if( !SCIPisFeasIntegral(scip, snf->transbinvarsolvals[j]) )
6698  {
6699  items[nitems] = j;
6700  nitems++;
6701  if( snf->transvarcoefs[j] == 1 )
6702  {
6703  n1itemsweight += snf->transvarvubcoefs[j];
6704 #ifndef NDEBUG
6705  nn1items++;
6706 #endif
6707  }
6708  else
6709  n2itemsminweight = MIN(n2itemsminweight, snf->transvarvubcoefs[j]);
6710  }
6711  /* j is in N1 and x*_j = 0 */
6712  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] < 0.5 )
6713  {
6714  flowcoverstatus[j] = -1;
6715  (*nnonflowcovervars)++;
6716  SCIPdebugMsg(scip, " <%d>: in N1-C1\n", j);
6717  }
6718  /* j is in N1 and x*_j = 1 */
6719  else if( snf->transvarcoefs[j] == 1 && snf->transbinvarsolvals[j] > 0.5 )
6720  {
6721  flowcoverstatus[j] = 1;
6722  (*nflowcovervars)++;
6723  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, snf->transvarvubcoefs[j]);
6724  SCIPdebugMsg(scip, " <%d>: in C1\n", j);
6725  }
6726  /* j is in N2 and x*_j = 1 */
6727  else if( snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] > 0.5 )
6728  {
6729  flowcoverstatus[j] = 1;
6730  (*nflowcovervars)++;
6731  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transvarvubcoefs[j]);
6732  SCIPdebugMsg(scip, " <%d>: in C2\n", j);
6733  }
6734  /* j is in N2 and x*_j = 0 */
6735  else
6736  {
6737  assert(snf->transvarcoefs[j] == -1 && snf->transbinvarsolvals[j] < 0.5);
6738  flowcoverstatus[j] = -1;
6739  (*nnonflowcovervars)++;
6740  SCIPdebugMsg(scip, " <%d>: in N2-C2\n", j);
6741  }
6742  }
6743  assert((*nflowcovervars) + (*nnonflowcovervars) + nitems == snf->ntransvars);
6744  assert(nn1items >= 0);
6745 
6746  /* to find a flow cover, transform the following knapsack problem
6747  *
6748  * (KP^SNF) max sum_{j in N1} ( x*_j - 1 ) z_j + sum_{j in N2} x*_j z_j
6749  * sum_{j in N1} u_j z_j - sum_{j in N2} u_j z_j > b
6750  * z_j in {0,1} for all j in N1 & N2
6751  *
6752  * 1. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6753  * positive weights and the constraint is a "<" constraint, by complementing all variables in N1
6754  *
6755  * (KP^SNF_rat) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6756  * sum_{j in N1} u_j z°_j + sum_{j in N2} u_j z_j < - b + sum_{j in N1} u_j
6757  * z°_j in {0,1} for all j in N1
6758  * z_j in {0,1} for all j in N2,
6759  * and solve it approximately under consideration of the fixing,
6760  * or
6761  * 2. to a knapsack problem in maximization form, such that all variables in the knapsack constraint have
6762  * positive integer weights and the constraint is a "<=" constraint, by complementing all variables in N1
6763  * and multiplying the constraint by a suitable scalar C
6764  *
6765  * (KP^SNF_int) max sum_{j in N1} ( 1 - x*_j ) z°_j + sum_{j in N2} x*_j z_j
6766  * sum_{j in N1} C u_j z°_j + sum_{j in N2} C u_j z_j <= c
6767  * z°_j in {0,1} for all j in N1
6768  * z_j in {0,1} for all j in N2,
6769  * where
6770  * c = floor[ C (- b + sum_{j in N1} u_j ) ] if frac[ C (- b + sum_{j in N1} u_j ) ] > 0
6771  * c = C (- b + sum_{j in N1} u_j ) - 1 if frac[ C (- b + sum_{j in N1} u_j ) ] = 0
6772  * and solve it exactly under consideration of the fixing.
6773  */
6774  SCIPdebugMsg(scip, "1. Transform KP^SNF to KP^SNF_rat:\n");
6775 
6776  /* get weight and profit of variables in KP^SNF_rat and check, whether all weights are already integral */
6777  for( j = 0; j < nitems; j++ )
6778  {
6779  transweightsreal[j] = snf->transvarvubcoefs[items[j]];
6780 
6781  if( snf->transvarcoefs[items[j]] == 1 )
6782  {
6783  transprofitsreal[j] = 1.0 - snf->transbinvarsolvals[items[j]];
6784  SCIPdebugMsg(scip, " <%d>: j in N1: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6785  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6786  }
6787  else
6788  {
6789  transprofitsreal[j] = snf->transbinvarsolvals[items[j]];
6790  SCIPdebugMsg(scip, " <%d>: j in N2: w_%d = %g, p_%d = %g %s\n", items[j], items[j], transweightsreal[j],
6791  items[j], transprofitsreal[j], SCIPisIntegral(scip, transweightsreal[j]) ? "" : " ----> NOT integral");
6792  }
6793  }
6794  /* get capacity of knapsack constraint in KP^SNF_rat */
6795  transcapacityreal = - snf->transrhs + QUAD_TO_DBL(flowcoverweight) + n1itemsweight; /*lint !e644*/
6796  SCIPdebugMsg(scip, " transcapacity = -rhs(%g) + flowcoverweight(%g) + n1itemsweight(%g) = %g\n",
6797  snf->transrhs, QUAD_TO_DBL(flowcoverweight), n1itemsweight, transcapacityreal);
6798 
6799  /* there exists no flow cover if the capacity of knapsack constraint in KP^SNF_rat after fixing
6800  * is less than or equal to zero
6801  */
6802  if( SCIPisFeasLE(scip, transcapacityreal/10, 0.0) )
6803  {
6804  assert(!(*found));
6805  goto TERMINATE;
6806  }
6807 
6808  /* KP^SNF_rat has been solved by fixing some variables in advance */
6809  assert(nitems >= 0);
6810  if( nitems == 0 )
6811  {
6812  /* get lambda = sum_{j in C1} u_j - sum_{j in C2} u_j - rhs */
6813  SCIPquadprecSumQD(flowcoverweight, flowcoverweight, -snf->transrhs);
6814  *lambda = QUAD_TO_DBL(flowcoverweight);
6815  *found = TRUE;
6816  goto TERMINATE;
6817  }
6818 
6819  /* Solve the KP^SNF_rat approximately */
6820 
6821  /* initialize number of (non-)solution items, should be changed to a nonnegative number in all possible paths below */
6822  nsolitems = -1;
6823  nnonsolitems = -1;
6824 
6825  /* suitable factor C was found*/
6826  /* solve KP^SNF_rat approximately */
6827  SCIP_CALL(SCIPsolveKnapsackApproximatelyLT(scip, nitems, transweightsreal, transprofitsreal, transcapacityreal,
6828  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, NULL));
6829 
6830  assert(nsolitems != -1);
6831  assert(nnonsolitems != -1);
6832 
6833  /* build the flow cover from the solution of KP^SNF_rat and KP^SNF_int, respectively and the fixing */
6834  assert(*nflowcovervars + *nnonflowcovervars + nsolitems + nnonsolitems == snf->ntransvars);
6835  buildFlowCover(scip, snf->transvarcoefs, snf->transvarvubcoefs, snf->transrhs, solitems, nonsolitems, nsolitems, nnonsolitems, nflowcovervars,
6836  nnonflowcovervars, flowcoverstatus, QUAD(&flowcoverweight), lambda);
6837  assert(*nflowcovervars + *nnonflowcovervars == snf->ntransvars);
6838 
6839  *found = SCIPisFeasGT(scip, *lambda, 0.0);
6840 
6841  TERMINATE:
6842  assert((!*found) || SCIPisFeasGT(scip, *lambda, 0.0));
6843 #ifdef SCIP_DEBUG
6844  if( *found )
6845  {
6846  SCIPdebugMsg(scip, "2. approximate solution:\n");
6847  for( j = 0; j < snf->ntransvars; j++ )
6848  {
6849  if( snf->transvarcoefs[j] == 1 && flowcoverstatus[j] == 1 )
6850  {
6851  SCIPdebugMsg(scip, " C1: + y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6852  }
6853  else if( snf->transvarcoefs[j] == -1 && flowcoverstatus[j] == 1 )
6854  {
6855  SCIPdebugMsg(scip, " C2: - y_%d [u_%d = %g]\n", j, j, snf->transvarvubcoefs[j]);
6856  }
6857  }
6858  SCIPdebugMsg(scip, " flowcoverweight(%g) = rhs(%g) + lambda(%g)\n", QUAD_TO_DBL(flowcoverweight), snf->transrhs, *lambda);
6859  }
6860 #endif
6861 
6862  /* free data structures */
6863  SCIPfreeBufferArray(scip, &nonsolitems);
6864  SCIPfreeBufferArray(scip, &solitems);
6865  SCIPfreeBufferArray(scip, &transweightsint);
6866  SCIPfreeBufferArray(scip, &transweightsreal);
6867  SCIPfreeBufferArray(scip, &transprofitsreal);
6868  SCIPfreeBufferArray(scip, &itemsint);
6869  SCIPfreeBufferArray(scip, &items);
6870 
6871  return SCIP_OKAY;
6872 }
6873 
6874 #endif
6875 
6876 /** evaluate the super-additive lifting function for the lifted simple generalized flowcover inequalities
6877  * for a given value \f$ x \in \{ u_j \mid j \in C- \} \f$.
6878  */
6879 static
6881  SCIP* scip, /**< SCIP data structure */
6882  LIFTINGDATA* liftingdata, /**< lifting data to use */
6883  SCIP_Real x /**< value where to evaluate lifting function */
6884  )
6885 {
6886  SCIP_Real QUAD(tmp);
6887  SCIP_Real xpluslambda;
6888  int i;
6889 
6890  assert( liftingdata != NULL );
6891 
6892  xpluslambda = x + liftingdata->lambda;
6893 
6894  i = 0;
6895  while( i < liftingdata->r && SCIPisGT(scip, xpluslambda, liftingdata->M[i+1]) )
6896  ++i;
6897 
6898  if( i < liftingdata->t )
6899  {
6900  if( SCIPisLE(scip, liftingdata->M[i], x) )
6901  {
6902  assert(SCIPisLE(scip, xpluslambda, liftingdata->M[i+1]));
6903  return i * liftingdata->lambda;
6904  }
6905 
6906  assert(i > 0 && SCIPisLE(scip, liftingdata->M[i], xpluslambda) && x <= liftingdata->M[i]);
6907 
6908  /* return x - liftingdata->M[i] + i * liftingdata->lambda */
6909  SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
6910  SCIPquadprecSumQD(tmp, tmp, x);
6911  SCIPquadprecSumQD(tmp, tmp, -liftingdata->M[i]);
6912  return QUAD_TO_DBL(tmp);
6913  }
6914 
6915  if( i < liftingdata->r )
6916  {
6917  assert(!SCIPisInfinity(scip, liftingdata->mp));
6918 
6919  /* p = liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml; */
6920  SCIPquadprecSumDD(tmp, liftingdata->m[i], -liftingdata->mp);
6921  SCIPquadprecSumQD(tmp, tmp, -liftingdata->ml);
6922  SCIPquadprecSumQD(tmp, tmp, liftingdata->lambda);
6923 
6924  /* p = MAX(0.0, p); */
6925  if( QUAD_HI(tmp) < 0.0 )
6926  {
6927  QUAD_ASSIGN(tmp, 0.0);
6928  }
6929 
6930  SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
6931  SCIPquadprecSumQD(tmp, tmp, liftingdata->ml);
6932 
6933  if( SCIPisLT(scip, QUAD_TO_DBL(tmp), xpluslambda) )
6934  return i * liftingdata->lambda;
6935 
6936  assert(SCIPisFeasLE(scip, liftingdata->M[i], xpluslambda) &&
6937  SCIPisFeasLE(scip, xpluslambda, liftingdata->M[i] + liftingdata->ml +
6938  MAX(0.0, liftingdata->m[i] - (liftingdata->mp - liftingdata->lambda) - liftingdata->ml)));
6939 
6940  SCIPquadprecProdDD(tmp, i, liftingdata->lambda);
6941  SCIPquadprecSumQD(tmp, tmp, x);
6942  SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[i]);
6943  return QUAD_TO_DBL(tmp);
6944  }
6945 
6946  assert(i == liftingdata->r && SCIPisLE(scip, liftingdata->M[liftingdata->r], xpluslambda));
6947 
6948  SCIPquadprecProdDD(tmp, liftingdata->r, liftingdata->lambda);
6949  SCIPquadprecSumQD(tmp, tmp, x);
6950  SCIPquadprecSumQD(tmp, tmp, - liftingdata->M[liftingdata->r]);
6951  return QUAD_TO_DBL(tmp);
6952 }
6953 
6954 /** computes
6955  * \f[
6956  * (\alpha_j, \beta_j) =
6957  * \begin{cases}
6958  * (0, 0) &\quad\text{if} M_i \leq u_j \leq M_{i+1} - \lambda \\
6959  * (1, M_i - i \lambda) &\quad\text{if} M_i − \lambda < u_j < M_i \\
6960  * \end{cases}
6961  * \f]
6962  */
6963 static
6965  SCIP* scip, /**< SCIP data structure */
6966  LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
6967  SCIP_Real vubcoef, /**< vub coefficient to get alpha and beta for */
6968  int* alpha, /**< get alpha coefficient for lifting */
6969  SCIP_Real* beta /**< get beta coefficient for lifting */
6970  )
6971 {
6972  SCIP_Real vubcoefpluslambda;
6973  int i;
6974 
6975  vubcoefpluslambda = vubcoef + liftingdata->lambda;
6976 
6977  i = 0;
6978  while( i < liftingdata->r && SCIPisGT(scip, vubcoefpluslambda, liftingdata->M[i+1]) )
6979  ++i;
6980 
6981  if( SCIPisLT(scip, vubcoef, liftingdata->M[i]) )
6982  {
6983  SCIP_Real QUAD(tmp);
6984  assert(liftingdata->M[i] < vubcoefpluslambda);
6985  *alpha = 1;
6986  SCIPquadprecProdDD(tmp, -i, liftingdata->lambda);
6987  SCIPquadprecSumQD(tmp, tmp, liftingdata->M[i]);
6988  *beta = QUAD_TO_DBL(tmp);
6989  }
6990  else
6991  {
6992  assert(SCIPisSumLE(scip, liftingdata->M[i], vubcoef));
6993  assert(i == liftingdata->r || SCIPisLE(scip, vubcoefpluslambda, liftingdata->M[i+1]));
6994  *alpha = 0;
6995  *beta = 0.0;
6996  }
6997 }
6998 
6999 /** compute relevant data for performing the sequence independent lifting */
7000 static
7002  SCIP* scip, /**< SCIP data structure */
7003  SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
7004  int* transvarflowcoverstatus, /**< pointer to store whether non-binary var is in L2 (2) or not (-1 or 1) */
7005  SCIP_Real lambda, /**< lambda */
7006  LIFTINGDATA* liftingdata, /**< pointer to lifting function struct */
7007  SCIP_Bool* valid /**< is the lifting data valid */
7008  )
7009 {
7010  int i;
7011  SCIP_Real QUAD(tmp);
7012  SCIP_Real QUAD(sumN2mC2LE);
7013  SCIP_Real QUAD(sumN2mC2GT);
7014  SCIP_Real QUAD(sumC1LE);
7015  SCIP_Real QUAD(sumC2);
7016 
7017 #ifndef NDEBUG
7018  /* for debugging */
7019  liftingdata->m = NULL;
7020  liftingdata->M = NULL;
7021  liftingdata->lambda = SCIP_INVALID;
7022  liftingdata->t = 0;
7023  liftingdata->mp = SCIP_INVALID;
7024 #endif
7025 
7026  SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->m, snf->ntransvars) );
7027 
7028  liftingdata->r = 0;
7029  QUAD_ASSIGN(sumN2mC2LE, 0.0);
7030  QUAD_ASSIGN(sumC1LE, 0.0);
7031  QUAD_ASSIGN(sumN2mC2GT, 0.0);
7032  QUAD_ASSIGN(sumC2, 0.0);
7033 
7034  liftingdata->mp = SCIPinfinity(scip);
7035 
7036  *valid = FALSE;
7037 
7038  for( i = 0; i < snf->ntransvars; ++i )
7039  {
7040  int s = (snf->transvarcoefs[i] + 1) + (transvarflowcoverstatus[i] + 1)/2;
7041 
7042  switch(s)
7043  {
7044  case 0: /* var is in N2 \ C2 */
7045  assert(snf->transvarvubcoefs[i] >= 0.0);
7046  assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == -1);
7047 
7048  if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7049  {
7050  SCIPquadprecSumQD(sumN2mC2GT, sumN2mC2GT, snf->transvarvubcoefs[i]);
7051  liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7052  }
7053  else
7054  {
7055  SCIPquadprecSumQD(sumN2mC2LE, sumN2mC2LE, snf->transvarvubcoefs[i]);
7056  }
7057  break;
7058  case 1: /* var is in C2 */
7059  assert(snf->transvarvubcoefs[i] > 0.0);
7060  assert(snf->transvarcoefs[i] == -1 && transvarflowcoverstatus[i] == 1);
7061 
7062  SCIPquadprecSumQD(sumC2, sumC2, snf->transvarvubcoefs[i]);
7063  break;
7064  case 3: /* var is in C1 */
7065  assert(snf->transvarcoefs[i] == 1 && transvarflowcoverstatus[i] == 1);
7066  assert(snf->transvarvubcoefs[i] > 0.0);
7067 
7068  if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7069  {
7070  liftingdata->m[liftingdata->r++] = snf->transvarvubcoefs[i];
7071  liftingdata->mp = MIN(liftingdata->mp, snf->transvarvubcoefs[i]);
7072  }
7073  else
7074  {
7075  SCIPquadprecSumQD(sumC1LE, sumC1LE, snf->transvarvubcoefs[i]);
7076  }
7077  break;
7078  default:
7079  assert(s == 2);
7080  continue;
7081  }
7082  }
7083 
7084  if( SCIPisInfinity(scip, liftingdata->mp) )
7085  {
7086  SCIPfreeBufferArray(scip, &liftingdata->m);
7087  return SCIP_OKAY;
7088  }
7089 
7090  SCIP_CALL( SCIPallocBufferArray(scip, &liftingdata->M, liftingdata->r + 1) );
7091 
7092  *valid = TRUE;
7093 
7094  SCIPquadprecSumQQ(tmp, sumC1LE, sumN2mC2LE);
7095  liftingdata->ml = MIN(lambda, QUAD_TO_DBL(tmp));
7096  SCIPquadprecSumQD(tmp, sumC2, snf->transrhs);
7097  liftingdata->d1 = QUAD_TO_DBL(tmp);
7098  SCIPquadprecSumQQ(tmp, tmp, sumN2mC2GT);
7099  SCIPquadprecSumQQ(tmp, tmp, sumN2mC2LE);
7100  liftingdata->d2 = QUAD_TO_DBL(tmp);
7101 
7102  SCIPsortDownReal(liftingdata->m, liftingdata->r);
7103 
7104  /* compute M[i] = sum_{i \in [1,r]} m[i] where m[*] is sorted decreasingly and M[0] = 0 */
7105  QUAD_ASSIGN(tmp, 0.0);
7106  for( i = 0; i < liftingdata->r; ++i)
7107  {
7108  liftingdata->M[i] = QUAD_TO_DBL(tmp);
7109  SCIPquadprecSumQD(tmp, tmp, liftingdata->m[i]);
7110  }
7111 
7112  liftingdata->M[liftingdata->r] = QUAD_TO_DBL(tmp);
7113 
7114  SCIP_UNUSED( SCIPsortedvecFindDownReal(liftingdata->m, liftingdata->mp, liftingdata->r, &liftingdata->t) );
7115  assert(liftingdata->m[liftingdata->t] == liftingdata->mp || SCIPisInfinity(scip, liftingdata->mp)); /*lint !e777*/
7116 
7117  /* compute t largest index sucht that m_t = mp
7118  * note that liftingdata->m[t-1] == mp due to zero based indexing of liftingdata->m
7119  */
7120  ++liftingdata->t;
7121  while( liftingdata->t < liftingdata->r && liftingdata->m[liftingdata->t] == liftingdata->mp ) /*lint !e777*/
7122  ++liftingdata->t;
7123 
7124  liftingdata->lambda = lambda;
7125 
7126  return SCIP_OKAY;
7127 }
7128 
7129 /** destroy data used for the sequence independent lifting */
7130 static
7132  SCIP* scip, /**< SCIP data structure */
7133  LIFTINGDATA* liftingdata /**< pointer to lifting function struct */
7134  )
7135 {
7136  SCIPfreeBufferArray(scip, &liftingdata->M);
7137  SCIPfreeBufferArray(scip, &liftingdata->m);
7138 }
7139 
7140 /** store the simple lifted flowcover cut defined by the given data in the given arrays
7141  * the array for storing the cut coefficients must be all zeros
7142  */
7143 static
7145  SCIP* scip, /**< SCIP data structure */
7146  SNF_RELAXATION* snf, /**< pointer to SNF relaxation */
7147  SCIP_AGGRROW* aggrrow, /**< aggrrow used to construct SNF relaxation */
7148  int* flowcoverstatus, /**< pointer to store whether variable is in flow cover (+1) or not (-1) */
7149  SCIP_Real lambda, /**< lambda */
7150  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7151  SCIP_Real* cutrhs, /**< pointer to right hand side of cut */
7152  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7153  int* nnz, /**< number of non-zeros in cut */
7154  SCIP_Bool* success /**< was the cut successfully generated */
7155  )
7156 {
7157  SCIP_Real QUAD(rhs);
7158  LIFTINGDATA liftingdata;
7159  int i;
7160 
7161  SCIP_CALL( computeLiftingData(scip, snf, flowcoverstatus, lambda, &liftingdata, success) );
7162  if( ! *success )
7163  return SCIP_OKAY;
7164  assert( liftingdata.m != NULL );
7165  assert( liftingdata.M != NULL );
7166  assert( liftingdata.lambda != SCIP_INVALID ); /*lint !e777*/
7167  assert( liftingdata.r >= 0 );
7168  assert( liftingdata.t >= 0 );
7169  assert( liftingdata.mp != SCIP_INVALID ); /*lint !e777*/
7170 
7171  QUAD_ASSIGN(rhs, liftingdata.d1);
7172 
7173  *nnz = 0;
7174 
7175  for( i = 0; i < snf->ntransvars; ++i )
7176  {
7177  int s = (snf->transvarcoefs[i] + 1) + (flowcoverstatus[i] + 1)/2;
7178 
7179  switch(s)
7180  {
7181  case 0: /* var is in N2 \ C2 */
7182  if( SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7183  {
7184  /* var is in L- */
7185  if( snf->origbinvars[i] != -1 )
7186  {
7187  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7188  cutinds[*nnz] = snf->origbinvars[i];
7189  cutcoefs[snf->origbinvars[i]] = -lambda;
7190  ++(*nnz);
7191  }
7192  else
7193  {
7194  SCIPquadprecSumQD(rhs, rhs, lambda);
7195  }
7196  }
7197  else
7198  {
7199  /* var is in L-- */
7200  if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7201  {
7202  assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7203  cutinds[*nnz] = snf->origcontvars[i];
7204  cutcoefs[snf->origcontvars[i]] = -snf->aggrcoefscont[i];
7205  ++(*nnz);
7206  }
7207 
7208  if( snf->origbinvars[i] != -1 && snf->aggrcoefsbin[i] != 0.0 )
7209  {
7210  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7211  cutinds[*nnz] = snf->origbinvars[i];
7212  cutcoefs[snf->origbinvars[i]] = -snf->aggrcoefsbin[i];
7213  ++(*nnz);
7214  }
7215 
7216  SCIPquadprecSumQD(rhs, rhs, snf->aggrconstants[i]);
7217  }
7218  break;
7219  case 1: /* var is in C2 */
7220  {
7221  assert(snf->transvarvubcoefs[i] > 0.0);
7222  assert(snf->transvarcoefs[i] == -1 && flowcoverstatus[i] == 1);
7223 
7224  if( snf->origbinvars[i] != -1 )
7225  {
7226  SCIP_Real liftedbincoef = evaluateLiftingFunction(scip, &liftingdata, snf->transvarvubcoefs[i]);
7227  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7228  if( liftedbincoef != 0.0 )
7229  {
7230  cutinds[*nnz] = snf->origbinvars[i];
7231  cutcoefs[snf->origbinvars[i]] = -liftedbincoef;
7232  ++(*nnz);
7233  SCIPquadprecSumQD(rhs, rhs, -liftedbincoef);
7234  }
7235  }
7236  break;
7237  }
7238  case 2: /* var is in N1 \ C1 */
7239  {
7240  int alpha;
7241  SCIP_Real beta;
7242 
7243  assert(snf->transvarcoefs[i] == 1 && flowcoverstatus[i] == -1);
7244 
7245  getAlphaAndBeta(scip, &liftingdata, snf->transvarvubcoefs[i], &alpha, &beta);
7246  assert(alpha == 0 || alpha == 1);
7247 
7248  if( alpha == 1 )
7249  {
7250  SCIP_Real QUAD(binvarcoef);
7251  assert(beta > 0.0);
7252 
7253  if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7254  {
7255  assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7256  cutinds[*nnz] = snf->origcontvars[i];
7257  cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7258  ++(*nnz);
7259  }
7260 
7261  SCIPquadprecSumDD(binvarcoef, snf->aggrcoefsbin[i], -beta);
7262  if( snf->origbinvars[i] != -1 )
7263  {
7264  SCIP_Real tmp;
7265 
7266  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7267 
7268  tmp = QUAD_TO_DBL(binvarcoef);
7269  if( tmp != 0.0 )
7270  {
7271  cutinds[*nnz] = snf->origbinvars[i];
7272  cutcoefs[snf->origbinvars[i]] = tmp;
7273  ++(*nnz);
7274  }
7275  }
7276  else
7277  {
7278  SCIPquadprecSumQQ(rhs, rhs, -binvarcoef);
7279  }
7280 
7281  SCIPquadprecSumQD(rhs, rhs, -snf->aggrconstants[i]);
7282  }
7283  break;
7284  }
7285  case 3: /* var is in C1 */
7286  {
7287  SCIP_Real bincoef = snf->aggrcoefsbin[i];
7288  SCIP_Real constant = snf->aggrconstants[i];
7289 
7290  if( snf->origbinvars[i] != -1 && SCIPisGT(scip, snf->transvarvubcoefs[i], lambda) )
7291  {
7292  /* var is in C++ */
7293  SCIP_Real QUAD(tmp);
7294  SCIP_Real QUAD(tmp2);
7295 
7296  SCIPquadprecSumDD(tmp, snf->transvarvubcoefs[i], -lambda);
7297 
7298  SCIPquadprecSumQD(tmp2, tmp, constant);
7299  constant = QUAD_TO_DBL(tmp2);
7300 
7301  SCIPquadprecSumQD(tmp2, tmp, -bincoef);
7302  bincoef = -QUAD_TO_DBL(tmp2);
7303  }
7304 
7305  if( snf->origbinvars[i] != -1 && bincoef != 0.0 )
7306  {
7307  assert(cutcoefs[snf->origbinvars[i]] == 0.0);
7308  cutinds[*nnz] = snf->origbinvars[i];
7309  cutcoefs[snf->origbinvars[i]] = bincoef;
7310  ++(*nnz);
7311  }
7312 
7313  if( snf->origcontvars[i] != -1 && snf->aggrcoefscont[i] != 0.0 )
7314  {
7315  assert(cutcoefs[snf->origcontvars[i]] == 0.0);
7316  cutinds[*nnz] = snf->origcontvars[i];
7317  cutcoefs[snf->origcontvars[i]] = snf->aggrcoefscont[i];
7318  ++(*nnz);
7319  }
7320 
7321  SCIPquadprecSumQD(rhs, rhs, -constant);
7322  break;
7323  }
7324  default:
7325  SCIPABORT();
7326  }
7327  }
7328 
7329  destroyLiftingData(scip, &liftingdata);
7330 
7331  {
7332  SCIP_ROW** rows = SCIPgetLPRows(scip);
7333  for( i = 0; i < aggrrow->nrows; ++i )
7334  {
7335  SCIP_ROW* row;
7336  SCIP_Real rowlhs;
7337  SCIP_Real rowrhs;
7338  SCIP_Real slackub;
7339  SCIP_Real slackcoef;
7340 
7341  slackcoef = aggrrow->rowweights[i] * aggrrow->slacksign[i];
7342  assert(slackcoef != 0.0);
7343 
7344  /* positive slack was implicitly handled in flow cover separation */
7345  if( slackcoef > 0.0 )
7346  continue;
7347 
7348  row = rows[aggrrow->rowsinds[i]];
7349 
7350  /* add the slack's definition multiplied with its coefficient to the cut */
7351  SCIP_CALL( varVecAddScaledRowCoefs(cutinds, cutcoefs, nnz, row, -aggrrow->rowweights[i]) );
7352 
7353  /* retrieve sides of row */
7354  rowlhs = row->lhs - row->constant;
7355  rowrhs = row->rhs - row->constant;
7356 
7357  if( row->integral )
7358  {
7359  rowrhs = SCIPfloor(scip, rowrhs);
7360  rowlhs = SCIPceil(scip, rowlhs);
7361  }
7362 
7363  slackub = rowrhs - rowlhs;
7364 
7365  /* move slack's constant to the right hand side, and add lambda to the right hand side if the
7366  * upper bound of the slack is larger than lambda, since then an artifical binary variable
7367  * for the slack would get coefficient -lambda
7368  */
7369  if( aggrrow->slacksign[i] == +1 )
7370  {
7371  SCIP_Real rhsslack;
7372  /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
7373  assert(!SCIPisInfinity(scip, row->rhs));
7374 
7375  rhsslack = rowrhs - SCIPgetRowMinActivity(scip, row);
7376  slackub = -aggrrow->rowweights[i] * MIN(rhsslack, slackub);
7377 
7378  if( SCIPisGE(scip, slackub, lambda) )
7379  SCIPquadprecSumQD(rhs, rhs, lambda);
7380 
7381  SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowrhs);
7382  }
7383  else
7384  {
7385  SCIP_Real lhsslack;
7386  /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
7387  assert(!SCIPisInfinity(scip, -row->lhs));
7388 
7389  lhsslack = SCIPgetRowMaxActivity(scip, row) - rowlhs;
7390  slackub = aggrrow->rowweights[i] * MIN(lhsslack, slackub);
7391 
7392  if( SCIPisGE(scip, slackub, lambda) )
7393  SCIPquadprecSumQD(rhs, rhs, lambda);
7394 
7395  SCIPquadprecSumQD(rhs, rhs, -aggrrow->rowweights[i] * rowlhs);
7396  }
7397  }
7398  }
7399 
7400  *cutrhs = QUAD_TO_DBL(rhs);
7401 
7402  /* relax rhs to zero, if it's very close to 0 */
7403  if( *cutrhs < 0.0 && *cutrhs >= -SCIPepsilon(scip) )
7404  *cutrhs = 0.0;
7405 
7406  return SCIP_OKAY;
7407 }
7408 
7409 /** calculates a lifted simple generalized flow cover cut out of the weighted sum of LP rows given by an aggregation row; the
7410  * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
7411  * participate in the cut.
7412  * For further details we refer to:
7413  *
7414  * Gu, Z., Nemhauser, G. L., & Savelsbergh, M. W. (1999). Lifted flow cover inequalities for mixed 0-1 integer programs.
7415  * Mathematical Programming, 85(3), 439-467.
7416  *
7417  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7418  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7419  *
7420  * @pre This method can be called if @p scip is in one of the following stages:
7421  * - \ref SCIP_STAGE_SOLVING
7422  *
7423  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
7424  */
7426  SCIP* scip, /**< SCIP data structure */
7427  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7428  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
7429  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
7430  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7431  SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
7432  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
7433  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
7434  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
7435  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
7436  SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
7437  int* cutrank, /**< pointer to return rank of generated cut */
7438  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
7439  SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
7440  )
7441 {
7442  int i;
7443  int nvars;
7444  SCIP_Bool localbdsused;
7445  SNF_RELAXATION snf;
7446  SCIP_Real lambda;
7447  SCIP_Real* tmpcoefs;
7448  int *transvarflowcoverstatus;
7449  int nflowcovervars;
7450  int nnonflowcovervars;
7451 
7452  nvars = SCIPgetNVars(scip);
7453 
7454  *success = FALSE;
7455 
7456  /* get data structures */
7457  SCIP_CALL( SCIPallocBufferArray(scip, &transvarflowcoverstatus, nvars) );
7458  SCIP_CALL( allocSNFRelaxation(scip, &snf, nvars) );
7459 
7460  SCIPdebug( printCutQuad(scip, sol, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, FALSE, aggrrow->local) );
7461 
7462  SCIP_CALL( constructSNFRelaxation(scip, sol, boundswitch, allowlocal, aggrrow->vals, QUAD(aggrrow->rhs), aggrrow->inds, aggrrow->nnz, &snf, success, &localbdsused) );
7463 
7464  if( ! *success )
7465  {
7466  goto TERMINATE;
7467  }
7468 
7469  *cutislocal = aggrrow->local || localbdsused;
7470 
7471  /* initialize lambda because gcc issues a stupid warning */
7472  lambda = 0.0;
7473  SCIP_CALL( getFlowCover(scip, &snf, &nflowcovervars, &nnonflowcovervars, transvarflowcoverstatus, &lambda, success) );
7474 
7475  if( ! *success )
7476  {
7477  goto TERMINATE;
7478  }
7479 
7480  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, nvars) );
7481 
7482  SCIP_CALL( generateLiftedFlowCoverCut(scip, &snf, aggrrow, transvarflowcoverstatus, lambda, tmpcoefs, cutrhs, cutinds, cutnnz, success) );
7483  SCIPdebugMsg(scip, "computed flowcover_%lli_%i:\n", SCIPgetNLPs(scip), SCIPgetNCuts(scip));
7484 
7485  /* if success is FALSE generateLiftedFlowCoverCut wont have touched the tmpcoefs array so we dont need to clean it then */
7486  if( *success )
7487  {
7488  if( postprocess )
7489  {
7490  SCIP_CALL( postprocessCut(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, cutrhs, success) );
7491  }
7492  else
7493  {
7494  SCIP_Real QUAD(rhs);
7495 
7496  QUAD_ASSIGN(rhs, *cutrhs);
7497  *success = ! removeZeros(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
7498  *cutrhs = QUAD_TO_DBL(rhs);
7499  }
7500 
7501  if( *success )
7502  {
7503  /* store cut sparse and calculate efficacy */
7504  for( i = 0; i < *cutnnz; ++i )
7505  {
7506  int j = cutinds[i];
7507  assert(tmpcoefs[j] != 0.0);
7508  cutcoefs[i] = tmpcoefs[j];
7509  tmpcoefs[j] = 0.0;
7510  }
7511 
7512  if( cutefficacy != NULL )
7513  *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
7514 
7515  if( cutrank != NULL )
7516  *cutrank = aggrrow->rank + 1;
7517  }
7518  else
7519  {
7520  /* clean buffer array */
7521  for( i = 0; i < *cutnnz; ++i )
7522  {
7523  int j = cutinds[i];
7524  assert(tmpcoefs[j] != 0.0);
7525  tmpcoefs[j] = 0.0;
7526  }
7527  }
7528  }
7529 
7530  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
7531 
7532  TERMINATE:
7533  destroySNFRelaxation(scip, &snf);
7534  SCIPfreeBufferArray(scip, &transvarflowcoverstatus);
7535 
7536  return SCIP_OKAY;
7537 }
7538 
7539 /* =========================================== knapsack cover =========================================== */
7540 
7541 /** Relax the row to a possibly fractional knapsack row containing no integer or continuous variables
7542  * and only having positive coefficients for binary variables. General integer and continuous variables
7543  * are complemented with variable or simple bounds such that their coefficient becomes positive and then
7544  * it is relaxed to zero.
7545  * All remaining binary variables are complemented with simple upper or lower bounds such that their
7546  * coefficient becomes positive.
7547  */
7548 static
7550  SCIP* scip, /**< SCIP data structure */
7551  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7552  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
7553  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
7554  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
7555  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
7556  int* nnz, /**< number of non-zeros in cut */
7557  int* varsign, /**< stores the sign of the transformed variable in summation */
7558  int* boundtype, /**< stores the bound used for transformed variable:
7559  * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
7560  SCIP_Bool* localbdsused, /**< pointer to store whether local bounds were used in transformation */
7561  SCIP_Bool* success /**< stores whether the row could successfully be transformed into a knapsack constraint.
7562  * Returns FALSE in case a continuous or general integer variable is unbounded in the
7563  * required direction. */
7564  )
7565 {
7566  SCIP_Real* bestbds;
7567  int i;
7568  int aggrrowbinstart;
7569  int firstnonbinvar;
7570  SCIP_VAR** vars;
7571 
7572  assert(varsign != NULL);
7573  assert(boundtype != NULL);
7574  assert(success != NULL);
7575  assert(localbdsused != NULL);
7576 
7577  *success = FALSE;
7578 
7579  /* allocate temporary memory to store best bounds and bound types */
7580  SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
7581 
7582  /* start with continuous variables, because using variable bounds can affect the untransformed binary
7583  * variables, and these changes have to be incorporated in the transformation of the binary variables
7584  * (binary variables have the smallest problem indices!)
7585  */
7586  SCIPsortDownInt(cutinds, *nnz);
7587 
7588  vars = SCIPgetVars(scip);
7589  firstnonbinvar = SCIPgetNBinVars(scip);
7590 
7591  /* determine best bounds for the continuous and general integer variables such that they will have
7592  * a positive coefficient in the transformation */
7593  for( i = 0; i < *nnz && cutinds[i] >= firstnonbinvar; ++i )
7594  {
7595  SCIP_Real QUAD(coef);
7596  int v = cutinds[i];
7597 
7598  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7599 
7600  if( QUAD_TO_DBL(coef) > 0.0 )
7601  {
7602  SCIP_Real simplebound;
7603 
7604  /* find closest lower bound in standard lower bound or variable lower bound for continuous variable
7605  * so that it will have a positive coefficient */
7606  SCIP_CALL( findBestLb(scip, vars[v], sol, 1, allowlocal, bestbds + i, &simplebound, boundtype + i) );
7607 
7608  /* cannot transform into knapsack */
7609  if( SCIPisInfinity(scip, -bestbds[i]) )
7610  goto TERMINATE;
7611 
7612  varsign[i] = +1;
7613  }
7614  else if( QUAD_TO_DBL(coef) < 0.0 )
7615  {
7616  SCIP_Real simplebound;
7617 
7618  /* find closest upper bound in standard upper bound or variable upper bound for continuous variable
7619  * so that it will have a positive coefficient */
7620  SCIP_CALL( findBestUb(scip, vars[v], sol, 1, allowlocal, bestbds + i, &simplebound, boundtype + i) );
7621 
7622  /* cannot transform into knapsack */
7623  if( SCIPisInfinity(scip, bestbds[i]) )
7624  goto TERMINATE;
7625 
7626  varsign[i] = -1;
7627  }
7628  }
7629 
7630  /* remember start of integer variables in the aggrrow */
7631  aggrrowbinstart = i;
7632 
7633  /* perform bound substitution for continuous variables */
7634  for( i = 0; i < aggrrowbinstart; ++i )
7635  {
7636  SCIP_Real QUAD(coef);
7637  int v = cutinds[i];
7638 
7639  performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], v, localbdsused);
7640 
7641  /* relax non-binary coefficient to zero after bound substitution */
7642  QUAD_ASSIGN(coef, 0.0);
7643  QUAD_ARRAY_STORE(cutcoefs, v, coef);
7644  }
7645 
7646  assert(i == aggrrowbinstart);
7647 
7648  /* remove non-binary variables because their coefficients have been set to zero after bound substitution */
7649  if( aggrrowbinstart != 0 )
7650  {
7651  *nnz -= aggrrowbinstart;
7652  BMSmoveMemoryArray(cutinds, cutinds + aggrrowbinstart, *nnz);
7653  }
7654  i = 0;
7655 
7656  /* after doing bound substitution of non-binary vars, some coefficients of binary vars might have changed, so here we
7657  * remove the ones that became 0 if any; also, we need that all remaining binary vars have positive coefficients,
7658  * thus we perform bound substitution with simple bounds (i.e. complementing) to achieve this.
7659  */
7660  while( i < *nnz )
7661  {
7662  SCIP_Real QUAD(coef);
7663  SCIP_Real simplebound;
7664  SCIP_Real bestlb;
7665  SCIP_Real bestub;
7666  SCIP_Bool setzero;
7667  int v = cutinds[i];
7668 
7669  assert( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY );
7670 
7671  assert(v < firstnonbinvar);
7672  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7673 
7674  /* due to variable bound usage for bound substitution of continuous variables cancellation may have occurred */
7675  if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
7676  {
7677  /* do not increase i, since last element is copied to the i-th position */
7678  setzero = TRUE;
7679  }
7680  else
7681  {
7682  /* perform bound substitution */
7683  if( QUAD_TO_DBL(coef) < 0.0 )
7684  {
7685  SCIP_CALL( findBestUb(scip, vars[v], sol, 0, allowlocal, &bestub, &simplebound, boundtype + i) );
7686 
7687  if( SCIPisZero(scip, bestub) )
7688  {
7689  /* binary variable is fixed to zero */
7690  setzero = TRUE;
7691  *localbdsused = *localbdsused || (boundtype[i] == -2);
7692  }
7693  else
7694  {
7695  varsign[i] = -1;
7696 
7697  performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
7698  QUAD_ARRAY_STORE(cutcoefs, v, -coef);
7699  setzero = FALSE;
7700  }
7701  }
7702  else
7703  {
7704  SCIP_CALL( findBestLb(scip, vars[v], sol, 0, allowlocal, &bestlb, &simplebound, boundtype + i) );
7705 
7706  if( !SCIPisZero(scip, bestlb) )
7707  {
7708  /* binary variable is fixed to one */
7709  performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
7710  setzero = TRUE;
7711  }
7712  else
7713  {
7714  varsign[i] = +1;
7715  setzero = FALSE;
7716  }
7717  }
7718 
7719  assert(boundtype[i] == -1 || boundtype[i] == -2);
7720  }
7721 
7722  /* increase i or remove zero coefficient (i.e. var with 0 coef) by shifting last nonzero to current position */
7723  if( setzero )
7724  {
7725  QUAD_ASSIGN(coef, 0.0);
7726  QUAD_ARRAY_STORE(cutcoefs, v, coef);
7727  --(*nnz);
7728  cutinds[i] = cutinds[*nnz];
7729  }
7730  else
7731  ++i;
7732  }
7733 
7734  /* relax rhs to zero if it is close to but slightly below zero */
7735  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
7736  QUAD_ASSIGN(*cutrhs, 0.0);
7737 
7738  *success = TRUE;
7739  TERMINATE:
7740  /*free temporary memory */
7741  SCIPfreeBufferArray(scip, &bestbds);
7742 
7743  return SCIP_OKAY;
7744 }
7745 
7746 /** determines the initial cover for the given (fractional) knapsack row */
7747 static
7749  SCIP* scip, /**< SCIP datastructure */
7750  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
7751  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
7752  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
7753  SCIP_Real cutrhs, /**< pointer to the right hand side of the cut */
7754  int cutnnz, /**< pointer to the number of non-zeros in the cut */
7755  int* varsign, /**< sign of coefficients for each nonzero in the row be transformation */
7756  int* coverstatus, /**< array to return the coverstatus for each variable in the knapsack row */
7757  int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
7758  SCIP_Real* covervals, /**< coefficient value of each variable in the cover */
7759  int* coversize, /**< pointer to return number of variables in the cover;
7760  * matches the length of the associated arrays */
7761  QUAD(SCIP_Real* coverweight) /**< pointer to return the weight of the cover;
7762  * the weight is the sum of the coefficient values of variables in the cover */
7763  )
7764 {
7765  SCIP_VAR** vars;
7766  int k;
7767  int j;
7768  QUAD_ASSIGN(*coverweight, 0);
7769  *coversize = 0;
7770  j = cutnnz-1;
7771  vars = SCIPgetVars(scip);
7772 
7773  for( k = 0; k < cutnnz; ++k )
7774  {
7775  SCIP_Real solval;
7776  int v = cutinds[k];
7777  SCIP_Real QUAD(coef);
7778  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7779 
7780  solval = SCIPgetSolVal(scip, sol, vars[v]);
7781  if( varsign[k] == -1 )
7782  solval = 1 - solval;
7783 
7784  if( SCIPisFeasEQ(scip, solval, 1.0) )
7785  {
7786  /* every variable with solution value 1 is forced into the cover */
7787  coverpos[*coversize] = k;
7788  covervals[*coversize] = QUAD_TO_DBL(coef);
7789  coverstatus[k] = 1;
7790  *coversize += 1;
7791  SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
7792  }
7793  else
7794  {
7795  coverpos[j] = k;
7796  covervals[j] = solval * QUAD_TO_DBL(coef);
7797  coverstatus[k] = 0;
7798  j -= 1;
7799  }
7800  }
7801 
7802  /* Use these two arrays to sort the variables by decreasing contribution
7803  * and pick them greedily in the while loop below until they are a cover.
7804  * Since the cover does not need to be minimal we do not need to remove any of the
7805  * variables with a high activity contribution even if they are not necessary after
7806  * picking the last variable.
7807  */
7808  SCIPsortDownRealInt(covervals + (*coversize), coverpos + (*coversize), cutnnz - (*coversize));
7809 
7810  /* overwrite covervals with the coefficients of the variables in the cover
7811  * as we need to sort decreasingly by those again for the lifting
7812  */
7813  while( *coversize < cutnnz &&
7814  SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) )
7815  {
7816  int v;
7817  SCIP_Real QUAD(coef);
7818  k = coverpos[*coversize];
7819  v = cutinds[k];
7820  coverstatus[k] = 1;
7821  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
7822  covervals[*coversize] = QUAD_TO_DBL(coef);
7823  SCIPquadprecSumQQ(*coverweight, *coverweight, coef);
7824  *coversize += 1;
7825  }
7826 
7827  /* there is no cover */
7828  if( SCIPisFeasLE(scip, QUAD_TO_DBL(*coverweight), cutrhs) || *coversize == 0 )
7829  return FALSE;
7830 
7831  SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(*coverweight), cutrhs);
7832  assert(*coversize > 0);
7833 
7834  return TRUE;
7835 }
7836 
7837 /** prepares the data needed to evaluate the lifting function */
7838 static
7840  SCIP* scip, /**< SCIP datastructure */
7841  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
7842  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
7843  QUAD(SCIP_Real cutrhs), /**< pointer to the right hand side of the cut */
7844  int* coverpos, /**< position of nonzero in the knapsack row for each variable in the cover */
7845  int coversize, /**< number of variables in the cover */
7846  QUAD(SCIP_Real coverweight), /**< weight of cover */
7847  SCIP_Real* covervals, /**< coefficient value of each variable in the cover;
7848  * on output stores the running sum of S^-(*) values */
7849  int* coverstatus, /**< coverstatus for each variable in the cover. After calling this function
7850  * variables in C^- will have the value -1, variables in C^+ the value 1,
7851  * and all variables outside the cover keep the value 0. */
7852  QUAD(SCIP_Real* abar), /**< pointer to store the reciprocal value of \bar{a} */
7853  int* cplussize /**< pointer to store the size of C^+ */
7854  )
7855 {
7856  int k;
7857  SCIP_Real QUAD(tmp);
7858  SCIP_Real QUAD(sigma);
7859 
7860  /* Now compute \bar{a}, the unique rational number such that for the cover C it holds that
7861  * b = \sum_{a_i \in C} \min(\bar{a}, a_i).
7862  * For that we need to sort by decreasing coefficients of the variables in the cover.
7863  * After the sorting the covervals array is free to be reused.
7864  */
7865  SCIPsortDownRealInt(covervals, coverpos, coversize);
7866 
7867  /* Now follows Algorithm 1 in the paper to compute \bar{a} */
7868 
7869  /* set \bar{a} = l_1 */
7870  QUAD_ARRAY_LOAD(*abar, cutcoefs, cutinds[coverpos[0]]);
7871  SCIPquadprecSumQQ(sigma, coverweight, -cutrhs);
7872 
7873  for( k = 1; k < coversize; ++k )
7874  {
7875  SCIP_Real QUAD(lkplus1);
7876  SCIP_Real QUAD(kdelta);
7877 
7878  /* load next coefficient l_{k+1} in sorted order of cover */
7879  QUAD_ARRAY_LOAD(lkplus1, cutcoefs, cutinds[coverpos[k]]);
7880 
7881  /* Let \delta = \bar{a} - l_{k+1} and compute k * \delta */
7882  SCIPquadprecSumQQ(kdelta, *abar, -lkplus1);
7883  SCIPquadprecProdQD(kdelta, kdelta, k);
7884 
7885  /* Set tmp = k * \delta - \sigma to check condition k * \delta < \sigma by tmp < 0 */
7886  SCIPquadprecSumQQ(tmp, kdelta, -sigma);
7887  if( QUAD_TO_DBL(tmp) < 0.0 )
7888  {
7889  /* Set \bar{a} = l_{k+1} and \sigma = \sigma - k*\delta */
7890  QUAD_ASSIGN_Q(*abar, lkplus1);
7891  SCIPquadprecSumQQ(sigma, sigma, -kdelta);
7892  }
7893  else
7894  {
7895  /* Set \bar{a} = \bar{a} - \sigma / k and \sigma = 0; break; */
7896  SCIP_Real minusoneoverk = -1.0 / k;
7897  SCIPquadprecProdQD(sigma, sigma, minusoneoverk);
7898  SCIPquadprecSumQQ(*abar, *abar, sigma);
7899  QUAD_ASSIGN(sigma, 0.0);
7900  break;
7901  }
7902  }
7903 
7904  if( QUAD_TO_DBL(sigma) > 0.0 )
7905  {
7906  SCIP_Real oneoverc = 1.0 / coversize;
7907  SCIPquadprecProdQD(*abar, cutrhs, oneoverc);
7908  }
7909 
7910  /* now we partition C into C^+ and C^-, where C^+ are all the elements of C whose weight is strictly larger than
7911  * \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
7912  * compute S^-(h) = sum of the h largest a_i^- and store S^-(h+1) in in covervals[h], for k = 0, ..., coversize - 1
7913  * (S^-(0) = 0 so it doesn't need to be stored; we use S to compute the lifted cut, see below)
7914  * we remember which elements of C^- in coverstatus, so that element in C^+ have coverstatus 1 and
7915  * elements in C^- have coverstatus -1 (elements not in C have coverstatus 0)
7916  */
7917  QUAD_ASSIGN(tmp, 0.0);
7918  *cplussize = 0;
7919  for( k = 0; k < coversize; ++k )
7920  {
7921  SCIP_Real QUAD(coef);
7922  SCIP_Real QUAD(coefminusabar);
7923 
7924  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[coverpos[k]]);
7925  SCIPquadprecSumQQ(coefminusabar, coef, -*abar);
7926  if( QUAD_TO_DBL(coefminusabar) > 0.0 )
7927  {
7928  /* coefficient is in C^+ because it is greater than \bar{a} and contributes only \bar{a} to the sum */
7929  SCIPquadprecSumQQ(tmp, tmp, *abar);
7930 
7931  /* rather be on the safe side in numerical corner cases and relax the coefficient to exactly \bar{a}.
7932  * In that case the coefficient is not treated as in C^+ but as being <= \bar{a} and therefore in C^-.
7933  */
7934  if( QUAD_TO_DBL(coefminusabar) > SCIPfeastol(scip) )
7935  ++(*cplussize);
7936  else
7937  coverstatus[coverpos[k]] = -1;
7938  }
7939  else
7940  {
7941  /* coefficient is in C^- because it is smaller or equal to \bar{a} */
7942  coverstatus[coverpos[k]] = -1;
7943  SCIPquadprecSumQQ(tmp, tmp, coef);
7944  }
7945  covervals[k] = QUAD_TO_DBL(tmp);
7946  SCIPdebugMsg(scip, "S^-(%d) = %g\n", k + 1, covervals[k]);
7947  }
7948 
7949  /* set abar to its reciprocal for faster computation of the lifting coefficients */
7950  SCIPquadprecDivDQ(*abar, 1, *abar);
7951 }
7952 
7953 /** evaluate the lifting function based on the given values */
7954 static
7956  SCIP* scip, /**< SCIP datastructure */
7957  QUAD(SCIP_Real x), /**< value to evaluate the lifting function at */
7958  QUAD(SCIP_Real abar), /**< the reciprocal value of \bar{a} */
7959  SCIP_Real* covervals, /**< the running sum of S^-(*) values */
7960  int coversize, /**< the size of the cover */
7961  int cplussize, /**< the size of C^+ */
7962  SCIP_Real* scale /**< pointer to update the scale to integrality when a fractional value is returned */
7963  )
7964 {
7965  SCIP_Real QUAD(tmp);
7966  SCIP_Real QUAD(hfrac);
7967  SCIP_Real cutcoef;
7968  SCIP_Real hreal;
7969  int h;
7970 
7971  /* the lifted value is at least the coeficient (a_k) divided by \bar{a} because the largest value
7972  * contributed to the running sum stored in C is \bar{a}
7973  * therefore we start the search for the correct h at floor(a_k / \bar{a})
7974  */
7975 
7976  SCIPdebugMsg(scip, "coef is %g, coversize is %d\n", QUAD_TO_DBL(x), coversize );
7977 
7978  SCIPquadprecProdQQ(hfrac, x, abar);
7979 
7980  /* if the coefficient is below \bar{a}, i.e. a / \bar{a} < 1 then g(a_k) = 0, otherwise g(a_k) > 0 */
7981  if( QUAD_TO_DBL(hfrac) < 1 )
7982  return 0.0;
7983 
7984  /* we perform h = MIN(h, coversize) in floating-point first because on some instances h was seen to exceed the range
7985  * of int */
7986  hreal = SCIPfloor(scip, QUAD_TO_DBL(hfrac));
7987  if( hreal > (SCIP_Real)coversize )
7988  h = coversize;
7989  else
7990  h = (int)hreal;
7991 
7992  SCIPquadprecSumQD(hfrac, hfrac, -h);
7993 
7994  assert(h > 0);
7995  if( h < cplussize && ABS(QUAD_TO_DBL(hfrac)) <= QUAD_EPSILON )
7996  {
7997  /* cutcoef can be increased by 0.5 because it is a multiple of \bar{a}
7998  * (This is the first non-dominated lifting function presented in the paper)
7999  */
8000  cutcoef = 0.5;
8001  *scale = 2.0;
8002  }
8003  else
8004  cutcoef = 0.0;
8005 
8006  /* decrease by one to make sure rounding errors or coefficients that are larger than the right hand side by themselves
8007  * did not push h too far */
8008  h--;
8009 
8010  /* now increase coefficient to its lifted value based on its size relative to the S^- values.
8011  * The coefficient a_i is lifted to the unique integer h such that S^-(h) < a_i <= S^-(h+1).
8012  * (todo: variables that have a coefficient above the right hand side can get an arbitrarily large coefficient but can
8013  * also be trivially fixed using the base row. Currently they get the coefficient |C| which is 1 above the right hand
8014  * side in the cover cut so that they can still be trivially fixed by propagating the cover cut.
8015  * We do not want to apply fixings here though because the LP should stay flushed during separation.
8016  * Possibly add a parameter to return additional fixings to the caller of the SCIPcalc*() functions in here
8017  * and the caller can add them as cuts to the sepastore or we add them to the sepastore here?)
8018  */
8019  while( h < coversize )
8020  {
8021  SCIPquadprecSumQD(tmp, x, -covervals[h]); /* recall: covervals[h] = S^-(h+1) */
8022  /* compare with standard epsilon tolerance since computation involves abar, which is computed like an activity */
8023  if( !SCIPisPositive(scip, QUAD_TO_DBL(tmp)) )
8024  break;
8025 
8026  ++h;
8027  }
8028 
8029  cutcoef += h;
8030 
8031  SCIPdebugMsg(scip, "x is %g, coversize is %d, h is %d\n", QUAD_TO_DBL(x), coversize, h );
8032  /* the lifted coefficient is h increased possibly by 0.5 for the case checked above */
8033  SCIPdebugMsg(scip, "lifted coef %g < %g <= %g to %g\n", h == 0 ? 0 : covervals[h-1], QUAD_TO_DBL(x),
8034  covervals[h], cutcoef);
8035 
8036  return cutcoef;
8037 }
8038 
8039 /** calculates a lifted knapsack cover cut out of the weighted sum of LP rows given by an aggregation row; the
8040  * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
8041  * participate in the cut.
8042  * For further details we refer to:
8043  *
8044  * Letchford, A. N., & Souli, G. (2019). On lifted cover inequalities: A new lifting procedure with unusual properties.
8045  * Operations Research Letters, 47(2), 83-87.
8046  *
8047  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8048  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8049  *
8050  * @pre This method can be called if @p scip is in one of the following stages:
8051  * - \ref SCIP_STAGE_SOLVING
8052  *
8053  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8054  */
8056  SCIP* scip, /**< SCIP data structure */
8057  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8058  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8059  SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute flow cover cut for */
8060  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8061  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8062  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8063  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8064  SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
8065  int* cutrank, /**< pointer to return rank of generated cut */
8066  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8067  SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
8068  )
8069 {
8070  int* varsign;
8071  int* boundtype;
8072  int* coverstatus;
8073  int* coverpos;
8074  int* tmpinds;
8075  SCIP_Real* tmpcoefs;
8076  SCIP_Real* covervals;
8077  SCIP_Real QUAD(rhs);
8078  SCIP_Real QUAD(coverweight);
8079  SCIP_Real QUAD(abar);
8080  SCIP_Bool transformed;
8081  SCIP_Bool local;
8082  SCIP_Real efficacy;
8083  SCIP_Real scale;
8084  int k;
8085  int nvars;
8086  int coversize;
8087  int cplussize;
8088  int nnz;
8089 
8090  assert(scip != NULL);
8091  assert(aggrrow != NULL);
8092  assert(cutcoefs != NULL);
8093  assert(cutrhs != NULL);
8094  assert(cutinds != NULL);
8095  assert(cutnnz != NULL);
8096  assert(cutefficacy != NULL);
8097  assert(cutislocal != NULL);
8098  assert(success != NULL);
8099 
8100  *success = FALSE;
8101 
8102  if( aggrrow->nnz == 0 )
8103  return SCIP_OKAY;
8104 
8105  for( k = 0; k < aggrrow->nrows; ++k )
8106  {
8107  /* cannot handle negative slack variables */
8108  if( aggrrow->rowweights[k] * aggrrow->slacksign[k] < 0 )
8109  return SCIP_OKAY;
8110  }
8111 
8112  /* allocate temporary memory */
8113  nvars = SCIPgetNVars(scip);
8114  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
8115  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
8116  SCIP_CALL( SCIPallocBufferArray(scip, &coverstatus, nvars) );
8117  SCIP_CALL( SCIPallocBufferArray(scip, &covervals, nvars) );
8118  SCIP_CALL( SCIPallocBufferArray(scip, &coverpos, nvars) );
8119  SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
8120  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, QUAD_ARRAY_SIZE(nvars)) );
8121 
8122  /* initialize cut with aggregation */
8123  nnz = aggrrow->nnz;
8124  QUAD_ASSIGN_Q(rhs, aggrrow->rhs);
8125 
8126  BMScopyMemoryArray(tmpinds, aggrrow->inds, nnz);
8127 
8128  for( k = 0; k < nnz; ++k )
8129  {
8130  SCIP_Real QUAD(coef);
8131  int j = tmpinds[k];
8132 
8133  QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
8134 
8135  QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
8136  assert(QUAD_HI(coef) != 0.0);
8137 
8138  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8139  }
8140  SCIPdebugMsg(scip, "Computing lifted knapsack cover for ");
8141  SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
8142 
8143  /* Transform aggregated row into a (fractional, i.e. with possibly fractional weights) knapsack constraint.
8144  * Uses simple or variable lower or upper bounds to relax out continuous and general integers
8145  * so that only binary variables remain and complements those such that they have a positive coefficient.
8146  */
8147  local = aggrrow->local;
8148  SCIP_CALL( cutsTransformKnapsackCover(scip, sol, allowlocal,
8149  tmpcoefs, QUAD(&rhs), tmpinds, &nnz, varsign, boundtype, &local, &transformed) );
8150 
8151  assert(allowlocal || !local);
8152 
8153  if( !transformed )
8154  goto TERMINATE;
8155 
8156  SCIPdebugMsg(scip, "Transformed knapsack relaxation ");
8157  SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
8158 
8159  if( !computeInitialKnapsackCover(scip, sol, tmpcoefs, tmpinds, QUAD_TO_DBL(rhs), nnz, varsign, coverstatus,
8160  coverpos, covervals, &coversize, QUAD(&coverweight)) )
8161  goto TERMINATE;
8162 
8163  SCIPdebugMsg(scip, "coverweight is %g and right hand side is %g\n", QUAD_TO_DBL(coverweight), QUAD_TO_DBL(rhs));
8164  assert(coversize > 0);
8165 
8166  /* by default do not scale the cut */
8167  scale = 1.0;
8168 
8169  if( coversize == 1 )
8170  {
8171  SCIP_Real QUAD(tmp);
8172  /* cover is trivial, return the fixing as cut */
8173  QUAD_ASSIGN(tmp, 0.0);
8174  for( k = 0; k < nnz; ++k )
8175  {
8176  if( coverstatus[k] == 0 )
8177  {
8178  QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8179  }
8180  else
8181  {
8182  tmpinds[0] = tmpinds[k];
8183  varsign[0] = varsign[k];
8184  }
8185  }
8186 
8187  nnz = 1;
8188  if( varsign[0] == -1 )
8189  {
8190  QUAD_ASSIGN(rhs, -1.0);
8191  QUAD_ASSIGN(tmp, -1.0);
8192  }
8193  else
8194  {
8195  QUAD_ASSIGN(rhs, 0.0);
8196  QUAD_ASSIGN(tmp, 1.0);
8197  }
8198 
8199  QUAD_ARRAY_STORE(tmpcoefs, tmpinds[0], tmp);
8200  }
8201  else
8202  {
8203  SCIP_Real QUAD(tmp);
8204 
8205  /* compute lifted cover inequality:
8206  * sum_{i \in C^-) x_i + sum_{i \in N \ C^-) g(a_i) x_i <= c - 1
8207  * where g(z) is equal to
8208  * - 0 if z is 0 (irrelevant as there shouldn't be element with weight 0 in the knapsack)
8209  * - 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
8210  * - h if S^-(h) < z <= S^-(h+1) for some h = 0, ..., coversize -1
8211  * the function S^- is defined above. Note that S^-(0) = 0
8212  * we store the cut coefficients in tmpcoef
8213  */
8214 
8215  SCIPdebugMsg(scip, "call prepareLiftingData: \n");
8216  /* prepare data required to evaluate lifting function */
8217  prepareLiftingData(scip, tmpcoefs, tmpinds, QUAD(rhs), coverpos, coversize,
8218  QUAD(coverweight), covervals, coverstatus, QUAD(&abar), &cplussize);
8219 
8220  /* compute lifted cover inequality */
8221  QUAD_ASSIGN(rhs, (coversize - 1));
8222  for( k = 0; k < nnz; )
8223  {
8224  SCIP_Real cutcoef;
8225  if( coverstatus[k] == -1 )
8226  { /* variables in C^- get the coefficients 1 */
8227  cutcoef = 1.0;
8228  }
8229  else
8230  { /* variables is either in C^+ or not in the cover and its coefficient value is computed with the lifing function */
8231  SCIP_Real QUAD(coef);
8232 
8233  SCIPdebugMsg(scip, "load QUAD(coef) from tmpcoefs[tmpinds[k] = %d]\n",tmpinds[k]);
8234  QUAD_ARRAY_LOAD(coef, tmpcoefs, tmpinds[k]);
8235 
8236  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));
8237 
8238  SCIPdebugMsg(scip, "call evaluateLiftingFunctionKnapsack:\n");
8239  cutcoef = evaluateLiftingFunctionKnapsack(scip, QUAD(coef), QUAD(abar), covervals, coversize, cplussize, &scale);
8240 
8241  /* if the coefficient value is zero then remove the nonzero entry and continue */
8242  if( cutcoef == 0.0 )
8243  {
8244  QUAD_ASSIGN(tmp, 0.0);
8245  QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8246  --nnz;
8247  coverstatus[k] = coverstatus[nnz];
8248  tmpinds[k] = tmpinds[nnz];
8249  varsign[k] = varsign[nnz];
8250  continue;
8251  }
8252  }
8253 
8254  /* directly undo the complementation before storing back the coefficient */
8255  if( varsign[k] == -1 )
8256  {
8257  /* variable was complemented so we have cutcoef * (1-x) = cutcoef - cutcoef * x.Thus we need to adjust the rhs
8258  * to rhs - cutcoef and flip the sign of cutcoef */
8259  cutcoef = -cutcoef;
8260  SCIPquadprecSumQD(rhs, rhs, cutcoef);
8261  }
8262 
8263  QUAD_ASSIGN(tmp, cutcoef);
8264  QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8265 
8266  ++k;
8267  }
8268  }
8269 
8270  /* calculate the efficacy of the computed cut and store the success flag if the efficacy exceeds the
8271  * one stored in the cutefficacy variable by the caller
8272  */
8273  efficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, nnz);
8274  *success = efficacy > *cutefficacy;
8275 
8276  SCIPdebugMsg(scip, "FINAL LCI:");
8277  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, nnz, FALSE, FALSE));
8278 
8279  if( *success )
8280  {
8281  /* return the cut into the given arrays/pointers */
8282  *cutislocal = local;
8283  *cutrhs = scale * QUAD_TO_DBL(rhs);
8284  *cutnnz = nnz;
8285 
8286  /* store cut in given array in sparse representation and clean buffer array */
8287  for( k = 0; k < nnz; ++k )
8288  {
8289  SCIP_Real QUAD(coef);
8290  int j = tmpinds[k];
8291 
8292  QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
8293  assert(QUAD_HI(coef) != 0.0);
8294 
8295  cutcoefs[k] = scale * QUAD_TO_DBL(coef);
8296  cutinds[k] = j;
8297  QUAD_ASSIGN(coef, 0.0);
8298  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
8299  }
8300 
8301  assert( cutefficacy != NULL );
8302  /* calculate efficacy again to make sure it matches the coefficients after they where rounded to double values
8303  * and after the cleanup and postprocessing step was applied. */
8304  *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, nnz);
8305 
8306  if( cutrank != NULL )
8307  *cutrank = aggrrow->rank + 1;
8308  }
8309 
8310  TERMINATE:
8311 
8312  /* if we aborted early the tmpcoefs array needs to be cleaned */
8313  if( !(*success) )
8314  {
8315  SCIP_Real QUAD(tmp);
8316  QUAD_ASSIGN(tmp, 0.0);
8317 
8318  for( k = 0; k < nnz; ++k )
8319  {
8320  QUAD_ARRAY_STORE(tmpcoefs, tmpinds[k], tmp);
8321  }
8322  }
8323 #ifndef NDEBUG
8324  for( k = 0; k < QUAD_ARRAY_SIZE(nvars); ++k )
8325  {
8326  if(tmpcoefs[k] != 0.0)
8327  {
8328  SCIPdebugMsg(scip, "tmpcoefs have not been reset\n");
8329  SCIPABORT();
8330  }
8331  }
8332 #endif
8333 
8334  /* free temporary memory */
8335  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
8336  SCIPfreeBufferArray(scip, &tmpinds);
8337  SCIPfreeBufferArray(scip, &coverpos);
8338  SCIPfreeBufferArray(scip, &covervals);
8339  SCIPfreeBufferArray(scip, &coverstatus);
8340  SCIPfreeBufferArray(scip, &boundtype);
8341  SCIPfreeBufferArray(scip, &varsign);
8342 
8343  return SCIP_OKAY;
8344 }
8345 
8346 
8347 /* =========================================== strongcg =========================================== */
8348 
8349 /** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
8350  * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
8351  *
8352  * Differs from cutsTransformMIR for continuous variables for which the lower bound must be used
8353  * when in case their coefficient is positive and the upper bound in case their coefficient is
8354  * negative. This forces all continuous variable to have a positive coefficient in the transformed
8355  * row.
8356  *
8357  * Transform variables (lb or ub):
8358  * \f[
8359  * \begin{array}{llll}
8360  * 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}\\
8361  * 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}
8362  * \end{array}
8363  * \f]
8364  * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
8365  *
8366  * Transform variables (vlb or vub):
8367  * \f[
8368  * \begin{array}{llll}
8369  * 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.} \\
8370  * 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.}
8371  * \end{array}
8372  * \f]
8373  * 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:
8374  * \f[
8375  * \begin{array}{ll}
8376  * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
8377  * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
8378  * \end{array}
8379  * \f]
8380  */
8381 static
8383  SCIP* scip, /**< SCIP data structure */
8384  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8385  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8386  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
8387  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8388  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8389  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8390  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8391  int* nnz, /**< number of non-zeros in cut */
8392  int* varsign, /**< stores the sign of the transformed variable in summation */
8393  int* boundtype, /**< stores the bound used for transformed variable:
8394  * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
8395  SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
8396  SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
8397  )
8398 {
8399  SCIP_Real* bestbds;
8400  int i;
8401  int aggrrowintstart;
8402  int nvars;
8403  int firstcontvar;
8404  SCIP_VAR** vars;
8405 
8406  assert(varsign != NULL);
8407  assert(boundtype != NULL);
8408  assert(freevariable != NULL);
8409  assert(localbdsused != NULL);
8410 
8411  *freevariable = FALSE;
8412  *localbdsused = FALSE;
8413 
8414  /* allocate temporary memory to store best bounds and bound types */
8415  SCIP_CALL( SCIPallocBufferArray(scip, &bestbds, 2*(*nnz)) );
8416 
8417  /* start with continuous variables, because using variable bounds can affect the untransformed integral
8418  * variables, and these changes have to be incorporated in the transformation of the integral variables
8419  * (continuous variables have largest problem indices!)
8420  */
8421  SCIPsortDownInt(cutinds, *nnz);
8422 
8423  vars = SCIPgetVars(scip);
8424  nvars = SCIPgetNVars(scip);
8425  firstcontvar = nvars - SCIPgetNContVars(scip);
8426 
8427  /* determine best bounds for the continuous variables such that they will have a positive coefficient in the transformation */
8428  for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
8429  {
8430  SCIP_Real QUAD(coef);
8431  int v = cutinds[i];
8432 
8433  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
8434 
8435  if( QUAD_TO_DBL(coef) > 0.0 )
8436  {
8437  SCIP_Real simplebound;
8438 
8439  /* find closest lower bound in standard lower bound or variable lower bound for continuous variable so that it will have a positive coefficient */
8440  SCIP_CALL( findBestLb(scip, vars[v], sol, usevbds ? 2 : 0, allowlocal, bestbds + i, &simplebound, boundtype + i) );
8441 
8442  /* cannot create transformation for strongcg cut */
8443  if( SCIPisInfinity(scip, -bestbds[i]) )
8444  {
8445  *freevariable = TRUE;
8446  goto TERMINATE;
8447  }
8448 
8449  varsign[i] = +1;
8450  }
8451  else if( QUAD_TO_DBL(coef) < 0.0 )
8452  {
8453  SCIP_Real simplebound;
8454 
8455  /* find closest upper bound in standard upper bound or variable upper bound for continuous variable so that it will have a positive coefficient */
8456  SCIP_CALL( findBestUb(scip, vars[v], sol, usevbds ? 2 : 0, allowlocal, bestbds + i, &simplebound, boundtype + i) );
8457 
8458  /* cannot create transformation for strongcg cut */
8459  if( SCIPisInfinity(scip, bestbds[i]) )
8460  {
8461  *freevariable = TRUE;
8462  goto TERMINATE;
8463  }
8464 
8465  varsign[i] = -1;
8466  }
8467  }
8468 
8469  /* remember start of integer variables in the aggrrow */
8470  aggrrowintstart = i;
8471 
8472  /* perform bound substitution for continuous variables */
8473  for( i = 0; i < aggrrowintstart; ++i )
8474  {
8475  performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestbds[i], cutinds[i], localbdsused);
8476  }
8477 
8478  assert(i == aggrrowintstart);
8479 
8480  /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
8481  * and perform the bound substitution for the integer variables that are left using simple bounds
8482  */
8483  while( i < *nnz )
8484  {
8485  SCIP_Real QUAD(coef);
8486  SCIP_Real bestlb;
8487  SCIP_Real bestub;
8488  int bestlbtype;
8489  int bestubtype;
8490  SCIP_BOUNDTYPE selectedbound;
8491  int v = cutinds[i];
8492 
8493  assert(v < firstcontvar);
8494  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
8495 
8496  /* due to variable bound usage for the continuous variables cancellation may have occurred */
8497  if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
8498  {
8499  QUAD_ASSIGN(coef, 0.0);
8500  QUAD_ARRAY_STORE(cutcoefs, v, coef);
8501  --(*nnz);
8502  cutinds[i] = cutinds[*nnz];
8503 
8504  /* do not increase i, since last element is copied to the i-th position */
8505  continue;
8506  }
8507 
8508  /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
8509  SCIP_CALL( determineBestBounds(scip, vars[v], sol, boundswitch, 0, allowlocal, FALSE, FALSE, NULL, NULL,
8510  &bestlb, &bestub, &bestlbtype, &bestubtype, &selectedbound, freevariable) );
8511 
8512  /* check if we have an unbounded integral variable */
8513  if( *freevariable )
8514  {
8515  goto TERMINATE;
8516  }
8517 
8518  /* perform bound substitution */
8519  if( selectedbound == SCIP_BOUNDTYPE_LOWER )
8520  {
8521  boundtype[i] = bestlbtype;
8522  varsign[i] = +1;
8523 
8524  performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlb, v, localbdsused);
8525  }
8526  else
8527  {
8528  assert(selectedbound == SCIP_BOUNDTYPE_UPPER);
8529  boundtype[i] = bestubtype;
8530  varsign[i] = -1;
8531 
8532  performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestub, v, localbdsused);
8533  }
8534 
8535  assert(boundtype[i] == -1 || boundtype[i] == -2);
8536 
8537  /* increase i */
8538  ++i;
8539  }
8540 
8541  /* relax rhs to zero if it is close to */
8542  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
8543  QUAD_ASSIGN(*cutrhs, 0.0);
8544 
8545  TERMINATE:
8546  /* free temporary memory */
8547  SCIPfreeBufferArray(scip, &bestbds);
8548 
8549  return SCIP_OKAY;
8550 }
8551 
8552 /** Calculate fractionalities \f$ f_0 := b - down(b) \f$, \f$ f_j := a^\prime_j - down(a^\prime_j) \f$,
8553  * 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
8554  * 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$
8555  * and derive strong CG cut \f$ \tilde{a} x^\prime \leq down(b) \f$
8556  * \f[
8557  * \begin{array}{rll}
8558  * integers : & \tilde{a}_j = down(a^\prime_j) &, if \qquad f_j \leq f_0 \\
8559  * & \tilde{a}_j = down(a^\prime_j) + p_j/(k + 1) &, if \qquad f_j > f_0 \\
8560  * continuous:& \tilde{a}_j = 0 &, if \qquad a^\prime_j \geq 0 \\
8561  * & \mbox{no strong CG cut found} &, if \qquad a^\prime_j < 0
8562  * \end{array}
8563  * \f]
8564  *
8565  * Transform inequality back to \f$ \hat{a}*x <= rhs \f$:
8566  *
8567  * (lb or ub):
8568  * \f[
8569  * \begin{array}{lllll}
8570  * 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} \\
8571  * 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}
8572  * \end{array}
8573  * \f]
8574  * \f[
8575  * and move the constant terms
8576  * \begin{array}{rl}
8577  * -\tilde{a}_j * lb_j == -\hat{a}_j * lb_j, & \mbox{or} \\
8578  * \tilde{a}_j * ub_j == -\hat{a}_j * ub_j &
8579  * \end{array}
8580  * \f]
8581  * to the rhs.
8582  *
8583  * (vlb or vub):
8584  * \f[
8585  * \begin{array}{lllll}
8586  * 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)} \\
8587  * 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)}
8588  * \end{array}
8589  * \f]
8590  * move the constant terms
8591  * \f[
8592  * \begin{array}{rl}
8593  * -\tilde{a}_j * dl_j == -\hat{a}_j * dl_j,& \mbox{or} \\
8594  * \tilde{a}_j * du_j == -\hat{a}_j * du_j &
8595  * \end{array}
8596  * \f]
8597  * to the rhs, and update the VB variable coefficients:
8598  * \f[
8599  * \begin{array}{ll}
8600  * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j * bl_j == \hat{a}_{zl_j} - \hat{a}_j * bl_j,& \mbox{or} \\
8601  * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j * bu_j == \hat{a}_{zu_j} - \hat{a}_j * bu_j &
8602  * \end{array}
8603  * \f]
8604  */
8605 static
8607  SCIP* scip, /**< SCIP data structure */
8608  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8609  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8610  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8611  int* nnz, /**< number of non-zeros in cut */
8612  int* varsign, /**< stores the sign of the transformed variable in summation */
8613  int* boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub)*/
8614  QUAD(SCIP_Real f0), /**< fractional value of rhs */
8615  SCIP_Real k /**< factor to strengthen strongcg cut */
8616  )
8617 {
8618  SCIP_Real QUAD(onedivoneminusf0);
8619  int i;
8620  int firstcontvar;
8621  SCIP_VAR** vars;
8622  int aggrrowintstart;
8623 
8624  assert(QUAD_HI(cutrhs) != NULL);
8625  assert(cutcoefs != NULL);
8626  assert(cutinds != NULL);
8627  assert(nnz != NULL);
8628  assert(boundtype != NULL);
8629  assert(varsign != NULL);
8630  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
8631 
8632  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
8633  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
8634 
8635  /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
8636  * without destroying the ordering of the aggrrow's non-zeros.
8637  * (due to sorting in cutsTransformStrongCG the ordering is continuous before integral)
8638  */
8639 
8640  firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
8641  vars = SCIPgetVars(scip);
8642 #ifndef NDEBUG
8643  /* in debug mode check, that all continuous variables of the aggrrow come before the integral variables */
8644  i = 0;
8645  while( i < *nnz && cutinds[i] >= firstcontvar )
8646  {
8647  assert(SCIPvarGetType(vars[cutinds[i]]) == SCIP_VARTYPE_CONTINUOUS);
8648  ++i;
8649  }
8650  while( i < *nnz )
8651  {
8652  assert(cutinds[i] < firstcontvar);
8653  assert(SCIPvarGetType(vars[cutinds[i]]) != SCIP_VARTYPE_CONTINUOUS);
8654  ++i;
8655  }
8656 #endif
8657 
8658  /* integer variables */
8659  for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
8660  {
8661  SCIP_VAR* var;
8662  SCIP_Real QUAD(aj);
8663  SCIP_Real QUAD(downaj);
8664  SCIP_Real QUAD(cutaj);
8665  SCIP_Real QUAD(fj);
8666  SCIP_Real QUAD(tmp);
8667  SCIP_Real bound;
8668  int v;
8669 
8670  v = cutinds[i];
8671  assert(0 <= v && v < SCIPgetNVars(scip));
8672 
8673  var = vars[v];
8674  assert(var != NULL);
8675  assert(SCIPvarGetProbindex(var) == v);
8676  assert(boundtype[i] == -1 || boundtype[i] == -2);
8677  assert(varsign[i] == +1 || varsign[i] == -1);
8678 
8679  /* calculate the coefficient in the retransformed cut */
8680  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
8681  QUAD_SCALE(aj, varsign[i]);
8682  SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
8683  SCIPquadprecSumQQ(fj, aj, -downaj);
8684  assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
8685 
8686  if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
8687  QUAD_ASSIGN_Q(cutaj, downaj); /* a_j */
8688  else
8689  {
8690  SCIP_Real pj;
8691 
8692  SCIPquadprecSumQQ(cutaj, fj, -f0);
8693  SCIPquadprecProdQD(cutaj, cutaj, k);
8694  SCIPquadprecProdQQ(cutaj, cutaj, onedivoneminusf0);
8695  pj = SCIPceil(scip, QUAD_TO_DBL(cutaj));
8696  assert(pj >= 0); /* should be >= 1, but due to rounding bias can be 0 if fj is almost equal to f0 */
8697  assert(pj <= k);
8698  SCIPquadprecDivDD(cutaj, pj, k + 1.0);
8699  SCIPquadprecSumQQ(cutaj, cutaj, downaj);
8700  }
8701 
8702  QUAD_SCALE(cutaj, varsign[i]);
8703 
8704  /* remove zero cut coefficients from cut */
8705  if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
8706  {
8707  QUAD_ASSIGN(cutaj, 0.0);
8708  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
8709  --*nnz;
8710  cutinds[i] = cutinds[*nnz];
8711  continue;
8712  }
8713 
8714  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
8715 
8716  /* integral var uses standard bound */
8717  assert(boundtype[i] < 0);
8718 
8719  /* 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 */
8720  if( varsign[i] == +1 )
8721  {
8722  /* lower bound was used */
8723  if( boundtype[i] == -1 )
8724  bound = SCIPvarGetLbGlobal(var);
8725  else
8726  bound = SCIPvarGetLbLocal(var);
8727  assert(!SCIPisInfinity(scip, -bound));
8728  }
8729  else
8730  {
8731  /* upper bound was used */
8732  if( boundtype[i] == -1 )
8733  bound = SCIPvarGetUbGlobal(var);
8734  else
8735  bound = SCIPvarGetUbLocal(var);
8736  assert(!SCIPisInfinity(scip, bound));
8737  }
8738  SCIPquadprecProdQD(tmp, cutaj, bound);
8739  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
8740  }
8741 
8742  /* now process the continuous variables; postpone deletion of zeros until all continuous variables have been processed */
8743  aggrrowintstart = i + 1;
8744 
8745 #ifndef NDEBUG
8746  /* in a strong CG cut, cut coefficients of continuous variables are always zero; check this in debug mode */
8747  for( i = 0; i < aggrrowintstart; ++i )
8748  {
8749  SCIP_Real QUAD(aj);
8750  SCIP_VAR* var;
8751  int v;
8752 
8753  v = cutinds[i];
8754  assert(firstcontvar <= v && v < SCIPgetNVars(scip));
8755 
8756  var = vars[v];
8757  assert(var != NULL);
8758  assert(!SCIPvarIsIntegral(var));
8759  assert(SCIPvarGetProbindex(var) == v);
8760  assert(varsign[i] == +1 || varsign[i] == -1);
8761 
8762  /* calculate the coefficient in the retransformed cut */
8763  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
8764  QUAD_SCALE(aj, varsign[i]);
8765 
8766  assert(QUAD_TO_DBL(aj) >= 0.0);
8767  }
8768 #endif
8769 
8770  /* set continuous variable coefficients to 0 */
8771  if( aggrrowintstart > 0 )
8772  {
8773  SCIP_Real QUAD(tmp);
8774  assert(aggrrowintstart <= *nnz);
8775 
8776  /* explicitly set continuous variable coefficients to 0 */
8777  QUAD_ASSIGN(tmp, 0.0);
8778  for( i = 0; i < aggrrowintstart; ++i )
8779  {
8780  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], tmp);
8781  }
8782 
8783  /* fill empty positions of the continuous variables by integral variables; copy all indices to the front or only
8784  * use the indices at the end, whatever is faster */
8785  *nnz -= aggrrowintstart;
8786  if( *nnz < aggrrowintstart )
8787  {
8788  BMScopyMemoryArray(cutinds, cutinds + aggrrowintstart, *nnz);
8789  }
8790  else
8791  {
8792  BMScopyMemoryArray(cutinds, cutinds + *nnz, aggrrowintstart);
8793  }
8794  }
8795 
8796  return SCIP_OKAY;
8797 }
8798 
8799 /** substitute aggregated slack variables:
8800  *
8801  * 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
8802  * variable only appears in its own row: \f$ a^\prime_r = scale \cdot weight[r] \cdot slacksign[r] \f$.
8803  *
8804  * Depending on the slack's type (integral or continuous), its coefficient in the cut calculates as follows:
8805  * \f[
8806  * \begin{array}{rll}
8807  * integers: & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & if \qquad f_r \leq f_0 \\
8808  * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + p_r/(k + 1), & if \qquad f_r > f_0 \\
8809  * continuous:& \hat{a}_r = \tilde{a}_r = 0, & if \qquad a^\prime_r \geq 0 \\
8810  * & \mbox{no strong CG cut found}, & if \qquad a^\prime_r < 0
8811  * \end{array}
8812  * \f]
8813  *
8814  * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
8815  */
8816 static
8818  SCIP* scip, /**< SCIP datastructure */
8819  SCIP_Real* weights, /**< row weights in row summation */
8820  int* slacksign, /**< stores the sign of the row's slack variable in summation */
8821  int* rowinds, /**< sparsity pattern of used rows */
8822  int nrowinds, /**< number of used rows */
8823  SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8824  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
8825  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
8826  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
8827  int* nnz, /**< number of non-zeros in cut */
8828  QUAD(SCIP_Real f0), /**< fractional value of rhs */
8829  SCIP_Real k /**< factor to strengthen strongcg cut */
8830  )
8831 { /*lint --e{715}*/
8832  SCIP_ROW** rows;
8833  SCIP_Real QUAD(onedivoneminusf0);
8834  int i;
8835 
8836  assert(scip != NULL);
8837  assert(weights != NULL);
8838  assert(slacksign != NULL);
8839  assert(rowinds != NULL);
8840  assert(SCIPisPositive(scip, scale));
8841  assert(cutcoefs != NULL);
8842  assert(QUAD_HI(cutrhs) != NULL);
8843  assert(cutinds != NULL);
8844  assert(nnz != NULL);
8845  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
8846 
8847  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
8848  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
8849 
8850  rows = SCIPgetLPRows(scip);
8851  for( i = 0; i < nrowinds; i++ )
8852  {
8853  SCIP_ROW* row;
8854  SCIP_Real QUAD(ar);
8855  SCIP_Real QUAD(downar);
8856  SCIP_Real QUAD(cutar);
8857  SCIP_Real QUAD(fr);
8858  SCIP_Real mul;
8859  int r;
8860 
8861  r = rowinds[i];
8862  assert(0 <= r && r < SCIPgetNLPRows(scip));
8863  assert(slacksign[i] == -1 || slacksign[i] == +1);
8864  assert(!SCIPisZero(scip, weights[i]));
8865 
8866  row = rows[r];
8867  assert(row != NULL);
8868  assert(row->len == 0 || row->cols != NULL);
8869  assert(row->len == 0 || row->cols_index != NULL);
8870  assert(row->len == 0 || row->vals != NULL);
8871 
8872  /* get the slack's coefficient a'_r in the aggregated row */
8873  SCIPquadprecProdDD(ar, slacksign[i] * scale, weights[i]);
8874 
8875  /* calculate slack variable's coefficient a_r in the cut */
8876  if( row->integral )
8877  {
8878  /* slack variable is always integral */
8879  SCIPquadprecEpsFloorQ(downar, ar, SCIPepsilon(scip)); /*lint !e666*/
8880  SCIPquadprecSumQQ(fr, ar, -downar);
8881  assert(QUAD_TO_DBL(fr) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fr) < 1.0);
8882 
8883  if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
8884  QUAD_ASSIGN_Q(cutar, downar); /* a_r */
8885  else
8886  {
8887  SCIP_Real pr;
8888 
8889  SCIPquadprecSumQQ(cutar, fr, -f0);
8890  SCIPquadprecProdQD(cutar, cutar, k);
8891  SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
8892  pr = SCIPceil(scip, QUAD_TO_DBL(cutar));
8893  assert(pr >= 0); /* should be >= 1, but due to rounding bias can be 0 if fr is almost equal to f0 */
8894  assert(pr <= k);
8895  SCIPquadprecDivDD(cutar, pr, k + 1.0);
8896  SCIPquadprecSumQQ(cutar, cutar, downar);
8897  }
8898  }
8899  else
8900  {
8901  /* slack variable is continuous: */
8902  assert(QUAD_TO_DBL(ar) >= 0.0);
8903  continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
8904  }
8905 
8906  /* if the coefficient was reduced to zero, ignore the slack variable */
8907  if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
8908  continue;
8909 
8910  /* depending on the slack's sign, we have
8911  * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
8912  * substitute a_r * s_r by adding a_r times the slack's definition to the cut.
8913  */
8914  mul = -slacksign[i] * QUAD_TO_DBL(cutar);
8915 
8916  /* add the slack's definition multiplied with a_j to the cut */
8917  SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
8918 
8919  /* move slack's constant to the right hand side */
8920  if( slacksign[i] == +1 )
8921  {
8922  SCIP_Real rhs;
8923 
8924  /* a*x + c + s == rhs => s == - a*x - c + rhs: move a_r * (rhs - c) to the right hand side */
8925  assert(!SCIPisInfinity(scip, row->rhs));
8926  rhs = row->rhs - row->constant;
8927  if( row->integral )
8928  {
8929  /* the right hand side was implicitly rounded down in row aggregation */
8930  rhs = SCIPfloor(scip, rhs);
8931  }
8932 
8933  SCIPquadprecProdQD(cutar, cutar, rhs);
8934  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -cutar);
8935  }
8936  else
8937  {
8938  SCIP_Real lhs;
8939 
8940  /* a*x + c - s == lhs => s == a*x + c - lhs: move a_r * (c - lhs) to the right hand side */
8941  assert(!SCIPisInfinity(scip, -row->lhs));
8942  lhs = row->lhs - row->constant;
8943  if( row->integral )
8944  {
8945  /* the left hand side was implicitly rounded up in row aggregation */
8946  lhs = SCIPceil(scip, lhs);
8947  }
8948 
8949  SCIPquadprecProdQD(cutar, cutar, lhs);
8950  SCIPquadprecSumQQ(*cutrhs, *cutrhs, cutar);
8951  }
8952  }
8953 
8954  /* relax rhs to zero, if it's very close to 0 */
8955  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
8956  QUAD_ASSIGN(*cutrhs, 0.0);
8957 
8958  return SCIP_OKAY;
8959 }
8960 
8961 
8962 /** calculates a strong CG cut out of the weighted sum of LP rows given by an aggregation row; the
8963  * aggregation row must not contain non-zero weights for modifiable rows, because these rows cannot
8964  * participate in a strongcg cut
8965  *
8966  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8967  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8968  *
8969  * @pre This method can be called if @p scip is in one of the following stages:
8970  * - \ref SCIP_STAGE_SOLVING
8971  *
8972  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
8973  */
8975  SCIP* scip, /**< SCIP data structure */
8976  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
8977  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
8978  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
8979  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
8980  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
8981  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce strong CG cut for */
8982  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce strong CG cut for */
8983  SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
8984  SCIP_AGGRROW* aggrrow, /**< the aggregation row to compute a strong CG cut for */
8985  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
8986  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
8987  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
8988  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
8989  SCIP_Real* cutefficacy, /**< pointer to store the efficacy of the cut, or NULL */
8990  int* cutrank, /**< pointer to return rank of generated cut */
8991  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
8992  SCIP_Bool* success /**< pointer to store whether a valid cut was returned */
8993  )
8994 {
8995  int i;
8996  int nvars;
8997  int* varsign;
8998  int* boundtype;
8999  SCIP_Real* tmpcoefs;
9000  SCIP_Real QUAD(downrhs);
9001  SCIP_Real QUAD(f0);
9002  SCIP_Real QUAD(tmp);
9003  SCIP_Real QUAD(rhs);
9004  SCIP_Real large;
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  /* determine value from which fractionalities are no longer reliable within tolerance */
9023  large = SCIPgetHugeValue(scip) * SCIPepsilon(scip);
9024 
9025  /* terminate if an integral slack fractionality is unreliable or a negative continuous slack variable is present */
9026  for( i = 0; i < aggrrow->nrows; ++i )
9027  if( ( scip->lp->rows[aggrrow->rowsinds[i]]->integral && ABS(aggrrow->rowweights[i] * scale) > large )
9028  || ( !scip->lp->rows[aggrrow->rowsinds[i]]->integral && aggrrow->rowweights[i] * aggrrow->slacksign[i] < 0.0 ) )
9029  return SCIP_OKAY;
9030 
9031  /* allocate temporary memory */
9032  nvars = SCIPgetNVars(scip);
9033  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
9034  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
9035  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, QUAD_ARRAY_SIZE(nvars)) );
9036 
9037  /* initialize cut with aggregation */
9038  *cutnnz = aggrrow->nnz;
9039  *cutislocal = aggrrow->local;
9040  SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
9041 
9042  if( *cutnnz > 0 )
9043  {
9044  int firstcontvar;
9045 
9046  BMScopyMemoryArray(cutinds, aggrrow->inds, *cutnnz);
9047 
9048  for( i = 0; i < *cutnnz; ++i )
9049  {
9050  SCIP_Real QUAD(coef);
9051  int j = cutinds[i];
9052 
9053  QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
9054  SCIPquadprecProdQD(coef, coef, scale);
9055 
9056  QUAD_HI(coef) = NONZERO(QUAD_HI(coef));
9057  assert(QUAD_HI(coef) != 0.0);
9058 
9059  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
9060  }
9061 
9062  /* Transform equation a*x == b, lb <= x <= ub into standard form
9063  * a'*x' == b, 0 <= x' <= ub'.
9064  *
9065  * Transform variables (lb or ub):
9066  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
9067  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
9068  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
9069  *
9070  * Transform variables (vlb or vub):
9071  * 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.
9072  * 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.
9073  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
9074  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
9075  * a_{zu_j} := a_{zu_j} + a_j * bu_j
9076  */
9077  SCIP_CALL( cutsTransformStrongCG(scip, sol, boundswitch, usevbds, allowlocal,
9078  tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, &freevariable, &localbdsused) );
9079 
9080  assert(allowlocal || !localbdsused);
9081  *cutislocal = *cutislocal || localbdsused;
9082 
9083  if( freevariable )
9084  goto TERMINATE;
9085 
9086  firstcontvar = nvars - SCIPgetNContVars(scip);
9087 
9088  /* terminate if an integral coefficient fractionality is unreliable */
9089  for( i = *cutnnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
9090  {
9091  SCIP_Real QUAD(coef);
9092 
9093  QUAD_ARRAY_LOAD(coef, tmpcoefs, cutinds[i]);
9094 
9095  if( ABS(QUAD_TO_DBL(coef)) > large )
9096  goto TERMINATE;
9097  }
9098 
9099  SCIPdebug(printCutQuad(scip, NULL, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9100  }
9101 
9102  /* terminate if the side fractionality is unreliable */
9103  if( ABS(QUAD_TO_DBL(rhs)) > large )
9104  goto TERMINATE;
9105 
9106  /* Calculate
9107  * - fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j)
9108  * - integer k >= 1 with 1/(k + 1) <= f_0 < 1/k
9109  * (=> k = up(1/f_0) - 1)
9110  * - 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)
9111  * (=> p_j = up( (f_j - f_0)/((1 - f_0)/k) ))
9112  * and derive strong CG cut
9113  * a~*x' <= (k+1) * down(b)
9114  * integers : a~_j = down(a'_j) , if f_j <= f_0
9115  * a~_j = down(a'_j) + p_j/(k + 1) , if f_j > f_0
9116  * continuous: a~_j = 0 , if a'_j >= 0
9117  * no strong CG cut found , if a'_j < 0
9118  *
9119  * Transform inequality back to a^*x <= rhs:
9120  *
9121  * (lb or ub):
9122  * 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
9123  * 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
9124  * and move the constant terms
9125  * -a~_j * lb_j == -a^_j * lb_j, or
9126  * a~_j * ub_j == -a^_j * ub_j
9127  * to the rhs.
9128  *
9129  * (vlb or vub):
9130  * 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)
9131  * 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)
9132  * move the constant terms
9133  * -a~_j * dl_j == -a^_j * dl_j, or
9134  * a~_j * du_j == -a^_j * du_j
9135  * to the rhs, and update the VB variable coefficients:
9136  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
9137  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
9138  */
9139  SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
9140  SCIPquadprecSumQQ(f0, rhs, -downrhs);
9141  assert(QUAD_TO_DBL(f0) >= -SCIPepsilon(scip) && QUAD_TO_DBL(f0) < 1.0);
9142 
9143  if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
9144  goto TERMINATE;
9145 
9146  /* renormalize the f0 value */
9147  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
9148 
9149  SCIPquadprecDivDQ(tmp, 1.0, f0);
9150  SCIPquadprecSumQD(tmp, tmp, -1.0);
9151  k = SCIPceil(scip, QUAD_TO_DBL(tmp));
9152  QUAD_ASSIGN_Q(rhs, downrhs);
9153 
9154  if( *cutnnz > 0 )
9155  {
9156  SCIP_CALL( cutsRoundStrongCG(scip, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, varsign, boundtype, QUAD(f0), k) );
9157  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9158  }
9159 
9160  /* substitute aggregated slack variables:
9161  *
9162  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
9163  * variable only appears in its own row:
9164  * a'_r = scale * weight[r] * slacksign[r].
9165  *
9166  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
9167  * integers : a_r = a~_r = (k + 1) * down(a'_r) , if f_r <= f0
9168  * a_r = a~_r = (k + 1) * down(a'_r) + p_r , if f_r > f0
9169  * continuous: a_r = a~_r = 0 , if a'_r >= 0
9170  * a_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
9171  *
9172  * Substitute a_r * s_r by adding a_r times the slack's definition to the cut.
9173  */
9174  SCIP_CALL( cutsSubstituteStrongCG(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
9175  aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), cutinds, cutnnz, QUAD(f0), k) );
9176  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9177 
9178  /* remove all nearly-zero coefficients from strong CG row and relax the right hand side correspondingly in order to
9179  * prevent numerical rounding errors
9180  */
9181  if( postprocess )
9182  {
9183  SCIP_CALL( postprocessCutQuad(scip, *cutislocal, cutinds, tmpcoefs, cutnnz, QUAD(&rhs), success) );
9184  }
9185  else
9186  {
9187  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, tmpcoefs, QUAD(&rhs), cutinds, cutnnz);
9188  }
9189  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), cutinds, *cutnnz, FALSE, FALSE));
9190 
9191  if( *success )
9192  {
9193  *cutrhs = QUAD_TO_DBL(rhs);
9194 
9195  /* store cut in given array in sparse representation and clean buffer array */
9196  for( i = 0; i < *cutnnz; ++i )
9197  {
9198  SCIP_Real QUAD(coef);
9199  int j = cutinds[i];
9200 
9201  QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
9202  assert(QUAD_HI(coef) != 0.0);
9203 
9204  cutcoefs[i] = QUAD_TO_DBL(coef);
9205  QUAD_ASSIGN(coef, 0.0);
9206  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
9207  }
9208 
9209  if( cutefficacy != NULL )
9210  *cutefficacy = calcEfficacy(scip, sol, cutcoefs, *cutrhs, cutinds, *cutnnz);
9211 
9212  if( cutrank != NULL )
9213  *cutrank = aggrrow->rank + 1;
9214  }
9215 
9216  TERMINATE:
9217 
9218  /* if we aborted early the tmpcoefs array needs to be cleaned */
9219  if( !(*success) )
9220  {
9221  QUAD_ASSIGN(tmp, 0.0);
9222 
9223  for( i = 0; i < *cutnnz; ++i )
9224  {
9225  QUAD_ARRAY_STORE(tmpcoefs, cutinds[i], tmp);
9226  }
9227  }
9228 
9229  /* free temporary memory */
9230  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
9231  SCIPfreeBufferArray(scip, &boundtype);
9232  SCIPfreeBufferArray(scip, &varsign);
9233 
9234  return SCIP_OKAY;
9235 }
void SCIPsortDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, int len)
SCIP_Real * transbinvarsolvals
Definition: cuts.c:4949
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:605
static SCIP_RETCODE postprocessCutQuad(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, QUAD(SCIP_Real *cutrhs), SCIP_Bool *success)
Definition: cuts.c:2420
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
SCIP_RETCODE SCIPcalcStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:8974
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1763
static SCIP_RETCODE computeLiftingData(SCIP *scip, SNF_RELAXATION *snf, int *transvarflowcoverstatus, SCIP_Real lambda, LIFTINGDATA *liftingdata, SCIP_Bool *valid)
Definition: cuts.c:7001
int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2494
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18293
#define NULL
Definition: def.h:267
SCIP_Real lambda
Definition: cuts.c:4939
SCIP_Real SCIPfeastol(SCIP *scip)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_Real d1
Definition: cuts.c:4937
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int ntransvars
Definition: cuts.c:4952
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_Real evaluateLiftingFunctionKnapsack(SCIP *scip, QUAD(SCIP_Real x), QUAD(SCIP_Real abar), SCIP_Real *covervals, int coversize, int cplussize, SCIP_Real *scale)
Definition: cuts.c:7955
int * origcontvars
Definition: cuts.c:4955
SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
Definition: cuts.c:1867
#define SCIPquadprecDivDQ(r, a, b)
Definition: dbldblarith.h:64
#define SCIPquadprecSumQD(r, a, b)
Definition: dbldblarith.h:62
static SCIP_RETCODE varVecAddScaledRowCoefsQuad(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:174
int * cols_index
Definition: struct_lp.h:228
SCIP_Real * aggrcoefscont
Definition: cuts.c:4958
public methods for memory management
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18271
enum SCIP_BaseStat SCIP_BASESTAT
Definition: type_lpi.h:96
static SCIP_RETCODE cutTightenCoefsQuad(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition: cuts.c:793
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18079
static void performBoundSubstitution(SCIP *scip, int *cutinds, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *nnz, int varsign, int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition: cuts.c:2925
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
static long bound
void SCIPaggrRowCancelVarWithBound(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_VAR *var, int pos, SCIP_Bool *valid)
Definition: cuts.c:1953
#define SQR(x)
Definition: def.h:214
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18135
#define QUAD_ARRAY_STORE(a, idx, x)
Definition: dbldblarith.h:55
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real transrhs
Definition: cuts.c:4953
static SCIP_RETCODE SCIPsolveKnapsackApproximatelyLT(SCIP *scip, int nitems, SCIP_Real *weights, SCIP_Real *profits, SCIP_Real capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
Definition: cuts.c:6002
int rank
Definition: struct_lp.h:248
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17600
#define MAXABSVBCOEF
Definition: cuts.c:4920
#define RESTRICT
Definition: def.h:279
static SCIP_Real computeMIREfficacy(SCIP *scip, SCIP_Real *RESTRICT coefs, SCIP_Real *RESTRICT solvals, SCIP_Real rhs, SCIP_Real contactivity, SCIP_Real contsqrnorm, SCIP_Real delta, int nvars, SCIP_Real minfrac, SCIP_Real maxfrac)
Definition: cuts.c:4138
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPquadprecProdQQ(r, a, b)
Definition: dbldblarith.h:66
SCIP_Real * M
Definition: cuts.c:4928
static SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
Definition: cuts.c:656
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1866
static SCIP_RETCODE generateLiftedFlowCoverCut(SCIP *scip, SNF_RELAXATION *snf, SCIP_AGGRROW *aggrrow, int *flowcoverstatus, SCIP_Real lambda, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *nnz, SCIP_Bool *success)
Definition: cuts.c:7144
struct LiftingData LIFTINGDATA
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17292
#define FALSE
Definition: def.h:94
#define EPSISINT(x, eps)
Definition: def.h:210
methods for the aggregation rows
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11184
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:17340
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:93
#define SCIPdebug(x)
Definition: pub_message.h:93
SCIP_Bool SCIPaggrRowIsLocal(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2579
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
static SCIP_RETCODE cutsTransformStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:8382
SCIP_RETCODE SCIPcutGenerationHeuristicCMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, int maxtestdelta, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:4220
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18313
#define MAXCMIRSCALE
Definition: cuts.c:2600
static SCIP_RETCODE cutsSubstituteMIR(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0))
Definition: cuts.c:3727
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17769
#define SCIP_UNUSED(x)
Definition: def.h:434
static SCIP_Real evaluateLiftingFunction(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real x)
Definition: cuts.c:6880
public methods for problem variables
static SCIP_RETCODE findBestUb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestub, SCIP_Real *simplebound, int *bestubtype)
Definition: cuts.c:2665
SCIP_RETCODE SCIPcalcKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:8055
int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2559
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
SCIP_Real SCIPaggrRowGetRhs(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2589
#define QUAD_SCALE(x, a)
Definition: dbldblarith.h:50
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18283
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
unsigned int integral
Definition: struct_lp.h:258
#define EPSFRAC(x, eps)
Definition: def.h:209
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPaggrRowPrint(SCIP *scip, SCIP_AGGRROW *aggrrow, FILE *file)
Definition: cuts.c:1784
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int * slacksign
Definition: struct_cuts.h:45
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define QUAD_ASSIGN(a, constant)
Definition: dbldblarith.h:51
defines macros for basic operations in double-double arithmetic giving roughly twice the precision of...
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
public methods for SCIP variables
int * rowsinds
Definition: struct_cuts.h:44
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
#define SCIPdebugMsg
Definition: scip_message.h:78
static void prepareLiftingData(SCIP *scip, SCIP_Real *cutcoefs, int *cutinds, QUAD(SCIP_Real cutrhs), int *coverpos, int coversize, QUAD(SCIP_Real coverweight), SCIP_Real *covervals, int *coverstatus, QUAD(SCIP_Real *abar), int *cplussize)
Definition: cuts.c:7839
internal methods for LP management
SCIP_VAR ** x
Definition: circlepacking.c:63
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2172
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: scip_var.c:6608
#define QUAD_TO_DBL(x)
Definition: dbldblarith.h:49
SCIP_Real SCIPgetRowMaxActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1956
static void getAlphaAndBeta(SCIP *scip, LIFTINGDATA *liftingdata, SCIP_Real vubcoef, int *alpha, SCIP_Real *beta)
Definition: cuts.c:6964
public methods for numerical tolerances
SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
Definition: cuts.c:2526
static void destroyLiftingData(SCIP *scip, LIFTINGDATA *liftingdata)
Definition: cuts.c:7131
public methods for querying solving statistics
SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
Definition: cuts.c:2012
static SCIP_Real calcEfficacyNormQuad(SCIP *scip, SCIP_Real *vals, int *inds, int nnz)
Definition: cuts.c:334
static SCIP_RETCODE cutTightenCoefs(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz, SCIP_Bool *redundant)
Definition: cuts.c:1172
SCIP_Real * vals
Definition: struct_lp.h:229
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:142
SCIP_Real * rowweights
Definition: struct_cuts.h:46
static SCIP_Bool removeZerosQuad(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition: cuts.c:471
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18089
int lppos
Definition: struct_lp.h:239
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
void SCIPsortDownInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
static SCIP_RETCODE varVecAddScaledRowCoefs(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, SCIP_Real scale)
Definition: cuts.c:129
#define SCIPquadprecEpsCeilQ(r, a, eps)
Definition: dbldblarith.h:76
#define QUAD_HI(x)
Definition: dbldblarith.h:45
int * transvarcoefs
Definition: cuts.c:4948
SCIP_Bool SCIPsortedvecFindDownReal(SCIP_Real *realarray, SCIP_Real val, int len, int *pos)
int t
Definition: cuts.c:4936
int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2504
static SCIP_Bool isIntegralScalar(SCIP_Real val, SCIP_Real scalar, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Real *intval)
Definition: lp.c:4900
#define SCIPerrorMessage
Definition: pub_message.h:64
#define QUAD_EPSILON
Definition: dbldblarith.h:42
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_COL ** cols
Definition: struct_lp.h:227
#define SCIPquadprecEpsFloorQ(r, a, eps)
Definition: dbldblarith.h:75
#define COPYSIGN
Definition: def.h:258
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17401
#define BMSmoveMemoryArray(ptr, source, num)
Definition: memory.h:138
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
#define QUAD(x)
Definition: dbldblarith.h:47
SCIP_Real lhs
Definition: struct_lp.h:204
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18345
SCIP_Real sepa_maxcoefratio
Definition: struct_set.h:542
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17420
static SCIP_Bool chgCoeffWithBound(SCIP *scip, SCIP_VAR *var, SCIP_Real oldcoeff, SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:701
int SCIPaggrRowGetRank(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2569
static SCIP_RETCODE cutsTransformMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *freevariable, SCIP_Bool *localbdsused)
Definition: cuts.c:3060
int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2549
#define REALABS(x)
Definition: def.h:197
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:18453
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:626
#define QUAD_ARRAY_LOAD(r, a, idx)
Definition: dbldblarith.h:54
void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
Definition: cuts.c:2479
#define SCIP_CALL(x)
Definition: def.h:380
SCIP main data structure.
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18303
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
Definition: scip_var.c:6631
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17302
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18335
SCIP_RETCODE SCIPaggrRowAddCustomCons(SCIP *scip, SCIP_AGGRROW *aggrrow, int *inds, SCIP_Real *vals, int len, SCIP_Real rhs, SCIP_Real weight, int rank, SCIP_Bool local)
Definition: cuts.c:2088
#define MINDELTA
static SCIP_RETCODE getClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestsub, SCIP_Real rowcoef, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: cuts.c:4969
#define SCIPquadprecProdDD(r, a, b)
Definition: dbldblarith.h:58
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17411
#define MAXBOUND
Definition: cuts.c:4921
static SCIP_Bool chgQuadCoeffWithBound(SCIP *scip, SCIP_VAR *var, QUAD(SCIP_Real oldcoeff), SCIP_Real newcoeff, SCIP_Bool cutislocal, QUAD(SCIP_Real *cutrhs))
Definition: cuts.c:746
static SCIP_RETCODE allocSNFRelaxation(SCIP *scip, SNF_RELAXATION *snf, int nvars)
Definition: cuts.c:5961
int var_probindex
Definition: struct_lp.h:178
SCIP_Real * aggrcoefsbin
Definition: cuts.c:4956
SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:3881
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
public data structures and miscellaneous methods
#define SCIP_Bool
Definition: def.h:91
static SCIP_RETCODE cutsSubstituteStrongCG(SCIP *scip, SCIP_Real *weights, int *slacksign, int *rowinds, int nrowinds, SCIP_Real scale, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:8817
SCIP_Real SCIPaggrRowCalcEfficacyNorm(SCIP *scip, SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2166
#define QUAD_LO(x)
Definition: dbldblarith.h:46
#define QUAD_ARRAY_SIZE(size)
Definition: dbldblarith.h:53
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition: cuts.c:1535
SCIP_Bool SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7425
#define MIN(x, y)
Definition: def.h:243
static SCIP_RETCODE determineBoundForSNF(SCIP *scip, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *rowcoefs, int *rowinds, int varposinrow, int8_t *binvarused, SCIP_Bool allowlocal, SCIP_Real boundswitch, SCIP_Real *bestlb, SCIP_Real *bestub, SCIP_Real *bestslb, SCIP_Real *bestsub, int *bestlbtype, int *bestubtype, int *bestslbtype, int *bestsubtype, SCIP_BOUNDTYPE *selectedbounds, SCIP_Bool *freevariable)
Definition: cuts.c:5227
public methods for LP management
static SCIP_RETCODE varVecAddScaledRowCoefsQuadScale(int *RESTRICT inds, SCIP_Real *RESTRICT vals, int *RESTRICT nnz, SCIP_ROW *row, QUAD(SCIP_Real scale))
Definition: cuts.c:221
public methods for cuts and aggregation rows
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17927
static SCIP_RETCODE constructSNFRelaxation(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_Real *rowcoefs, QUAD(SCIP_Real rowrhs), int *rowinds, int nnz, SNF_RELAXATION *snf, SCIP_Bool *success, SCIP_Bool *localbdsused)
Definition: cuts.c:5408
int * origbinvars
Definition: cuts.c:4954
#define SCIPquadprecProdQD(r, a, b)
Definition: dbldblarith.h:63
SCIP_Real * SCIPaggrRowGetRowWeights(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2515
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
static SCIP_RETCODE cutsRoundStrongCG(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, QUAD(SCIP_Real f0), SCIP_Real k)
Definition: cuts.c:8606
static SCIP_RETCODE addOneRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *rowtoolong)
Definition: cuts.c:2178
#define MAXDNOM
Definition: cons_linear.c:182
static SCIP_RETCODE getClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *rowcoefs, int8_t *binvarused, SCIP_Real bestslb, SCIP_Real rowcoef, SCIP_Real *closestvub, int *closestvubidx)
Definition: cuts.c:5099
char sepa_efficacynorm
Definition: struct_set.h:551
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2144
SCIP_Real * transvarvubcoefs
Definition: cuts.c:4951
SCIP_Real * vals
Definition: struct_cuts.h:42
struct SNF_Relaxation SNF_RELAXATION
SCIP_ROW ** rows
Definition: struct_lp.h:303
#define SCIPquadprecSumQQ(r, a, b)
Definition: dbldblarith.h:67
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
public methods for the LP relaxation, rows and columns
#define QUAD_ASSIGN_Q(a, b)
Definition: dbldblarith.h:52
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
#define SCIP_REAL_MAX
Definition: def.h:174
SCIP_Real rhs
Definition: struct_lp.h:205
SCIP_Real constant
Definition: struct_lp.h:203
#define MAXSCALE
SCIP_Real * r
Definition: circlepacking.c:59
methods for sorting joint arrays of various types
static SCIP_RETCODE cutsRoundMIR(SCIP *scip, SCIP_Real *RESTRICT cutcoefs, QUAD(SCIP_Real *RESTRICT cutrhs), int *RESTRICT cutinds, int *RESTRICT nnz, int *RESTRICT varsign, int *RESTRICT boundtype, QUAD(SCIP_Real f0))
Definition: cuts.c:3416
SCIP_RETCODE SCIPaggrRowCopy(SCIP *scip, SCIP_AGGRROW **aggrrow, SCIP_AGGRROW *source)
Definition: cuts.c:1821
#define SCIPquadprecDivDD(r, a, b)
Definition: dbldblarith.h:61
int r
Definition: cuts.c:4935
#define MAX(x, y)
Definition: def.h:239
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE determineBestBounds(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real boundswitch, int usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, SCIP_Bool ignoresol, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real *bestlb, SCIP_Real *bestub, int *bestlbtype, int *bestubtype, SCIP_BOUNDTYPE *selectedbound, SCIP_Bool *freevariable)
Definition: cuts.c:2726
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPaggrRowSumRows(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real *weights, int *rowinds, int nrowinds, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *valid)
Definition: cuts.c:2287
void SCIPselectWeightedDownRealRealInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
public methods for solutions
SCIP_Real SCIPgetHugeValue(SCIP *scip)
static SCIP_Bool removeZeros(SCIP *scip, SCIP_Real minval, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *cutnnz)
Definition: cuts.c:564
static void destroySNFRelaxation(SCIP *scip, SNF_RELAXATION *snf)
Definition: cuts.c:5982
SCIP_SET * set
Definition: struct_scip.h:73
int SCIPgetNCuts(SCIP *scip)
Definition: scip_cut.c:787
static void buildFlowCover(SCIP *scip, int *coefs, SCIP_Real *vubcoefs, SCIP_Real rhs, int *solitems, int *nonsolitems, int nsolitems, int nnonsolitems, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, QUAD(SCIP_Real *flowcoverweight), SCIP_Real *lambda)
Definition: cuts.c:6097
public methods for message output
data structures for LP management
SCIP_Real * aggrconstants
Definition: cuts.c:4960
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:618
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17501
void SCIPsortDownInt(int *intarray, int len)
static SCIP_RETCODE postprocessCut(SCIP *scip, SCIP_Bool cutislocal, int *cutinds, SCIP_Real *cutcoefs, int *nnz, SCIP_Real *cutrhs, SCIP_Bool *success)
Definition: cuts.c:2351
#define SCIP_Real
Definition: def.h:173
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:146
SCIP_Real SCIPgetRowMinActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1939
public methods for message handling
static SCIP_RETCODE findBestLb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, int usevbds, SCIP_Bool allowlocal, SCIP_Real *bestlb, SCIP_Real *simplebound, int *bestlbtype)
Definition: cuts.c:2604
#define SCIP_INVALID
Definition: def.h:193
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1731
#define SCIPquadprecSumDD(r, a, b)
Definition: dbldblarith.h:60
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18325
#define SCIP_Longint
Definition: def.h:158
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition: misc.c:9557
SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17585
#define NONZERO(x)
Definition: cuts.c:123
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real d2
Definition: cuts.c:4938
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18145
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Real ml
Definition: cuts.c:4941
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:570
static SCIP_RETCODE getFlowCover(SCIP *scip, SNF_RELAXATION *snf, int *nflowcovervars, int *nnonflowcovervars, int *flowcoverstatus, SCIP_Real *lambda, SCIP_Bool *found)
Definition: cuts.c:6613
static SCIP_RETCODE cutsTransformKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int *cutinds, int *nnz, int *varsign, int *boundtype, SCIP_Bool *localbdsused, SCIP_Bool *success)
Definition: cuts.c:7549
void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2141
static SCIP_Bool computeInitialKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, int *cutinds, SCIP_Real cutrhs, int cutnnz, int *varsign, int *coverstatus, int *coverpos, SCIP_Real *covervals, int *coversize, QUAD(SCIP_Real *coverweight))
Definition: cuts.c:7748
#define SCIP_CALL_ABORT(x)
Definition: def.h:359
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_LP * lp
Definition: struct_scip.h:92
SCIP_Longint SCIPgetNLPs(SCIP *scip)
#define SCIPABORT()
Definition: def.h:352
SCIP_Real * m
Definition: cuts.c:4929
public methods for global and local (sub)problems
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17611
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
datastructures for global SCIP settings
static SCIP_Real calcEfficacyDenseStorageQuad(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:396
static void performBoundSubstitutionSimple(SCIP *scip, SCIP_Real *cutcoefs, QUAD(SCIP_Real *cutrhs), int boundtype, SCIP_Real boundval, int probindex, SCIP_Bool *localbdsused)
Definition: cuts.c:3005
void SCIPsortDownReal(SCIP_Real *realarray, int len)
SCIP_Real * transcontvarsolvals
Definition: cuts.c:4950
#define MAXDELTA
unsigned int local
Definition: struct_lp.h:259
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
#define EPSZ(x, eps)
Definition: def.h:203
#define ABS(x)
Definition: def.h:235
SCIP_Real mp
Definition: cuts.c:4940
int len
Definition: struct_lp.h:235
static SCIP_Real calcEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_Real *cutcoefs, SCIP_Real cutrhs, int *cutinds, int cutnnz)
Definition: cuts.c:269
SCIP_Bool local
Definition: struct_cuts.h:52
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17749
methods for selecting (weighted) k-medians
memory allocation routines