Scippy

SCIP

Solving Constraint Integer Programs

cuts.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright 2002-2022 Zuse Institute Berlin */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cuts.c
26  * @ingroup OTHER_CFILES
27  * @brief methods for aggregation of rows
28  * @author Jakob Witzig
29  * @author Leona Gottwald
30  * @author Marc Pfetsch
31  */
32 
33 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34 
35 #include "blockmemshell/memory.h"
36 #include "scip/cuts.h"
37 #include "scip/dbldblarith.h"
38 #include "scip/lp.h"
39 #include "scip/pub_lp.h"
40 #include "scip/pub_message.h"
41 #include "scip/pub_misc.h"
42 #include "scip/pub_misc_select.h"
43 #include "scip/pub_misc_sort.h"
44 #include "scip/pub_var.h"
45 #include "scip/scip_cut.h"
46 #include "scip/scip_lp.h"
47 #include "scip/scip_mem.h"
48 #include "scip/scip_message.h"
49 #include "scip/scip_numerics.h"
50 #include "scip/scip_prob.h"
51 #include "scip/scip_sol.h"
52 #include "scip/scip_solvingstats.h"
53 #include "scip/scip_var.h"
54 #include "scip/struct_lp.h"
55 #include "scip/struct_scip.h"
56 #include "scip/struct_set.h"
57 
58 /* =========================================== general static functions =========================================== */
59 #ifdef SCIP_DEBUG
60 static
61 void printCutQuad(
62  SCIP* scip, /**< SCIP data structure */
63  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
64  SCIP_Real* cutcoefs, /**< non-zero coefficients of cut */
65  QUAD(SCIP_Real cutrhs), /**< right hand side of the MIR row */
66  int* cutinds, /**< indices of problem variables for non-zero coefficients */
67  int cutnnz, /**< number of non-zeros in cut */
68  SCIP_Bool ignorsol,
69  SCIP_Bool islocal
70  )
71 {
72  SCIP_Real QUAD(activity);
73  SCIP_VAR** vars;
74  int i;
75 
76  assert(scip != NULL);
77  vars = SCIPgetVars(scip);
78 
79  SCIPdebugMessage("CUT:");
80  QUAD_ASSIGN(activity, 0.0);
81  for( i = 0; i < cutnnz; ++i )
82  {
83  SCIP_Real QUAD(coef);
84 
85  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
86 
87  SCIPdebugPrintf(" %+g<%s>", QUAD_TO_DBL(coef), SCIPvarGetName(vars[cutinds[i]]));
88 
89  if( !ignorsol )
90  {
91  SCIPquadprecProdQD(coef, coef, (sol == NULL ? SCIPvarGetLPSol(vars[cutinds[i]]) : SCIPgetSolVal(scip, sol, vars[cutinds[i]])));
92  }
93  else
94  {
95  if( cutcoefs[i] > 0.0 )
96  {
97  SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]])));
98  }
99  else
100  {
101  SCIPquadprecProdQD(coef, coef, (islocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]])));
102  }
103  }
104 
105  SCIPquadprecSumQQ(activity, activity, coef);
106  }
107  SCIPdebugPrintf(" <= %.6f (activity: %g)\n", QUAD_TO_DBL(cutrhs), QUAD_TO_DBL(activity));
108 }
109 #endif
110 
111 /** macro to make sure a value is not equal to zero, i.e. NONZERO(x) != 0.0
112  * will be TRUE for every x including 0.0
113  *
114  * To avoid branches it will add 1e-100 with the same sign as x to x which will
115  * be rounded away for any sane non-zero value but will make sure the value is
116  * never exactly 0.0.
117  */
118 #define NONZERO(x) (COPYSIGN(1e-100, (x)) + (x))
119 
120 /** add a scaled row to a dense vector indexed over the problem variables and keep the
121  * index of non-zeros up-to-date
122  */
123 static
125  int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
126  SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
127  int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
128  SCIP_ROW* row, /**< row coefficients to add to variable vector */
129  SCIP_Real scale /**< scale for adding given row to variable vector */
130  )
131 {
132  int i;
133 
134  assert(inds != NULL);
135  assert(vals != NULL);
136  assert(nnz != NULL);
137  assert(row != NULL);
138 
139  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
140  for( i = 0 ; i < row->len; ++i )
141  {
142  SCIP_Real val;
143  int probindex;
144 
145  probindex = row->cols[i]->var_probindex;
146  val = vals[probindex];
147 
148  if( val == 0.0 )
149  inds[(*nnz)++] = probindex;
150 
151  val += row->vals[i] * scale;
152 
153  /* the value must not be exactly zero due to sparsity pattern */
154  val = NONZERO(val);
155 
156  assert(val != 0.0);
157  vals[probindex] = val;
158  }
159 
160  return SCIP_OKAY;
161 }
162 
163 /** add a scaled row to a dense vector indexed over the problem variables and keep the
164  * index of non-zeros up-to-date
165  *
166  * This is the quad precision version of varVecAddScaledRowCoefs().
167  */
168 static
170  int*RESTRICT inds, /**< pointer to array with variable problem indices of non-zeros in variable vector */
171  SCIP_Real*RESTRICT vals, /**< array with values of variable vector */
172  int*RESTRICT nnz, /**< number of non-zeros coefficients of variable vector */
173  SCIP_ROW* row, /**< row coefficients to add to variable vector */
174  SCIP_Real scale /**< scale for adding given row to variable vector */
175  )
176 {
177  int i;
178 
179  assert(inds != NULL);
180  assert(vals != NULL);
181  assert(nnz != NULL);
182  assert(row != NULL);
183 
184  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
185  for( i = 0 ; i < row->len; ++i )
186  {
187  SCIP_Real QUAD(val);
188  int probindex;
189 
190  probindex = row->cols[i]->var_probindex;
191  QUAD_ARRAY_LOAD(val, vals, probindex);
192 
193  if( QUAD_HI(val) == 0.0 )
194  inds[(*nnz)++] = probindex;
195 
196  SCIPquadprecSumQD(val, val, row->vals[i] * scale);
197 
198  /* the value must not be exactly zero due to sparsity pattern */
199  QUAD_HI(val) = NONZERO(QUAD_HI(val));
200  assert(QUAD_HI(val) != 0.0);
201 
202  QUAD_ARRAY_STORE(vals, probindex, val);
203  }
204 
205  return SCIP_OKAY;
206 }
207 
208 /** calculates the cut efficacy for the given solution */
209 static
211  SCIP* scip, /**< SCIP data structure */
212  SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
213  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
214  SCIP_Real cutrhs, /**< the right hand side of the cut */
215  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
216  int cutnnz /**< the number of non-zeros in the cut */
217  )
218 {
219  SCIP_VAR** vars;
220  SCIP_Real norm = 0.0;
221  SCIP_Real activity = 0.0;
222  int i;
223 
224  assert(scip != NULL);
225  assert(cutcoefs != NULL);
226  assert(cutinds != NULL);
227 
228  vars = SCIPgetVars(scip);
229 
230  switch( scip->set->sepa_efficacynorm )
231  {
232  case 'e':
233  for( i = 0; i < cutnnz; ++i )
234  {
235  activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
236  norm += SQR(cutcoefs[i]);
237  }
238  norm = SQRT(norm);
239  break;
240  case 'm':
241  for( i = 0; i < cutnnz; ++i )
242  {
243  SCIP_Real absval;
244 
245  activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
246  absval = REALABS(cutcoefs[i]);
247  norm = MAX(norm, absval);
248  }
249  break;
250  case 's':
251  for( i = 0; i < cutnnz; ++i )
252  {
253  activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
254  norm += REALABS(cutcoefs[i]);
255  }
256  break;
257  case 'd':
258  for( i = 0; i < cutnnz; ++i )
259  {
260  activity += cutcoefs[i] * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
261  if( !SCIPisZero(scip, cutcoefs[i]) )
262  norm = 1.0;
263  }
264  break;
265  default:
266  SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", scip->set->sepa_efficacynorm);
267  assert(FALSE); /*lint !e506*/
268  }
269 
270  return (activity - cutrhs) / MAX(1e-6, norm);
271 }
272 
273 /** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter */
274 static
276  SCIP* scip, /**< SCIP data structure */
277  SCIP_Real* vals, /**< array of the non-zero coefficients in the vector; this is a quad precision array! */
278  int* inds, /**< array of the problem indices of variables with a non-zero coefficient in the vector */
279  int nnz /**< the number of non-zeros in the vector */
280  )
281 {
282  SCIP_Real norm = 0.0;
283  SCIP_Real QUAD(coef);
284  int i;
285 
286  assert(scip != NULL);
287  assert(scip->set != NULL);
288 
289  switch( scip->set->sepa_efficacynorm )
290  {
291  case 'e':
292  for( i = 0; i < nnz; ++i )
293  {
294  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
295  norm += SQR(QUAD_TO_DBL(coef));
296  }
297  norm = SQRT(norm);
298  break;
299  case 'm':
300  for( i = 0; i < nnz; ++i )
301  {
302  SCIP_Real absval;
303  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
304 
305  absval = REALABS(QUAD_TO_DBL(coef));
306  norm = MAX(norm, absval);
307  }
308  break;
309  case 's':
310  for( i = 0; i < nnz; ++i )
311  {
312  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
313  norm += REALABS(QUAD_TO_DBL(coef));
314  }
315  break;
316  case 'd':
317  for( i = 0; i < nnz; ++i )
318  {
319  QUAD_ARRAY_LOAD(coef, vals, inds[i]);
320  if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
321  {
322  norm = 1.0;
323  break;
324  }
325  }
326  break;
327  default:
328  SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
329  assert(FALSE); /*lint !e506*/
330  }
331 
332  return norm;
333 }
334 
335 /** calculates the cut efficacy for the given solution; the cut coefs are stored densely and in quad precision */
336 static
338  SCIP* scip, /**< SCIP data structure */
339  SCIP_SOL* sol, /**< solution to calculate the efficacy for (NULL for LP solution) */
340  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut; this is a quad precision array! */
341  SCIP_Real cutrhs, /**< the right hand side of the cut */
342  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
343  int cutnnz /**< the number of non-zeros in the cut */
344  )
345 {
346  SCIP_VAR** vars;
347  SCIP_Real norm = 0.0;
348  SCIP_Real activity = 0.0;
349  SCIP_Real QUAD(coef);
350  int i;
351 
352  assert(scip != NULL);
353  assert(cutcoefs != NULL);
354  assert(cutinds != NULL);
355  assert(scip->set != NULL);
356 
357  vars = SCIPgetVars(scip);
358 
359  switch( scip->set->sepa_efficacynorm )
360  {
361  case 'e':
362  for( i = 0; i < cutnnz; ++i )
363  {
364  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
365  activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
366  norm += SQR(QUAD_TO_DBL(coef));
367  }
368  norm = SQRT(norm);
369  break;
370  case 'm':
371  for( i = 0; i < cutnnz; ++i )
372  {
373  SCIP_Real absval;
374 
375  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
376  activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
377  absval = REALABS(QUAD_TO_DBL(coef));
378  norm = MAX(norm, absval);
379  }
380  break;
381  case 's':
382  for( i = 0; i < cutnnz; ++i )
383  {
384  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
385  activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
386  norm += REALABS(QUAD_TO_DBL(coef));
387  }
388  break;
389  case 'd':
390  for( i = 0; i < cutnnz; ++i )
391  {
392  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]);
393  activity += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[cutinds[i]]);
394  if( !SCIPisZero(scip, QUAD_TO_DBL(coef)) )
395  norm = 1.0;
396  }
397  break;
398  default:
399  SCIPerrorMessage("invalid efficacy norm parameter '%c.'\n", scip->set->sepa_efficacynorm);
400  assert(FALSE); /*lint !e506*/
401  }
402 
403  return (activity - cutrhs) / MAX(1e-6, norm);
404 }
405 
406 /** safely remove all items with |a_i| or |u_i - l_i| below the given value
407  *
408  * Returns TRUE if the cut became redundant.
409  * If it is a local cut, use local bounds, otherwise, use global bounds.
410  */
411 static
413  SCIP* scip, /**< SCIP data structure */
414  SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
415  SCIP_Bool cutislocal, /**< is the cut local? */
416  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
417  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
418  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
419  int* cutnnz /**< the number of non-zeros in the cut */
420  )
421 {
422  int i;
423  SCIP_VAR** vars;
424 
425  vars = SCIPgetVars(scip);
426 
427  for( i = 0; i < *cutnnz; )
428  {
429  SCIP_Real QUAD(val);
430  SCIP_Real lb;
431  SCIP_Real ub;
432  int v;
433  SCIP_Bool isfixed;
434 
435  v = cutinds[i];
436  QUAD_ARRAY_LOAD(val, cutcoefs, v);
437 
438  if( cutislocal )
439  {
440  lb = SCIPvarGetLbLocal(vars[v]);
441  ub = SCIPvarGetUbLocal(vars[v]);
442  }
443  else
444  {
445  lb = SCIPvarGetLbGlobal(vars[v]);
446  ub = SCIPvarGetUbGlobal(vars[v]);
447  }
448 
449  if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
450  isfixed = TRUE;
451  else
452  isfixed = FALSE;
453 
454  if( isfixed || EPSZ(QUAD_TO_DBL(val), minval) )
455  {
456  if( REALABS(QUAD_TO_DBL(val)) > QUAD_EPSILON )
457  {
458  /* adjust right hand side with max contribution */
459  if( QUAD_TO_DBL(val) < 0.0 )
460  {
461  if( SCIPisInfinity(scip, ub) )
462  return TRUE;
463  else
464  {
465  SCIPquadprecProdQD(val, val, ub);
466  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
467  }
468  }
469  else
470  {
471  if( SCIPisInfinity(scip, -lb) )
472  return TRUE;
473  else
474  {
475  SCIPquadprecProdQD(val, val, lb);
476  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -val);
477  }
478  }
479  }
480 
481  QUAD_ASSIGN(val, 0.0);
482  QUAD_ARRAY_STORE(cutcoefs, v, val);
483 
484  /* remove non-zero entry */
485  --(*cutnnz);
486  cutinds[i] = cutinds[*cutnnz];
487  }
488  else
489  ++i;
490  }
491 
492  /* relax rhs to 0, if it's very close to 0 */
493  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
494  QUAD_ASSIGN(*cutrhs, 0.0);
495 
496  return FALSE;
497 }
498 
499 /** safely remove all items with |a_i| or |u_i - l_i| below the given value
500  *
501  * Returns TRUE if the cut became redundant.
502  * If it is a local cut, use local bounds, otherwise, use global bounds.
503  */
504 static
506  SCIP* scip, /**< SCIP data structure */
507  SCIP_Real minval, /**< minimal absolute value of coefficients that should not be removed */
508  SCIP_Bool cutislocal, /**< is the cut local? */
509  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
510  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
511  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
512  int* cutnnz /**< the number of non-zeros in the cut */
513  )
514 {
515  int i;
516  SCIP_VAR** vars;
517 
518  vars = SCIPgetVars(scip);
519 
520  /* loop over non-zeros and remove values below minval; values above QUAD_EPSILON are cancelled with their bound
521  * to avoid numerical rounding errors
522  */
523  for( i = 0; i < *cutnnz; )
524  {
525  SCIP_Real val;
526  SCIP_Real lb;
527  SCIP_Real ub;
528  int v;
529  SCIP_Bool isfixed;
530 
531  v = cutinds[i];
532  val = cutcoefs[v];
533 
534  if( cutislocal )
535  {
536  lb = SCIPvarGetLbLocal(vars[v]);
537  ub = SCIPvarGetUbLocal(vars[v]);
538  }
539  else
540  {
541  lb = SCIPvarGetLbGlobal(vars[v]);
542  ub = SCIPvarGetUbGlobal(vars[v]);
543  }
544 
545  if( !(SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub)) && SCIPisEQ(scip, ub, lb) )
546  isfixed = TRUE;
547  else
548  isfixed = FALSE;
549 
550  if( EPSZ(val, minval) || isfixed )
551  {
552  if( REALABS(val) > QUAD_EPSILON )
553  {
554  /* adjust left and right hand sides with max contribution */
555  if( val < 0.0 )
556  {
557  if( SCIPisInfinity(scip, ub) )
558  return TRUE;
559  else
560  {
561  SCIPquadprecSumQD(*cutrhs, *cutrhs, -val * ub);
562  }
563  }
564  else
565  {
566  if( SCIPisInfinity(scip, -lb) )
567  return TRUE;
568  else
569  {
570  SCIPquadprecSumQD(*cutrhs, *cutrhs, -val * lb);
571  }
572  }
573  }
574 
575  cutcoefs[v] = 0.0;
576 
577  /* remove non-zero entry */
578  --(*cutnnz);
579  cutinds[i] = cutinds[*cutnnz];
580  }
581  else
582  ++i;
583  }
584 
585  /* relax rhs to 0, if it's very close to 0 */
586  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= -SCIPepsilon(scip) )
587  QUAD_ASSIGN(*cutrhs, 0.0);
588 
589  return FALSE;
590 }
591 
592 /** compare absolute values of coefficients in quad precision */
593 static
594 SCIP_DECL_SORTINDCOMP(compareAbsCoefsQuad)
595 {
596  SCIP_Real abscoef1;
597  SCIP_Real abscoef2;
598  SCIP_Real QUAD(coef1);
599  SCIP_Real QUAD(coef2);
600  SCIP_Real* coefs = (SCIP_Real*) dataptr;
601 
602  QUAD_ARRAY_LOAD(coef1, coefs, ind1);
603  QUAD_ARRAY_LOAD(coef2, coefs, ind2);
604 
605  abscoef1 = REALABS(QUAD_TO_DBL(coef1));
606  abscoef2 = REALABS(QUAD_TO_DBL(coef2));
607 
608  if( abscoef1 < abscoef2 )
609  return -1;
610  if( abscoef2 < abscoef1 )
611  return 1;
612 
613  return 0;
614 }
615 
616 /** compare absolute values of coefficients */
617 static
618 SCIP_DECL_SORTINDCOMP(compareAbsCoefs)
619 {
620  SCIP_Real abscoef1;
621  SCIP_Real abscoef2;
622  SCIP_Real* coefs = (SCIP_Real*) dataptr;
623 
624  abscoef1 = REALABS(coefs[ind1]);
625  abscoef2 = REALABS(coefs[ind2]);
626 
627  if( abscoef1 < abscoef2 )
628  return -1;
629  if( abscoef2 < abscoef1 )
630  return 1;
631 
632  return 0;
633 }
634 
635 /** change given coefficient to new given value, adjust right hand side using the variables bound;
636  * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
637  */
638 static
640  SCIP* scip, /**< SCIP data structure */
641  SCIP_VAR* var, /**< variable the coefficient belongs to */
642  SCIP_Real oldcoeff, /**< old coefficient value */
643  SCIP_Real newcoeff, /**< new coefficient value */
644  SCIP_Bool cutislocal, /**< is the cut local? */
645  QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
646  )
647 {
648  SCIP_Real QUAD(delta);
649 
650  SCIPquadprecSumDD(delta, newcoeff, -oldcoeff);
651 
652  if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
653  {
654  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
655 
656  if( SCIPisInfinity(scip, ub) )
657  return TRUE;
658  else
659  {
660  SCIPquadprecProdQD(delta, delta, ub);
661  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
662  }
663  }
664  else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
665  {
666  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
667 
668  if( SCIPisInfinity(scip, -lb) )
669  return TRUE;
670  else
671  {
672  SCIPquadprecProdQD(delta, delta, lb);
673  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
674  }
675  }
676 
677  return FALSE;
678 }
679 
680 /** change given (quad) coefficient to new given value, adjust right hand side using the variables bound;
681  * returns TRUE if the right hand side would need to be changed to infinity and FALSE otherwise
682  */
683 static
685  SCIP* scip, /**< SCIP data structure */
686  SCIP_VAR* var, /**< variable the coefficient belongs to */
687  QUAD(SCIP_Real oldcoeff), /**< old coefficient value */
688  SCIP_Real newcoeff, /**< new coefficient value */
689  SCIP_Bool cutislocal, /**< is the cut local? */
690  QUAD(SCIP_Real* cutrhs) /**< pointer to adjust right hand side of cut */
691  )
692 {
693  SCIP_Real QUAD(delta);
694 
695  SCIPquadprecSumQD(delta, -oldcoeff, newcoeff);
696 
697  if( QUAD_TO_DBL(delta) > QUAD_EPSILON )
698  {
699  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
700 
701  if( SCIPisInfinity(scip, ub) )
702  return TRUE;
703  else
704  {
705  SCIPquadprecProdQD(delta, delta, ub);
706  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
707  }
708  }
709  else if( QUAD_TO_DBL(delta) < -QUAD_EPSILON )
710  {
711  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
712 
713  if( SCIPisInfinity(scip, -lb) )
714  return TRUE;
715  else
716  {
717  SCIPquadprecProdQD(delta, delta, lb);
718  SCIPquadprecSumQQ(*cutrhs, *cutrhs, delta);
719  }
720  }
721 
722  return FALSE;
723 }
724 
725 /** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
726  * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse quad precision array;
727  *
728  * This is the quad precision version of cutTightenCoefs() below.
729  */
730 static
732  SCIP* scip, /**< SCIP data structure */
733  SCIP_Bool cutislocal, /**< is the cut local? */
734  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
735  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
736  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
737  int* cutnnz, /**< the number of non-zeros in the cut */
738  SCIP_Bool* redundant /**< whether the cut was detected to be redundant */
739  )
740 {
741  int i;
742  int nintegralvars;
743  SCIP_Bool isintegral = TRUE;
744  SCIP_VAR** vars;
745  SCIP_Real QUAD(maxacttmp);
746  SCIP_Real maxact;
747  SCIP_Real maxabsintval = 0.0;
748  SCIP_Real maxabscontval = 0.0;
749 
750  QUAD_ASSIGN(maxacttmp, 0.0);
751 
752  vars = SCIPgetVars(scip);
753  nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
754 
755  assert(redundant != NULL);
756  *redundant = FALSE;
757 
758  /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
759  for( i = 0; i < *cutnnz; ++i )
760  {
761  SCIP_Real QUAD(val);
762 
763  assert(cutinds[i] >= 0);
764  assert(vars[cutinds[i]] != NULL);
765 
766  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
767 
768  if( QUAD_TO_DBL(val) < 0.0 )
769  {
770  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
771 
772  if( SCIPisInfinity(scip, -lb) )
773  return SCIP_OKAY;
774 
775  if( cutinds[i] < nintegralvars )
776  maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
777  else
778  {
779  maxabscontval = MAX(maxabscontval, -QUAD_TO_DBL(val));
780  isintegral = FALSE;
781  }
782 
783  SCIPquadprecProdQD(val, val, lb);
784  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
785  }
786  else
787  {
788  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
789 
790  if( SCIPisInfinity(scip, ub) )
791  return SCIP_OKAY;
792 
793  if( cutinds[i] < nintegralvars )
794  maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
795  else
796  {
797  maxabscontval = MAX(maxabscontval, QUAD_TO_DBL(val));
798  isintegral = FALSE;
799  }
800 
801  SCIPquadprecProdQD(val, val, ub);
802  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
803  }
804  }
805 
806  maxact = QUAD_TO_DBL(maxacttmp);
807 
808  /* cut is redundant in activity bounds */
809  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
810  {
811  *redundant = TRUE;
812  return SCIP_OKAY;
813  }
814 
815  /* cut is only on integral variables, try to scale to integral coefficients */
816  if( isintegral )
817  {
818  SCIP_Real equiscale;
819  SCIP_Real intscalar;
820  SCIP_Bool success;
821  SCIP_Real* intcoeffs;
822 
823  SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
824 
825  equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
826 
827  for( i = 0; i < *cutnnz; ++i )
828  {
829  SCIP_Real QUAD(val);
830 
831  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
832  SCIPquadprecProdQD(val, val, equiscale);
833 
834  intcoeffs[i] = QUAD_TO_DBL(val);
835  }
836 
837  SCIP_CALL( SCIPcalcIntegralScalar(intcoeffs, *cutnnz, -SCIPsumepsilon(scip), SCIPepsilon(scip),
838  (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
839 
840  SCIPfreeBufferArray(scip, &intcoeffs);
841 
842  if( success )
843  {
844  /* if successful, apply the scaling */
845  intscalar *= equiscale;
846 
847  SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
848 
849  for( i = 0; i < *cutnnz; )
850  {
851  SCIP_Real QUAD(val);
852  SCIP_Real intval;
853 
854  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
855  SCIPquadprecProdQD(val, val, intscalar);
856 
857  intval = SCIPround(scip, QUAD_TO_DBL(val));
858 
859  if( chgQuadCoeffWithBound(scip, vars[cutinds[i]], QUAD(val), intval, cutislocal, QUAD(cutrhs)) )
860  {
861  /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
862  *redundant = TRUE;
863  return SCIP_OKAY;
864  }
865 
866  if( intval != 0.0 )
867  {
868  QUAD_ASSIGN(val, intval);
869  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
870  ++i;
871  }
872  else
873  {
874  /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
875  QUAD_ASSIGN(val, 0.0);
876  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
877  --(*cutnnz);
878  cutinds[i] = cutinds[*cutnnz];
879  }
880  }
881 
882  SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
883 
884  /* recompute the maximal activity after scaling to integral values */
885  QUAD_ASSIGN(maxacttmp, 0.0);
886  maxabsintval = 0.0;
887 
888  for( i = 0; i < *cutnnz; ++i )
889  {
890  SCIP_Real QUAD(val);
891 
892  assert(cutinds[i] >= 0);
893  assert(vars[cutinds[i]] != NULL);
894 
895  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
896 
897  if( QUAD_TO_DBL(val) < 0.0 )
898  {
899  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
900 
901  maxabsintval = MAX(maxabsintval, -QUAD_TO_DBL(val));
902 
903  SCIPquadprecProdQD(val, val, lb);
904 
905  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
906  }
907  else
908  {
909  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
910 
911  maxabsintval = MAX(maxabsintval, QUAD_TO_DBL(val));
912 
913  SCIPquadprecProdQD(val, val, ub);
914 
915  SCIPquadprecSumQQ(maxacttmp, maxacttmp, val);
916  }
917  }
918 
919  maxact = QUAD_TO_DBL(maxacttmp);
920 
921  assert(EPSISINT(maxact, 1e-4));
922  maxact = SCIPround(scip, maxact);
923  QUAD_ASSIGN(maxacttmp, maxact);
924 
925  /* check again for redundancy */
926  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
927  {
928  *redundant = TRUE;
929  return SCIP_OKAY;
930  }
931  }
932  else
933  {
934  /* otherwise, apply the equilibrium scaling */
935  isintegral = FALSE;
936 
937  /* perform the scaling */
938  SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
939 
940  SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
941  maxabsintval *= equiscale;
942 
943  for( i = 0; i < *cutnnz; ++i )
944  {
945  SCIP_Real QUAD(val);
946 
947  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
948  SCIPquadprecProdQD(val, val, equiscale);
949  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
950  }
951  }
952  }
953  else
954  {
955  /* cut has integer and continuous variables, so scale it to equilibrium */
956  SCIP_Real scale;
957  SCIP_Real maxabsval;
958 
959  maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
960  maxabsval = MIN(maxabsval, maxabsintval);
961  maxabsval = MAX(maxabsval, maxabscontval);
962 
963  scale = 1.0 / maxabsval; /*lint !e795*/
964 
965  /* perform the scaling */
966  SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
967  maxact = QUAD_TO_DBL(maxacttmp);
968 
969  SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
970  maxabsintval *= scale;
971 
972  for( i = 0; i < *cutnnz; ++i )
973  {
974  SCIP_Real QUAD(val);
975 
976  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
977  SCIPquadprecProdQD(val, val, scale);
978  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], val);
979  }
980  }
981 
982  /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
983  if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
984  return SCIP_OKAY;
985 
986  SCIPsortDownInd(cutinds, compareAbsCoefsQuad, (void*) cutcoefs, *cutnnz);
987 
988  /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
989  for( i = 0; i < *cutnnz; )
990  {
991  SCIP_Real QUAD(val);
992 
993  if( cutinds[i] >= nintegralvars )
994  {
995  ++i;
996  continue;
997  }
998 
999  QUAD_ARRAY_LOAD(val, cutcoefs, cutinds[i]);
1000 
1001  assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1002 
1003  if( QUAD_TO_DBL(val) < 0.0 && SCIPisLE(scip, maxact + QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1004  {
1005  SCIP_Real QUAD(coef);
1006  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1007 
1008  SCIPquadprecSumQQ(coef, *cutrhs, -maxacttmp);
1009 
1010  if( isintegral )
1011  {
1012  /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1013  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1014  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1015  }
1016 
1017  if( QUAD_TO_DBL(coef) > QUAD_TO_DBL(val) )
1018  {
1019  SCIP_Real QUAD(delta);
1020  SCIP_Real QUAD(tmp);
1021 
1022  SCIPquadprecSumQQ(delta, -val, coef);
1023  SCIPquadprecProdQD(delta, delta, lb);
1024 
1025  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1026  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1027  QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
1028  cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1029 
1030  QUAD_ASSIGN_Q(*cutrhs, tmp);
1031 
1032  assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
1033 
1034  if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1035  {
1036  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1037  maxact = QUAD_TO_DBL(maxacttmp);
1038  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1039  }
1040  else
1041  {
1042  QUAD_ASSIGN(coef, 0.0);
1043  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1044  --(*cutnnz);
1045  cutinds[i] = cutinds[*cutnnz];
1046  continue;
1047  }
1048  }
1049  }
1050  else if( QUAD_TO_DBL(val) > 0.0 && SCIPisLE(scip, maxact - QUAD_TO_DBL(val), QUAD_TO_DBL(*cutrhs)) )
1051  {
1052  SCIP_Real QUAD(coef);
1053  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1054 
1055  SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
1056 
1057  if( isintegral )
1058  {
1059  /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1060  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1061  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1062  }
1063 
1064  if( QUAD_TO_DBL(coef) < QUAD_TO_DBL(val) )
1065  {
1066  SCIP_Real QUAD(delta);
1067  SCIP_Real QUAD(tmp);
1068 
1069  SCIPquadprecSumQQ(delta, -val, coef);
1070  SCIPquadprecProdQD(delta, delta, ub);
1071 
1072  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1073  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1074  QUAD_TO_DBL(val), QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
1075  cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1076 
1077  QUAD_ASSIGN_Q(*cutrhs, tmp);
1078 
1079  assert(SCIPisGE(scip, QUAD_TO_DBL(coef), 0.0));
1080 
1081  if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1082  {
1083  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1084  maxact = QUAD_TO_DBL(maxacttmp);
1085  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1086  }
1087  else
1088  {
1089  QUAD_ASSIGN(coef, 0.0);
1090  QUAD_ARRAY_STORE(cutcoefs, cutinds[i], coef);
1091  --(*cutnnz);
1092  cutinds[i] = cutinds[*cutnnz];
1093  continue;
1094  }
1095  }
1096  }
1097  else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1098  break;
1099 
1100  ++i;
1101  }
1102 
1103  return SCIP_OKAY;
1104 }
1105 
1106 /** scales the cut and then tightens the coefficients of the given cut based on the maximal activity;
1107  * see cons_linear.c consdataTightenCoefs() for details; the cut is given in a semi-sparse array;
1108  */
1109 static
1111  SCIP* scip, /**< SCIP data structure */
1112  SCIP_Bool cutislocal, /**< is the cut local? */
1113  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1114  QUAD(SCIP_Real* cutrhs), /**< the right hand side of the cut */
1115  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1116  int* cutnnz, /**< the number of non-zeros in the cut */
1117  SCIP_Bool* redundant /**< pointer to return whtether the cut was detected to be redundant */
1118  )
1119 {
1120  int i;
1121  int nintegralvars;
1122  SCIP_Bool isintegral = TRUE;
1123  SCIP_VAR** vars;
1124  SCIP_Real QUAD(maxacttmp);
1125  SCIP_Real maxact;
1126  SCIP_Real maxabsintval = 0.0;
1127  SCIP_Real maxabscontval = 0.0;
1128 
1129  QUAD_ASSIGN(maxacttmp, 0.0);
1130 
1131  vars = SCIPgetVars(scip);
1132  nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1133 
1134  assert(redundant != NULL);
1135  *redundant = FALSE;
1136 
1137  /* compute maximal activity and maximal absolute coefficient values for all and for integral variables in the cut */
1138  for( i = 0; i < *cutnnz; ++i )
1139  {
1140  SCIP_Real val;
1141 
1142  assert(cutinds[i] >= 0);
1143  assert(vars[cutinds[i]] != NULL);
1144 
1145  val = cutcoefs[cutinds[i]];
1146 
1147  if( val < 0.0 )
1148  {
1149  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1150 
1151  if( SCIPisInfinity(scip, -lb) )
1152  return SCIP_OKAY;
1153 
1154  if( cutinds[i] < nintegralvars )
1155  maxabsintval = MAX(maxabsintval, -val);
1156  else
1157  {
1158  maxabscontval = MAX(maxabscontval, -val);
1159  isintegral = FALSE;
1160  }
1161 
1162  SCIPquadprecSumQD(maxacttmp, maxacttmp, val * lb);
1163  }
1164  else
1165  {
1166  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1167 
1168  if( SCIPisInfinity(scip, ub) )
1169  return SCIP_OKAY;
1170 
1171  if( cutinds[i] < nintegralvars )
1172  maxabsintval = MAX(maxabsintval, val);
1173  else
1174  {
1175  maxabscontval = MAX(maxabscontval, val);
1176  isintegral = FALSE;
1177  }
1178 
1179  SCIPquadprecSumQD(maxacttmp, maxacttmp, val * ub);
1180  }
1181  }
1182 
1183  maxact = QUAD_TO_DBL(maxacttmp);
1184 
1185  /* cut is redundant in activity bounds */
1186  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1187  {
1188  *redundant = TRUE;
1189  return SCIP_OKAY;
1190  }
1191 
1192  /* cut is only on integral variables, try to scale to integral coefficients */
1193  if( isintegral )
1194  {
1195  SCIP_Real equiscale;
1196  SCIP_Real intscalar;
1197  SCIP_Bool success;
1198  SCIP_Real* intcoeffs;
1199 
1200  SCIP_CALL( SCIPallocBufferArray(scip, &intcoeffs, *cutnnz) );
1201 
1202  equiscale = 1.0 / MIN((maxact - QUAD_TO_DBL(*cutrhs)), maxabsintval);
1203 
1204  for( i = 0; i < *cutnnz; ++i )
1205  {
1206  SCIP_Real val;
1207 
1208  val = equiscale * cutcoefs[cutinds[i]];
1209 
1210  intcoeffs[i] = val;
1211  }
1212 
1213  SCIP_CALL( SCIPcalcIntegralScalar(intcoeffs, *cutnnz, -SCIPsumepsilon(scip), SCIPepsilon(scip),
1214  (SCIP_Longint)scip->set->sepa_maxcoefratio, scip->set->sepa_maxcoefratio, &intscalar, &success) );
1215 
1216  SCIPfreeBufferArray(scip, &intcoeffs);
1217 
1218  if( success )
1219  {
1220  /* if successful, apply the scaling */
1221  intscalar *= equiscale;
1222 
1223  SCIPquadprecProdQD(*cutrhs, *cutrhs, intscalar);
1224 
1225  for( i = 0; i < *cutnnz; )
1226  {
1227  SCIP_Real val;
1228  SCIP_Real intval;
1229 
1230  val = cutcoefs[cutinds[i]];
1231  val *= intscalar;
1232 
1233  intval = SCIPround(scip, val);
1234 
1235  if( chgCoeffWithBound(scip, vars[cutinds[i]], val, intval, cutislocal, QUAD(cutrhs)) )
1236  {
1237  /* TODO maybe change the coefficient to the other value instead of discarding the cut? */
1238  *redundant = TRUE;
1239  return SCIP_OKAY;
1240  }
1241 
1242  if( intval != 0.0 )
1243  {
1244  cutcoefs[cutinds[i]] = intval;
1245  ++i;
1246  }
1247  else
1248  {
1249  /* this must not be -0.0, otherwise the clean buffer memory is not cleared properly */
1250  cutcoefs[cutinds[i]] = 0.0;
1251  --(*cutnnz);
1252  cutinds[i] = cutinds[*cutnnz];
1253  }
1254  }
1255 
1256  SCIPquadprecEpsFloorQ(*cutrhs, *cutrhs, SCIPfeastol(scip)); /*lint !e666*/
1257 
1258  /* recompute the maximal activity after scaling to integral values */
1259  QUAD_ASSIGN(maxacttmp, 0.0);
1260  maxabsintval = 0.0;
1261 
1262  for( i = 0; i < *cutnnz; ++i )
1263  {
1264  SCIP_Real val;
1265 
1266  assert(cutinds[i] >= 0);
1267  assert(vars[cutinds[i]] != NULL);
1268 
1269  val = cutcoefs[cutinds[i]];
1270 
1271  if( val < 0.0 )
1272  {
1273  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1274 
1275  maxabsintval = MAX(maxabsintval, -val);
1276 
1277  val *= lb;
1278 
1279  SCIPquadprecSumQD(maxacttmp, maxacttmp, val);
1280  }
1281  else
1282  {
1283  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1284 
1285  maxabsintval = MAX(maxabsintval, val);
1286 
1287  val *= ub;
1288 
1289  SCIPquadprecSumQD(maxacttmp, maxacttmp, val);
1290  }
1291  }
1292 
1293  maxact = QUAD_TO_DBL(maxacttmp);
1294 
1295  assert(EPSISINT(maxact, 1e-4));
1296  maxact = SCIPround(scip, maxact);
1297  QUAD_ASSIGN(maxacttmp, maxact);
1298 
1299  /* check again for redundancy */
1300  if( SCIPisFeasLE(scip, maxact, QUAD_TO_DBL(*cutrhs)) )
1301  {
1302  *redundant = TRUE;
1303  return SCIP_OKAY;
1304  }
1305  }
1306  else
1307  {
1308  /* otherwise, apply the equilibrium scaling */
1309  isintegral = FALSE;
1310 
1311  /* perform the scaling */
1312  SCIPquadprecProdQD(maxacttmp, maxacttmp, equiscale);
1313 
1314  SCIPquadprecProdQD(*cutrhs, *cutrhs, equiscale);
1315  maxabsintval *= equiscale;
1316 
1317  for( i = 0; i < *cutnnz; ++i )
1318  cutcoefs[cutinds[i]] *= equiscale;
1319  }
1320  }
1321  else
1322  {
1323  /* cut has integer and continuous variables, so scale it to equilibrium */
1324  SCIP_Real scale;
1325  SCIP_Real maxabsval;
1326 
1327  maxabsval = maxact - QUAD_TO_DBL(*cutrhs);
1328  maxabsval = MIN(maxabsval, maxabsintval);
1329  maxabsval = MAX(maxabsval, maxabscontval);
1330 
1331  scale = 1.0 / maxabsval; /*lint !e795*/
1332 
1333  /* perform the scaling */
1334  SCIPquadprecProdQD(maxacttmp, maxacttmp, scale);
1335  maxact = QUAD_TO_DBL(maxacttmp);
1336 
1337  SCIPquadprecProdQD(*cutrhs, *cutrhs, scale);
1338  maxabsintval *= scale;
1339 
1340  for( i = 0; i < *cutnnz; ++i )
1341  cutcoefs[cutinds[i]] *= scale;
1342  }
1343 
1344  /* no coefficient tightening can be performed since the precondition doesn't hold for any of the variables */
1345  if( SCIPisGT(scip, maxact - maxabsintval, QUAD_TO_DBL(*cutrhs)) )
1346  return SCIP_OKAY;
1347 
1348  SCIPsortDownInd(cutinds, compareAbsCoefs, (void*) cutcoefs, *cutnnz);
1349 
1350  /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1351  for( i = 0; i < *cutnnz; )
1352  {
1353  SCIP_Real val;
1354 
1355  if( cutinds[i] >= nintegralvars )
1356  {
1357  ++i;
1358  continue;
1359  }
1360 
1361  val = cutcoefs[cutinds[i]];
1362 
1363  assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1364 
1365  if( val < 0.0 && SCIPisLE(scip, maxact + val, QUAD_TO_DBL(*cutrhs)) )
1366  {
1367  SCIP_Real QUAD(coef);
1368  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1369 
1370  SCIPquadprecSumQQ(coef, -maxacttmp, *cutrhs);
1371 
1372  if( isintegral )
1373  {
1374  /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1375  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1376  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1377  }
1378 
1379  if( QUAD_TO_DBL(coef) > val )
1380  {
1381  SCIP_Real QUAD(delta);
1382  SCIP_Real QUAD(tmp);
1383 
1384  SCIPquadprecSumQD(delta, coef, -val);
1385  SCIPquadprecProdQD(delta, delta, lb);
1386 
1387  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1388  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1389  val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp), lb,
1390  cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1391 
1392  QUAD_ASSIGN_Q(*cutrhs, tmp);
1393 
1394  assert(!SCIPisPositive(scip, QUAD_TO_DBL(coef)));
1395 
1396  if( SCIPisNegative(scip, QUAD_TO_DBL(coef)) )
1397  {
1398  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1399  maxact = QUAD_TO_DBL(maxacttmp);
1400  cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
1401  }
1402  else
1403  {
1404  cutcoefs[cutinds[i]] = 0.0;
1405  --(*cutnnz);
1406  cutinds[i] = cutinds[*cutnnz];
1407  continue;
1408  }
1409  }
1410  }
1411  else if( val > 0.0 && SCIPisLE(scip, maxact - val, QUAD_TO_DBL(*cutrhs)) )
1412  {
1413  SCIP_Real QUAD(coef);
1414  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1415 
1416  SCIPquadprecSumQQ(coef, maxacttmp, -*cutrhs);
1417 
1418  if( isintegral )
1419  {
1420  /* if cut is integral, the true coefficient must also be integral; thus round it to exact integral value */
1421  assert(SCIPisFeasIntegral(scip, QUAD_TO_DBL(coef)));
1422  QUAD_ASSIGN(coef, SCIPround(scip, QUAD_TO_DBL(coef)));
1423  }
1424 
1425  if( QUAD_TO_DBL(coef) < val )
1426  {
1427  SCIP_Real QUAD(delta);
1428  SCIP_Real QUAD(tmp);
1429 
1430  SCIPquadprecSumQD(delta, coef, -val);
1431  SCIPquadprecProdQD(delta, delta, ub);
1432 
1433  SCIPquadprecSumQQ(tmp, delta, *cutrhs);
1434  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1435  val, QUAD_TO_DBL(coef), QUAD_TO_DBL(*cutrhs), QUAD_TO_DBL(tmp),
1436  cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1437 
1438  QUAD_ASSIGN_Q(*cutrhs, tmp);
1439 
1440  assert(! SCIPisNegative(scip, QUAD_TO_DBL(coef)));
1441 
1442  if( SCIPisPositive(scip, QUAD_TO_DBL(coef)) )
1443  {
1444  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1445  maxact = QUAD_TO_DBL(maxacttmp);
1446  cutcoefs[cutinds[i]] = QUAD_TO_DBL(coef);
1447  }
1448  else
1449  {
1450  cutcoefs[cutinds[i]] = 0.0;
1451  --(*cutnnz);
1452  cutinds[i] = cutinds[*cutnnz];
1453  continue;
1454  }
1455  }
1456  }
1457  else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1458  break;
1459 
1460  ++i;
1461  }
1462 
1463  return SCIP_OKAY;
1464 }
1465 
1466 /** perform activity based coefficient tightening on the given cut; returns TRUE if the cut was detected
1467  * to be redundant due to activity bounds
1468  *
1469  * See also cons_linear.c:consdataTightenCoefs().
1470  */
1472  SCIP* scip, /**< SCIP data structure */
1473  SCIP_Bool cutislocal, /**< is the cut local? */
1474  SCIP_Real* cutcoefs, /**< array of the non-zero coefficients in the cut */
1475  SCIP_Real* cutrhs, /**< the right hand side of the cut */
1476  int* cutinds, /**< array of the problem indices of variables with a non-zero coefficient in the cut */
1477  int* cutnnz, /**< the number of non-zeros in the cut */
1478  int* nchgcoefs /**< number of changed coefficients */
1479  )
1480 {
1481  int i;
1482  int nintegralvars;
1483  SCIP_VAR** vars;
1484  SCIP_Real* absvals;
1485  SCIP_Real QUAD(maxacttmp);
1486  SCIP_Real maxact;
1487  SCIP_Real maxabsval = 0.0;
1488  SCIP_Bool redundant = FALSE;
1489 
1490  assert(nchgcoefs != NULL);
1491 
1492  QUAD_ASSIGN(maxacttmp, 0.0);
1493 
1494  vars = SCIPgetVars(scip);
1495  nintegralvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
1496  SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &absvals, *cutnnz) );
1497 
1498  assert(nchgcoefs != NULL);
1499  *nchgcoefs = 0;
1500 
1501  for( i = 0; i < *cutnnz; ++i )
1502  {
1503  assert(cutinds[i] >= 0);
1504  assert(vars[cutinds[i]] != NULL);
1505 
1506  if( cutcoefs[i] < 0.0 )
1507  {
1508  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1509 
1510  if( SCIPisInfinity(scip, -lb) )
1511  goto TERMINATE;
1512 
1513  if( cutinds[i] < nintegralvars )
1514  {
1515  maxabsval = MAX(maxabsval, -cutcoefs[i]);
1516  absvals[i] = -cutcoefs[i];
1517  }
1518  else
1519  absvals[i] = 0.0;
1520 
1521  SCIPquadprecSumQD(maxacttmp, maxacttmp, lb * cutcoefs[i]);
1522  }
1523  else
1524  {
1525  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1526 
1527  if( SCIPisInfinity(scip, ub) )
1528  goto TERMINATE;
1529 
1530  if( cutinds[i] < nintegralvars )
1531  {
1532  maxabsval = MAX(maxabsval, cutcoefs[i]);
1533  absvals[i] = cutcoefs[i];
1534  }
1535  else
1536  absvals[i] = 0.0;
1537 
1538  SCIPquadprecSumQD(maxacttmp, maxacttmp, ub * cutcoefs[i]);
1539  }
1540  }
1541 
1542  maxact = QUAD_TO_DBL(maxacttmp);
1543 
1544  /* cut is redundant in activity bounds */
1545  if( SCIPisFeasLE(scip, maxact, *cutrhs) )
1546  {
1547  redundant = TRUE;
1548  goto TERMINATE;
1549  }
1550 
1551  /* terminate, because coefficient tightening cannot be performed; also excludes the case in which no integral variable is present */
1552  if( SCIPisGT(scip, maxact - maxabsval, *cutrhs) )
1553  goto TERMINATE;
1554 
1555  SCIPsortDownRealRealInt(absvals, cutcoefs, cutinds, *cutnnz);
1556  SCIPfreeBufferArray(scip, &absvals);
1557 
1558  /* loop over the integral variables and try to tighten the coefficients; see cons_linear for more details */
1559  for( i = 0; i < *cutnnz; ++i )
1560  {
1561  /* due to sorting, we can exit if we reached a continuous variable: all further integral variables have 0 coefficents anyway */
1562  if( cutinds[i] >= nintegralvars )
1563  break;
1564 
1565  assert(SCIPvarIsIntegral(vars[cutinds[i]]));
1566 
1567  if( cutcoefs[i] < 0.0 && SCIPisLE(scip, maxact + cutcoefs[i], *cutrhs) )
1568  {
1569  SCIP_Real coef = (*cutrhs) - maxact;
1570  SCIP_Real lb = cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]);
1571 
1572  coef = floor(coef);
1573 
1574  if( coef > cutcoefs[i] )
1575  {
1576  SCIP_Real QUAD(delta);
1577  SCIP_Real QUAD(tmp);
1578 
1579  SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
1580  SCIPquadprecProdQD(delta, delta, lb);
1581 
1582  SCIPquadprecSumQD(tmp, delta, *cutrhs);
1583  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1584  cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp), lb,
1585  cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]));
1586 
1587  *cutrhs = QUAD_TO_DBL(tmp);
1588 
1589  assert(!SCIPisPositive(scip, coef));
1590 
1591  ++(*nchgcoefs);
1592 
1593  if( SCIPisNegative(scip, coef) )
1594  {
1595  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1596  maxact = QUAD_TO_DBL(maxacttmp);
1597  cutcoefs[i] = coef;
1598  }
1599  else
1600  {
1601  --(*cutnnz);
1602  cutinds[i] = cutinds[*cutnnz];
1603  cutcoefs[i] = cutcoefs[*cutnnz];
1604  continue;
1605  }
1606  }
1607  }
1608  else if( cutcoefs[i] > 0.0 && SCIPisLE(scip, maxact - cutcoefs[i], *cutrhs) )
1609  {
1610  SCIP_Real coef = maxact - (*cutrhs);
1611  SCIP_Real ub = cutislocal ? SCIPvarGetUbLocal(vars[cutinds[i]]) : SCIPvarGetUbGlobal(vars[cutinds[i]]);
1612 
1613  coef = ceil(coef);
1614 
1615  if( coef < cutcoefs[i] )
1616  {
1617  SCIP_Real QUAD(delta);
1618  SCIP_Real QUAD(tmp);
1619 
1620  SCIPquadprecSumDD(delta, coef, -cutcoefs[i]);
1621  SCIPquadprecProdQD(delta, delta, ub);
1622 
1623  SCIPquadprecSumQD(tmp, delta, *cutrhs);
1624  SCIPdebugPrintf("tightened coefficient from %g to %g; rhs changed from %g to %g; the bounds are [%g,%g]\n",
1625  cutcoefs[i], coef, (*cutrhs), QUAD_TO_DBL(tmp),
1626  cutislocal ? SCIPvarGetLbLocal(vars[cutinds[i]]) : SCIPvarGetLbGlobal(vars[cutinds[i]]), ub);
1627 
1628  *cutrhs = QUAD_TO_DBL(tmp);
1629 
1630  assert(!SCIPisNegative(scip, coef));
1631 
1632  ++(*nchgcoefs);
1633 
1634  if( SCIPisPositive(scip, coef) )
1635  {
1636  SCIPquadprecSumQQ(maxacttmp, maxacttmp, delta);
1637  maxact = QUAD_TO_DBL(maxacttmp);
1638  cutcoefs[i] = coef;
1639  }
1640  else
1641  {
1642  --(*cutnnz);
1643  cutinds[i] = cutinds[*cutnnz];
1644  cutcoefs[i] = cutcoefs[*cutnnz];
1645  continue;
1646  }
1647  }
1648  }
1649  else /* due to sorting we can stop completely if the precondition was not fulfilled for this variable */
1650  break;
1651  }
1652 
1653  TERMINATE:
1654  SCIPfreeBufferArrayNull(scip, &absvals);
1655 
1656  return redundant;
1657 }
1658 
1659 /* =========================================== aggregation row =========================================== */
1660 
1661 
1662 /** create an empty aggregation row */
1664  SCIP* scip, /**< SCIP data structure */
1665  SCIP_AGGRROW** aggrrow /**< pointer to return aggregation row */
1666  )
1667 {
1668  int nvars;
1669  assert(scip != NULL);
1670  assert(aggrrow != NULL);
1671 
1672  SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
1673 
1674  nvars = SCIPgetNVars(scip);
1675 
1676  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)) );
1677  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*aggrrow)->inds, nvars) );
1678 
1679  BMSclearMemoryArray((*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars));
1680 
1681  (*aggrrow)->local = FALSE;
1682  (*aggrrow)->nnz = 0;
1683  (*aggrrow)->rank = 0;
1684  QUAD_ASSIGN((*aggrrow)->rhs, 0.0);
1685  (*aggrrow)->rowsinds = NULL;
1686  (*aggrrow)->slacksign = NULL;
1687  (*aggrrow)->rowweights = NULL;
1688  (*aggrrow)->nrows = 0;
1689  (*aggrrow)->rowssize = 0;
1690 
1691  return SCIP_OKAY;
1692 }
1693 
1694 /** free a aggregation row */
1696  SCIP* scip, /**< SCIP data structure */
1697  SCIP_AGGRROW** aggrrow /**< pointer to aggregation row that should be freed */
1698  )
1699 {
1700  int nvars;
1701 
1702  assert(scip != NULL);
1703  assert(aggrrow != NULL);
1704 
1705  nvars = SCIPgetNVars(scip);
1706 
1707  SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->inds, nvars);
1708  SCIPfreeBlockMemoryArray(scip, &(*aggrrow)->vals, QUAD_ARRAY_SIZE(nvars)); /*lint !e647*/
1709  SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowsinds, (*aggrrow)->rowssize);
1710  SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->slacksign, (*aggrrow)->rowssize);
1711  SCIPfreeBlockMemoryArrayNull(scip, &(*aggrrow)->rowweights, (*aggrrow)->rowssize);
1712  SCIPfreeBlockMemory(scip, aggrrow);
1713 }
1714 
1715 /** output aggregation row to file stream */
1717  SCIP* scip, /**< SCIP data structure */
1718  SCIP_AGGRROW* aggrrow, /**< pointer to return aggregation row */
1719  FILE* file /**< output file (or NULL for standard output) */
1720  )
1721 {
1722  SCIP_VAR** vars;
1723  SCIP_MESSAGEHDLR* messagehdlr;
1724  int i;
1725 
1726  assert(scip != NULL);
1727  assert(aggrrow != NULL);
1728 
1729  vars = SCIPgetVars(scip);
1730  assert(vars != NULL);
1731 
1732  messagehdlr = SCIPgetMessagehdlr(scip);
1733  assert(messagehdlr);
1734 
1735  /* print coefficients */
1736  if( aggrrow->nnz == 0 )
1737  SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
1738 
1739  for( i = 0; i < aggrrow->nnz; ++i )
1740  {
1741  SCIP_Real QUAD(val);
1742 
1743  QUAD_ARRAY_LOAD(val, aggrrow->vals, aggrrow->inds[i]);
1744  assert(SCIPvarGetProbindex(vars[aggrrow->inds[i]]) == aggrrow->inds[i]);
1745  SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", QUAD_TO_DBL(val), SCIPvarGetName(vars[aggrrow->inds[i]]));
1746  }
1747 
1748  /* print right hand side */
1749  SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", QUAD_TO_DBL(aggrrow->rhs));
1750 }
1751 
1752 /** copy a aggregation row */
1754  SCIP* scip, /**< SCIP data structure */
1755  SCIP_AGGRROW** aggrrow, /**< pointer to return aggregation row */
1756  SCIP_AGGRROW* source /**< source aggregation row */
1757  )
1758 {
1759  int nvars;
1760 
1761  assert(scip != NULL);
1762  assert(aggrrow != NULL);
1763  assert(source != NULL);
1764 
1765  nvars = SCIPgetNVars(scip);
1766  SCIP_CALL( SCIPallocBlockMemory(scip, aggrrow) );
1767 
1768  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->vals, source->vals, QUAD_ARRAY_SIZE(nvars)) );
1769  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->inds, source->inds, nvars) );
1770  (*aggrrow)->nnz = source->nnz;
1771  QUAD_ASSIGN_Q((*aggrrow)->rhs, source->rhs);
1772 
1773  if( source->nrows > 0 )
1774  {
1775  assert(source->rowsinds != NULL);
1776  assert(source->slacksign != NULL);
1777  assert(source->rowweights != NULL);
1778 
1779  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowsinds, source->rowsinds, source->nrows) );
1780  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->slacksign, source->slacksign, source->nrows) );
1781  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*aggrrow)->rowweights, source->rowweights, source->nrows) );
1782  }
1783  else
1784  {
1785  (*aggrrow)->rowsinds = NULL;
1786  (*aggrrow)->slacksign = NULL;
1787  (*aggrrow)->rowweights = NULL;
1788  }
1789 
1790  (*aggrrow)->nrows = source->nrows;
1791  (*aggrrow)->rowssize = source->nrows;
1792  (*aggrrow)->rank = source->rank;
1793  (*aggrrow)->local = source->local;
1794 
1795  return SCIP_OKAY;
1796 }
1797 
1798 /** add weighted row to aggregation row */
1800  SCIP* scip, /**< SCIP data structure */
1801  SCIP_AGGRROW* aggrrow, /**< aggregation row */
1802  SCIP_ROW* row, /**< row to add to aggregation row */
1803  SCIP_Real weight, /**< scale for adding given row to aggregation row */
1804  int sidetype /**< specify row side type (-1 = lhs, 0 = automatic, 1 = rhs) */
1805  )
1806 {
1807  SCIP_Real sideval;
1808  SCIP_Bool uselhs;
1809  int i;
1810 
1811  assert(row->lppos >= 0);
1812 
1813  /* update local flag */
1814  aggrrow->local = aggrrow->local || row->local;
1815 
1816  /* update rank */
1817  aggrrow->rank = MAX(row->rank, aggrrow->rank);
1818 
1819  i = aggrrow->nrows++;
1820 
1821  if( aggrrow->nrows > aggrrow->rowssize )
1822  {
1823  int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
1824  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
1825  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
1826  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
1827  aggrrow->rowssize = newsize;
1828  }
1829  aggrrow->rowsinds[i] = SCIProwGetLPPos(row);
1830  aggrrow->rowweights[i] = weight;
1831 
1832  if( sidetype == -1 )
1833  {
1834  assert( ! SCIPisInfinity(scip, -row->lhs) );
1835  uselhs = TRUE;
1836  }
1837  else if( sidetype == 1 )
1838  {
1839  assert( ! SCIPisInfinity(scip, row->rhs) );
1840  uselhs = FALSE;
1841  }
1842  else
1843  {
1844  /* Automatically decide, whether we want to use the left or the right hand side of the row in the summation.
1845  * If possible, use the side that leads to a positive slack value in the summation.
1846  */
1847  if( SCIPisInfinity(scip, row->rhs) || (!SCIPisInfinity(scip, -row->lhs) && weight < 0.0) )
1848  uselhs = TRUE;
1849  else
1850  uselhs = FALSE;
1851  }
1852 
1853  if( uselhs )
1854  {
1855  aggrrow->slacksign[i] = -1;
1856  sideval = row->lhs - row->constant;
1857  if( row->integral )
1858  sideval = SCIPceil(scip, sideval); /* row is integral: round left hand side up */
1859  }
1860  else
1861  {
1862  aggrrow->slacksign[i] = +1;
1863  sideval = row->rhs - row->constant;
1864  if( row->integral )
1865  sideval = SCIPfloor(scip, sideval); /* row is integral: round right hand side up */
1866  }
1867 
1868  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, weight * sideval);
1869 
1870  /* add up coefficients */
1871  SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
1872 
1873  return SCIP_OKAY;
1874 }
1875 
1876 /** Removes a given variable @p var from position @p pos the aggregation row and updates the right-hand side according
1877  * to sign of the coefficient, i.e., rhs -= coef * bound, where bound = lb if coef >= 0 and bound = ub, otherwise.
1878  *
1879  * @note: The choice of global or local bounds depend on the validity (global or local) of the aggregation row.
1880  *
1881  * @note: The list of non-zero indices will be updated by swapping the last non-zero index to @p pos.
1882  */
1884  SCIP* scip, /**< SCIP data structure */
1885  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
1886  SCIP_VAR* var, /**< variable that should be removed */
1887  int pos, /**< position of the variable in the aggregation row */
1888  SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
1889  )
1890 {
1891  SCIP_Real QUAD(val);
1892  int v;
1893 
1894  assert(valid != NULL);
1895  assert(pos >= 0);
1896 
1897  v = aggrrow->inds[pos];
1898  assert(v == SCIPvarGetProbindex(var));
1899 
1900  QUAD_ARRAY_LOAD(val, aggrrow->vals, v);
1901 
1902  *valid = TRUE;
1903 
1904  /* adjust left and right hand sides with max contribution */
1905  if( QUAD_TO_DBL(val) < 0.0 )
1906  {
1907  SCIP_Real ub = aggrrow->local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1908 
1909  if( SCIPisInfinity(scip, ub) )
1910  QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
1911  else
1912  {
1913  SCIPquadprecProdQD(val, val, ub);
1914  SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
1915  }
1916  }
1917  else
1918  {
1919  SCIP_Real lb = aggrrow->local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1920 
1921  if( SCIPisInfinity(scip, -lb) )
1922  QUAD_ASSIGN(aggrrow->rhs, SCIPinfinity(scip));
1923  else
1924  {
1925  SCIPquadprecProdQD(val, val, lb);
1926  SCIPquadprecSumQQ(aggrrow->rhs, aggrrow->rhs, -val);
1927  }
1928  }
1929 
1930  QUAD_ASSIGN(val, 0.0);
1931  QUAD_ARRAY_STORE(aggrrow->vals, v, val);
1932 
1933  /* remove non-zero entry */
1934  --(aggrrow->nnz);
1935  aggrrow->inds[pos] = aggrrow->inds[aggrrow->nnz];
1936 
1937  if( SCIPisInfinity(scip, QUAD_HI(aggrrow->rhs)) )
1938  *valid = FALSE;
1939 }
1940 
1941 /** add the objective function with right-hand side @p rhs and scaled by @p scale to the aggregation row */
1943  SCIP* scip, /**< SCIP data structure */
1944  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
1945  SCIP_Real rhs, /**< right-hand side of the artificial row */
1946  SCIP_Real scale /**< scalar */
1947  )
1948 {
1949  SCIP_VAR** vars;
1950  SCIP_Real QUAD(val);
1951  int nvars;
1952 
1953  assert(scip != NULL);
1954  assert(aggrrow != NULL);
1955 
1956  vars = SCIPgetVars(scip);
1957  nvars = SCIPgetNVars(scip);
1958 
1959  /* add all variables straight forward if the aggregation row is empty */
1960  if( aggrrow->nnz == 0 )
1961  {
1962  int i;
1963  for( i = 0; i < nvars; ++i )
1964  {
1965  assert(SCIPvarGetProbindex(vars[i]) == i);
1966 
1967  /* skip all variables with zero objective coefficient */
1968  if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
1969  continue;
1970 
1971  QUAD_ASSIGN(val, scale * SCIPvarGetObj(vars[i]));
1972  QUAD_ARRAY_STORE(aggrrow->vals, i, val);
1973  aggrrow->inds[aggrrow->nnz++] = i;
1974  }
1975 
1976  /* add right-hand side value */
1977  QUAD_ASSIGN(aggrrow->rhs, scale * rhs);
1978  }
1979  else
1980  {
1981  int i;
1982  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
1983  for( i = 0 ; i < nvars; ++i )
1984  {
1985  assert(SCIPvarGetProbindex(vars[i]) == i);
1986 
1987  /* skip all variables with zero objective coefficient */
1988  if( SCIPisZero(scip, scale * SCIPvarGetObj(vars[i])) )
1989  continue;
1990 
1991  QUAD_ARRAY_LOAD(val, aggrrow->vals, i); /* val = aggrrow->vals[i] */
1992 
1993  if( QUAD_HI(val) == 0.0 )
1994  aggrrow->inds[aggrrow->nnz++] = i;
1995 
1996  SCIPquadprecSumQD(val, val, scale * SCIPvarGetObj(vars[i]));
1997 
1998  /* the value must not be exactly zero due to sparsity pattern */
1999  QUAD_HI(val) = NONZERO(QUAD_HI(val));
2000  assert(QUAD_HI(val) != 0.0);
2001 
2002  QUAD_ARRAY_STORE(aggrrow->vals, i, val);
2003  }
2004 
2005  /* add right-hand side value */
2006  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, scale * rhs);
2007  }
2008 
2009  return SCIP_OKAY;
2010 }
2011 
2012 /** add weighted constraint to the aggregation row */
2014  SCIP* scip, /**< SCIP data structure */
2015  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2016  int* inds, /**< variable problem indices in constraint to add to the aggregation row */
2017  SCIP_Real* vals, /**< values of constraint to add to the aggregation row */
2018  int len, /**< length of constraint to add to the aggregation row */
2019  SCIP_Real rhs, /**< right hand side of constraint to add to the aggregation row */
2020  SCIP_Real weight, /**< (positive) scale for adding given constraint to the aggregation row */
2021  int rank, /**< rank to use for given constraint */
2022  SCIP_Bool local /**< is constraint only valid locally */
2023  )
2024 {
2025  int i;
2026 
2027  assert(weight >= 0.0);
2028  assert(!SCIPisInfinity(scip, REALABS(weight * rhs)));
2029 
2030  /* update local flag */
2031  aggrrow->local = aggrrow->local || local;
2032 
2033  /* update rank */
2034  aggrrow->rank = MAX(rank, aggrrow->rank);
2035 
2036  /* add right hand side value */
2037  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, weight * rhs);
2038 
2039  /* add the non-zeros to the aggregation row and keep non-zero index up to date */
2040  for( i = 0 ; i < len; ++i )
2041  {
2042  SCIP_Real QUAD(val);
2043  int probindex = inds[i];
2044 
2045  QUAD_ARRAY_LOAD(val, aggrrow->vals, probindex); /* val = aggrrow->vals[probindex] */
2046 
2047  if( QUAD_HI(val) == 0.0 )
2048  aggrrow->inds[aggrrow->nnz++] = probindex;
2049 
2050  SCIPquadprecSumQD(val, val, vals[i] * weight);
2051 
2052  /* the value must not be exactly zero due to sparsity pattern */
2053  QUAD_HI(val) = NONZERO(QUAD_HI(val));
2054  assert(QUAD_HI(val) != 0.0);
2055 
2056  QUAD_ARRAY_STORE(aggrrow->vals, probindex, val);
2057  }
2058 
2059  return SCIP_OKAY;
2060 }
2061 
2062 /** clear all entries int the aggregation row but don't free memory */
2064  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2065  )
2066 {
2067  int i;
2068  SCIP_Real QUAD(tmp);
2069 
2070  QUAD_ASSIGN(tmp, 0.0);
2071 
2072  for( i = 0; i < aggrrow->nnz; ++i )
2073  {
2074  QUAD_ARRAY_STORE(aggrrow->vals, aggrrow->inds[i], tmp);
2075  }
2076 
2077  aggrrow->nnz = 0;
2078  aggrrow->nrows = 0;
2079  aggrrow->rank = 0;
2080  QUAD_ASSIGN(aggrrow->rhs, 0.0);
2081  aggrrow->local = FALSE;
2082 }
2083 
2084 /** calculates the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
2085  *
2086  * @return the efficacy norm of the given aggregation row, which depends on the "separating/efficacynorm" parameter
2087  */
2089  SCIP* scip, /**< SCIP data structure */
2090  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2091  )
2092 {
2093  return calcEfficacyNormQuad(scip, aggrrow->vals, aggrrow->inds, aggrrow->nnz);
2094 }
2095 
2096 /** Adds one row to the aggregation row. Differs from SCIPaggrRowAddRow() by providing some additional
2097  * parameters required for SCIPaggrRowSumRows()
2098  */
2099 static
2101  SCIP* scip, /**< SCIP data structure */
2102  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2103  SCIP_ROW* row, /**< the row to add */
2104  SCIP_Real weight, /**< weight of row to add */
2105  SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
2106  SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
2107  int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
2108  int maxaggrlen, /**< maximal length of aggregation row */
2109  SCIP_Bool* rowtoolong /**< is the aggregated row too long */
2110  )
2111 {
2112  SCIP_Real sideval;
2113  SCIP_Bool uselhs;
2114  int i;
2115 
2116  assert( rowtoolong != NULL );
2117  *rowtoolong = FALSE;
2118 
2119  if( SCIPisFeasZero(scip, weight) || SCIProwIsModifiable(row) || (SCIProwIsLocal(row) && !allowlocal) )
2120  {
2121  return SCIP_OKAY;
2122  }
2123 
2124  if( sidetypebasis && !SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
2125  {
2127 
2128  if( stat == SCIP_BASESTAT_LOWER )
2129  {
2130  assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
2131  uselhs = TRUE;
2132  }
2133  else if( stat == SCIP_BASESTAT_UPPER )
2134  {
2135  assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
2136  uselhs = FALSE;
2137  }
2138  else if( SCIPisInfinity(scip, SCIProwGetRhs(row)) || (weight < 0.0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row))) )
2139  uselhs = TRUE;
2140  else
2141  uselhs = FALSE;
2142  }
2143  else if( (weight < 0.0 && !SCIPisInfinity(scip, -row->lhs)) || SCIPisInfinity(scip, row->rhs) )
2144  uselhs = TRUE;
2145  else
2146  uselhs = FALSE;
2147 
2148  if( uselhs )
2149  {
2150  assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
2151 
2152  if( weight > 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
2153  return SCIP_OKAY;
2154 
2155  sideval = row->lhs - row->constant;
2156  /* row is integral? round left hand side up */
2157  if( row->integral )
2158  sideval = SCIPceil(scip, sideval);
2159  }
2160  else
2161  {
2162  assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
2163 
2164  if( weight < 0.0 && ((negslack == 0) || (negslack == 1 && !row->integral)) )
2165  return SCIP_OKAY;
2166 
2167  sideval = row->rhs - row->constant;
2168  /* row is integral? round right hand side down */
2169  if( row->integral )
2170  sideval = SCIPfloor(scip, sideval);
2171  }
2172 
2173  /* add right hand side, update rank and local flag */
2174  SCIPquadprecSumQD(aggrrow->rhs, aggrrow->rhs, sideval * weight);
2175  aggrrow->rank = MAX(aggrrow->rank, row->rank);
2176  aggrrow->local = aggrrow->local || row->local;
2177 
2178  /* ensure the array for storing the row information is large enough */
2179  i = aggrrow->nrows++;
2180  if( aggrrow->nrows > aggrrow->rowssize )
2181  {
2182  int newsize = SCIPcalcMemGrowSize(scip, aggrrow->nrows);
2183  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowsinds, aggrrow->rowssize, newsize) );
2184  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->slacksign, aggrrow->rowssize, newsize) );
2185  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &aggrrow->rowweights, aggrrow->rowssize, newsize) );
2186  aggrrow->rowssize = newsize;
2187  }
2188 
2189  /* add information of addditional row */
2190  aggrrow->rowsinds[i] = row->lppos;
2191  aggrrow->rowweights[i] = weight;
2192  aggrrow->slacksign[i] = uselhs ? -1 : 1;
2193 
2194  /* add up coefficients */
2195  SCIP_CALL( varVecAddScaledRowCoefsQuad(aggrrow->inds, aggrrow->vals, &aggrrow->nnz, row, weight) );
2196 
2197  /* check if row is too long now */
2198  if( aggrrow->nnz > maxaggrlen )
2199  *rowtoolong = TRUE;
2200 
2201  return SCIP_OKAY;
2202 }
2203 
2204 /** aggregate rows using the given weights; the current content of the aggregation
2205  * row, \p aggrrow, gets overwritten
2206  */
2208  SCIP* scip, /**< SCIP data structure */
2209  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2210  SCIP_Real* weights, /**< row weights in row summation */
2211  int* rowinds, /**< array to store indices of non-zero entries of the weights array, or NULL */
2212  int nrowinds, /**< number of non-zero entries in weights array, -1 if rowinds is NULL */
2213  SCIP_Bool sidetypebasis, /**< choose sidetypes of row (lhs/rhs) based on basis information? */
2214  SCIP_Bool allowlocal, /**< should local rows allowed to be used? */
2215  int negslack, /**< should negative slack variables allowed to be used? (0: no, 1: only for integral rows, 2: yes) */
2216  int maxaggrlen, /**< maximal length of aggregation row */
2217  SCIP_Bool* valid /**< is the aggregation valid */
2218  )
2219 {
2220  SCIP_ROW** rows;
2221  SCIP_VAR** vars;
2222  int nrows;
2223  int nvars;
2224  int k;
2225  SCIP_Bool rowtoolong;
2226 
2227  assert( scip != NULL );
2228  assert( aggrrow != NULL );
2229  assert( valid != NULL );
2230 
2231  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2232  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
2233 
2234  SCIPaggrRowClear(aggrrow);
2235  *valid = FALSE;
2236 
2237  if( rowinds != NULL && nrowinds > -1 )
2238  {
2239  for( k = 0; k < nrowinds; ++k )
2240  {
2241  SCIP_CALL( addOneRow(scip, aggrrow, rows[rowinds[k]], weights[rowinds[k]], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
2242 
2243  if( rowtoolong )
2244  return SCIP_OKAY;
2245  }
2246  }
2247  else
2248  {
2249  for( k = 0; k < nrows; ++k )
2250  {
2251  if( weights[k] != 0.0 )
2252  {
2253  SCIP_CALL( addOneRow(scip, aggrrow, rows[k], weights[k], sidetypebasis, allowlocal, negslack, maxaggrlen, &rowtoolong) );
2254 
2255  if( rowtoolong )
2256  return SCIP_OKAY;
2257  }
2258  }
2259  }
2260 
2261  SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, valid);
2262 
2263  return SCIP_OKAY;
2264 }
2265 
2266 /** checks for cut redundancy and performs activity based coefficient tightening;
2267  * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
2268  * to remove small coefficients (relative to the maximum absolute coefficient)
2269  */
2270 static
2272  SCIP* scip, /**< SCIP data structure */
2273  SCIP_Bool cutislocal, /**< is the cut a local cut */
2274  int* cutinds, /**< variable problem indices of non-zeros in cut */
2275  SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
2276  int* nnz, /**< number non-zeros coefficients of cut */
2277  SCIP_Real* cutrhs, /**< right hand side of cut */
2278  SCIP_Bool* success /**< pointer to return whether post-processing was succesful or cut is redundant */
2279  )
2280 {
2281  int i;
2282  SCIP_Bool redundant;
2283  SCIP_Real maxcoef;
2284  SCIP_Real minallowedcoef;
2285  SCIP_Real QUAD(rhs);
2286 
2287  assert(scip != NULL);
2288  assert(cutinds != NULL);
2289  assert(cutcoefs != NULL);
2290  assert(cutrhs != NULL);
2291  assert(success != NULL);
2292 
2293  *success = FALSE;
2294 
2295  QUAD_ASSIGN(rhs, *cutrhs);
2296 
2297  if( removeZeros(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz) )
2298  {
2299  /* right hand side was changed to infinity -> cut is redundant */
2300  return SCIP_OKAY;
2301  }
2302 
2303  if( *nnz == 0 )
2304  return SCIP_OKAY;
2305 
2306  SCIP_CALL( cutTightenCoefs(scip, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz, &redundant) );
2307 
2308  if( redundant )
2309  {
2310  /* cut is redundant */
2311  return SCIP_OKAY;
2312  }
2313 
2314  maxcoef = 0.0;
2315  for( i = 0; i < *nnz; ++i )
2316  {
2317  SCIP_Real absval = REALABS(cutcoefs[cutinds[i]]);
2318  maxcoef = MAX(absval, maxcoef);
2319  }
2320 
2321  maxcoef /= scip->set->sepa_maxcoefratio;
2322  minallowedcoef = SCIPsumepsilon(scip);
2323  minallowedcoef = MAX(minallowedcoef, maxcoef);
2324 
2325  *success = ! removeZeros(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(&rhs), cutinds, nnz);
2326  *cutrhs = QUAD_TO_DBL(rhs);
2327 
2328  return SCIP_OKAY;
2329 }
2330 
2331 
2332 /** checks for cut redundancy and performs activity based coefficient tightening;
2333  * removes coefficients that are zero with QUAD_EPSILON tolerance and uses variable bounds
2334  * to remove small coefficients (relative to the maximum absolute coefficient).
2335  * The cutcoefs must be a quad precision array, i.e. allocated with size
2336  * QUAD_ARRAY_SIZE(nvars) and accessed with QUAD_ARRAY_LOAD and QUAD_ARRAY_STORE
2337  * macros.
2338  */
2339 static
2341  SCIP* scip, /**< SCIP data structure */
2342  SCIP_Bool cutislocal, /**< is the cut a local cut */
2343  int* cutinds, /**< variable problem indices of non-zeros in cut */
2344  SCIP_Real* cutcoefs, /**< non-zeros coefficients of cut */
2345  int* nnz, /**< number non-zeros coefficients of cut */
2346  QUAD(SCIP_Real* cutrhs), /**< right hand side of cut */
2347  SCIP_Bool* success /**< pointer to return whether the cleanup was successful or if it is useless */
2348  )
2349 {
2350  int i;
2351  SCIP_Bool redundant;
2352  SCIP_Real maxcoef;
2353  SCIP_Real minallowedcoef;
2354 
2355  assert(scip != NULL);
2356  assert(cutinds != NULL);
2357  assert(cutcoefs != NULL);
2358  assert(QUAD_HI(cutrhs) != NULL);
2359  assert(success != NULL);
2360 
2361  *success = FALSE;
2362 
2363  if( removeZerosQuad(scip, SCIPfeastol(scip), cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz) )
2364  {
2365  /* right hand side was changed to infinity -> cut is redundant */
2366  return SCIP_OKAY;
2367  }
2368 
2369  if( *nnz == 0 )
2370  return SCIP_OKAY;
2371 
2372  SCIP_CALL( cutTightenCoefsQuad(scip, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz, &redundant) );
2373  if( redundant )
2374  {
2375  /* cut is redundant */
2376  return SCIP_OKAY;
2377  }
2378 
2379  maxcoef = 0.0;
2380  for( i = 0; i < *nnz; ++i )
2381  {
2382  SCIP_Real abscoef;
2383  SCIP_Real QUAD(coef);
2384  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[i]); /* coef = cutcoefs[cutinds[i]] */
2385  abscoef = REALABS(QUAD_TO_DBL(coef));
2386  maxcoef = MAX(abscoef, maxcoef);
2387  }
2388 
2389  maxcoef /= scip->set->sepa_maxcoefratio;
2390  minallowedcoef = SCIPsumepsilon(scip);
2391  minallowedcoef = MAX(minallowedcoef, maxcoef);
2392 
2393  *success = ! removeZerosQuad(scip, minallowedcoef, cutislocal, cutcoefs, QUAD(cutrhs), cutinds, nnz);
2394 
2395  return SCIP_OKAY;
2396 }
2397 
2398 /** removes almost zero entries from the aggregation row. */
2400  SCIP* scip, /**< SCIP datastructure */
2401  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2402  SCIP_Bool useglbbounds, /**< consider global bound although the cut is local? */
2403  SCIP_Bool* valid /**< pointer to return whether the aggregation row is still valid */
2404  )
2405 {
2406  assert(aggrrow != NULL);
2407  assert(valid != NULL);
2408 
2409  *valid = ! removeZerosQuad(scip, SCIPsumepsilon(scip), useglbbounds ? FALSE : aggrrow->local, aggrrow->vals,
2410  QUAD(&aggrrow->rhs), aggrrow->inds, &aggrrow->nnz);
2411 }
2412 
2413 /** get number of aggregated rows */
2415  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2416  )
2417 {
2418  assert(aggrrow != NULL);
2419 
2420  return aggrrow->nrows;
2421 }
2422 
2423 /** get array with lp positions of rows used in aggregation */
2425  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2426  )
2427 {
2428  assert(aggrrow != NULL);
2429  assert(aggrrow->rowsinds != NULL || aggrrow->nrows == 0);
2430 
2431  return aggrrow->rowsinds;
2432 }
2433 
2434 /** get array with weights of aggregated rows */
2436  SCIP_AGGRROW* aggrrow /**< the aggregation row */
2437  )
2438 {
2439  assert(aggrrow != NULL);
2440  assert(aggrrow->rowweights != NULL || aggrrow->nrows == 0);
2441 
2442  return aggrrow->rowweights;
2443 }
2444 
2445 /** checks whether a given row has been added to the aggregation row */
2447  SCIP_AGGRROW* aggrrow, /**< the aggregation row */
2448  SCIP_ROW* row /**< row for which it is checked whether it has been added to the aggregation */
2449  )
2450 {
2451  int i;
2452  int rowind;
2453 
2454  assert(aggrrow != NULL);
2455  assert(row != NULL);
2456 
2457  rowind = SCIProwGetLPPos(row);
2458 
2459  for( i = 0; i < aggrrow->nrows; ++i )
2460  {
2461  if( aggrrow->rowsinds[i] == rowind )
2462  return TRUE;
2463  }
2464 
2465  return FALSE;
2466 }
2467 
2468 /** gets the array of corresponding variable problem indices for each non-zero in the aggregation row */
2470  SCIP_AGGRROW* aggrrow /**< aggregation row */
2471  )
2472 {
2473  assert(aggrrow != NULL);
2474 
2475  return aggrrow->inds;
2476 }
2477 
2478 /** gets the number of non-zeros in the aggregation row */
2480  SCIP_AGGRROW* aggrrow /**< aggregation row */
2481  )
2482 {
2483  assert(aggrrow != NULL);
2484 
2485  return aggrrow->nnz;
2486 }
2487 
2488 /** gets the rank of the aggregation row */
2490  SCIP_AGGRROW* aggrrow /**< aggregation row */
2491  )
2492 {
2493  assert(aggrrow != NULL);
2494 
2495  return aggrrow->rank;
2496 }
2497 
2498 /** checks if the aggregation row is only valid locally */
2500  SCIP_AGGRROW* aggrrow /**< aggregation row */
2501  )
2502 {
2503  assert(aggrrow != NULL);
2504 
2505  return aggrrow->local;
2506 }
2507 
2508 /** gets the right hand side of the aggregation row */
2510  SCIP_AGGRROW* aggrrow /**< aggregation row */
2511  )
2512 {
2513  assert(aggrrow != NULL);
2514 
2515  return QUAD_TO_DBL(aggrrow->rhs);
2516 }
2517 
2518 /* =========================================== c-MIR =========================================== */
2519 
2520 #define MAXCMIRSCALE 1e+6 /**< maximal scaling (scale/(1-f0)) allowed in c-MIR calculations */
2521 
2522 /** finds the best lower bound of the variable to use for MIR transformation */
2523 static
2525  SCIP* scip, /**< SCIP data structure */
2526  SCIP_VAR* var, /**< problem variable */
2527  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2528  int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
2529  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2530  SCIP_Real* bestlb, /**< pointer to store best bound value */
2531  SCIP_Real* simplebound, /**< pointer to store simple bound value */
2532  int* bestlbtype /**< pointer to store best bound type */
2533  )
2534 {
2535  assert(bestlb != NULL);
2536  assert(bestlbtype != NULL);
2537 
2538  *bestlb = SCIPvarGetLbGlobal(var);
2539  *bestlbtype = -1;
2540 
2541  if( allowlocal )
2542  {
2543  SCIP_Real loclb;
2544 
2545  loclb = SCIPvarGetLbLocal(var);
2546  if( SCIPisGT(scip, loclb, *bestlb) )
2547  {
2548  *bestlb = loclb;
2549  *bestlbtype = -2;
2550  }
2551  }
2552 
2553  *simplebound = *bestlb;
2554 
2555  if( usevbds && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
2556  {
2557  SCIP_Real bestvlb;
2558  int bestvlbidx;
2559 
2560  SCIP_CALL( SCIPgetVarClosestVlb(scip, var, sol, &bestvlb, &bestvlbidx) );
2561  if( bestvlbidx >= 0 && (bestvlb > *bestlb || (*bestlbtype < 0 && SCIPisGE(scip, bestvlb, *bestlb))) )
2562  {
2563  SCIP_VAR** vlbvars;
2564 
2565  /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2566  /**@todo this check is not needed for continuous variables; but allowing all but binary variables
2567  * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
2568  */
2569  vlbvars = SCIPvarGetVlbVars(var);
2570  assert(vlbvars != NULL);
2571  if( (usevbds == 2 || SCIPvarGetType(vlbvars[bestvlbidx]) == SCIP_VARTYPE_BINARY) &&
2572  SCIPvarGetProbindex(vlbvars[bestvlbidx]) < SCIPvarGetProbindex(var) )
2573  {
2574  *bestlb = bestvlb;
2575  *bestlbtype = bestvlbidx;
2576  }
2577  }
2578  }
2579 
2580  return SCIP_OKAY;
2581 }
2582 
2583 /** finds the best upper bound of the variable to use for MIR transformation */
2584 static
2586  SCIP* scip, /**< SCIP data structure */
2587  SCIP_VAR* var, /**< problem variable */
2588  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2589  int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
2590  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2591  SCIP_Real* bestub, /**< pointer to store best bound value */
2592  SCIP_Real* simplebound, /**< pointer to store simple bound */
2593  int* bestubtype /**< pointer to store best bound type */
2594  )
2595 {
2596  assert(bestub != NULL);
2597  assert(bestubtype != NULL);
2598 
2599  *bestub = SCIPvarGetUbGlobal(var);
2600  *bestubtype = -1;
2601 
2602  if( allowlocal )
2603  {
2604  SCIP_Real locub;
2605 
2606  locub = SCIPvarGetUbLocal(var);
2607  if( SCIPisLT(scip, locub, *bestub) )
2608  {
2609  *bestub = locub;
2610  *bestubtype = -2;
2611  }
2612  }
2613 
2614  *simplebound = *bestub;
2615 
2616  if( usevbds && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
2617  {
2618  SCIP_Real bestvub;
2619  int bestvubidx;
2620 
2621  SCIP_CALL( SCIPgetVarClosestVub(scip, var, sol, &bestvub, &bestvubidx) );
2622  if( bestvubidx >= 0 && (bestvub < *bestub || (*bestubtype < 0 && SCIPisLE(scip, bestvub, *bestub))) )
2623  {
2624  SCIP_VAR** vubvars;
2625 
2626  /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2627  /**@todo this check is not needed for continuous variables; but allowing all but binary variables
2628  * to be replaced by variable bounds seems to be buggy (wrong result on gesa2)
2629  */
2630  vubvars = SCIPvarGetVubVars(var);
2631  assert(vubvars != NULL);
2632  if( (usevbds == 2 || SCIPvarGetType(vubvars[bestvubidx]) == SCIP_VARTYPE_BINARY) &&
2633  SCIPvarGetProbindex(vubvars[bestvubidx]) < SCIPvarGetProbindex(var) )
2634  {
2635  *bestub = bestvub;
2636  *bestubtype = bestvubidx;
2637  }
2638  }
2639  }
2640 
2641  return SCIP_OKAY;
2642 }
2643 
2644 /** determine the best bounds with respect to the given solution for complementing the given variable */
2645 static
2647  SCIP* scip, /**< SCIP data structure */
2648  SCIP_VAR* var, /**< variable to determine best bound for */
2649  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2650  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
2651  int usevbds, /**< should variable bounds be used in bound transformation? (0: no, 1: only binary, 2: all) */
2652  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2653  SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
2654  SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
2655  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
2656  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
2657  * NULL for using closest bound for all variables */
2658  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
2659  * NULL for using closest bound for all variables */
2660  SCIP_Real* bestlb, /**< pointer to store best lower bound of variable */
2661  SCIP_Real* bestub, /**< pointer to store best upper bound of variable */
2662  int* bestlbtype, /**< pointer to store type of best lower bound of variable */
2663  int* bestubtype, /**< pointer to store type of best upper bound of variable */
2664  SCIP_BOUNDTYPE* selectedbound, /**< pointer to store whether the lower bound or the upper bound should be preferred */
2665  SCIP_Bool* freevariable /**< pointer to store if this is a free variable */
2666  )
2667 {
2668  SCIP_Real simplelb;
2669  SCIP_Real simpleub;
2670  int v;
2671 
2672  v = SCIPvarGetProbindex(var);
2673 
2674  /* check if the user specified a bound to be used */
2675  if( boundsfortrans != NULL && boundsfortrans[v] > -3 )
2676  {
2677  assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || ( boundsfortrans[v] == -2 || boundsfortrans[v] == -1 ));
2678  assert(boundtypesfortrans != NULL);
2679 
2680  /* user has explicitly specified a bound to be used */
2681  if( boundtypesfortrans[v] == SCIP_BOUNDTYPE_LOWER )
2682  {
2683  /* user wants to use lower bound */
2684  *bestlbtype = boundsfortrans[v];
2685  if( *bestlbtype == -1 )
2686  *bestlb = SCIPvarGetLbGlobal(var); /* use global standard lower bound */
2687  else if( *bestlbtype == -2 )
2688  *bestlb = SCIPvarGetLbLocal(var); /* use local standard lower bound */
2689  else
2690  {
2691  SCIP_VAR** vlbvars;
2692  SCIP_Real* vlbcoefs;
2693  SCIP_Real* vlbconsts;
2694  int k;
2695 
2696  assert(!ignoresol);
2697 
2698  /* use the given variable lower bound */
2699  vlbvars = SCIPvarGetVlbVars(var);
2700  vlbcoefs = SCIPvarGetVlbCoefs(var);
2701  vlbconsts = SCIPvarGetVlbConstants(var);
2702  k = boundsfortrans[v];
2703  assert(k >= 0 && k < SCIPvarGetNVlbs(var));
2704  assert(vlbvars != NULL);
2705  assert(vlbcoefs != NULL);
2706  assert(vlbconsts != NULL);
2707 
2708  *bestlb = vlbcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vlbvars[k]) : SCIPgetSolVal(scip, sol, vlbvars[k])) + vlbconsts[k];
2709  }
2710 
2711  assert(!SCIPisInfinity(scip, - *bestlb));
2712  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2713 
2714  /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
2715  SCIP_CALL( findBestUb(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestub, &simpleub, bestubtype) );
2716  }
2717  else
2718  {
2719  assert(boundtypesfortrans[v] == SCIP_BOUNDTYPE_UPPER);
2720 
2721  /* user wants to use upper bound */
2722  *bestubtype = boundsfortrans[v];
2723  if( *bestubtype == -1 )
2724  *bestub = SCIPvarGetUbGlobal(var); /* use global standard upper bound */
2725  else if( *bestubtype == -2 )
2726  *bestub = SCIPvarGetUbLocal(var); /* use local standard upper bound */
2727  else
2728  {
2729  SCIP_VAR** vubvars;
2730  SCIP_Real* vubcoefs;
2731  SCIP_Real* vubconsts;
2732  int k;
2733 
2734  assert(!ignoresol);
2735 
2736  /* use the given variable upper bound */
2737  vubvars = SCIPvarGetVubVars(var);
2738  vubcoefs = SCIPvarGetVubCoefs(var);
2739  vubconsts = SCIPvarGetVubConstants(var);
2740  k = boundsfortrans[v];
2741  assert(k >= 0 && k < SCIPvarGetNVubs(var));
2742  assert(vubvars != NULL);
2743  assert(vubcoefs != NULL);
2744  assert(vubconsts != NULL);
2745 
2746  /* we have to avoid cyclic variable bound usage, so we enforce to use only variable bounds variables of smaller index */
2747  *bestub = vubcoefs[k] * (sol == NULL ? SCIPvarGetLPSol(vubvars[k]) : SCIPgetSolVal(scip, sol, vubvars[k])) + vubconsts[k];
2748  }
2749 
2750  assert(!SCIPisInfinity(scip, *bestub));
2751  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2752 
2753  /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
2754  SCIP_CALL( findBestLb(scip, var, sol, fixintegralrhs ? usevbds : 0, allowlocal && fixintegralrhs, bestlb, &simplelb, bestlbtype) );
2755  }
2756  }
2757  else
2758  {
2759  SCIP_Real varsol;
2760 
2761  /* bound selection should be done automatically */
2762 
2763  /* find closest lower bound in standard lower bound (and variable lower bounds for continuous variables) */
2764  SCIP_CALL( findBestLb(scip, var, sol, usevbds, allowlocal, bestlb, &simplelb, bestlbtype) );
2765 
2766  /* find closest upper bound in standard upper bound (and variable upper bounds for continuous variables) */
2767  SCIP_CALL( findBestUb(scip, var, sol, usevbds, allowlocal, bestub, &simpleub, bestubtype) );
2768 
2769  /* check, if variable is free variable */
2770  if( SCIPisInfinity(scip, - *bestlb) && SCIPisInfinity(scip, *bestub) )
2771  {
2772  /* we found a free variable in the row with non-zero coefficient
2773  * -> MIR row can't be transformed in standard form
2774  */
2775  *freevariable = TRUE;
2776  return SCIP_OKAY;
2777  }
2778 
2779  if( !ignoresol )
2780  {
2781  /* select transformation bound */
2782  varsol = (sol == NULL ? SCIPvarGetLPSol(var) : SCIPgetSolVal(scip, sol, var));
2783 
2784  if( SCIPisInfinity(scip, *bestub) ) /* if there is no ub, use lb */
2785  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2786  else if( SCIPisInfinity(scip, - *bestlb) ) /* if there is no lb, use ub */
2787  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2788  else if( SCIPisLT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2789  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2790  else if( SCIPisGT(scip, varsol, (1.0 - boundswitch) * (*bestlb) + boundswitch * (*bestub)) )
2791  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2792  else if( *bestlbtype == -1 ) /* prefer global standard bounds */
2793  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2794  else if( *bestubtype == -1 ) /* prefer global standard bounds */
2795  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2796  else if( ((*bestlbtype) >= 0 || (*bestubtype) >= 0) && !SCIPisEQ(scip, *bestlb - simplelb, simpleub - *bestub) )
2797  {
2798  if( *bestlb - simplelb > simpleub - *bestub )
2799  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2800  else
2801  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2802  }
2803  else if( *bestlbtype >= 0 ) /* prefer variable bounds over local bounds */
2804  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2805  else if( *bestubtype >= 0 ) /* prefer variable bounds over local bounds */
2806  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2807  else /* no decision yet? just use lower bound */
2808  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2809  }
2810  else
2811  {
2812  SCIP_Real glbub = SCIPvarGetUbGlobal(var);
2813  SCIP_Real glblb = SCIPvarGetLbGlobal(var);
2814  SCIP_Real distlb = REALABS(glblb - *bestlb);
2815  SCIP_Real distub = REALABS(glbub - *bestub);
2816 
2817  assert(!SCIPisInfinity(scip, - *bestlb) || !SCIPisInfinity(scip, *bestub));
2818 
2819  if( SCIPisInfinity(scip, - *bestlb) )
2820  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2821  else if( !SCIPisNegative(scip, *bestlb) )
2822  {
2823  if( SCIPisInfinity(scip, *bestub) )
2824  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2825  else if( SCIPisZero(scip, glblb) )
2826  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2827  else if( SCIPisLE(scip, distlb, distub) )
2828  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2829  else
2830  *selectedbound = SCIP_BOUNDTYPE_UPPER;
2831  }
2832  else
2833  {
2834  assert(!SCIPisInfinity(scip, - *bestlb));
2835  *selectedbound = SCIP_BOUNDTYPE_LOWER;
2836  }
2837  }
2838  }
2839 
2840  return SCIP_OKAY; /*lint !e438*/
2841 }
2842 
2843 /** performs the bound substitution step with the given variable or simple bounds for the variable with the given problem index */
2844 static
2846  SCIP* scip, /**< SCIP datastructure */
2847  int* cutinds, /**< index array of nonzeros in the cut */
2848  SCIP_Real* cutcoefs, /**< array of cut coefficients */
2849  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
2850  int* nnz, /**< pointer to number of nonzeros of the cut */
2851  int varsign, /**< stores the sign of the transformed variable in summation */
2852  int boundtype, /**< stores the bound used for transformed variable:
2853  * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
2854  SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
2855  int probindex, /**< problem index of variable to perform the substitution step for */
2856  SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
2857  )
2858 {
2859  SCIP_Real QUAD(coef);
2860  SCIP_Real QUAD(tmp);
2861 
2862  assert(!SCIPisInfinity(scip, -varsign * boundval));
2863 
2864  QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
2865 
2866  /* standard (bestlbtype < 0) or variable (bestlbtype >= 0) lower bound? */
2867  if( boundtype < 0 )
2868  {
2869  SCIPquadprecProdQD(tmp, coef, boundval);
2870  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
2871  *localbdsused = *localbdsused || (boundtype == -2);
2872  }
2873  else
2874  {
2875  SCIP_VAR** vbdvars;
2876  SCIP_Real* vbdcoefs;
2877  SCIP_Real* vbdconsts;
2878  SCIP_Real QUAD(zcoef);
2879  int zidx;
2880  SCIP_VAR* var = SCIPgetVars(scip)[probindex];
2881 
2882  if( varsign == +1 )
2883  {
2884  vbdvars = SCIPvarGetVlbVars(var);
2885  vbdcoefs = SCIPvarGetVlbCoefs(var);
2886  vbdconsts = SCIPvarGetVlbConstants(var);
2887  assert(0 <= boundtype && boundtype < SCIPvarGetNVlbs(var));
2888  }
2889  else
2890  {
2891  vbdvars = SCIPvarGetVubVars(var);
2892  vbdcoefs = SCIPvarGetVubCoefs(var);
2893  vbdconsts = SCIPvarGetVubConstants(var);
2894  assert(0 <= boundtype && boundtype < SCIPvarGetNVubs(var));
2895  }
2896 
2897  assert(vbdvars != NULL);
2898  assert(vbdcoefs != NULL);
2899  assert(vbdconsts != NULL);
2900  assert(SCIPvarIsActive(vbdvars[boundtype]));
2901 
2902  zidx = SCIPvarGetProbindex(vbdvars[boundtype]);
2903 
2904  SCIPquadprecProdQD(tmp, coef, vbdconsts[boundtype]);
2905  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
2906 
2907  /* check if integral variable already exists in the row */
2908  QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
2909 
2910  if( QUAD_HI(zcoef) == 0.0 )
2911  cutinds[(*nnz)++] = zidx;
2912 
2913  SCIPquadprecProdQD(tmp, coef, vbdcoefs[boundtype]);
2914  SCIPquadprecSumQQ(zcoef, zcoef, tmp);
2915 
2916  QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
2917  assert(QUAD_HI(zcoef) != 0.0);
2918 
2919  QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
2920  }
2921 }
2922 
2923 /** performs the bound substitution step with the simple bound for the variable with the given problem index */
2924 static
2926  SCIP* scip, /**< SCIP datastructure */
2927  SCIP_Real* cutcoefs, /**< array of cut coefficients */
2928  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of the cut */
2929  int boundtype, /**< stores the bound used for transformed variable:
2930  * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
2931  SCIP_Real boundval, /**< array of best bound to be used for the substitution for each nonzero index */
2932  int probindex, /**< problem index of variable to perform the substitution step for */
2933  SCIP_Bool* localbdsused /**< pointer to updated whether a local bound was used for substitution */
2934  )
2935 {
2936  SCIP_Real QUAD(coef);
2937  SCIP_Real QUAD(tmp);
2938 
2939  assert(!SCIPisInfinity(scip, ABS(boundval)));
2940 
2941  QUAD_ARRAY_LOAD(coef, cutcoefs, probindex);
2942 
2943  /* must be a standard bound */
2944  assert( boundtype < 0 );
2945 
2946  SCIPquadprecProdQD(tmp, coef, boundval);
2947  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
2948  *localbdsused = *localbdsused || (boundtype == -2);
2949 }
2950 
2951 
2952 /** Transform equation \f$ a \cdot x = b; lb \leq x \leq ub \f$ into standard form
2953  * \f$ a^\prime \cdot x^\prime = b,\; 0 \leq x^\prime \leq ub' \f$.
2954  *
2955  * Transform variables (lb or ub):
2956  * \f[
2957  * \begin{array}{llll}
2958  * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \mbox{if lb is used in transformation}\\
2959  * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if ub is used in transformation}
2960  * \end{array}
2961  * \f]
2962  * and move the constant terms \f$ a_j\, lb_j \f$ or \f$ a_j\, ub_j \f$ to the rhs.
2963  *
2964  * Transform variables (vlb or vub):
2965  * \f[
2966  * \begin{array}{llll}
2967  * x^\prime_j := x_j - (bl_j\, zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \mbox{if vlb is used in transf.} \\
2968  * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \mbox{if vub is used in transf.}
2969  * \end{array}
2970  * \f]
2971  * move the constant terms \f$ a_j\, dl_j \f$ or \f$ a_j\, du_j \f$ to the rhs, and update the coefficient of the VLB variable:
2972  * \f[
2973  * \begin{array}{ll}
2974  * a_{zl_j} := a_{zl_j} + a_j\, bl_j,& \mbox{or} \\
2975  * a_{zu_j} := a_{zu_j} + a_j\, bu_j &
2976  * \end{array}
2977  * \f]
2978  */
2979 static
2981  SCIP* scip, /**< SCIP data structure */
2982  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
2983  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
2984  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
2985  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
2986  SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
2987  SCIP_Bool ignoresol, /**< should the LP solution be ignored? (eg, apply MIR to dualray) */
2988  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
2989  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
2990  * NULL for using closest bound for all variables */
2991  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
2992  * NULL for using closest bound for all variables */
2993  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
2994  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
2995  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
2996  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
2997  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
2998  int* nnz, /**< number of non-zeros in cut */
2999  int* varsign, /**< stores the sign of the transformed variable in summation */
3000  int* boundtype, /**< stores the bound used for transformed variable:
3001  * vlb/vub_idx, or -1 for global lb/ub, or -2 for local lb/ub */
3002  SCIP_Bool* freevariable, /**< stores whether a free variable was found in MIR row -> invalid summation */
3003  SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
3004  )
3005 {
3006  SCIP_Real QUAD(tmp);
3007  SCIP_Real* bestlbs;
3008  SCIP_Real* bestubs;
3009  int* bestlbtypes;
3010  int* bestubtypes;
3011  SCIP_BOUNDTYPE* selectedbounds;
3012  int i;
3013  int aggrrowintstart;
3014  int nvars;
3015  int firstcontvar;
3016  SCIP_VAR** vars;
3017 
3018  assert(varsign != NULL);
3019  assert(boundtype != NULL);
3020  assert(freevariable != NULL);
3021  assert(localbdsused != NULL);
3022 
3023  *freevariable = FALSE;
3024  *localbdsused = FALSE;
3025 
3026  /* allocate temporary memory to store best bounds and bound types */
3027  SCIP_CALL( SCIPallocBufferArray(scip, &bestlbs, 2*(*nnz)) );
3028  SCIP_CALL( SCIPallocBufferArray(scip, &bestubs, 2*(*nnz)) );
3029  SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtypes, 2*(*nnz)) );
3030  SCIP_CALL( SCIPallocBufferArray(scip, &bestubtypes, 2*(*nnz)) );
3031  SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, 2*(*nnz)) );
3032 
3033  /* start with continuous variables, because using variable bounds can affect the untransformed integral
3034  * variables, and these changes have to be incorporated in the transformation of the integral variables
3035  * (continuous variables have largest problem indices!)
3036  */
3037  SCIPsortDownInt(cutinds, *nnz);
3038 
3039  vars = SCIPgetVars(scip);
3040  nvars = SCIPgetNVars(scip);
3041  firstcontvar = nvars - SCIPgetNContVars(scip);
3042 
3043  /* determine the best bounds for the continuous variables */
3044  for( i = 0; i < *nnz && cutinds[i] >= firstcontvar; ++i )
3045  {
3046  SCIP_CALL( determineBestBounds(scip, vars[cutinds[i]], sol, boundswitch, usevbds ? 2 : 0, allowlocal, fixintegralrhs,
3047  ignoresol, boundsfortrans, boundtypesfortrans,
3048  bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
3049 
3050  if( *freevariable )
3051  goto TERMINATE;
3052  }
3053 
3054  /* remember start of integer variables in the aggrrow */
3055  aggrrowintstart = i;
3056 
3057  /* perform bound substitution for continuous variables */
3058  for( i = 0; i < aggrrowintstart; ++i )
3059  {
3060  int v = cutinds[i];
3061 
3062  if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
3063  {
3064  assert(!SCIPisInfinity(scip, -bestlbs[i]));
3065 
3066  /* use lower bound as transformation bound: x'_j := x_j - lb_j */
3067  boundtype[i] = bestlbtypes[i];
3068  varsign[i] = +1;
3069 
3070  performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestlbs[i], v, localbdsused);
3071  }
3072  else
3073  {
3074  assert(!SCIPisInfinity(scip, bestubs[i]));
3075 
3076  /* use upper bound as transformation bound: x'_j := ub_j - x_j */
3077  boundtype[i] = bestubtypes[i];
3078  varsign[i] = -1;
3079 
3080  performBoundSubstitution(scip, cutinds, cutcoefs, QUAD(cutrhs), nnz, varsign[i], boundtype[i], bestubs[i], v, localbdsused);
3081  }
3082  }
3083 
3084  /* remove integral variables that now have a zero coefficient due to variable bound usage of continuous variables
3085  * and determine the bound to use for the integer variables that are left
3086  */
3087  while( i < *nnz )
3088  {
3089  SCIP_Real QUAD(coef);
3090  int v = cutinds[i];
3091  assert(cutinds[i] < firstcontvar);
3092 
3093  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3094 
3095  /* due to variable bound usage for the continuous variables cancellation may have occurred */
3096  if( EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON) )
3097  {
3098  QUAD_ASSIGN(coef, 0.0);
3099  QUAD_ARRAY_STORE(cutcoefs, v, coef);
3100  --(*nnz);
3101  cutinds[i] = cutinds[*nnz];
3102  /* do not increase i, since last element is copied to the i-th position */
3103  continue;
3104  }
3105 
3106  /* determine the best bounds for the integral variable, usevbd can be set to 0 here as vbds are only used for continuous variables */
3107  SCIP_CALL( determineBestBounds(scip, vars[v], sol, boundswitch, 0, allowlocal, fixintegralrhs,
3108  ignoresol, boundsfortrans, boundtypesfortrans,
3109  bestlbs + i, bestubs + i, bestlbtypes + i, bestubtypes + i, selectedbounds + i, freevariable) );
3110 
3111  /* increase i */
3112  ++i;
3113 
3114  if( *freevariable )
3115  goto TERMINATE;
3116  }
3117 
3118  /* now perform the bound substitution on the remaining integral variables which only uses standard bounds */
3119  for( i = aggrrowintstart; i < *nnz; ++i )
3120  {
3121  int v = cutinds[i];
3122 
3123  /* perform bound substitution */
3124  if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
3125  {
3126  assert(!SCIPisInfinity(scip, - bestlbs[i]));
3127  assert(bestlbtypes[i] < 0);
3128 
3129  /* use lower bound as transformation bound: x'_j := x_j - lb_j */
3130  boundtype[i] = bestlbtypes[i];
3131  varsign[i] = +1;
3132 
3133  performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestlbs[i], v, localbdsused);
3134  }
3135  else
3136  {
3137  assert(!SCIPisInfinity(scip, bestubs[i]));
3138  assert(bestubtypes[i] < 0);
3139 
3140  /* use upper bound as transformation bound: x'_j := ub_j - x_j */
3141  boundtype[i] = bestubtypes[i];
3142  varsign[i] = -1;
3143 
3144  performBoundSubstitutionSimple(scip, cutcoefs, QUAD(cutrhs), boundtype[i], bestubs[i], v, localbdsused);
3145  }
3146  }
3147 
3148  if( fixintegralrhs )
3149  {
3150  SCIP_Real f0;
3151 
3152  /* check if rhs is fractional */
3153  f0 = EPSFRAC(QUAD_TO_DBL(*cutrhs), SCIPsumepsilon(scip));
3154  if( f0 < minfrac || f0 > maxfrac )
3155  {
3156  SCIP_Real bestviolgain;
3157  SCIP_Real bestnewf0;
3158  int besti;
3159 
3160  /* choose complementation of one variable differently such that f0 is in correct range */
3161  besti = -1;
3162  bestviolgain = -1e+100;
3163  bestnewf0 = 1.0;
3164  for( i = 0; i < *nnz; i++ )
3165  {
3166  int v;
3167  SCIP_Real QUAD(coef);
3168 
3169  v = cutinds[i];
3170  assert(0 <= v && v < nvars);
3171 
3172  QUAD_ARRAY_LOAD(coef, cutcoefs, v);
3173  assert(!EPSZ(QUAD_TO_DBL(coef), QUAD_EPSILON));
3174 
3175  if( boundtype[i] < 0
3176  && ((varsign[i] == +1 && !SCIPisInfinity(scip, bestubs[i]) && bestubtypes[i] < 0)
3177  || (varsign[i] == -1 && !SCIPisInfinity(scip, -bestlbs[i]) && bestlbtypes[i] < 0)) )
3178  {
3179  SCIP_Real fj;
3180  SCIP_Real newfj;
3181  SCIP_Real newrhs;
3182  SCIP_Real newf0;
3183  SCIP_Real solval;
3184  SCIP_Real viol;
3185  SCIP_Real newviol;
3186  SCIP_Real violgain;
3187 
3188  /* currently: a'_j = varsign * a_j -> f'_j = a'_j - floor(a'_j)
3189  * after complementation: a''_j = -varsign * a_j -> f''_j = a''_j - floor(a''_j) = 1 - f'_j
3190  * rhs'' = rhs' + varsign * a_j * (lb_j - ub_j)
3191  * cut violation from f0 and fj: f'_0 - f'_j * x'_j
3192  * after complementation: f''_0 - f''_j * x''_j
3193  *
3194  * for continuous variables, we just set f'_j = f''_j = |a'_j|
3195  */
3196  newrhs = QUAD_TO_DBL(*cutrhs) + varsign[i] * QUAD_TO_DBL(coef) * (bestlbs[i] - bestubs[i]);
3197  newf0 = EPSFRAC(newrhs, SCIPsumepsilon(scip));
3198 
3199  if( newf0 < minfrac || newf0 > maxfrac )
3200  continue;
3201  if( v >= firstcontvar )
3202  {
3203  fj = REALABS(QUAD_TO_DBL(coef));
3204  newfj = fj;
3205  }
3206  else
3207  {
3208  fj = SCIPfrac(scip, varsign[i] * QUAD_TO_DBL(coef));
3209  newfj = SCIPfrac(scip, -varsign[i] * QUAD_TO_DBL(coef));
3210  }
3211 
3212  if( !ignoresol )
3213  {
3214  solval = (sol == NULL ? SCIPvarGetLPSol(vars[v]) : SCIPgetSolVal(scip, sol, vars[v]));
3215  viol = f0 - fj * (varsign[i] == +1 ? solval - bestlbs[i] : bestubs[i] - solval);
3216  newviol = newf0 - newfj * (varsign[i] == -1 ? solval - bestlbs[i] : bestubs[i] - solval);
3217  violgain = newviol - viol;
3218  }
3219  else
3220  {
3221  /* todo: this should be done, this can improve the dualray significantly */
3222  SCIPerrorMessage("Cannot handle closest bounds with ignoring the LP solution.\n");
3223  return SCIP_INVALIDCALL;
3224  }
3225 
3226  /* prefer larger violations; for equal violations, prefer smaller f0 values since then the possibility that
3227  * we f_j > f_0 is larger and we may improve some coefficients in rounding
3228  */
3229  if( SCIPisGT(scip, violgain, bestviolgain) || (SCIPisGE(scip, violgain, bestviolgain) && newf0 < bestnewf0) )
3230  {
3231  besti = i;
3232  bestviolgain = violgain;
3233  bestnewf0 = newf0;
3234  }
3235  }
3236  }
3237 
3238  if( besti >= 0 )
3239  {
3240  SCIP_Real QUAD(coef);
3241  assert(besti < *nnz);
3242  assert(boundtype[besti] < 0);
3243  assert(!SCIPisInfinity(scip, -bestlbs[besti]));
3244  assert(!SCIPisInfinity(scip, bestubs[besti]));
3245 
3246  QUAD_ARRAY_LOAD(coef, cutcoefs, cutinds[besti]);
3247  QUAD_SCALE(coef, varsign[besti]);
3248 
3249  /* switch the complementation of this variable */
3250  SCIPquadprecSumDD(tmp, bestlbs[besti], - bestubs[besti]);
3251  SCIPquadprecProdQQ(tmp, tmp, coef);
3252  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3253 
3254  if( varsign[besti] == +1 )
3255  {
3256  /* switch to upper bound */
3257  assert(bestubtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
3258  boundtype[besti] = bestubtypes[besti];
3259  varsign[besti] = -1;
3260  }
3261  else
3262  {
3263  /* switch to lower bound */
3264  assert(bestlbtypes[besti] < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
3265  boundtype[besti] = bestlbtypes[besti];
3266  varsign[besti] = +1;
3267  }
3268  *localbdsused = *localbdsused || (boundtype[besti] == -2);
3269  }
3270  }
3271  }
3272 
3273  TERMINATE:
3274 
3275  /*free temporary memory */
3276  SCIPfreeBufferArray(scip, &selectedbounds);
3277  SCIPfreeBufferArray(scip, &bestubtypes);
3278  SCIPfreeBufferArray(scip, &bestlbtypes);
3279  SCIPfreeBufferArray(scip, &bestubs);
3280  SCIPfreeBufferArray(scip, &bestlbs);
3281 
3282  return SCIP_OKAY;
3283 }
3284 
3285 /** Calculate fractionalities \f$ f_0 := b - down(b), f_j := a^\prime_j - down(a^\prime_j) \f$, and derive MIR cut \f$ \tilde{a} \cdot x' \leq down(b) \f$
3286  * \f[
3287  * \begin{array}{rll}
3288  * integers :& \tilde{a}_j = down(a^\prime_j), & if \qquad f_j \leq f_0 \\
3289  * & \tilde{a}_j = down(a^\prime_j) + (f_j - f_0)/(1 - f_0),& if \qquad f_j > f_0 \\
3290  * continuous:& \tilde{a}_j = 0, & if \qquad a^\prime_j \geq 0 \\
3291  * & \tilde{a}_j = a^\prime_j/(1 - f_0), & if \qquad a^\prime_j < 0
3292  * \end{array}
3293  * \f]
3294  *
3295  * Transform inequality back to \f$ \hat{a} \cdot x \leq rhs \f$:
3296  *
3297  * (lb or ub):
3298  * \f[
3299  * \begin{array}{lllll}
3300  * x^\prime_j := x_j - lb_j,& x_j = x^\prime_j + lb_j,& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{if lb was used in transformation} \\
3301  * x^\prime_j := ub_j - x_j,& x_j = ub_j - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{if ub was used in transformation}
3302  * \end{array}
3303  * \f]
3304  * and move the constant terms
3305  * \f[
3306  * \begin{array}{cl}
3307  * -\tilde{a}_j \cdot lb_j = -\hat{a}_j \cdot lb_j,& \mbox{or} \\
3308  * \tilde{a}_j \cdot ub_j = -\hat{a}_j \cdot ub_j &
3309  * \end{array}
3310  * \f]
3311  * to the rhs.
3312  *
3313  * (vlb or vub):
3314  * \f[
3315  * \begin{array}{lllll}
3316  * x^\prime_j := x_j - (bl_j \cdot zl_j + dl_j),& x_j = x^\prime_j + (bl_j\, zl_j + dl_j),& a^\prime_j = a_j,& \hat{a}_j := \tilde{a}_j,& \mbox{(vlb)} \\
3317  * x^\prime_j := (bu_j\, zu_j + du_j) - x_j,& x_j = (bu_j\, zu_j + du_j) - x^\prime_j,& a^\prime_j = -a_j,& \hat{a}_j := -\tilde{a}_j,& \mbox{(vub)}
3318  * \end{array}
3319  * \f]
3320  * move the constant terms
3321  * \f[
3322  * \begin{array}{cl}
3323  * -\tilde{a}_j\, dl_j = -\hat{a}_j\, dl_j,& \mbox{or} \\
3324  * \tilde{a}_j\, du_j = -\hat{a}_j\, du_j &
3325  * \end{array}
3326  * \f]
3327  * to the rhs, and update the VB variable coefficients:
3328  * \f[
3329  * \begin{array}{ll}
3330  * \hat{a}_{zl_j} := \hat{a}_{zl_j} - \tilde{a}_j\, bl_j = \hat{a}_{zl_j} - \hat{a}_j\, bl_j,& \mbox{or} \\
3331  * \hat{a}_{zu_j} := \hat{a}_{zu_j} + \tilde{a}_j\, bu_j = \hat{a}_{zu_j} - \hat{a}_j\, bu_j &
3332  * \end{array}
3333  * \f]
3334  */
3335 static
3337  SCIP* scip, /**< SCIP data structure */
3338  SCIP_Real*RESTRICT cutcoefs, /**< array of coefficients of cut */
3339  QUAD(SCIP_Real*RESTRICT cutrhs), /**< pointer to right hand side of cut */
3340  int*RESTRICT cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3341  int*RESTRICT nnz, /**< number of non-zeros in cut */
3342  int*RESTRICT varsign, /**< stores the sign of the transformed variable in summation */
3343  int*RESTRICT boundtype, /**< stores the bound used for transformed variable (vlb/vub_idx or -1 for lb/ub) */
3344  QUAD(SCIP_Real f0) /**< fractional value of rhs */
3345  )
3346 {
3347  SCIP_Real QUAD(tmp);
3348  SCIP_Real QUAD(onedivoneminusf0);
3349  int i;
3350  int firstcontvar;
3351  SCIP_VAR** vars;
3352  int ndelcontvars;
3353 
3354  assert(QUAD_HI(cutrhs) != NULL);
3355  assert(cutcoefs != NULL);
3356  assert(cutinds != NULL);
3357  assert(nnz != NULL);
3358  assert(boundtype != NULL);
3359  assert(varsign != NULL);
3360  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
3361 
3362  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
3363  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
3364 
3365  /* Loop backwards to process integral variables first and be able to delete coefficients of integral variables
3366  * without destroying the ordering of the aggrrow's non-zeros.
3367  * (due to sorting in cutsTransformMIR the ordering is continuous before integral)
3368  */
3369 
3370  firstcontvar = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
3371  vars = SCIPgetVars(scip);
3372 #ifndef NDEBUG
3373  /*in debug mode check that all continuous variables of the aggrrow come before the integral variables */
3374  i = 0;
3375  while( i < *nnz && cutinds[i] >= firstcontvar )
3376  ++i;
3377 
3378  while( i < *nnz )
3379  {
3380  assert(cutinds[i] < firstcontvar);
3381  ++i;
3382  }
3383 #endif
3384 
3385  for( i = *nnz - 1; i >= 0 && cutinds[i] < firstcontvar; --i )
3386  {
3387  SCIP_VAR* var;
3388  SCIP_Real QUAD(cutaj);
3389  int v;
3390 
3391  v = cutinds[i];
3392  assert(0 <= v && v < SCIPgetNVars(scip));
3393 
3394  var = vars[v];
3395  assert(var != NULL);
3396  assert(SCIPvarGetProbindex(var) == v);
3397  assert(varsign[i] == +1 || varsign[i] == -1);
3398 
3399  /* calculate the coefficient in the retransformed cut */
3400  {
3401  SCIP_Real QUAD(aj);
3402  SCIP_Real QUAD(downaj);
3403  SCIP_Real QUAD(fj);
3404 
3405  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
3406  QUAD_SCALE(aj, varsign[i]);
3407 
3408  SCIPquadprecEpsFloorQ(downaj, aj, SCIPepsilon(scip)); /*lint !e666*/
3409  SCIPquadprecSumQQ(fj, aj, -downaj);
3410  assert(QUAD_TO_DBL(fj) >= -SCIPepsilon(scip) && QUAD_TO_DBL(fj) < 1.0);
3411 
3412  if( SCIPisLE(scip, QUAD_TO_DBL(fj), QUAD_TO_DBL(f0)) )
3413  {
3414  QUAD_ASSIGN_Q(cutaj, downaj);
3415  }
3416  else
3417  {
3418  SCIPquadprecSumQQ(tmp, fj, -f0);
3419  SCIPquadprecProdQQ(tmp, tmp, onedivoneminusf0);
3420  SCIPquadprecSumQQ(cutaj, tmp, downaj);
3421  }
3422 
3423  QUAD_SCALE(cutaj, varsign[i]);
3424  }
3425 
3426  /* remove zero cut coefficients from cut */
3427  if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
3428  {
3429  QUAD_ASSIGN(cutaj, 0.0);
3430  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3431  --*nnz;
3432  cutinds[i] = cutinds[*nnz];
3433  continue;
3434  }
3435 
3436  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3437 
3438  /* integral var uses standard bound */
3439  assert(boundtype[i] < 0);
3440 
3441  /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
3442  if( varsign[i] == +1 )
3443  {
3444  /* lower bound was used */
3445  if( boundtype[i] == -1 )
3446  {
3447  assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
3448  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
3449  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetLbGlobal(var) */
3450  }
3451  else
3452  {
3453  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
3454  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
3455  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetLbLocal(var) */
3456  }
3457  }
3458  else
3459  {
3460  /* upper bound was used */
3461  if( boundtype[i] == -1 )
3462  {
3463  assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
3464  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
3465  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetUbGlobal(var) */
3466  }
3467  else
3468  {
3469  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
3470  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
3471  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp); /* rhs += cutaj * SCIPvarGetUbLocal(var) */
3472  }
3473  }
3474  }
3475 
3476  /* now process the continuous variables; postpone deletetion of zeros till all continuous variables have been processed */
3477  ndelcontvars = 0;
3478  while( i >= ndelcontvars )
3479  {
3480  SCIP_VAR* var;
3481  SCIP_Real QUAD(cutaj);
3482  SCIP_Real QUAD(aj);
3483  int v;
3484 
3485  v = cutinds[i];
3486  assert(0 <= v && v < SCIPgetNVars(scip));
3487 
3488  var = vars[v];
3489  assert(var != NULL);
3490  assert(SCIPvarGetProbindex(var) == v);
3491  assert(varsign[i] == +1 || varsign[i] == -1);
3492  assert( v >= firstcontvar );
3493 
3494  /* calculate the coefficient in the retransformed cut */
3495  QUAD_ARRAY_LOAD(aj, cutcoefs, v);
3496 
3497  if( QUAD_TO_DBL(aj) * varsign[i] >= 0.0 )
3498  QUAD_ASSIGN(cutaj, 0.0);
3499  else
3500  SCIPquadprecProdQQ(cutaj, onedivoneminusf0, aj); /* cutaj = varsign[i] * aj * onedivoneminusf0; // a^_j */
3501 
3502  /* remove zero cut coefficients from cut; move a continuous var from the beginning
3503  * to the current position, so that all integral variables stay behind the continuous
3504  * variables
3505  */
3506  if( EPSZ(QUAD_TO_DBL(cutaj), QUAD_EPSILON) )
3507  {
3508  QUAD_ASSIGN(cutaj, 0.0);
3509  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3510  cutinds[i] = cutinds[ndelcontvars];
3511  varsign[i] = varsign[ndelcontvars];
3512  boundtype[i] = boundtype[ndelcontvars];
3513  ++ndelcontvars;
3514  continue;
3515  }
3516 
3517  QUAD_ARRAY_STORE(cutcoefs, v, cutaj);
3518 
3519  /* check for variable bound use */
3520  if( boundtype[i] < 0 )
3521  {
3522  /* standard bound */
3523 
3524  /* move the constant term -a~_j * lb_j == -a^_j * lb_j , or a~_j * ub_j == -a^_j * ub_j to the rhs */
3525  if( varsign[i] == +1 )
3526  {
3527  /* lower bound was used */
3528  if( boundtype[i] == -1 )
3529  {
3530  assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)));
3531  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbGlobal(var));
3532  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3533  }
3534  else
3535  {
3536  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
3537  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetLbLocal(var));
3538  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3539  }
3540  }
3541  else
3542  {
3543  /* upper bound was used */
3544  if( boundtype[i] == -1 )
3545  {
3546  assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)));
3547  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbGlobal(var));
3548  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3549  }
3550  else
3551  {
3552  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
3553  SCIPquadprecProdQD(tmp, cutaj, SCIPvarGetUbLocal(var));
3554  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3555  }
3556  }
3557  }
3558  else
3559  {
3560  SCIP_VAR** vbz;
3561  SCIP_Real* vbb;
3562  SCIP_Real* vbd;
3563  SCIP_Real QUAD(zcoef);
3564  int vbidx;
3565  int zidx;
3566 
3567  /* variable bound */
3568  vbidx = boundtype[i];
3569 
3570  /* change mirrhs and cutaj of integer variable z_j of variable bound */
3571  if( varsign[i] == +1 )
3572  {
3573  /* variable lower bound was used */
3574  assert(0 <= vbidx && vbidx < SCIPvarGetNVlbs(var));
3575  vbz = SCIPvarGetVlbVars(var);
3576  vbb = SCIPvarGetVlbCoefs(var);
3577  vbd = SCIPvarGetVlbConstants(var);
3578  }
3579  else
3580  {
3581  /* variable upper bound was used */
3582  assert(0 <= vbidx && vbidx < SCIPvarGetNVubs(var));
3583  vbz = SCIPvarGetVubVars(var);
3584  vbb = SCIPvarGetVubCoefs(var);
3585  vbd = SCIPvarGetVubConstants(var);
3586  }
3587  assert(SCIPvarIsActive(vbz[vbidx]));
3588  zidx = SCIPvarGetProbindex(vbz[vbidx]);
3589  assert(0 <= zidx && zidx < firstcontvar);
3590 
3591  SCIPquadprecProdQD(tmp, cutaj, vbd[vbidx]);
3592  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3593 
3594  SCIPquadprecProdQD(tmp, cutaj, vbb[vbidx]);
3595  QUAD_ARRAY_LOAD(zcoef, cutcoefs, zidx);
3596 
3597  /* update sparsity pattern */
3598  if( QUAD_HI(zcoef) == 0.0 )
3599  cutinds[(*nnz)++] = zidx;
3600 
3601  SCIPquadprecSumQQ(zcoef, zcoef, -tmp);
3602  QUAD_HI(zcoef) = NONZERO(QUAD_HI(zcoef));
3603  QUAD_ARRAY_STORE(cutcoefs, zidx, zcoef);
3604  assert(QUAD_HI(zcoef) != 0.0);
3605  }
3606 
3607  /* advance to next variable */
3608  --i;
3609  }
3610 
3611  /* fill the empty position due to deleted continuous variables */
3612  if( ndelcontvars > 0 )
3613  {
3614  assert(ndelcontvars <= *nnz);
3615  *nnz -= ndelcontvars;
3616  if( *nnz < ndelcontvars )
3617  {
3618  BMScopyMemoryArray(cutinds, cutinds + ndelcontvars, *nnz);
3619  }
3620  else
3621  {
3622  BMScopyMemoryArray(cutinds, cutinds + *nnz, ndelcontvars);
3623  }
3624  }
3625 
3626  return SCIP_OKAY;
3627 }
3628 
3629 /** substitute aggregated slack variables:
3630  *
3631  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
3632  * variable only appears in its own row: \f$ a^\prime_r = scale * weight[r] * slacksign[r]. \f$
3633  *
3634  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
3635  * \f[
3636  * \begin{array}{rll}
3637  * integers : & \hat{a}_r = \tilde{a}_r = down(a^\prime_r), & \mbox{if}\qquad f_r <= f0 \\
3638  * & \hat{a}_r = \tilde{a}_r = down(a^\prime_r) + (f_r - f0)/(1 - f0),& \mbox{if}\qquad f_r > f0 \\
3639  * continuous:& \hat{a}_r = \tilde{a}_r = 0, & \mbox{if}\qquad a^\prime_r >= 0 \\
3640  * & \hat{a}_r = \tilde{a}_r = a^\prime_r/(1 - f0), & \mbox{if}\qquad a^\prime_r < 0
3641  * \end{array}
3642  * \f]
3643  *
3644  * Substitute \f$ \hat{a}_r \cdot s_r \f$ by adding \f$ \hat{a}_r \f$ times the slack's definition to the cut.
3645  */
3646 static
3648  SCIP* scip, /**< SCIP data structure */
3649  SCIP_Real* weights, /**< row weights in row summation */
3650  int* slacksign, /**< stores the sign of the row's slack variable in summation */
3651  int* rowinds, /**< sparsity pattern of used rows */
3652  int nrowinds, /**< number of used rows */
3653  SCIP_Real scale, /**< additional scaling factor multiplied to all rows */
3654  SCIP_Real* cutcoefs, /**< array of coefficients of cut */
3655  QUAD(SCIP_Real* cutrhs), /**< pointer to right hand side of cut */
3656  int* cutinds, /**< array of variables problem indices for non-zero coefficients in cut */
3657  int* nnz, /**< number of non-zeros in cut */
3658  QUAD(SCIP_Real f0) /**< fractional value of rhs */
3659  )
3660 { /*lint --e{715}*/
3661  SCIP_ROW** rows;
3662  SCIP_Real QUAD(onedivoneminusf0);
3663  int i;
3664 
3665  assert(scip != NULL);
3666  assert(weights != NULL || nrowinds == 0);
3667  assert(slacksign != NULL || nrowinds == 0);
3668  assert(rowinds != NULL || nrowinds == 0);
3669  assert(scale > 0.0);
3670  assert(cutcoefs != NULL);
3671  assert(QUAD_HI(cutrhs) != NULL);
3672  assert(cutinds != NULL);
3673  assert(nnz != NULL);
3674  assert(0.0 < QUAD_TO_DBL(f0) && QUAD_TO_DBL(f0) < 1.0);
3675 
3676  SCIPquadprecSumQD(onedivoneminusf0, -f0, 1.0);
3677  SCIPquadprecDivDQ(onedivoneminusf0, 1.0, onedivoneminusf0);
3678 
3679  rows = SCIPgetLPRows(scip);
3680  for( i = 0; i < nrowinds; i++ )
3681  {
3682  SCIP_ROW* row;
3683  SCIP_Real ar;
3684  SCIP_Real downar;
3685  SCIP_Real QUAD(cutar);
3686  SCIP_Real QUAD(fr);
3687  SCIP_Real QUAD(tmp);
3688  SCIP_Real mul;
3689  int r;
3690 
3691  r = rowinds[i]; /*lint !e613*/
3692  assert(0 <= r && r < SCIPgetNLPRows(scip));
3693  assert(slacksign[i] == -1 || slacksign[i] == +1); /*lint !e613*/
3694  assert(!SCIPisZero(scip, weights[i])); /*lint !e613*/
3695 
3696  row = rows[r];
3697  assert(row != NULL);
3698  assert(row->len == 0 || row->cols != NULL);
3699  assert(row->len == 0 || row->cols_index != NULL);
3700  assert(row->len == 0 || row->vals != NULL);
3701 
3702  /* get the slack's coefficient a'_r in the aggregated row */
3703  ar = slacksign[i] * scale * weights[i]; /*lint !e613*/
3704 
3705  /* calculate slack variable's coefficient a^_r in the cut */
3706  if( row->integral
3707  && ((slacksign[i] == +1 && SCIPisFeasIntegral(scip, row->rhs - row->constant))
3708  || (slacksign[i] == -1 && SCIPisFeasIntegral(scip, row->lhs - row->constant))) ) /*lint !e613*/
3709  {
3710  /* slack variable is always integral:
3711  * a^_r = a~_r = down(a'_r) , if f_r <= f0
3712  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
3713  */
3714  downar = EPSFLOOR(ar, QUAD_EPSILON);
3715  SCIPquadprecSumDD(fr, ar, -downar);
3716  if( SCIPisLE(scip, QUAD_TO_DBL(fr), QUAD_TO_DBL(f0)) )
3717  QUAD_ASSIGN(cutar, downar);
3718  else
3719  {
3720  SCIPquadprecSumQQ(cutar, fr, -f0);
3721  SCIPquadprecProdQQ(cutar, cutar, onedivoneminusf0);
3722  SCIPquadprecSumQD(cutar, cutar, downar);
3723  }
3724  }
3725  else
3726  {
3727  /* slack variable is continuous:
3728  * a^_r = a~_r = 0 , if a'_r >= 0
3729  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
3730  */
3731  if( ar >= 0.0 )
3732  continue; /* slack can be ignored, because its coefficient is reduced to 0.0 */
3733  else
3734  SCIPquadprecProdQD(cutar, onedivoneminusf0, ar);
3735  }
3736 
3737  /* if the coefficient was reduced to zero, ignore the slack variable */
3738  if( EPSZ(QUAD_TO_DBL(cutar), QUAD_EPSILON) )
3739  continue;
3740 
3741  /* depending on the slack's sign, we have
3742  * a*x + c + s == rhs => s == - a*x - c + rhs, or a*x + c - s == lhs => s == a*x + c - lhs
3743  * substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
3744  */
3745  mul = -slacksign[i] * QUAD_TO_DBL(cutar); /*lint !e613*/
3746 
3747  /* add the slack's definition multiplied with a^_j to the cut */
3748  SCIP_CALL( varVecAddScaledRowCoefsQuad(cutinds, cutcoefs, nnz, row, mul) );
3749 
3750  /* move slack's constant to the right hand side */
3751  if( slacksign[i] == +1 ) /*lint !e613*/
3752  {
3753  SCIP_Real QUAD(rowrhs);
3754 
3755  /* a*x + c + s == rhs => s == - a*x - c + rhs: move a^_r * (rhs - c) to the right hand side */
3756  assert(!SCIPisInfinity(scip, row->rhs));
3757  SCIPquadprecSumDD(rowrhs, row->rhs, -row->constant);
3758  if( row->integral )
3759  {
3760  /* the right hand side was implicitly rounded down in row aggregation */
3761  QUAD_ASSIGN(rowrhs, SCIPfloor(scip, QUAD_TO_DBL(rowrhs)));
3762  }
3763  SCIPquadprecProdQQ(tmp, cutar, rowrhs);
3764  SCIPquadprecSumQQ(*cutrhs, *cutrhs, -tmp);
3765  }
3766  else
3767  {
3768  SCIP_Real QUAD(rowlhs);
3769 
3770  /* a*x + c - s == lhs => s == a*x + c - lhs: move a^_r * (c - lhs) to the right hand side */
3771  assert(!SCIPisInfinity(scip, -row->lhs));
3772  SCIPquadprecSumDD(rowlhs, row->lhs, -row->constant);
3773  if( row->integral )
3774  {
3775  /* the left hand side was implicitly rounded up in row aggregation */
3776  QUAD_ASSIGN(rowlhs, SCIPceil(scip, QUAD_TO_DBL(rowlhs)));
3777  }
3778  SCIPquadprecProdQQ(tmp, cutar, rowlhs);
3779  SCIPquadprecSumQQ(*cutrhs, *cutrhs, tmp);
3780  }
3781  }
3782 
3783  /* relax rhs to zero, if it's very close to 0 */
3784  if( QUAD_TO_DBL(*cutrhs) < 0.0 && QUAD_TO_DBL(*cutrhs) >= SCIPepsilon(scip) )
3785  QUAD_ASSIGN(*cutrhs, 0.0);
3786 
3787  return SCIP_OKAY;
3788 }
3789 
3790 /** calculates an MIR cut out of the weighted sum of LP rows; The weights of modifiable rows are set to 0.0, because
3791  * these rows cannot participate in an MIR cut.
3792  *
3793  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3794  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3795  *
3796  * @pre This method can be called if @p scip is in one of the following stages:
3797  * - \ref SCIP_STAGE_SOLVING
3798  *
3799  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
3800  */
3802  SCIP* scip, /**< SCIP data structure */
3803  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
3804  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
3805  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
3806  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
3807  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
3808  SCIP_Bool fixintegralrhs, /**< should complementation tried to be adjusted such that rhs gets fractional? */
3809  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
3810  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
3811  * NULL for using closest bound for all variables */
3812  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
3813  * NULL for using closest bound for all variables */
3814  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
3815  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
3816  SCIP_Real scale, /**< additional scaling factor multiplied to the aggrrow; must be positive */
3817  SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
3818  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut if its efficacy improves cutefficacy */
3819  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut if its efficacy improves cutefficacy */
3820  int* cutinds, /**< array to store the indices of non-zero coefficients in the cut if its efficacy improves cutefficacy */
3821  int* cutnnz, /**< pointer to store the number of non-zeros in the cut if its efficacy improves cutefficacy */
3822  SCIP_Real* cutefficacy, /**< pointer to store efficacy of cut, or NULL */
3823  int* cutrank, /**< pointer to return rank of generated cut or NULL if it improves cutefficacy */
3824  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally if it improves cutefficacy */
3825  SCIP_Bool* success /**< pointer to store whether the returned coefficients are a valid MIR cut and it improves cutefficacy */
3826  )
3827 {
3828  int i;
3829  int nvars;
3830  int tmpnnz;
3831  int* varsign;
3832  int* boundtype;
3833  int* tmpinds;
3834  SCIP_Real* tmpcoefs;
3835 
3836  SCIP_Real QUAD(rhs);
3837  SCIP_Real QUAD(downrhs);
3838  SCIP_Real QUAD(f0);
3839  SCIP_Bool freevariable;
3840  SCIP_Bool localbdsused;
3841  SCIP_Bool tmpislocal;
3842 
3843  assert(aggrrow != NULL);
3844  assert(SCIPisPositive(scip, scale));
3845  assert(success != NULL);
3846 
3847  SCIPdebugMessage("calculating MIR cut (scale: %g)\n", scale);
3848 
3849  *success = FALSE;
3850 
3851  /* allocate temporary memory */
3852  nvars = SCIPgetNVars(scip);
3853  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
3854  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
3855  SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, nvars) );
3856  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcoefs, QUAD_ARRAY_SIZE(nvars)) );
3857 
3858  /* initialize cut with aggregation */
3859  tmpnnz = aggrrow->nnz;
3860  tmpislocal = aggrrow->local;
3861 
3862  SCIPquadprecProdQD(rhs, aggrrow->rhs, scale);
3863 
3864  if( tmpnnz > 0 )
3865  {
3866  BMScopyMemoryArray(tmpinds, aggrrow->inds, tmpnnz);
3867 
3868  for( i = 0; i < tmpnnz; ++i )
3869  {
3870  SCIP_Real QUAD(coef);
3871  int k = aggrrow->inds[i];
3872 
3873  QUAD_ARRAY_LOAD(coef, aggrrow->vals, k);
3874 
3875  SCIPquadprecProdQD(coef, coef, scale);
3876 
3877  QUAD_ARRAY_STORE(tmpcoefs, k, coef);
3878 
3879  assert(QUAD_HI(coef) != 0.0);
3880  }
3881 
3882  /* Transform equation a*x == b, lb <= x <= ub into standard form
3883  * a'*x' == b, 0 <= x' <= ub'.
3884  *
3885  * Transform variables (lb or ub):
3886  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
3887  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
3888  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
3889  *
3890  * Transform variables (vlb or vub):
3891  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
3892  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
3893  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
3894  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
3895  * a_{zu_j} := a_{zu_j} + a_j * bu_j
3896  */
3897  SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, fixintegralrhs, FALSE,
3898  boundsfortrans, boundtypesfortrans, minfrac, maxfrac, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, varsign, boundtype, &freevariable, &localbdsused) );
3899  assert(allowlocal || !localbdsused);
3900  tmpislocal = tmpislocal || localbdsused;
3901 
3902  if( freevariable )
3903  goto TERMINATE;
3904  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE));
3905  }
3906 
3907  /* Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
3908  * a~*x' <= down(b)
3909  * integers : a~_j = down(a'_j) , if f_j <= f_0
3910  * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
3911  * continuous: a~_j = 0 , if a'_j >= 0
3912  * a~_j = a'_j/(1 - f0) , if a'_j < 0
3913  *
3914  * Transform inequality back to a^*x <= rhs:
3915  *
3916  * (lb or ub):
3917  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
3918  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
3919  * and move the constant terms
3920  * -a~_j * lb_j == -a^_j * lb_j, or
3921  * a~_j * ub_j == -a^_j * ub_j
3922  * to the rhs.
3923  *
3924  * (vlb or vub):
3925  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
3926  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
3927  * move the constant terms
3928  * -a~_j * dl_j == -a^_j * dl_j, or
3929  * a~_j * du_j == -a^_j * du_j
3930  * to the rhs, and update the VB variable coefficients:
3931  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
3932  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
3933  */
3934  SCIPquadprecEpsFloorQ(downrhs, rhs, SCIPepsilon(scip)); /*lint !e666*/
3935 
3936  SCIPquadprecSumQQ(f0, rhs, -downrhs);
3937 
3938  if( QUAD_TO_DBL(f0) < minfrac || QUAD_TO_DBL(f0) > maxfrac )
3939  goto TERMINATE;
3940 
3941  /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
3942  * If this gives a scalar that is very big, we better do not generate this cut.
3943  */
3944  if( REALABS(scale)/(1.0 - QUAD_TO_DBL(f0)) > MAXCMIRSCALE )
3945  goto TERMINATE;
3946 
3947  /* renormalize f0 value */
3948  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
3949 
3950  QUAD_ASSIGN_Q(rhs, downrhs);
3951 
3952  if( tmpnnz > 0 )
3953  {
3954  SCIP_CALL( cutsRoundMIR(scip, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, varsign, boundtype, QUAD(f0)) );
3955  SCIPdebug(printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE));
3956  }
3957 
3958  /* substitute aggregated slack variables:
3959  *
3960  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
3961  * variable only appears in its own row:
3962  * a'_r = scale * weight[r] * slacksign[r].
3963  *
3964  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
3965  * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
3966  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
3967  * continuous: a^_r = a~_r = 0 , if a'_r >= 0
3968  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
3969  *
3970  * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
3971  */
3972  SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
3973  aggrrow->nrows, scale, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz, QUAD(f0)) );
3974  SCIPdebug( printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE) );
3975 
3976  if( postprocess )
3977  {
3978  /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
3979  * prevent numerical rounding errors
3980  */
3981  SCIP_CALL( postprocessCutQuad(scip, tmpislocal, tmpinds, tmpcoefs, &tmpnnz, QUAD(&rhs), success) );
3982  }
3983  else
3984  {
3985  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), tmpislocal, tmpcoefs, QUAD(&rhs), tmpinds, &tmpnnz);
3986  }
3987 
3988  SCIPdebug( printCutQuad(scip, sol, tmpcoefs, QUAD(rhs), tmpinds, tmpnnz, FALSE, FALSE) );
3989 
3990  if( *success )
3991  {
3992  SCIP_Real mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, tmpcoefs, QUAD_TO_DBL(rhs), tmpinds, tmpnnz);
3993 
3994  if( SCIPisEfficacious(scip, mirefficacy) && (cutefficacy == NULL || mirefficacy > *cutefficacy) )
3995  {
3996  BMScopyMemoryArray(cutinds, tmpinds, tmpnnz);
3997  *cutnnz = tmpnnz;
3998  *cutrhs = QUAD_TO_DBL(rhs);
3999  *cutislocal = tmpislocal;
4000 
4001  /* clean tmpcoefs and go back to double precision */
4002  for( i = 0; i < *cutnnz; ++i )
4003  {
4004  SCIP_Real QUAD(coef);
4005  int j = cutinds[i];
4006 
4007  QUAD_ARRAY_LOAD(coef, tmpcoefs, j);
4008 
4009  cutcoefs[i] = QUAD_TO_DBL(coef);
4010  QUAD_ASSIGN(coef, 0.0);
4011  QUAD_ARRAY_STORE(tmpcoefs, j, coef);
4012  }
4013 
4014  if( cutefficacy != NULL )
4015  *cutefficacy = mirefficacy;
4016 
4017  if( cutrank != NULL )
4018  *cutrank = aggrrow->rank + 1;
4019  }
4020  else
4021  {
4022  *success = FALSE;
4023  }
4024  }
4025 
4026  TERMINATE:
4027  if( !(*success) )
4028  {
4029  SCIP_Real QUAD(tmp);
4030 
4031  QUAD_ASSIGN(tmp, 0.0);
4032  for( i = 0; i < tmpnnz; ++i )
4033  {
4034  QUAD_ARRAY_STORE(tmpcoefs, tmpinds[i], tmp);
4035  }
4036  }
4037 
4038  /* free temporary memory */
4039  SCIPfreeCleanBufferArray(scip, &tmpcoefs);
4040  SCIPfreeBufferArray(scip, &tmpinds);
4041  SCIPfreeBufferArray(scip, &boundtype);
4042  SCIPfreeBufferArray(scip, &varsign);
4043 
4044  return SCIP_OKAY;
4045 }
4046 
4047 /** compute the efficacy of the MIR cut for the given values without computing the cut.
4048  * This is used for the CMIR cut generation heuristic.
4049  */
4050 static
4052  SCIP* scip, /**< SCIP datastructure */
4053  SCIP_Real*RESTRICT coefs, /**< array with coefficients in row */
4054  SCIP_Real*RESTRICT solvals, /**< solution values of variables in the row */
4055  SCIP_Real rhs, /**< right hand side of MIR cut */
4056  SCIP_Real contactivity, /**< aggregated activity of continuous variables in the row */
4057  SCIP_Real contsqrnorm, /**< squared norm of continuous variables */
4058  SCIP_Real delta, /**< delta value to compute the violation for */
4059  int nvars, /**< number of variables in the row, i.e. the size of coefs and solvals arrays */
4060  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4061  SCIP_Real maxfrac /**< maximal fractionality of rhs to produce MIR cut for */
4062  )
4063 {
4064  int i;
4065  SCIP_Real f0pluseps;
4066  SCIP_Real f0;
4067  SCIP_Real onedivoneminusf0;
4068  SCIP_Real scale;
4069  SCIP_Real downrhs;
4070  SCIP_Real norm;
4071  SCIP_Real contscale;
4072 
4073  scale = 1.0 / delta;
4074  rhs *= scale;
4075  downrhs = SCIPfloor(scip, rhs);
4076  f0 = rhs - downrhs;
4077 
4078  if( f0 < minfrac || f0 > maxfrac )
4079  return 0.0;
4080 
4081  onedivoneminusf0 = 1.0 / (1.0 - f0);
4082 
4083  contscale = scale * onedivoneminusf0;
4084 
4085  /* We multiply the coefficients of the base inequality roughly by scale/(1-f0).
4086  * If this gives a scalar that is very big, we better do not generate this cut.
4087  */
4088  if( contscale > MAXCMIRSCALE )
4089  return 0.0;
4090 
4091  rhs = downrhs;
4092  rhs -= contscale * contactivity;
4093  norm = SQR(contscale) * contsqrnorm;
4094 
4095  assert(!SCIPisFeasZero(scip, f0));
4096  assert(!SCIPisFeasZero(scip, 1.0 - f0));
4097 
4098  f0pluseps = f0 + SCIPepsilon(scip);
4099 
4100  for( i = 0; i < nvars; ++i )
4101  {
4102  SCIP_Real floorai = floor(scale * coefs[i]);
4103  SCIP_Real fi = (scale * coefs[i]) - floorai;
4104 
4105  if( fi > f0pluseps )
4106  floorai += (fi - f0) * onedivoneminusf0;
4107 
4108  rhs -= solvals[i] * floorai;
4109  norm += SQR(floorai);
4110  }
4111 
4112  norm = SQRT(norm);
4113 
4114  return - rhs / MAX(norm, 1e-6);
4115 }
4116 
4117 /** calculates an MIR cut out of an aggregation of LP rows
4118  *
4119  * Given the aggregation, it is transformed to a mixed knapsack set via complementation (using bounds or variable bounds)
4120  * Then, different scalings of the mkset are used to generate a MIR and the best is chosen.
4121  * One of the steps of the MIR is to round the coefficients of the integer variables down,
4122  * so one would prefer to have integer coefficients for integer variables which are far away from their bounds in the
4123  * mkset.
4124  *
4125  * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4126  * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4127  *
4128  * @pre This method can be called if @p scip is in one of the following stages:
4129  * - \ref SCIP_STAGE_SOLVING
4130  *
4131  * See \ref SCIP_Stage "SCIP_STAGE" for a complete list of all possible solving stages.
4132  */
4134  SCIP* scip, /**< SCIP data structure */
4135  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
4136  SCIP_Bool postprocess, /**< apply a post-processing step to the resulting cut? */
4137  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
4138  SCIP_Bool usevbds, /**< should variable bounds be used in bound transformation? */
4139  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
4140  int maxtestdelta, /**< maximum number of deltas to test */
4141  int* boundsfortrans, /**< bounds that should be used for transformed variables: vlb_idx/vub_idx,
4142  * -1 for global lb/ub, -2 for local lb/ub, or -3 for using closest bound;
4143  * NULL for using closest bound for all variables */
4144  SCIP_BOUNDTYPE* boundtypesfortrans, /**< type of bounds that should be used for transformed variables;
4145  * NULL for using closest bound for all variables */
4146  SCIP_Real minfrac, /**< minimal fractionality of rhs to produce MIR cut for */
4147  SCIP_Real maxfrac, /**< maximal fractionality of rhs to produce MIR cut for */
4148  SCIP_AGGRROW* aggrrow, /**< aggrrow to compute MIR cut for */
4149  SCIP_Real* cutcoefs, /**< array to store the non-zero coefficients in the cut */
4150  SCIP_Real* cutrhs, /**< pointer to store the right hand side of the cut */
4151  int* cutinds, /**< array to store the problem indices of variables with a non-zero coefficient in the cut */
4152  int* cutnnz, /**< pointer to store the number of non-zeros in the cut */
4153  SCIP_Real* cutefficacy, /**< pointer to store efficacy of best cut; only cuts that are strictly better than the value of
4154  * this efficacy on input to this function are returned */
4155  int* cutrank, /**< pointer to return rank of generated cut (or NULL) */
4156  SCIP_Bool* cutislocal, /**< pointer to store whether the generated cut is only valid locally */
4157  SCIP_Bool* success /**< pointer to store whether a valid and efficacious cut was returned */
4158  )
4159 {
4160  int i;
4161  int firstcontvar;
4162  int nvars;
4163  int intstart;
4164  int ntmpcoefs;
4165  int* varsign;
4166  int* boundtype;
4167  int* mksetinds;
4168  SCIP_Real* mksetcoefs;
4169  SCIP_Real QUAD(mksetrhs);
4170  int mksetnnz;
4171  SCIP_Real* bounddist;
4172  int* bounddistpos;
4173  int nbounddist;
4174  SCIP_Real* tmpcoefs;
4175  SCIP_Real* tmpvalues;
4176  SCIP_Real* deltacands;
4177  int ndeltacands;
4178  SCIP_Real bestdelta;
4179  SCIP_Real bestefficacy;
4180  SCIP_Real maxabsmksetcoef;
4181  SCIP_VAR** vars;
4182  SCIP_Bool freevariable;
4183  SCIP_Bool localbdsused;
4184  SCIP_Real contactivity;
4185  SCIP_Real contsqrnorm;
4186 
4187  assert(aggrrow != NULL);
4188  assert(aggrrow->nrows + aggrrow->nnz >= 1);
4189  assert(success != NULL);
4190 
4191  *success = FALSE;
4192  nvars = SCIPgetNVars(scip);
4193  firstcontvar = nvars - SCIPgetNContVars(scip);
4194  vars = SCIPgetVars(scip);
4195 
4196  /* allocate temporary memory */
4197  SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) );
4198  SCIP_CALL( SCIPallocBufferArray(scip, &boundtype, nvars) );
4199  SCIP_CALL( SCIPallocCleanBufferArray(scip, &mksetcoefs, QUAD_ARRAY_SIZE(nvars)) );
4200  SCIP_CALL( SCIPallocBufferArray(scip, &mksetinds, nvars) );
4201  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, nvars + aggrrow->nrows) );
4202  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars + aggrrow->nrows) );
4203  SCIP_CALL( SCIPallocBufferArray(scip, &deltacands, aggrrow->nnz + 6) );
4204 
4205  /* we only compute bound distance for integer variables; we allocate an array of length aggrrow->nnz to store this, since
4206  * this is the largest number of integer variables. (in contrast to the number of total variables which can be 2 *
4207  * aggrrow->nnz variables: if all are continuous and we use variable bounds to completement, we introduce aggrrow->nnz
4208  * extra vars)
4209  */
4210  SCIP_CALL( SCIPallocBufferArray(scip, &bounddist, aggrrow->nnz) );
4211  SCIP_CALL( SCIPallocBufferArray(scip, &bounddistpos, aggrrow->nnz) );
4212 
4213  /* initialize mkset with aggregation */
4214  mksetnnz = aggrrow->nnz;
4215  QUAD_ASSIGN_Q(mksetrhs, aggrrow->rhs);
4216 
4217  BMScopyMemoryArray(mksetinds, aggrrow->inds, mksetnnz);
4218 
4219  for( i = 0; i < mksetnnz; ++i )
4220  {
4221  int j = mksetinds[i];
4222  SCIP_Real QUAD(coef);
4223  QUAD_ARRAY_LOAD(coef, aggrrow->vals, j);
4224  QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4225  assert(QUAD_HI(coef) != 0.0);
4226  }
4227 
4228  *cutislocal = aggrrow->local;
4229 
4230  /* Transform equation a*x == b, lb <= x <= ub into standard form
4231  * a'*x' == b, 0 <= x' <= ub'.
4232  *
4233  * Transform variables (lb or ub):
4234  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, if lb is used in transformation
4235  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, if ub is used in transformation
4236  * and move the constant terms "a_j * lb_j" or "a_j * ub_j" to the rhs.
4237  *
4238  * Transform variables (vlb or vub):
4239  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, if vlb is used in transf.
4240  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, if vub is used in transf.
4241  * move the constant terms "a_j * dl_j" or "a_j * du_j" to the rhs, and update the coefficient of the VLB variable:
4242  * a_{zl_j} := a_{zl_j} + a_j * bl_j, or
4243  * a_{zu_j} := a_{zu_j} + a_j * bu_j
4244  */
4245  SCIP_CALL( cutsTransformMIR(scip, sol, boundswitch, usevbds, allowlocal, FALSE, FALSE,
4246  boundsfortrans, boundtypesfortrans, minfrac, maxfrac, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, &freevariable, &localbdsused) );
4247 
4248  assert(allowlocal || !localbdsused);
4249 
4250  if( freevariable )
4251  goto TERMINATE;
4252 
4253  SCIPdebugMessage("transformed aggrrow row:\n");
4254  SCIPdebug( printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE) );
4255 
4256  /* found positions of integral variables that are strictly between their bounds */
4257  maxabsmksetcoef = -1.0;
4258  nbounddist = 0;
4259 
4260  for( i = mksetnnz - 1; i >= 0 && mksetinds[i] < firstcontvar; --i )
4261  {
4262  SCIP_VAR* var = vars[mksetinds[i]];
4263  SCIP_Real primsol = SCIPgetSolVal(scip, sol, var);
4264  SCIP_Real lb = SCIPvarGetLbLocal(var);
4265  SCIP_Real ub = SCIPvarGetUbLocal(var);
4266  SCIP_Real QUAD(coef);
4267 
4268  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4269 
4270  if( SCIPisEQ(scip, primsol, lb) || SCIPisEQ(scip, primsol, ub) )
4271  continue;
4272 
4273  bounddist[nbounddist] = MIN(ub - primsol, primsol - lb);
4274  bounddistpos[nbounddist] = i;
4275  deltacands[nbounddist] = QUAD_TO_DBL(coef);
4276  ++nbounddist;
4277  }
4278 
4279  /* no fractional variable; so abort here */
4280  if( nbounddist == 0 )
4281  goto TERMINATE;
4282 
4283  intstart = i + 1;
4284  ndeltacands = nbounddist;
4285 
4286  SCIPsortDownRealRealInt(bounddist, deltacands, bounddistpos, nbounddist);
4287 
4288  {
4289  SCIP_Real intscale;
4290  SCIP_Bool intscalesuccess;
4291 
4292  SCIP_CALL( SCIPcalcIntegralScalar(deltacands, nbounddist, -QUAD_EPSILON, SCIPsumepsilon(scip), (SCIP_Longint)10000, 10000.0, &intscale, &intscalesuccess) );
4293 
4294  if( intscalesuccess )
4295  {
4296  SCIP_Real intf0;
4297  SCIP_Real intscalerhs;
4298  SCIP_Real delta;
4299 
4300  intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4301  delta = 1.0 / intscale;
4302  intf0 = intscalerhs - floor(intscalerhs);
4303 
4304  if( ! SCIPisFeasIntegral(scip, intf0) )
4305  {
4306  if( intf0 < minfrac || intf0 > maxfrac )
4307  {
4308  intscale *= ceil(MAX(minfrac, (1.0 - maxfrac)) / MIN(intf0, (1.0 - intf0)));
4309  intscalerhs = QUAD_TO_DBL(mksetrhs) * intscale;
4310  delta = 1.0 / intscale;
4311  intf0 = intscalerhs - floor(intscalerhs);
4312  }
4313 
4314  if( intf0 >= minfrac && intf0 <= maxfrac )
4315  {
4316  if( ! SCIPisEQ(scip, delta, 1.0) )
4317  deltacands[ndeltacands++] = delta;
4318 
4319  if( intf0 < maxfrac )
4320  {
4321  SCIP_Real delta2;
4322 
4323  delta2 = 1.0 / (intscale * floor(maxfrac / intf0));
4324 
4325  if( ! SCIPisEQ(scip, delta, delta2) && ! SCIPisEQ(scip, delta2, 1.0) )
4326  deltacands[ndeltacands++] = delta2;
4327  }
4328  }
4329  }
4330  }
4331  }
4332 
4333  for( i = 0; i < nbounddist; ++i )
4334  {
4335  SCIP_Real absmksetcoef;
4336 
4337  absmksetcoef = REALABS(deltacands[i]);
4338  maxabsmksetcoef = MAX(absmksetcoef, maxabsmksetcoef);
4339 
4340  deltacands[i] = absmksetcoef;
4341  }
4342 
4343  /* also test 1.0 and maxabsmksetcoef + 1.0 as last delta values */
4344  if( maxabsmksetcoef != -1.0 )
4345  deltacands[ndeltacands++] = maxabsmksetcoef + 1.0;
4346 
4347  deltacands[ndeltacands++] = 1.0;
4348 
4349  maxtestdelta = MIN(ndeltacands, maxtestdelta);
4350 
4351  /* For each delta
4352  * Calculate fractionalities f_0 := b - down(b), f_j := a'_j - down(a'_j) , and derive MIR cut
4353  * a~*x' <= down(b)
4354  * integers : a~_j = down(a'_j) , if f_j <= f_0
4355  * a~_j = down(a'_j) + (f_j - f0)/(1 - f0), if f_j > f_0
4356  * continuous: a~_j = 0 , if a'_j >= 0
4357  * a~_j = a'_j/(1 - f0) , if a'_j < 0
4358  *
4359  * Transform inequality back to a^*x <= rhs:
4360  *
4361  * (lb or ub):
4362  * x'_j := x_j - lb_j, x_j == x'_j + lb_j, a'_j == a_j, a^_j := a~_j, if lb was used in transformation
4363  * x'_j := ub_j - x_j, x_j == ub_j - x'_j, a'_j == -a_j, a^_j := -a~_j, if ub was used in transformation
4364  * and move the constant terms
4365  * -a~_j * lb_j == -a^_j * lb_j, or
4366  * a~_j * ub_j == -a^_j * ub_j
4367  * to the rhs.
4368  *
4369  * (vlb or vub):
4370  * x'_j := x_j - (bl_j * zl_j + dl_j), x_j == x'_j + (bl_j * zl_j + dl_j), a'_j == a_j, a^_j := a~_j, (vlb)
4371  * x'_j := (bu_j * zu_j + du_j) - x_j, x_j == (bu_j * zu_j + du_j) - x'_j, a'_j == -a_j, a^_j := -a~_j, (vub)
4372  * move the constant terms
4373  * -a~_j * dl_j == -a^_j * dl_j, or
4374  * a~_j * du_j == -a^_j * du_j
4375  * to the rhs, and update the VB variable coefficients:
4376  * a^_{zl_j} := a^_{zl_j} - a~_j * bl_j == a^_{zl_j} - a^_j * bl_j, or
4377  * a^_{zu_j} := a^_{zu_j} + a~_j * bu_j == a^_{zu_j} - a^_j * bu_j
4378  */
4379 
4380  ntmpcoefs = 0;
4381  for( i = intstart; i < mksetnnz; ++i )
4382  {
4383  SCIP_VAR* var;
4384  SCIP_Real solval;
4385  SCIP_Real QUAD(coef);
4386 
4387  var = vars[mksetinds[i]];
4388 
4389  /* get the soltion value of the continuous variable */
4390  solval = SCIPgetSolVal(scip, sol, var);
4391 
4392  /* now compute the solution value in the transform space considering complementation */
4393  if( boundtype[i] == -1 )
4394  {
4395  /* variable was complemented with global (simple) bound */
4396  if( varsign[i] == -1 )
4397  solval = SCIPvarGetUbGlobal(var) - solval;
4398  else
4399  solval = solval - SCIPvarGetLbGlobal(var);
4400  }
4401  else
4402  {
4403  assert(boundtype[i] == -2);
4404 
4405  /* variable was complemented with local (simple) bound */
4406  if( varsign[i] == -1 )
4407  solval = SCIPvarGetUbLocal(var) - solval;
4408  else
4409  solval = solval - SCIPvarGetLbLocal(var);
4410  }
4411 
4412  tmpvalues[ntmpcoefs] = solval;
4413  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4414  tmpcoefs[ntmpcoefs] = varsign[i] * QUAD_TO_DBL(coef);
4415  ++ntmpcoefs;
4416  }
4417 
4418  assert(ntmpcoefs == mksetnnz - intstart);
4419 
4420  contactivity = 0.0;
4421  contsqrnorm = 0.0;
4422  for( i = 0; i < intstart; ++i )
4423  {
4424  SCIP_Real solval;
4425  SCIP_Real QUAD(mksetcoef);
4426 
4427  QUAD_ARRAY_LOAD(mksetcoef, mksetcoefs, mksetinds[i]);
4428 
4429  if( varsign[i] * QUAD_TO_DBL(mksetcoef) >= 0.0 )
4430  continue;
4431 
4432  /* get the soltion value of the continuous variable */
4433  solval = SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4434 
4435  /* now compute the solution value in the transform space considering complementation */
4436  switch( boundtype[i] )
4437  {
4438  case -1:
4439  /* variable was complemented with global (simple) bound */
4440  if( varsign[i] == -1 )
4441  solval = SCIPvarGetUbGlobal(vars[mksetinds[i]]) - solval;
4442  else
4443  solval = solval - SCIPvarGetLbGlobal(vars[mksetinds[i]]);
4444  break;
4445  case -2:
4446  /* variable was complemented with local (simple) bound */
4447  if( varsign[i] == -1 )
4448  solval = SCIPvarGetUbLocal(vars[mksetinds[i]]) - solval;
4449  else
4450  solval = solval - SCIPvarGetLbLocal(vars[mksetinds[i]]);
4451  break;
4452  default:
4453  /* variable was complemented with a variable bound */
4454  if( varsign[i] == -1 )
4455  {
4456  SCIP_Real coef;
4457  SCIP_Real constant;
4458  SCIP_Real vbdsolval;
4459 
4460  coef = SCIPvarGetVubCoefs(vars[mksetinds[i]])[boundtype[i]];
4461  constant = SCIPvarGetVubConstants(vars[mksetinds[i]])[boundtype[i]];
4462  vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVubVars(vars[mksetinds[i]])[boundtype[i]]);
4463 
4464  solval = (coef * vbdsolval + constant) - solval;
4465  }
4466  else
4467  {
4468  SCIP_Real coef;
4469  SCIP_Real constant;
4470  SCIP_Real vbdsolval;
4471 
4472  coef = SCIPvarGetVlbCoefs(vars[mksetinds[i]])[boundtype[i]];
4473  constant = SCIPvarGetVlbConstants(vars[mksetinds[i]])[boundtype[i]];
4474  vbdsolval = SCIPgetSolVal(scip, sol, SCIPvarGetVlbVars(vars[mksetinds[i]])[boundtype[i]]);
4475 
4476  solval = solval - (coef * vbdsolval + constant);
4477  }
4478  }
4479 
4480  contactivity += solval * (QUAD_TO_DBL(mksetcoef) * varsign[i]);
4481  contsqrnorm += QUAD_TO_DBL(mksetcoef) * QUAD_TO_DBL(mksetcoef);
4482  }
4483 
4484  {
4485  SCIP_ROW** rows;
4486 
4487  rows = SCIPgetLPRows(scip);
4488 
4489  for( i = 0; i < aggrrow->nrows; ++i )
4490  {
4491  SCIP_ROW* row;
4492  SCIP_Real slackval;
4493 
4494  row = rows[aggrrow->rowsinds[i]];
4495 
4496  if( (aggrrow->rowweights[i] * aggrrow->slacksign[i]) >= 0.0 && !row->integral )
4497  continue;
4498 
4499  /* compute solution value of slack variable */
4500  slackval = SCIPgetRowSolActivity(scip, row, sol);
4501 
4502  if( aggrrow->slacksign[i] == +1 )
4503  {
4504  /* right hand side */
4505  assert(!SCIPisInfinity(scip, row->rhs));
4506 
4507  slackval = row->rhs - slackval;
4508  }
4509  else
4510  {
4511  /* left hand side */
4512  assert(aggrrow->slacksign[i] == -1);
4513  assert(!SCIPisInfinity(scip, -row->lhs));
4514 
4515  slackval = slackval - row->lhs;
4516  }
4517 
4518  if( row->integral )
4519  {
4520  /* if row is integral add variable to tmp arrays */
4521  tmpvalues[ntmpcoefs] = slackval;
4522  tmpcoefs[ntmpcoefs] = aggrrow->rowweights[i] * aggrrow->slacksign[i];
4523  ++ntmpcoefs;
4524  }
4525  else
4526  {
4527  SCIP_Real slackcoeff = (aggrrow->rowweights[i] * aggrrow->slacksign[i]);
4528 
4529  /* otherwise add it to continuous activity */
4530  contactivity += slackval * slackcoeff;
4531  contsqrnorm += SQR(slackcoeff);
4532  }
4533  }
4534  }
4535 
4536  /* try all candidates for delta and remember best */
4537  bestdelta = SCIP_INVALID;
4538  bestefficacy = -SCIPinfinity(scip);
4539 
4540  for( i = 0; i < maxtestdelta; ++i )
4541  {
4542  int j;
4543  SCIP_Real efficacy;
4544 
4545  /* check if we have seen this value of delta before */
4546  SCIP_Bool deltaseenbefore = FALSE;
4547  for( j = 0; j < i; ++j )
4548  {
4549  if( SCIPisEQ(scip, deltacands[i], deltacands[j]) )
4550  {
4551  deltaseenbefore = TRUE;
4552  break;
4553  }
4554  }
4555 
4556  /* skip this delta value and allow one more delta value if available */
4557  if( deltaseenbefore )
4558  {
4559  maxtestdelta = MIN(maxtestdelta + 1, ndeltacands);
4560  continue;
4561  }
4562 
4563  efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, deltacands[i], ntmpcoefs, minfrac, maxfrac);
4564 
4565  if( efficacy > bestefficacy )
4566  {
4567  bestefficacy = efficacy;
4568  bestdelta = deltacands[i];
4569  }
4570  }
4571 
4572  /* no delta was found that yielded any cut */
4573  if( bestdelta == SCIP_INVALID ) /*lint !e777*/
4574  goto TERMINATE;
4575 
4576  /* try bestdelta divided by 2, 4 and 8 */
4577  {
4578  SCIP_Real basedelta = bestdelta;
4579  for( i = 2; i <= 8 ; i *= 2 )
4580  {
4581  SCIP_Real efficacy;
4582  SCIP_Real delta;
4583 
4584  delta = basedelta / i;
4585 
4586  efficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(mksetrhs), contactivity, contsqrnorm, delta, ntmpcoefs, minfrac, maxfrac);
4587 
4588  if( efficacy > bestefficacy )
4589  {
4590  bestefficacy = efficacy;
4591  bestdelta = delta;
4592  }
4593  }
4594  }
4595 
4596  /* try to improve efficacy by switching complementation of integral variables that are not at their bounds
4597  * in order of non-increasing bound distance
4598  */
4599  for( i = 0; i < nbounddist; ++i )
4600  {
4601  int k;
4602  SCIP_Real newefficacy;
4603  SCIP_Real QUAD(newrhs);
4604  SCIP_Real bestlb;
4605  SCIP_Real bestub;
4606  SCIP_Real oldsolval;
4607  SCIP_Real simplebnd;
4608  int bestlbtype;
4609  int bestubtype;
4610 
4611  k = bounddistpos[i];
4612 
4613  SCIP_CALL( findBestLb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestlb, &simplebnd, &bestlbtype) );
4614 
4615  if( SCIPisInfinity(scip, -bestlb) )
4616  continue;
4617 
4618  SCIP_CALL( findBestUb(scip, vars[mksetinds[k]], sol, 0, allowlocal, &bestub, &simplebnd, &bestubtype) );
4619 
4620  if( SCIPisInfinity(scip, bestub) )
4621  continue;
4622 
4623  /* switch the complementation of this variable */
4624 #ifndef NDEBUG
4625  {
4626  SCIP_Real QUAD(coef);
4627  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[k]);
4628  assert(SCIPisEQ(scip, tmpcoefs[k - intstart], varsign[k] * QUAD_TO_DBL(coef)));
4629  }
4630 #endif
4631 
4632  /* compute this: newrhs = mksetrhs + tmpcoefs[k - intstart] * (bestlb - bestub); */
4633  SCIPquadprecSumQD(newrhs, mksetrhs, tmpcoefs[k - intstart] * (bestlb - bestub));
4634  tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4635 
4636  oldsolval = tmpvalues[k - intstart];
4637  tmpvalues[k - intstart] = varsign[k] == +1 ? bestub - SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) : SCIPgetSolVal(scip, sol, vars[mksetinds[k]]) - bestlb;
4638 
4639  /* compute new violation */
4640  newefficacy = computeMIREfficacy(scip, tmpcoefs, tmpvalues, QUAD_TO_DBL(newrhs), contactivity, contsqrnorm, bestdelta, ntmpcoefs, minfrac, maxfrac);
4641 
4642  /* check if violaton was increased */
4643  if( newefficacy > bestefficacy )
4644  {
4645  /* keep change of complementation */
4646  bestefficacy = newefficacy;
4647  QUAD_ASSIGN_Q(mksetrhs, newrhs);
4648 
4649  if( varsign[k] == +1 )
4650  {
4651  /* switch to upper bound */
4652  assert(bestubtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4653  boundtype[k] = bestubtype;
4654  varsign[k] = -1;
4655  }
4656  else
4657  {
4658  /* switch to lower bound */
4659  assert(bestlbtype < 0); /* cannot switch to a variable bound (would lead to further coef updates) */
4660  boundtype[k] = bestlbtype;
4661  varsign[k] = +1;
4662  }
4663 
4664  localbdsused = localbdsused || (boundtype[k] == -2);
4665  }
4666  else
4667  {
4668  /* undo the change of the complementation */
4669  tmpcoefs[k - intstart] = -tmpcoefs[k - intstart];
4670  tmpvalues[k - intstart] = oldsolval;
4671  }
4672  } /*lint !e438*/
4673 
4674  if( bestefficacy > 0.0 )
4675  {
4676  SCIP_Real mirefficacy;
4677  SCIP_Real QUAD(downrhs);
4678  SCIP_Real QUAD(f0);
4679  SCIP_Real scale;
4680 
4681  scale = 1.0 / bestdelta;
4682  SCIPquadprecProdQD(mksetrhs, mksetrhs, scale);
4683 
4684  SCIPquadprecEpsFloorQ(downrhs, mksetrhs, SCIPepsilon(scip)); /*lint !e666*/
4685  SCIPquadprecSumQQ(f0, mksetrhs, -downrhs);
4686 
4687  /* renormaliize f0 value */
4688  SCIPquadprecSumDD(f0, QUAD_HI(f0), QUAD_LO(f0));
4689 
4690  for( i = 0; i < mksetnnz; ++i )
4691  {
4692  SCIP_Real QUAD(coef);
4693 
4694  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4695  SCIPquadprecProdQD(coef, coef, scale);
4696  QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], coef);
4697  }
4698  SCIPdebugMessage("applied best scale (=%.13g):\n", scale);
4699  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4700 
4701  QUAD_ASSIGN_Q(mksetrhs, downrhs);
4702 
4703  SCIP_CALL( cutsRoundMIR(scip, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, varsign, boundtype, QUAD(f0)) );
4704 
4705  SCIPdebugMessage("rounded MIR cut:\n");
4706  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4707 
4708  /* substitute aggregated slack variables:
4709  *
4710  * The coefficient of the slack variable s_r is equal to the row's weight times the slack's sign, because the slack
4711  * variable only appears in its own row:
4712  * a'_r = scale * weight[r] * slacksign[r].
4713  *
4714  * Depending on the slacks type (integral or continuous), its coefficient in the cut calculates as follows:
4715  * integers : a^_r = a~_r = down(a'_r) , if f_r <= f0
4716  * a^_r = a~_r = down(a'_r) + (f_r - f0)/(1 - f0), if f_r > f0
4717  * continuous: a^_r = a~_r = 0 , if a'_r >= 0
4718  * a^_r = a~_r = a'_r/(1 - f0) , if a'_r < 0
4719  *
4720  * Substitute a^_r * s_r by adding a^_r times the slack's definition to the cut.
4721  */
4722  SCIP_CALL( cutsSubstituteMIR(scip, aggrrow->rowweights, aggrrow->slacksign, aggrrow->rowsinds,
4723  aggrrow->nrows, scale, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz, QUAD(f0)) );
4724 
4725  SCIPdebugMessage("substituted slacks in MIR cut:\n");
4726  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4727 
4728 #ifndef NDEBUG
4729  {
4730  SCIP_Real efficacy = -QUAD_TO_DBL(mksetrhs);
4731  for( i = 0; i < mksetnnz; ++i )
4732  {
4733  SCIP_Real QUAD(coef);
4734  QUAD_ARRAY_LOAD(coef, mksetcoefs, mksetinds[i]);
4735  efficacy += QUAD_TO_DBL(coef) * SCIPgetSolVal(scip, sol, vars[mksetinds[i]]);
4736  }
4737 
4738  if( !EPSZ(SCIPrelDiff(efficacy, bestefficacy), 1e-4) )
4739  {
4740  SCIPdebugMessage("efficacy of cmir cut is different than expected efficacy: %f != %f\n", efficacy, bestefficacy);
4741  }
4742  }
4743 #endif
4744 
4745  *cutislocal = *cutislocal || localbdsused;
4746 
4747  /* remove all nearly-zero coefficients from MIR row and relax the right hand side correspondingly in order to
4748  * prevent numerical rounding errors
4749  */
4750  if( postprocess )
4751  {
4752  SCIP_CALL( postprocessCutQuad(scip, *cutislocal, mksetinds, mksetcoefs, &mksetnnz, QUAD(&mksetrhs), success) );
4753  }
4754  else
4755  {
4756  *success = ! removeZerosQuad(scip, SCIPsumepsilon(scip), *cutislocal, mksetcoefs, QUAD(&mksetrhs), mksetinds, &mksetnnz);
4757  }
4758 
4759  SCIPdebugMessage("post-processed cut (success = %s):\n", *success ? "TRUE" : "FALSE");
4760  SCIPdebug(printCutQuad(scip, sol, mksetcoefs, QUAD(mksetrhs), mksetinds, mksetnnz, FALSE, FALSE));
4761 
4762  if( *success )
4763  {
4764  mirefficacy = calcEfficacyDenseStorageQuad(scip, sol, mksetcoefs, QUAD_TO_DBL(mksetrhs), mksetinds, mksetnnz);
4765 
4766  if( SCIPisEfficacious(scip, mirefficacy) && mirefficacy > *cutefficacy )
4767  {
4768  BMScopyMemoryArray(cutinds, mksetinds, mksetnnz);
4769  for( i = 0; i < mksetnnz; ++i )
4770  {
4771  SCIP_Real QUAD(coef);
4772  int j = cutinds[i];
4773 
4774  QUAD_ARRAY_LOAD(coef, mksetcoefs, j);
4775 
4776  cutcoefs[i] = QUAD_TO_DBL(coef);
4777  QUAD_ASSIGN(coef, 0.0);
4778  QUAD_ARRAY_STORE(mksetcoefs, j, coef);
4779  }
4780  *cutnnz = mksetnnz;
4781  *cutrhs = QUAD_TO_DBL(mksetrhs);
4782  *cutefficacy = mirefficacy;
4783  if( cutrank != NULL )
4784  *cutrank = aggrrow->rank + 1;
4785  *cutislocal = *cutislocal || localbdsused;
4786  }
4787  else
4788  *success = FALSE;
4789  }
4790  }
4791 
4792  TERMINATE:
4793  /* if we aborted early we need to clean the mksetcoefs */
4794  if( !(*success) )
4795  {
4796  SCIP_Real QUAD(tmp);
4797  QUAD_ASSIGN(tmp, 0.0);
4798 
4799  for( i = 0; i < mksetnnz; ++i )
4800  {
4801  QUAD_ARRAY_STORE(mksetcoefs, mksetinds[i], tmp);
4802  }
4803  }
4804 
4805  /* free temporary memory */
4806  SCIPfreeBufferArray(scip, &bounddistpos);
4807  SCIPfreeBufferArray(scip, &bounddist);
4808  SCIPfreeBufferArray(scip, &deltacands);
4809  SCIPfreeBufferArray(scip, &tmpvalues);
4810  SCIPfreeBufferArray(scip, &tmpcoefs);
4811  SCIPfreeBufferArray(scip, &mksetinds);
4812  SCIPfreeCleanBufferArray(scip, &mksetcoefs);
4813  SCIPfreeBufferArray(scip, &boundtype);
4814  SCIPfreeBufferArray(scip, &varsign);
4815 
4816  return SCIP_OKAY;
4817 }
4818 
4819 /* =========================================== flow cover =========================================== */
4820 
4821 #define NO_EXACT_KNAPSACK
4822 
4823 #ifndef NO_EXACT_KNAPSACK
4824 #define MAXDNOM 1000LL
4825 #define MINDELTA 1e-03
4826 #define MAXDELTA 1e-09
4827 #define MAXSCALE 1000.0
4828 #define MAXDYNPROGSPACE 1000000
4829 #endif
4830 
4831 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for snf relaxation */
4832 #define MAXBOUND 1e+10 /**< maximal value of normal bounds used for snf relaxation */
4833 
4834 /** structure that contains all data required to perform the sequence independent lifting
4835  */
4836 typedef
4837 struct LiftingData
4838 {
4839  SCIP_Real* M; /**< \f$ M_0 := 0.0 \f$ and \f$ M_i := M_i-1 + m_i \f$ */
4840  SCIP_Real* m; /**< non-increasing array of variable upper bound coefficients
4841  * for all variables in \f$ C^{++} \f$ and \f$ L^- \f$,
4842  * where \f$ C = C^+ \cup C^- \f$ is the flowcover and
4843  * \f$ C^{++} := \{ j \in C^+ \mid u_j > \lambda \} \f$
4844  * \f$ L^- := \{ j \in (N^- \setminus C^-) \mid u_j > \lambda \} \f$
4845  */
4846  int r; /**< size of array m */
4847  int t; /**< index of smallest value in m that comes from a variable in \f$ C^{++} \f$ */
4848  SCIP_Real d1; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in C^- \f$ */
4849  SCIP_Real d2; /**< right hand side of single-node-flow set plus the sum of all \f$ u_j \f$ for \f$ j \in N^- \f$ */
4850  SCIP_Real lambda; /**< excess of the flowcover */
4851  SCIP_Real mp; /**< smallest variable bound coefficient of variable in \f$ C^{++} (min_{j \in C++} u_j) \f$ */
4852  SCIP_Real ml; /**< \f$ ml := min(\lambda, \sum_{j \in C^+ \setminus C^{++}} u_j) \f$ */
4853 } LIFTINGDATA;
4854 
4855 /** structure that contains all the data that defines the single-node-flow relaxation of an aggregation row */
4856 typedef
4857 struct SNF_Relaxation
4858 {
4859  int* transvarcoefs; /**< coefficients of all vars in relaxed set */
4860  SCIP_Real* transbinvarsolvals; /**< sol val of bin var in vub of all vars in relaxed set */
4861  SCIP_Real* transcontvarsolvals;/**< sol val of all real vars in relaxed set */
4862  SCIP_Real* transvarvubcoefs; /**< coefficient in vub of all vars in relaxed set */
4863  int ntransvars; /**< number of vars in relaxed set */
4864  SCIP_Real transrhs; /**< rhs in relaxed set */
4865  int* origbinvars; /**< associated original binary var for all vars in relaxed set */
4866  int* origcontvars; /**< associated original continuous var for all vars in relaxed set */
4867  SCIP_Real* aggrcoefsbin; /**< aggregation coefficient of the original binary var used to define the
4868  * continuous variable in the relaxed set */
4869  SCIP_Real* aggrcoefscont; /**< aggregation coefficient of the original continuous var used to define the
4870  * continuous variable in the relaxed set */
4871  SCIP_Real* aggrconstants; /**< aggregation constant used to define the continuous variable in the relaxed set */
4872 } SNF_RELAXATION;
4873 
4874 /** get solution value and index of variable lower bound (with binary variable) which is closest to the current LP
4875  * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
4876  * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
4877  * given variable
4878  */
4879 static
4881  SCIP* scip, /**< SCIP data structure */
4882  SCIP_VAR* var, /**< given active problem variable */
4883  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
4884  SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
4885  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
4886  * was not used (0) or was not used but is contained in the row (-1)
4887  */
4888  SCIP_Real bestsub, /**< closest simple upper bound of given variable */
4889  SCIP_Real rowcoef, /**< coefficient of given variable in current row */
4890  SCIP_Real* closestvlb, /**< pointer to store the LP sol value of the closest variable lower bound */
4891  int* closestvlbidx /**< pointer to store the index of the closest vlb; -1 if no vlb was found */
4892  )
4893 {
4894  int nvlbs;
4895  int nbinvars;
4896 
4897  assert(scip != NULL);
4898  assert(var != NULL);
4899  assert(bestsub == SCIPvarGetUbGlobal(var) || bestsub == SCIPvarGetUbLocal(var)); /*lint !e777*/
4900  assert(!SCIPisInfinity(scip, bestsub));
4901  assert(!EPSZ(rowcoef, QUAD_EPSILON));
4902  assert(rowcoefs != NULL);
4903  assert(binvarused != NULL);
4904  assert(closestvlb != NULL);
4905  assert(closestvlbidx != NULL);
4906 
4907  nvlbs = SCIPvarGetNVlbs(var);
4908  nbinvars = SCIPgetNBinVars(scip);
4909 
4910  *closestvlbidx = -1;
4911  *closestvlb = -SCIPinfinity(scip);
4912  if( nvlbs > 0 )
4913  {
4914  SCIP_VAR** vlbvars;
4915  SCIP_Real* vlbcoefs;
4916  SCIP_Real* vlbconsts;
4917  int i;
4918 
4919  vlbvars = SCIPvarGetVlbVars(var);
4920  vlbcoefs = SCIPvarGetVlbCoefs(var);
4921  vlbconsts = SCIPvarGetVlbConstants(var);
4922 
4923  for( i = 0; i < nvlbs; i++ )
4924  {
4925  SCIP_Real rowcoefbinvar;
4926  SCIP_Real val1;
4927  SCIP_Real val2;
4928  SCIP_Real vlbsol;
4929  SCIP_Real rowcoefsign;
4930  int probidxbinvar;
4931 
4932  if( bestsub > vlbconsts[i] )
4933  continue;
4934 
4935  /* for numerical reasons, ignore variable bounds with large absolute coefficient and
4936  * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
4937  */
4938  if( REALABS(vlbcoefs[i]) > MAXABSVBCOEF )
4939  continue;
4940 
4941  /* use only variable lower bounds l~_i * x_i + d_i with x_i binary which are active */
4942  probidxbinvar = SCIPvarGetProbindex(vlbvars[i]);
4943 
4944  /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
4945  * ensures that the problem index is between 0 and nbinvars - 1
4946  */
4947  if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
4948  continue;
4949 
4950  assert(SCIPvarIsBinary(vlbvars[i]));
4951 
4952  /* check if current variable lower bound l~_i * x_i + d_i imposed on y_j meets the following criteria:
4953  * (let a_j = coefficient of y_j in current row,
4954  * u_j = closest simple upper bound imposed on y_j,
4955  * c_i = coefficient of x_i in current row)
4956  * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k yet
4957  * if a_j > 0:
4958  * 1. u_j <= d_i
4959  * 2. a_j ( u_j - d_i ) + c_i <= 0
4960  * 3. a_j l~_i + c_i <= 0
4961  * if a_j < 0:
4962  * 1. u_j <= d_i
4963  * 2. a_j ( u_j - d_i ) + c_i >= 0
4964  * 3. a_j l~_i + c_i >= 0
4965  */
4966 
4967  /* has already been used in the SNF relaxation */
4968  if( binvarused[probidxbinvar] == 1 )
4969  continue;
4970 
4971  /* get the row coefficient */
4972  {
4973  SCIP_Real QUAD(tmp);
4974  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
4975  rowcoefbinvar = QUAD_TO_DBL(tmp);
4976  }
4977  rowcoefsign = COPYSIGN(1.0, rowcoef);
4978 
4979  val2 = rowcoefsign * ((rowcoef * vlbcoefs[i]) + rowcoefbinvar);
4980 
4981  /* variable lower bound does not meet criteria */
4982  if( val2 > 0.0 || SCIPisInfinity(scip, -val2) )
4983  continue;
4984 
4985  val1 = rowcoefsign * ((rowcoef * (bestsub - vlbconsts[i])) + rowcoefbinvar);
4986 
4987  /* variable lower bound does not meet criteria */
4988  if( val1 > 0.0 )
4989  continue;
4990 
4991  vlbsol = vlbcoefs[i] * SCIPgetSolVal(scip, sol, vlbvars[i]) + vlbconsts[i];
4992  if( vlbsol > *closestvlb )
4993  {
4994  *closestvlb = vlbsol;
4995  *closestvlbidx = i;
4996  }
4997  assert(*closestvlbidx >= 0);
4998  }
4999  }
5000 
5001  return SCIP_OKAY;
5002 }
5003 
5004 /** get LP solution value and index of variable upper bound (with binary variable) which is closest to the current LP
5005  * solution value of a given variable; candidates have to meet certain criteria in order to ensure the nonnegativity
5006  * of the variable upper bound imposed on the real variable in the 0-1 single node flow relaxation associated with the
5007  * given variable
5008  */
5009 static
5011  SCIP* scip, /**< SCIP data structure */
5012  SCIP_VAR* var, /**< given active problem variable */
5013  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5014  SCIP_Real* rowcoefs, /**< (dense) array of coefficients of row */
5015  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5016  * was not used (0) or was not used but is contained in the row (-1)
5017  */
5018  SCIP_Real bestslb, /**< closest simple lower bound of given variable */
5019  SCIP_Real rowcoef, /**< coefficient of given variable in current row */
5020  SCIP_Real* closestvub, /**< pointer to store the LP sol value of the closest variable upper bound */
5021  int* closestvubidx /**< pointer to store the index of the closest vub; -1 if no vub was found */
5022  )
5023 {
5024  int nvubs;
5025  int nbinvars;
5026 
5027  assert(scip != NULL);
5028  assert(var != NULL);
5029  assert(bestslb == SCIPvarGetLbGlobal(var) || bestslb == SCIPvarGetLbLocal(var)); /*lint !e777*/
5030  assert(!SCIPisInfinity(scip, - bestslb));
5031  assert(!EPSZ(rowcoef, QUAD_EPSILON));
5032  assert(rowcoefs != NULL);
5033  assert(binvarused != NULL);
5034  assert(closestvub != NULL);
5035  assert(closestvubidx != NULL);
5036 
5037  nvubs = SCIPvarGetNVubs(var);
5038  nbinvars = SCIPgetNBinVars(scip);
5039 
5040  *closestvubidx = -1;
5041  *closestvub = SCIPinfinity(scip);
5042  if( nvubs > 0 )
5043  {
5044  SCIP_VAR** vubvars;
5045  SCIP_Real* vubcoefs;
5046  SCIP_Real* vubconsts;
5047  int i;
5048 
5049  vubvars = SCIPvarGetVubVars(var);
5050  vubcoefs = SCIPvarGetVubCoefs(var);
5051  vubconsts = SCIPvarGetVubConstants(var);
5052 
5053  for( i = 0; i < nvubs; i++ )
5054  {
5055  SCIP_Real rowcoefbinvar;
5056  SCIP_Real val1;
5057  SCIP_Real val2;
5058  SCIP_Real vubsol;
5059  SCIP_Real rowcoefsign;
5060  int probidxbinvar;
5061 
5062  if( bestslb < vubconsts[i] )
5063  continue;
5064 
5065  /* for numerical reasons, ignore variable bounds with large absolute coefficient and
5066  * those which lead to an infinite variable bound coefficient (val2) in snf relaxation
5067  */
5068  if( REALABS(vubcoefs[i]) > MAXABSVBCOEF )
5069  continue;
5070 
5071  /* use only variable upper bound u~_i * x_i + d_i with x_i binary and which are active */
5072  probidxbinvar = SCIPvarGetProbindex(vubvars[i]);
5073 
5074  /* if the variable is not active the problem index is -1, so we cast to unsigned int before the comparison which
5075  * ensures that the problem index is between 0 and nbinvars - 1
5076  */
5077  if( (unsigned int)probidxbinvar >= (unsigned int)nbinvars )
5078  continue;
5079 
5080  assert(SCIPvarIsBinary(vubvars[i]));
5081 
5082  /* checks if current variable upper bound u~_i * x_i + d_i meets the following criteria
5083  * (let a_j = coefficient of y_j in current row,
5084  * l_j = closest simple lower bound imposed on y_j,
5085  * c_i = coefficient of x_i in current row)
5086  * 0. no other non-binary variable y_k has used a variable bound with x_i to get transformed variable y'_k
5087  * if a > 0:
5088  * 1. l_j >= d_i
5089  * 2. a_j ( l_i - d_i ) + c_i >= 0
5090  * 3. a_j u~_i + c_i >= 0
5091  * if a < 0:
5092  * 1. l_j >= d_i
5093  * 2. a_j ( l_j - d_i ) + c_i <= 0
5094  * 3. a_j u~_i + c_i <= 0
5095  */
5096 
5097  /* has already been used in the SNF relaxation */
5098  if( binvarused[probidxbinvar] == 1 )
5099  continue;
5100 
5101  /* get the row coefficient */
5102  {
5103  SCIP_Real QUAD(tmp);
5104  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidxbinvar);
5105  rowcoefbinvar = QUAD_TO_DBL(tmp);
5106  }
5107  rowcoefsign = COPYSIGN(1.0, rowcoef);
5108 
5109  val2 = rowcoefsign * ((rowcoef * vubcoefs[i]) + rowcoefbinvar);
5110 
5111  /* variable upper bound does not meet criteria */
5112  if( val2 < 0.0 || SCIPisInfinity(scip, val2) )
5113  continue;
5114 
5115  val1 = rowcoefsign * ((rowcoef * (bestslb - vubconsts[i])) + rowcoefbinvar);
5116 
5117  /* variable upper bound does not meet criteria */
5118  if( val1 < 0.0 )
5119  continue;
5120 
5121  vubsol = vubcoefs[i] * SCIPgetSolVal(scip, sol, vubvars[i]) + vubconsts[i];
5122  if( vubsol < *closestvub )
5123  {
5124  *closestvub = vubsol;
5125  *closestvubidx = i;
5126  }
5127  assert(*closestvubidx >= 0);
5128  }
5129  }
5130 
5131  return SCIP_OKAY;
5132 }
5133 
5134 /** determines the bounds to use for constructing the single-node-flow relaxation of a variable in
5135  * the given row.
5136  */
5137 static
5139  SCIP* scip, /**< SCIP data structure */
5140  SCIP_SOL* sol, /**< solution to use for variable bound; NULL for LP solution */
5141  SCIP_VAR** vars, /**< array of problem variables */
5142  SCIP_Real* rowcoefs, /**< (dense) array of variable coefficients in the row */
5143  int* rowinds, /**< array with positions of non-zero values in the rowcoefs array */
5144  int varposinrow, /**< position of variable in the rowinds array for which the bounds should be determined */
5145  int8_t* binvarused, /**< array that stores if a binary variable was already used (+1)
5146  * was not used (0) or was not used but is contained in the row (-1)
5147  */
5148  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5149  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5150  SCIP_Real* bestlb, /**< pointer to store best lower bound for transformation */
5151  SCIP_Real* bestub, /**< pointer to store best upper bound for transformation */
5152  SCIP_Real* bestslb, /**< pointer to store best simple lower bound for transformation */
5153  SCIP_Real* bestsub, /**< pointer to store best simple upper bound for transformation */
5154  int* bestlbtype, /**< pointer to store type of best lower bound */
5155  int* bestubtype, /**< pointer to store type of best upper bound */
5156  int* bestslbtype, /**< pointer to store type of best simple lower bound */
5157  int* bestsubtype, /**< pointer to store type of best simple upper bound */
5158  SCIP_BOUNDTYPE* selectedbounds, /**< pointer to store the preferred bound for the transformation */
5159  SCIP_Bool* freevariable /**< pointer to store if variable is a free variable */
5160  )
5161 {
5162  SCIP_VAR* var;
5163 
5164  SCIP_Real rowcoef;
5165  SCIP_Real solval;
5166  SCIP_Real simplebound;
5167 
5168  int probidx;
5169 
5170  bestlb[varposinrow] = -SCIPinfinity(scip);
5171  bestub[varposinrow] = SCIPinfinity(scip);
5172  bestlbtype[varposinrow] = -3;
5173  bestubtype[varposinrow] = -3;
5174 
5175  probidx = rowinds[varposinrow];
5176  var = vars[probidx];
5177  {
5178  SCIP_Real QUAD(tmp);
5179  QUAD_ARRAY_LOAD(tmp, rowcoefs, probidx);
5180  rowcoef = QUAD_TO_DBL(tmp);
5181  }
5182 
5183  assert(!EPSZ(rowcoef, QUAD_EPSILON));
5184 
5185  /* get closest simple lower bound and closest simple upper bound */
5186  SCIP_CALL( findBestLb(scip, var, sol, 0, allowlocal, &bestslb[varposinrow], &simplebound, &bestslbtype[varposinrow]) );
5187  SCIP_CALL( findBestUb(scip, var, sol, 0, allowlocal, &bestsub[varposinrow], &simplebound, &bestsubtype[varposinrow]) );
5188 
5189  /* do not use too large bounds */
5190  if( bestslb[varposinrow] <= -MAXBOUND )
5191  bestslb[varposinrow] = -SCIPinfinity(scip);
5192 
5193  if( bestsub[varposinrow] >= MAXBOUND )
5194  bestsub[varposinrow] = SCIPinfinity(scip);
5195 
5196  solval = SCIPgetSolVal(scip, sol, var);
5197 
5198  SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g(%d),%g(%d)]>:\n", varposinrow, rowcoef, SCIPvarGetName(var), probidx,
5199  solval, bestslb[varposinrow], bestslbtype[varposinrow], bestsub[varposinrow], bestsubtype[varposinrow]);
5200 
5201  /* mixed integer set cannot be relaxed to 0-1 single node flow set because both simple bounds are -infinity
5202  * and infinity, respectively
5203  */
5204  if( SCIPisInfinity(scip, -bestslb[varposinrow]) && SCIPisInfinity(scip, bestsub[varposinrow]) )
5205  {
5206  *freevariable = TRUE;
5207  return SCIP_OKAY;
5208  }
5209 
5210  /* get closest lower bound that can be used to define the real variable y'_j in the 0-1 single node flow
5211  * relaxation
5212  */
5213  if( !SCIPisInfinity(scip, bestsub[varposinrow]) )
5214  {
5215  bestlb[varposinrow] = bestslb[varposinrow];
5216  bestlbtype[varposinrow] = bestslbtype[varposinrow];
5217 
5219  {
5220  SCIP_Real bestvlb;
5221  int bestvlbidx;
5222 
5223  SCIP_CALL( getClosestVlb(scip, var, sol, rowcoefs, binvarused, bestsub[varposinrow], rowcoef, &bestvlb, &bestvlbidx) );
5224  if( SCIPisGT(scip, bestvlb, bestlb[varposinrow]) )
5225  {
5226  bestlb[varposinrow] = bestvlb;
5227  bestlbtype[varposinrow] = bestvlbidx;
5228  }
5229  }
5230  }
5231 
5232  /* get closest upper bound that can be used to define the real variable y'_j in the 0-1 single node flow
5233  * relaxation
5234  */
5235  if( !SCIPisInfinity(scip, -bestslb[varposinrow]) )
5236  {
5237  bestub[varposinrow] = bestsub[varposinrow];
5238  bestubtype[varposinrow] = bestsubtype[varposinrow];
5239 
5241  {
5242  SCIP_Real bestvub;
5243  int bestvubidx;
5244 
5245  SCIP_CALL( getClosestVub(scip, var, sol, rowcoefs, binvarused, bestslb[varposinrow], rowcoef, &bestvub, &bestvubidx) );
5246  if( SCIPisLT(scip, bestvub, bestub[varposinrow]) )
5247  {
5248  bestub[varposinrow] = bestvub;
5249  bestubtype[varposinrow] = bestvubidx;
5250  }
5251  }
5252  }
5253  SCIPdebugMsg(scip, " bestlb=%g(%d), bestub=%g(%d)\n", bestlb[varposinrow], bestlbtype[varposinrow], bestub[varposinrow], bestubtype[varposinrow]);
5254 
5255  /* mixed integer set cannot be relaxed to 0-1 single node flow set because there are no suitable bounds
5256  * to define the transformed variable y'_j
5257  */
5258  if( SCIPisInfinity(scip, -bestlb[varposinrow]) && SCIPisInfinity(scip, bestub[varposinrow]) )
5259  {
5260  *freevariable = TRUE;
5261  return SCIP_OKAY;
5262  }
5263 
5264  *freevariable = FALSE;
5265 
5266  /* select best upper bound if it is closer to the LP value of y_j and best lower bound otherwise and use this bound
5267  * to define the real variable y'_j with 0 <= y'_j <= u'_j x_j in the 0-1 single node flow relaxation;
5268  * prefer variable bounds
5269  */
5270  if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) && bestlbtype[varposinrow] >= 0 )
5271  {
5272  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5273  }
5274  else if( SCIPisEQ(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow])
5275  && bestubtype[varposinrow] >= 0 )
5276  {
5277  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5278  }
5279  else if( SCIPisLE(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]) )
5280  {
5281  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_LOWER;
5282  }
5283  else
5284  {
5285  assert(SCIPisGT(scip, solval, (1.0 - boundswitch) * bestlb[varposinrow] + boundswitch * bestub[varposinrow]));
5286  selectedbounds[varposinrow] = SCIP_BOUNDTYPE_UPPER;
5287  }
5288 
5289  if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_LOWER && bestlbtype[varposinrow] >= 0 )
5290  {
5291  int vlbvarprobidx;
5292  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5293 
5294  /* mark binary variable of vlb so that it is not used for other continuous variables
5295  * by setting it's position in the aggrrow to a negative value
5296  */
5297  vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[varposinrow]]);
5298  binvarused[vlbvarprobidx] = 1;
5299  }
5300  else if( selectedbounds[varposinrow] == SCIP_BOUNDTYPE_UPPER && bestubtype[varposinrow] >= 0 )
5301  {
5302  int vubvarprobidx;
5303  SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
5304 
5305  /* mark binary variable of vub so that it is not used for other continuous variables
5306  * by setting it's position in the aggrrow to a negative value
5307  */
5308  vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[varposinrow]]);
5309  binvarused[vubvarprobidx] = 1;
5310  }
5311 
5312  return SCIP_OKAY; /*lint !e438*/
5313 }
5314 
5315 /** construct a 0-1 single node flow relaxation (with some additional simple constraints) of a mixed integer set
5316  * corresponding to the given aggrrow a * x <= rhs
5317  */
5318 static
5320  SCIP* scip, /**< SCIP data structure */
5321  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
5322  SCIP_Real boundswitch, /**< fraction of domain up to which lower bound is used in transformation */
5323  SCIP_Bool allowlocal, /**< should local information allowed to be used, resulting in a local cut? */
5324  SCIP_Real* rowcoefs, /**< array of coefficients of row */
5325  QUAD(SCIP_Real rowrhs), /**< pointer to right hand side of row */
5326  int* rowinds, /**< array of variables problem indices for non-zero coefficients in row */
5327  int nnz, /**< number of non-zeros in row */
5328  SNF_RELAXATION* snf, /**< stores the sign of the transformed variable in summation */
5329  SCIP_Bool* success, /**< stores whether the transformation was valid */
5330  SCIP_Bool* localbdsused /**< pointer to store whether local bounds were used in transformation */
5331  )
5332 {
5333  SCIP_VAR** vars;
5334  int i;
5335  int nnonbinvarsrow;
5336  int8_t* binvarused;
5337  int nbinvars;
5338  SCIP_Real QUAD(transrhs);
5339 
5340  /* arrays to store the selected bound for each non-binary variable in the row */
5341  SCIP_Real* bestlb;
5342  SCIP_Real* bestub;
5343  SCIP_Real* bestslb;
5344  SCIP_Real* bestsub;
5345  int* bestlbtype;
5346  int* bestubtype;
5347  int* bestslbtype;
5348  int* bestsubtype;
5349  SCIP_BOUNDTYPE* selectedbounds;
5350 
5351  *success = FALSE;
5352 
5353  SCIPdebugMsg(scip, "--------------------- construction of SNF relaxation ------------------------------------\n");
5354 
5355  nbinvars = SCIPgetNBinVars(scip);
5356  vars = SCIPgetVars(scip);
5357 
5358  SCIP_CALL( SCIPallocBufferArray(scip, &bestlb, nnz) );
5359  SCIP_CALL( SCIPallocBufferArray(scip, &bestub, nnz) );
5360  SCIP_CALL( SCIPallocBufferArray(scip, &bestslb, nnz) );
5361  SCIP_CALL( SCIPallocBufferArray(scip, &bestsub, nnz) );
5362  SCIP_CALL( SCIPallocBufferArray(scip, &bestlbtype, nnz) );
5363  SCIP_CALL( SCIPallocBufferArray(scip, &bestubtype, nnz) );
5364  SCIP_CALL( SCIPallocBufferArray(scip, &bestslbtype, nnz) );
5365  SCIP_CALL( SCIPallocBufferArray(scip, &bestsubtype, nnz) );
5366  SCIP_CALL( SCIPallocBufferArray(scip, &selectedbounds, nnz) );
5367 
5368  /* sort descending to have continuous variables first */
5369  SCIPsortDownInt(rowinds, nnz);
5370 
5371  /* array to store whether a binary variable is in the row (-1) or has been used (1) due to variable bound usage */
5372  SCIP_CALL( SCIPallocCleanBufferArray(scip, &binvarused, nbinvars) );
5373 
5374  for( i = nnz - 1; i >= 0 && rowinds[i] < nbinvars; --i )
5375  binvarused[rowinds[i]] = -1;
5376 
5377  nnonbinvarsrow = i + 1;
5378  /* determine the bounds to use for transforming the non-binary variables */
5379  for( i = 0; i < nnonbinvarsrow; ++i )
5380  {
5381  SCIP_Bool freevariable;
5382 
5383  assert(rowinds[i] >= nbinvars);
5384 
5385  SCIP_CALL( determineBoundForSNF(scip, sol, vars, rowcoefs, rowinds, i, binvarused, allowlocal, boundswitch,
5386  bestlb, bestub, bestslb, bestsub, bestlbtype, bestubtype, bestslbtype, bestsubtype, selectedbounds, &freevariable) );
5387 
5388  if( freevariable )
5389  {
5390  int j;
5391 
5392  /* clear binvarused at indices of binary variables of row */
5393  for( j = nnz - 1; j >= nnonbinvarsrow; --j )
5394  binvarused[rowinds[j]] = 0;
5395 
5396  /* clear binvarused at indices of selected variable bounds */
5397  for( j = 0; j < i; ++j )
5398  {
5399  if( selectedbounds[j] == SCIP_BOUNDTYPE_LOWER && bestlbtype[j] >= 0 )
5400  {
5401  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(vars[rowinds[j]]);
5402  binvarused[SCIPvarGetProbindex(vlbvars[bestlbtype[j]])] = 0;
5403  }
5404  else if( selectedbounds[j] == SCIP_BOUNDTYPE_UPPER && bestubtype[j] >= 0 )
5405  {
5406  SCIP_VAR** vubvars = SCIPvarGetVubVars(vars[rowinds[j]]);
5407  binvarused[SCIPvarGetProbindex(vubvars[bestubtype[j]])] = 0;
5408  }
5409  }
5410 
5411  /* terminate */
5412  goto TERMINATE;
5413  }
5414  }
5415 
5416  *localbdsused = FALSE;
5417  QUAD_ASSIGN_Q(transrhs, rowrhs);
5418  snf->ntransvars = 0;
5419 
5420  assert(snf->transvarcoefs != NULL); /* for lint */
5421  assert(snf->transvarvubcoefs != NULL);
5422  assert(snf->transbinvarsolvals != NULL);
5423  assert(snf->transcontvarsolvals != NULL);
5424  assert(snf->aggrconstants != NULL);
5425  assert(snf->aggrcoefscont != NULL);
5426  assert(snf->origcontvars != NULL);
5427  assert(snf->origbinvars != NULL);
5428  assert(snf->aggrcoefsbin != NULL);
5429 
5430  /* transform non-binary variables */
5431  for( i = 0; i < nnonbinvarsrow; ++i )
5432  {
5433  SCIP_VAR* var;
5434  SCIP_Real QUAD(rowcoef);
5435  SCIP_Real solval;
5436  int probidx;
5437 
5438  probidx = rowinds[i];
5439  var = vars[probidx];
5440  QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5441  solval = SCIPgetSolVal(scip, sol, var);
5442 
5443  assert(probidx >= nbinvars);
5444 
5445  if( selectedbounds[i] == SCIP_BOUNDTYPE_LOWER )
5446  {
5447  /* use bestlb to define y'_j */
5448 
5449  assert(!SCIPisInfinity(scip, bestsub[i]));
5450  assert(!SCIPisInfinity(scip, - bestlb[i]));
5451  assert(bestsubtype[i] == -1 || bestsubtype[i] == -2);
5452  assert(bestlbtype[i] > -3 && bestlbtype[i] < SCIPvarGetNVlbs(var));
5453 
5454  /* store for y_j that bestlb is the bound used to define y'_j and that y'_j is the associated real variable
5455  * in the relaxed set
5456  */
5457  snf->origcontvars[snf->ntransvars] = probidx;
5458 
5459  if( bestlbtype[i] < 0 )
5460  {
5461  SCIP_Real QUAD(val);
5462  SCIP_Real QUAD(contsolval);
5463  SCIP_Real QUAD(rowcoeftimesbestsub);
5464 
5465  /* use simple lower bound in bestlb = l_j <= y_j <= u_j = bestsub to define
5466  * y'_j = - a_j ( y_j - u_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
5467  * y'_j = a_j ( y_j - u_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
5468  * put j into the set
5469  * N2 if a_j > 0
5470  * N1 if a_j < 0
5471  * and update the right hand side of the constraint in the relaxation
5472  * rhs = rhs - a_j u_j
5473  */
5474  SCIPquadprecSumDD(val, bestsub[i], -bestlb[i]);
5475  SCIPquadprecProdQQ(val, val, rowcoef);
5476  SCIPquadprecSumDD(contsolval, solval, -bestsub[i]);
5477  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5478 
5479  if( bestlbtype[i] == -2 || bestsubtype[i] == -2 )
5480  *localbdsused = TRUE;
5481 
5482  SCIPquadprecProdQD(rowcoeftimesbestsub, rowcoef, bestsub[i]);
5483 
5484  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5485  snf->origbinvars[snf->ntransvars] = -1;
5486  snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5487 
5488  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5489  {
5490  snf->transvarcoefs[snf->ntransvars] = - 1;
5491  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5492  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5493  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5494 
5495  /* aggregation information for y'_j */
5496  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestsub);
5497  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5498  }
5499  else
5500  {
5501  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5502  snf->transvarcoefs[snf->ntransvars] = 1;
5503  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5504  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5505  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5506 
5507  /* aggregation information for y'_j */
5508  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestsub);
5509  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5510  }
5511  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestsub);
5512 
5513  SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5514  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5515  snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestsub), QUAD_TO_DBL(rowcoef), bestsub[i], QUAD_TO_DBL(transrhs));
5516  }
5517  else
5518  {
5519  SCIP_Real QUAD(rowcoefbinary);
5520  SCIP_Real varsolvalbinary;
5521  SCIP_Real QUAD(val);
5522  SCIP_Real QUAD(contsolval);
5523  SCIP_Real QUAD(rowcoeftimesvlbconst);
5524  int vlbvarprobidx;
5525 
5526  SCIP_VAR** vlbvars = SCIPvarGetVlbVars(var);
5527  SCIP_Real* vlbconsts = SCIPvarGetVlbConstants(var);
5528  SCIP_Real* vlbcoefs = SCIPvarGetVlbCoefs(var);
5529 
5530  /* use variable lower bound in bestlb = l~_j x_j + d_j <= y_j <= u_j = bestsub to define
5531  * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j l~_j + c_j ) x_j if a_j > 0
5532  * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j l~_j + c_j ) x_j if a_j < 0,
5533  * where c_j is the coefficient of x_j in the row, put j into the set
5534  * N2 if a_j > 0
5535  * N1 if a_j < 0
5536  * and update the right hand side of the constraint in the relaxation
5537  * rhs = rhs - a_j d_j
5538  */
5539 
5540  vlbvarprobidx = SCIPvarGetProbindex(vlbvars[bestlbtype[i]]);
5541  assert(binvarused[vlbvarprobidx] == 1);
5542  assert(vlbvarprobidx < nbinvars);
5543 
5544  QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vlbvarprobidx);
5545  varsolvalbinary = SCIPgetSolVal(scip, sol, vlbvars[bestlbtype[i]]);
5546 
5547  SCIPquadprecProdQD(val, rowcoef, vlbcoefs[bestlbtype[i]]);
5548  SCIPquadprecSumQQ(val, val, rowcoefbinary);
5549  {
5550  SCIP_Real QUAD(tmp);
5551 
5552  SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
5553  SCIPquadprecSumDD(contsolval, solval, - vlbconsts[bestlbtype[i]]);
5554  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5555  SCIPquadprecSumQQ(contsolval, contsolval, tmp);
5556  }
5557 
5558  SCIPquadprecProdQD(rowcoeftimesvlbconst, rowcoef, vlbconsts[bestlbtype[i]]);
5559 
5560  /* clear the binvarpos array, since the variable has been processed */
5561  binvarused[vlbvarprobidx] = 0;
5562 
5563  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5564  snf->origbinvars[snf->ntransvars] = vlbvarprobidx;
5565 
5566  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5567  {
5568  snf->transvarcoefs[snf->ntransvars] = - 1;
5569  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5570  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5571  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5572 
5573  /* aggregation information for y'_j */
5574  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5575  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5576  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvlbconst);
5577  }
5578  else
5579  {
5580  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5581  snf->transvarcoefs[snf->ntransvars] = 1;
5582  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5583  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5584  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5585 
5586  /* aggregation information for y'_j */
5587  snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5588  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5589  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvlbconst);
5590  }
5591  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvlbconst);
5592 
5593  SCIPdebugMsg(scip, " --> bestlb used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5594  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5595  snf->ntransvars, SCIPvarGetName(vlbvars[bestlbtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvlbconst), QUAD_TO_DBL(rowcoef),
5596  vlbconsts[bestlbtype[i]], snf->transrhs );
5597  }
5598  }
5599  else
5600  {
5601  /* use bestub to define y'_j */
5602 
5603  assert(!SCIPisInfinity(scip, bestub[i]));
5604  assert(!SCIPisInfinity(scip, - bestslb[i]));
5605  assert(bestslbtype[i] == -1 || bestslbtype[i] == -2);
5606  assert(bestubtype[i] > -3 && bestubtype[i] < SCIPvarGetNVubs(var));
5607 
5608  /* store for y_j that y'_j is the associated real variable
5609  * in the relaxed set
5610  */
5611  snf->origcontvars[snf->ntransvars] = probidx;
5612 
5613  if( bestubtype[i] < 0 )
5614  {
5615  SCIP_Real QUAD(val);
5616  SCIP_Real QUAD(contsolval);
5617  SCIP_Real QUAD(rowcoeftimesbestslb);
5618 
5619  /* use simple upper bound in bestslb = l_j <= y_j <= u_j = bestub to define
5620  * y'_j = a_j ( y_j - l_j ) with 0 <= y'_j <= a_j ( u_j - l_j ) x_j and x_j = 1 if a_j > 0
5621  * y'_j = - a_j ( y_j - l_j ) with 0 <= y'_j <= - a_j ( u_j - l_j ) x_j and x_j = 1 if a_j < 0,
5622  * put j into the set
5623  * N1 if a_j > 0
5624  * N2 if a_j < 0
5625  * and update the right hand side of the constraint in the relaxation
5626  * rhs = rhs - a_j l_j
5627  */
5628  SCIPquadprecSumDD(val, bestub[i], - bestslb[i]);
5629  SCIPquadprecProdQQ(val, val, rowcoef);
5630  SCIPquadprecSumDD(contsolval, solval, - bestslb[i]);
5631  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5632 
5633  if( bestubtype[i] == -2 || bestslbtype[i] == -2 )
5634  *localbdsused = TRUE;
5635 
5636  SCIPquadprecProdQD(rowcoeftimesbestslb, rowcoef, bestslb[i]);
5637 
5638  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5639  snf->origbinvars[snf->ntransvars] = -1;
5640  snf->aggrcoefsbin[snf->ntransvars] = 0.0;
5641 
5642  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5643  {
5644  snf->transvarcoefs[snf->ntransvars] = 1;
5645  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5646  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5647  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5648 
5649  /* aggregation information for y'_j */
5650  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5651  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesbestslb);
5652  }
5653  else
5654  {
5655  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5656  snf->transvarcoefs[snf->ntransvars] = - 1;
5657  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5658  snf->transbinvarsolvals[snf->ntransvars] = 1.0;
5659  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5660 
5661  /* aggregation information for y'_j */
5662  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5663  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesbestslb);
5664  }
5665  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesbestslb);
5666 
5667  SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., Y'_%d <= %g x_%d (=1), rhs=%g-(%g*%g)=%g\n",
5668  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5669  snf->ntransvars, QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesbestslb), QUAD_TO_DBL(rowcoef), bestslb[i], QUAD_TO_DBL(transrhs));
5670  }
5671  else
5672  {
5673  SCIP_Real QUAD(rowcoefbinary);
5674  SCIP_Real varsolvalbinary;
5675  SCIP_Real QUAD(val);
5676  SCIP_Real QUAD(contsolval);
5677  SCIP_Real QUAD(rowcoeftimesvubconst);
5678  int vubvarprobidx;
5679 
5680  SCIP_VAR** vubvars = SCIPvarGetVubVars(var);
5681  SCIP_Real* vubconsts = SCIPvarGetVubConstants(var);
5682  SCIP_Real* vubcoefs = SCIPvarGetVubCoefs(var);
5683 
5684  /* use variable upper bound in bestslb = l_j <= y_j <= u~_j x_j + d_j = bestub to define
5685  * y'_j = a_j ( y_j - d_j ) + c_j x_j with 0 <= y'_j <= ( a_j u~_j + c_j ) x_j if a_j > 0
5686  * y'_j = - ( a_j ( y_j - d_j ) + c_j x_j ) with 0 <= y'_j <= - ( a_j u~_j + c_j ) x_j if a_j < 0,
5687  * where c_j is the coefficient of x_j in the row, put j into the set
5688  * N1 if a_j > 0
5689  * N2 if a_j < 0
5690  * and update the right hand side of the constraint in the relaxation
5691  * rhs = rhs - a_j d_j
5692  */
5693 
5694  vubvarprobidx = SCIPvarGetProbindex(vubvars[bestubtype[i]]);
5695  assert(binvarused[vubvarprobidx] == 1);
5696  assert(vubvarprobidx < nbinvars);
5697 
5698  QUAD_ARRAY_LOAD(rowcoefbinary, rowcoefs, vubvarprobidx);
5699  varsolvalbinary = SCIPgetSolVal(scip, sol, vubvars[bestubtype[i]]);
5700 
5701  /* clear the binvarpos array, since the variable has been processed */
5702  binvarused[vubvarprobidx] = 0;
5703 
5704  SCIPquadprecProdQD(val, rowcoef, vubcoefs[bestubtype[i]]);
5705  SCIPquadprecSumQQ(val, val, rowcoefbinary);
5706  {
5707  SCIP_Real QUAD(tmp);
5708  SCIPquadprecProdQD(tmp, rowcoefbinary, varsolvalbinary);
5709  SCIPquadprecSumDD(contsolval, solval, - vubconsts[bestubtype[i]]);
5710  SCIPquadprecProdQQ(contsolval, contsolval, rowcoef);
5711  SCIPquadprecSumQQ(contsolval, contsolval, tmp);
5712  }
5713 
5714  SCIPquadprecProdQD(rowcoeftimesvubconst, rowcoef, vubconsts[bestubtype[i]]);
5715  /* store aggregation information for y'_j for transforming cuts for the SNF relaxation back to the problem variables later */
5716  snf->origbinvars[snf->ntransvars] = vubvarprobidx;
5717 
5718  if( QUAD_TO_DBL(rowcoef) > QUAD_EPSILON )
5719  {
5720  snf->transvarcoefs[snf->ntransvars] = 1;
5721  snf->transvarvubcoefs[snf->ntransvars] = QUAD_TO_DBL(val);
5722  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5723  snf->transcontvarsolvals[snf->ntransvars] = QUAD_TO_DBL(contsolval);
5724 
5725  /* aggregation information for y'_j */
5726  snf->aggrcoefsbin[snf->ntransvars] = QUAD_TO_DBL(rowcoefbinary);
5727  snf->aggrcoefscont[snf->ntransvars] = QUAD_TO_DBL(rowcoef);
5728  snf->aggrconstants[snf->ntransvars] = - QUAD_TO_DBL(rowcoeftimesvubconst);
5729  }
5730  else
5731  {
5732  assert(QUAD_TO_DBL(rowcoef) < QUAD_EPSILON);
5733  snf->transvarcoefs[snf->ntransvars] = - 1;
5734  snf->transvarvubcoefs[snf->ntransvars] = - QUAD_TO_DBL(val);
5735  snf->transbinvarsolvals[snf->ntransvars] = varsolvalbinary;
5736  snf->transcontvarsolvals[snf->ntransvars] = - QUAD_TO_DBL(contsolval);
5737 
5738  /* aggregation information for y'_j */
5739  snf->aggrcoefsbin[snf->ntransvars] = - QUAD_TO_DBL(rowcoefbinary);
5740  snf->aggrcoefscont[snf->ntransvars] = - QUAD_TO_DBL(rowcoef);
5741  snf->aggrconstants[snf->ntransvars] = QUAD_TO_DBL(rowcoeftimesvubconst);
5742  }
5743  SCIPquadprecSumQQ(transrhs, transrhs, -rowcoeftimesvubconst);
5744 
5745  /* store for x_j that y'_j is the associated real variable in the 0-1 single node flow relaxation */
5746 
5747  SCIPdebugMsg(scip, " --> bestub used for trans: ... %s y'_%d + ..., y'_%d <= %g x_%d (=%s), rhs=%g-(%g*%g)=%g\n",
5748  snf->transvarcoefs[snf->ntransvars] == 1 ? "+" : "-", snf->ntransvars, snf->ntransvars, snf->transvarvubcoefs[snf->ntransvars],
5749  snf->ntransvars, SCIPvarGetName(vubvars[bestubtype[i]]), QUAD_TO_DBL(transrhs) + QUAD_TO_DBL(rowcoeftimesvubconst), QUAD_TO_DBL(rowcoef),
5750  vubconsts[bestubtype[i]], QUAD_TO_DBL(transrhs));
5751  }
5752  }
5753 
5754  /* make sure the coefficient is not negative due to small numerical rounding errors */
5755  assert(snf->transvarvubcoefs[snf->ntransvars] > -QUAD_EPSILON);
5756  snf->transvarvubcoefs[snf->ntransvars] = MAX(snf->transvarvubcoefs[snf->ntransvars], 0.0);
5757 
5758  ++snf->ntransvars;
5759  }
5760 
5761  snf->transrhs = QUAD_TO_DBL(transrhs);
5762 
5763  /* transform remaining binary variables of row */
5764  for( i = nnonbinvarsrow; i < nnz; ++i )
5765  {
5766  SCIP_VAR* var;
5767  SCIP_Real QUAD(rowcoef);
5768  int probidx;
5769  SCIP_Real val;
5770  SCIP_Real contsolval;
5771  SCIP_Real varsolval;
5772 
5773  probidx = rowinds[i];
5774  /* variable should be binary */
5775  assert(probidx < nbinvars);
5776 
5777  /* binary variable was processed together with a non-binary variable */
5778  if( binvarused[probidx] == 0 )
5779  continue;
5780 
5781  /* binary variable was not processed yet, so the binvarused value sould be -1 */
5782  assert(binvarused[probidx] == -1);
5783 
5784  /* set binvarused to zero since it has been processed */
5785  binvarused[probidx] = 0;
5786 
5787  var = vars[probidx];
5788  QUAD_ARRAY_LOAD(rowcoef, rowcoefs, probidx);
5789 
5790  assert(!EPSZ(QUAD_TO_DBL(rowcoef), QUAD_EPSILON));
5791 
5792  varsolval = SCIPgetSolVal(scip, sol, var);
5793  SCIPdebugMsg(scip, " %d: %g <%s, idx=%d, lp=%g, [%g, %g]>:\n", i, QUAD_TO_DBL(rowcoef), SCIPvarGetName(var), probidx, varsolval,