1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2020 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file misc_rowprep.c
17 * @ingroup OTHER_CFILES
18 * @brief linear inequalities in preparation
19 * @author Stefan Vigerske
20 * @author Benjamin Mueller
21 * @author Felipe Serrano
22 */
23
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25
26 #include "scip/pub_misc_rowprep.h"
27 #include "scip/pub_misc_sort.h"
28 #include "scip/pub_var.h"
29 #include "scip/scip_lp.h"
30 #include "scip/scip_mem.h"
31 #include "scip/scip_message.h"
32 #include "scip/scip_numerics.h"
33 #include "scip/scip_sepa.h"
34 #include "scip/scip_sol.h"
35 #include "scip/scip_tree.h"
36 #include "scip/struct_misc.h"
37 #include "scip/struct_scip.h"
38 #include "scip/set.h"
39
40 #define ROWPREP_SCALEUP_VIOLNONZERO (10.0*SCIPepsilon(scip)) /**< minimal violation for considering up-scaling of rowprep (we want to avoid upscaling very small violations) */
41 #define ROWPREP_SCALEUP_MINVIOLFACTOR 2.0 /**< scale up will target a violation of ~MINVIOLFACTOR*minviol, where minviol is given by caller */
42 #define ROWPREP_SCALEUP_MAXMINCOEF (1.0 / SCIPfeastol(scip)) /**< scale up only if min. coef is below this number (before scaling) */
43 #define ROWPREP_SCALEUP_MAXMAXCOEF SCIPgetHugeValue(scip) /**< scale up only if max. coef will not exceed this number by scaling */
44 #define ROWPREP_SCALEUP_MAXSIDE SCIPgetHugeValue(scip) /**< scale up only if side will not exceed this number by scaling */
45 #define ROWPREP_SCALEDOWN_MINMAXCOEF (1.0 / SCIPfeastol(scip)) /**< scale down if max. coef is at least this number (before scaling) */
46 #define ROWPREP_SCALEDOWN_MINCOEF SCIPfeastol(scip) /**< scale down only if min. coef does not drop below this number by scaling */
47
48 #ifndef M_SQRT2
49 #define M_SQRT2 sqrt(2.0)
50 #endif
51
52 /** adds a variable to the `rowprep->modifiedvars` array, if recording of modification has been enabled and the variable is not fixed */
53 static
54 SCIP_RETCODE rowprepRecordModifiedVar(
55 SCIP* scip, /**< SCIP data structure */
56 SCIP_ROWPREP* rowprep, /**< rowprep */
57 SCIP_VAR* var /**< variable to add */
58 )
59 {
60 int oldsize;
61
62 if( !rowprep->recordmodifications )
63 return SCIP_OKAY;
64
65 /* do not record for fixed variables, as they are not suitable for branching */
66 if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
67 {
68 SCIPdebugMsg(scip, "skip recording modification for fixed variable <%s>[%g,%g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
69 return SCIP_OKAY;
70 }
71
72 /* increase modifiedvars array size */
73 if( rowprep->nmodifiedvars >= rowprep->modifiedvarssize )
74 {
75 oldsize = rowprep->modifiedvarssize;
76 rowprep->modifiedvarssize = SCIPcalcMemGrowSize(scip, rowprep->nmodifiedvars + 1);
77
78 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->modifiedvars, oldsize, rowprep->modifiedvarssize) );
79 }
80
81 rowprep->modifiedvars[rowprep->nmodifiedvars] = var;
82 ++rowprep->nmodifiedvars;
83
84 return SCIP_OKAY;
85 }
86
87 /** sort terms by absolute value of coefficients, from largest to smallest */
88 static
89 SCIP_RETCODE rowprepCleanupSortTerms(
90 SCIP* scip, /**< SCIP data structure */
91 SCIP_ROWPREP* rowprep /**< rowprep to be sorted */
92 )
93 {
94 int i;
95
96 assert(scip != NULL);
97 assert(rowprep != NULL);
98
99 /* special treatment for cuts with few variables */
100 switch( rowprep->nvars )
101 {
102 case 0:
103 case 1:
104 break;
105
106 case 2:
107 {
108 if( REALABS(rowprep->coefs[0]) < REALABS(rowprep->coefs[1]) )
109 {
110 SCIP_Real tmp1;
111 SCIP_VAR* tmp2;
112
113 tmp1 = rowprep->coefs[0];
114 rowprep->coefs[0] = rowprep->coefs[1];
115 rowprep->coefs[1] = tmp1;
116
117 tmp2 = rowprep->vars[0];
118 rowprep->vars[0] = rowprep->vars[1];
119 rowprep->vars[1] = tmp2;
120 }
121 break;
122 }
123
124 default :
125 {
126 SCIP_Real* abscoefs;
127
128 SCIP_CALL( SCIPallocBufferArray(scip, &abscoefs, rowprep->nvars) );
129 for( i = 0; i < rowprep->nvars; ++i )
130 abscoefs[i] = REALABS(rowprep->coefs[i]);
131 SCIPsortDownRealRealPtr(abscoefs, rowprep->coefs, (void**)rowprep->vars, rowprep->nvars);
132 SCIPfreeBufferArray(scip, &abscoefs);
133 }
134 }
135
136 /* forget about coefs that are exactly zero (unlikely to have some) */
137 while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
138 --rowprep->nvars;
139
140 return SCIP_OKAY;
141 }
142
143 /** try to improve coef range by aggregating row with variable bounds
144 *
145 * Assumes terms have been sorted by rowprepCleanupSortTerms().
146 */
147 static
148 SCIP_RETCODE rowprepCleanupImproveCoefrange(
149 SCIP* scip, /**< SCIP data structure */
150 SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
151 SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
152 SCIP_Real maxcoefrange /**< maximal allowed coefficients range */
153 )
154 {
155 SCIP_VAR* var;
156 SCIP_Real lb;
157 SCIP_Real ub;
158 SCIP_Real ref;
159 SCIP_Real coef;
160 SCIP_Real mincoef;
161 SCIP_Real maxcoef;
162 SCIP_Real loss[2];
163 int maxcoefidx;
164 int pos;
165
166 maxcoefidx = 0;
167 if( rowprep->nvars > 0 )
168 {
169 maxcoef = REALABS(rowprep->coefs[0]);
170 mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
171 }
172 else
173 mincoef = maxcoef = 1.0;
174
175 /* eliminate minimal or maximal coefs as long as coef range is too large
176 * this is likely going to eliminate coefs that are within eps of 0.0
177 * if not, then we do so after scaling (or should we enforce this here?)
178 */
179 while( maxcoef / mincoef > maxcoefrange )
180 {
181 SCIPdebugMsg(scip, "cut coefficients have very large range: mincoef = %g maxcoef = %g\n", mincoef, maxcoef);
182
183 /* max/min can only be > 1 if there is more than one var
184 * we need this below for updating the max/min coef after eliminating a term
185 */
186 assert(rowprep->nvars > 1);
187
188 /* try to reduce coef range by aggregating with variable bounds
189 * that is, eliminate a term like a*x from a*x + ... <= side by adding -a*x <= -a*lb(x)
190 * with ref(x) the reference point we try to eliminate, this would weaken the cut by a*(lb(x)-ref(x))
191 *
192 * we consider eliminating either the term with maximal or the one with minimal coefficient,
193 * taking the one that leads to the least weakening of the cut
194 *
195 * TODO (suggested by @bzfserra, see !496):
196 * - Also one could think of not completely removing the coefficient but do an aggregation that makes the coefficient look better. For instance:
197 * say you have $`a x + 0.1 y \leq r`$ and $`y`$ has only an upper bound, $`y \leq b`$,
198 * then you can't really remove $`y`$. However, you could aggregate it with $`0.9 \cdot (y \leq b)`$ to get
199 * $`a x + y \leq r + 0.9 b`$, which has better numerics (and hopefully still cuts the point... actually, if for the point you want to separate, $`y^* = b`$, then the violation is the same)
200 */
201
202 for( pos = 0; pos < 2; ++pos )
203 {
204 var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
205 coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
206 lb = SCIPvarGetLbLocal(var);
207 ub = SCIPvarGetUbLocal(var);
208 ref = SCIPgetSolVal(scip, sol, var);
209 assert(coef != 0.0);
210
211 /* make sure reference point is something reasonable within the bounds, preferable the value from the solution */
212 if( SCIPisInfinity(scip, REALABS(ref)) )
213 ref = 0.0;
214 ref = MAX(lb, MIN(ub, ref));
215
216 /* check whether we can eliminate coef*var from rowprep and how much we would loose w.r.t. ref(x) */
217 if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
218 {
219 /* we would need to aggregate with -coef*var <= -coef*lb(x) */
220 if( SCIPisInfinity(scip, -lb) )
221 loss[pos] = SCIP_INVALID;
222 else
223 loss[pos] = REALABS(coef) * (ref - lb);
224 }
225 else
226 {
227 assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
228 /* we would need to aggregate with -coef*var >= -coef*ub(x) */
229 if( SCIPisInfinity(scip, ub) )
230 loss[pos] = SCIP_INVALID;
231 else
232 loss[pos] = REALABS(coef) * (ub - ref);
233 }
234 assert(loss[pos] >= 0.0); /* assuming SCIP_INVALID >= 0 */
235
236 SCIPdebugMsg(scip, "aggregating %g*<%s> %c= ... with <%s>[%g] %c= %g looses %g\n",
237 coef, SCIPvarGetName(var), rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? '<' : '>',
238 SCIPvarGetName(var), ref,
239 ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? '>' : '<',
240 ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? lb : ub, loss[pos]);
241 }
242
243 /*lint --e{777} */
244 if( loss[0] == SCIP_INVALID && loss[1] == SCIP_INVALID )
245 break; /* cannot eliminate coefficient */
246
247 /* select position with smaller loss */
248 pos = (loss[1] == SCIP_INVALID || loss[1] > loss[0]) ? 0 : 1;
249
250 /* now do the actual elimination */
251 var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
252 coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
253
254 /* eliminate coef*var from rowprep: increase side */
255 if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
256 {
257 /* we aggregate with -coef*var <= -coef*lb(x) */
258 assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
259 SCIProwprepAddConstant(rowprep, coef * SCIPvarGetLbLocal(var));
260 rowprep->local |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
261 }
262 else
263 {
264 assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
265 /* we aggregate with -coef*var >= -coef*ub(x) */
266 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
267 SCIProwprepAddConstant(rowprep, coef * SCIPvarGetUbLocal(var));
268 rowprep->local |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
269 }
270
271 /* eliminate coef*var from rowprep: remove coef */
272 if( pos == 0 )
273 {
274 /* set first term to zero */
275 rowprep->coefs[maxcoefidx] = 0.0;
276
277 /* update index */
278 ++maxcoefidx;
279
280 /* update maxcoef */
281 maxcoef = REALABS(rowprep->coefs[maxcoefidx]);
282 }
283 else
284 {
285 /* forget last term */
286 --rowprep->nvars;
287
288 /* update mincoef */
289 mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
290 }
291
292 /* (potentially) remember the variable that has been removed here */
293 SCIP_CALL( rowprepRecordModifiedVar(scip, rowprep, var) );
294 }
295
296 /* if maximal coefs were removed, then there are now 0's in the beginning of the coefs array
297 * -> move all remaining coefs and vars up front
298 */
299 if( maxcoefidx > 0 )
300 {
301 int i;
302 for( i = maxcoefidx; i < rowprep->nvars; ++i )
303 {
304 rowprep->vars[i-maxcoefidx] = rowprep->vars[i];
305 rowprep->coefs[i-maxcoefidx] = rowprep->coefs[i];
306 }
307 rowprep->nvars -= maxcoefidx;
308 }
309
310 return SCIP_OKAY;
311 }
312
313
314 /** scales up rowprep if it seems useful */
315 static
316 void rowprepCleanupScaleup(
317 SCIP* scip, /**< SCIP data structure */
318 SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
319 SCIP_Real* viol, /**< violation of cut in sol (input and output) */
320 SCIP_Real minviol /**< minimal violation we try to achieve */
321 )
322 {
323 SCIP_Real scalefactor;
324 SCIP_Real mincoef;
325 SCIP_Real maxcoef;
326
327 assert(scip != NULL);
328 assert(rowprep != NULL);
329 assert(viol != NULL);
330
331 /* if violation is very small than better don't scale up */
332 if( *viol < ROWPREP_SCALEUP_VIOLNONZERO )
333 return;
334
335 /* if violation is already above minviol, then nothing to do */
336 if( *viol >= minviol )
337 return;
338 assert(!SCIPisInfinity(scip, *viol));
339
340 /* if violation is sufficiently positive (>10*eps), but has not reached minviol,
341 * then consider scaling up to reach approx MINVIOLFACTOR*minviol
342 */
343 scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
344
345 /* scale by approx. scalefactor, if minimal coef is not so large yet and maximal coef and rhs don't get huge by doing so (or have been so before) */
346 mincoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[rowprep->nvars-1]) : 1.0;
347 maxcoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[0]) : 1.0;
348 if( mincoef < ROWPREP_SCALEUP_MAXMINCOEF && scalefactor * maxcoef < ROWPREP_SCALEUP_MAXMAXCOEF && scalefactor * REALABS(rowprep->side) < ROWPREP_SCALEUP_MAXSIDE )
349 {
350 int scaleexp;
351
352 /* SCIPinfoMessage(scip, NULL, "scale up by ~%g, viol=%g: ", scalefactor, myviol);
353 SCIPprintRowprep(scip, rowprep, NULL); */
354
355 /* SCIPscaleRowprep returns the actually applied scale factor */
356 scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
357 *viol = ldexp(*viol, scaleexp);
358
359 /* SCIPinfoMessage(scip, NULL, "scaled up by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
360 SCIPprintRowprep(scip, rowprep, NULL); */
361 }
362 }
363
364 /** scales down rowprep if it improves coefs and keeps rowprep violated */
365 static
366 void rowprepCleanupScaledown(
367 SCIP* scip, /**< SCIP data structure */
368 SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
369 SCIP_Real* viol, /**< violation of cut in sol (input and output) */
370 SCIP_Real minviol /**< minimal violation we try to keep */
371 )
372 {
373 SCIP_Real scalefactor;
374
375 /* if maxcoef < ROWPREP_SCALEDOWN_MINMAXCOEF (or no terms), then don't consider scaling down */
376 if( rowprep->nvars == 0 || REALABS(rowprep->coefs[0]) < ROWPREP_SCALEDOWN_MINMAXCOEF )
377 return;
378
379 /* consider scaling down so that maxcoef ~ 10 */
380 scalefactor = 10.0 / REALABS(rowprep->coefs[0]);
381
382 /* if minimal violation would be lost by scaling down, then increase scalefactor such that minviol is still reached */
383 if( *viol > minviol && !SCIPisInfinity(scip, *viol) && scalefactor * *viol < minviol )
384 {
385 assert(minviol > 0.0); /* since viol >= 0, the if-condition should ensure that minviol > 0 */
386 assert(*viol > 0.0); /* since minviol > 0, the if-condition ensures viol > 0 */
387 scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
388 }
389
390 /* scale by approx. scalefactor if scaling down and minimal coef does not get too small
391 * myviol < minviol (-> scalefactor > 1) or mincoef < feastol before scaling is possible, in which case we also don't scale down
392 */
393 if( scalefactor < 1.0 && scalefactor * REALABS(rowprep->coefs[rowprep->nvars-1]) > ROWPREP_SCALEDOWN_MINCOEF )
394 {
395 int scaleexp;
396
397 /* SCIPinfoMessage(scip, NULL, "scale down by ~%g, viol=%g: ", scalefactor, myviol);
398 SCIPprintRowprep(scip, rowprep, NULL); */
399
400 scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
401 if( !SCIPisInfinity(scip, *viol) )
402 *viol = ldexp(*viol, scaleexp);
403
404 /* SCIPinfoMessage(scip, NULL, "scaled down by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
405 SCIPprintRowprep(scip, rowprep, NULL); */
406 }
407 }
408
409 /** rounds almost integral coefs to integrals, thereby trying to relax the cut */
410 static
411 SCIP_RETCODE rowprepCleanupIntegralCoefs(
412 SCIP* scip, /**< SCIP data structure */
413 SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
414 SCIP_Real* viol /**< NULL or violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
415 )
416 {
417 SCIP_Real coef;
418 SCIP_Real roundcoef;
419 int i;
420
421 assert(scip != NULL);
422 assert(rowprep != NULL);
423
424 /* Coefficients smaller than epsilon are rounded to 0.0 when added to row and
425 * coefficients very close to integral values are rounded to integers when added to LP.
426 * Both cases can be problematic if variable value is very large (bad numerics).
427 * Thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible),
428 * i.e., bound coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x).
429 * Or in other words, we aggregate with the variable bound.
430 *
431 * If the required bound of x is not finite, then only round coef (introduces an error).
432 * @TODO If only the opposite bound is available, then one could move the coefficient
433 * away from the closest integer so that the SCIP_ROW won't try to round it.
434 */
435 for( i = 0; i < rowprep->nvars; ++i )
436 {
437 coef = rowprep->coefs[i];
438 roundcoef = SCIPround(scip, coef);
439 if( coef != roundcoef && SCIPisEQ(scip, coef, roundcoef) ) /*lint !e777*/
440 {
441 SCIP_Real xbnd;
442 SCIP_VAR* var;
443
444 var = rowprep->vars[i];
445 if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
446 if( rowprep->local )
447 xbnd = coef > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
448 else
449 xbnd = coef > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
450 else
451 if( rowprep->local )
452 xbnd = coef > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
453 else
454 xbnd = coef > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
455
456 if( !SCIPisInfinity(scip, REALABS(xbnd)) )
457 {
458 /* if there is a bound, then relax row side so rounding coef will not introduce an error */
459 SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.15g, round coefficient to %g and add constant %g\n",
460 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef, (coef-roundcoef) * xbnd);
461 SCIProwprepAddConstant(rowprep, (coef-roundcoef) * xbnd);
462 }
463 else
464 {
465 /* if there is no bound, then we make the coef integral, too, even though this will introduce an error
466 * however, SCIP_ROW would do this anyway, but doing this here might eliminate some epsilon coefs (so they don't determine mincoef below)
467 * and helps to get a more accurate row violation value
468 */
469 SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.15g, round coefficient to %g without relaxing side (!)\n",
470 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef);
471 }
472 rowprep->coefs[i] = roundcoef;
473 if( viol != NULL )
474 *viol = SCIP_INVALID;
475
476 /* (potentially) remember the variable which coef has been modified here */
477 SCIP_CALL( rowprepRecordModifiedVar(scip, rowprep, var) );
478 }
479 }
480
481 /* forget about coefs that became exactly zero by the above step */
482 while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
483 --rowprep->nvars;
484
485 return SCIP_OKAY;
486 }
487
488 /** relaxes almost zero side */
489 static
490 void rowprepCleanupSide(
491 SCIP* scip, /**< SCIP data structure */
492 SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
493 SCIP_Real* viol /**< NULL or violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
494 )
495 {
496 /* SCIP_ROW handling will replace a side close to 0 by 0.0, even if that makes the row more restrictive
497 * we thus relax the side here so that it will either be 0 now or will not be rounded to 0 later
498 */
499 if( rowprep->side == 0.0 || !SCIPisZero(scip, rowprep->side) )
500 return;
501
502 if( rowprep->side > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
503 rowprep->side = 1.1*SCIPepsilon(scip);
504 else if( rowprep->side < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT )
505 rowprep->side = -1.1*SCIPepsilon(scip);
506 else
507 rowprep->side = 0.0;
508
509 if( rowprep->recordmodifications )
510 rowprep->modifiedside = TRUE;
511
512 if( viol != NULL )
513 *viol = SCIP_INVALID;
514 }
515
516 /** creates a SCIP_ROWPREP datastructure
517 *
518 * Initial row represents 0 ≤ 0.
519 */
520 SCIP_RETCODE SCIPcreateRowprep(
521 SCIP* scip, /**< SCIP data structure */
522 SCIP_ROWPREP** rowprep, /**< buffer to store pointer to rowprep */
523 SCIP_SIDETYPE sidetype, /**< whether cut will be or lower-equal or larger-equal type */
524 SCIP_Bool local /**< whether cut will be valid only locally */
525 )
526 {
527 assert(scip != NULL);
528 assert(rowprep != NULL);
529
530 SCIP_CALL( SCIPallocBlockMemory(scip, rowprep) );
531 BMSclearMemory(*rowprep);
532
533 (*rowprep)->sidetype = sidetype;
534 (*rowprep)->local = local;
535
536 return SCIP_OKAY;
537 }
538
539 /** frees a SCIP_ROWPREP datastructure */
540 void SCIPfreeRowprep(
541 SCIP* scip, /**< SCIP data structure */
542 SCIP_ROWPREP** rowprep /**< pointer that stores pointer to rowprep */
543 )
544 {
545 assert(scip != NULL);
546 assert(rowprep != NULL);
547 assert(*rowprep != NULL);
548
549 SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->vars, (*rowprep)->varssize);
550 SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->coefs, (*rowprep)->varssize);
551 SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->modifiedvars, (*rowprep)->modifiedvarssize);
552 SCIPfreeBlockMemory(scip, rowprep);
553 }
554
555 /** creates a copy of a SCIP_ROWPREP datastructure */
556 SCIP_RETCODE SCIPcopyRowprep(
557 SCIP* scip, /**< SCIP data structure */
558 SCIP_ROWPREP** target, /**< buffer to store pointer of rowprep copy */
559 SCIP_ROWPREP* source /**< rowprep to copy */
560 )
561 {
562 assert(scip != NULL);
563 assert(target != NULL);
564 assert(source != NULL);
565
566 SCIP_CALL( SCIPduplicateBlockMemory(scip, target, source) );
567 if( source->coefs != NULL )
568 {
569 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->coefs, source->coefs, source->varssize) );
570 }
571 if( source->vars != NULL )
572 {
573 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->vars, source->vars, source->varssize) );
574 }
575
576 (*target)->recordmodifications = FALSE;
577 (*target)->modifiedvars = NULL;
578 (*target)->modifiedvarssize = 0;
579 (*target)->nmodifiedvars = 0;
580 (*target)->modifiedside = FALSE;
581
582 return SCIP_OKAY;
583 }
584
585 /** gives number of terms in rowprep */
586 int SCIProwprepGetNVars(
587 SCIP_ROWPREP* rowprep /**< rowprep */
588 )
589 {
590 assert(rowprep != NULL);
591
592 return rowprep->nvars;
593 }
594
595 /** gives variables of rowprep (feel free to modify) */
596 SCIP_VAR** SCIProwprepGetVars(
597 SCIP_ROWPREP* rowprep /**< rowprep */
598 )
599 {
600 assert(rowprep != NULL);
601
602 return rowprep->vars;
603 }
604
605 /** gives coefficients of rowprep (feel free to modify) */
606 SCIP_Real* SCIProwprepGetCoefs(
607 SCIP_ROWPREP* rowprep /**< rowprep */
608 )
609 {
610 assert(rowprep != NULL);
611
612 return rowprep->coefs;
613 }
614
615 /** gives side of rowprep */
616 SCIP_Real SCIProwprepGetSide(
617 SCIP_ROWPREP* rowprep /**< rowprep */
618 )
619 {
620 assert(rowprep != NULL);
621
622 return rowprep->side;
623 }
624
625 /** gives kind of inequality of rowprep */
626 SCIP_SIDETYPE SCIProwprepGetSidetype(
627 SCIP_ROWPREP* rowprep /**< rowprep */
628 )
629 {
630 assert(rowprep != NULL);
631
632 return rowprep->sidetype;
633 }
634
635 /** returns whether rowprep is locally valid only */
636 SCIP_Bool SCIProwprepIsLocal(
637 SCIP_ROWPREP* rowprep /**< rowprep */
638 )
639 {
640 assert(rowprep != NULL);
641
642 return rowprep->local;
643 }
644
645 /** returns name of rowprep (feel free to modify) */
646 char* SCIProwprepGetName(
647 SCIP_ROWPREP* rowprep /**< rowprep */
648 )
649 {
650 assert(rowprep != NULL);
651
652 return rowprep->name;
653 }
654
655 /** returns number of variables which coefficients were modified in cleanup */
656 int SCIProwprepGetNModifiedVars(
657 SCIP_ROWPREP* rowprep /**< rowprep */
658 )
659 {
660 assert(rowprep != NULL);
661
662 return rowprep->nmodifiedvars;
663 }
664
665 /** returns variables which coefficients were modified in cleanup */
666 SCIP_VAR** SCIProwprepGetModifiedVars(
667 SCIP_ROWPREP* rowprep /**< rowprep */
668 )
669 {
670 assert(rowprep != NULL);
671
672 return rowprep->modifiedvars;
673 }
674
675 /** resets rowprep to have 0 terms and side 0.0 */
676 void SCIProwprepReset(
677 SCIP_ROWPREP* rowprep /**< rowprep */
678 )
679 {
680 assert(rowprep != NULL);
681
682 rowprep->nvars = 0;
683 rowprep->side = 0.0;
684
685 rowprep->recordmodifications = FALSE;
686 rowprep->nmodifiedvars = 0;
687 rowprep->modifiedside = FALSE;
688 }
689
690 #ifdef NDEBUG
691 #undef SCIProwprepAddSide
692 #undef SCIProwprepAddConstant
693 #endif
694
695 /** adds constant value to side of rowprep */
696 void SCIProwprepAddSide(
697 SCIP_ROWPREP* rowprep, /**< rowprep */
698 SCIP_Real side /**< constant value to be added to side */
699 )
700 {
701 assert(rowprep != NULL);
702
703 rowprep->side += side;
704 }
705
706 /** adds constant term to rowprep
707 *
708 * Substracts constant from side.
709 */
710 void SCIProwprepAddConstant(
711 SCIP_ROWPREP* rowprep, /**< rowprep */
712 SCIP_Real constant /**< constant value to be added */
713 )
714 {
715 SCIProwprepAddSide(rowprep, -constant);
716 }
717
718 /** sets side type of rowprep */
719 void SCIProwprepSetSidetype(
720 SCIP_ROWPREP* rowprep, /**< rowprep */
721 SCIP_SIDETYPE sidetype /**< new side type */
722 )
723 {
724 assert(rowprep != NULL);
725
726 rowprep->sidetype = sidetype;
727 }
728
729 /** sets whether rowprep is local */
730 void SCIProwprepSetLocal(
731 SCIP_ROWPREP* rowprep, /**< rowprep */
732 SCIP_Bool islocal /**< whether rowprep is local */
733 )
734 {
735 assert(rowprep != NULL);
736
737 rowprep->local = islocal;
738 }
739
740 /** enables recording for where modifications were done in cleanup */
741 void SCIProwprepRecordModifications(
742 SCIP_ROWPREP* rowprep /**< rowprep */
743 )
744 {
745 assert(rowprep != NULL);
746
747 rowprep->recordmodifications = TRUE;
748 }
749
750 /** prints a rowprep */
751 void SCIPprintRowprep(
752 SCIP* scip, /**< SCIP data structure */
753 SCIP_ROWPREP* rowprep, /**< rowprep to be printed */
754 FILE* file /**< file to print to, or NULL for stdout */
755 )
756 {
757 int i;
758
759 assert(scip != NULL);
760 assert(rowprep != NULL);
761
762 if( *rowprep->name != '\0' )
763 {
764 SCIPinfoMessage(scip, file, "[%s](%c) ", rowprep->name, rowprep->local ? 'l' : 'g');
765 }
766
767 for( i = 0; i < rowprep->nvars; ++i )
768 {
769 SCIPinfoMessage(scip, file, "%+.15g*<%s> ", rowprep->coefs[i], SCIPvarGetName(rowprep->vars[i]));
770 }
771
772 SCIPinfoMessage(scip, file, rowprep->sidetype == SCIP_SIDETYPE_LEFT ? ">= %.15g\n" : "<= %.15g\n", rowprep->side);
773 }
774
775 /** prints a rowprep and values in solution */
776 void SCIPprintRowprepSol(
777 SCIP* scip, /**< SCIP data structure */
778 SCIP_ROWPREP* rowprep, /**< rowprep to be printed */
779 SCIP_SOL* sol, /**< solution for activity */
780 FILE* file /**< file to print to, or NULL for stdout */
781 )
782 {
783 SCIP_VAR* var;
784 SCIP_Real coef;
785 SCIP_Real term;
786 SCIP_Real maxterm;
787 SCIP_Real activity;
788 SCIP_Real violation;
789 int maxtermidx;
790 int i;
791
792 assert(scip != NULL);
793 assert(rowprep != NULL);
794
795 if( *rowprep->name != '\0' )
796 {
797 SCIPinfoMessage(scip, file, "[%s](%c) ", rowprep->name, rowprep->local ? 'l' : 'g');
798 }
799
800 activity = 0.0;
801 maxterm = REALABS(rowprep->side);
802 maxtermidx = -1;
803 for( i = 0; i < rowprep->nvars; ++i )
804 {
805 coef = rowprep->coefs[i];
806 var = rowprep->vars[i];
807 SCIPinfoMessage(scip, file, "%+.15g*<%s>(%.15g) ", coef, SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
808
809 term = coef * SCIPgetSolVal(scip, sol, var);
810 if( REALABS(term) > maxterm )
811 {
812 maxterm = term;
813 maxtermidx = i;
814 }
815
816 activity += term;
817 }
818
819 SCIPinfoMessage(scip, file, rowprep->sidetype == SCIP_SIDETYPE_LEFT ? ">= %.15g" : "<= %.15g", rowprep->side);
820
821 if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
822 /* cut is activity <= side -> violation is activity - side (if positive) */
823 violation = activity - rowprep->side;
824 else
825 /* cut is activity >= side -> violation is side - activity (if positive) */
826 violation = rowprep->side - activity;
827
828 SCIPinfoMessage(scip, file, "; activity %.15g", activity);
829 SCIPinfoMessage(scip, file, "; violation %e", violation);
830 SCIPinfoMessage(scip, file, "; maxterm %e at pos %d\n", maxterm, maxtermidx);
831 }
832
833 /** ensures that rowprep has space for at least given number of additional terms
834 *
835 * Useful when knowing in advance how many terms will be added.
836 */
837 SCIP_RETCODE SCIPensureRowprepSize(
838 SCIP* scip, /**< SCIP data structure */
839 SCIP_ROWPREP* rowprep, /**< rowprep */
840 int size /**< number of additional terms for which to alloc space in rowprep */
841 )
842 {
843 int oldsize;
844
845 assert(scip != NULL);
846 assert(rowprep != NULL);
847 assert(size >= 0);
848
849 if( rowprep->varssize >= rowprep->nvars + size )
850 return SCIP_OKAY; /* already enough space left */
851
852 /* realloc vars and coefs array */
853 oldsize = rowprep->varssize;
854 rowprep->varssize = SCIPcalcMemGrowSize(scip, rowprep->nvars + size);
855
856 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->vars, oldsize, rowprep->varssize) );
857 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->coefs, oldsize, rowprep->varssize) );
858
859 return SCIP_OKAY;
860 }
861
862 /** adds a term coef*var to a rowprep */
863 SCIP_RETCODE SCIPaddRowprepTerm(
864 SCIP* scip, /**< SCIP data structure */
865 SCIP_ROWPREP* rowprep, /**< rowprep */
866 SCIP_VAR* var, /**< variable to add */
867 SCIP_Real coef /**< coefficient to add */
868 )
869 {
870 assert(scip != NULL);
871 assert(rowprep != NULL);
872 assert(var != NULL);
873
874 if( coef == 0.0 )
875 return SCIP_OKAY;
876
877 SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, 1) );
878 assert(rowprep->varssize > rowprep->nvars);
879
880 rowprep->vars[rowprep->nvars] = var;
881 rowprep->coefs[rowprep->nvars] = coef;
882 ++rowprep->nvars;
883
884 return SCIP_OKAY;
885 }
886
887 /** adds several terms coef*var to a rowprep */
888 SCIP_RETCODE SCIPaddRowprepTerms(
889 SCIP* scip, /**< SCIP data structure */
890 SCIP_ROWPREP* rowprep, /**< rowprep */
891 int nvars, /**< number of terms to add */
892 SCIP_VAR** vars, /**< variables to add */
893 SCIP_Real* coefs /**< coefficients to add */
894 )
895 {
896 assert(scip != NULL);
897 assert(rowprep != NULL);
898 assert(vars != NULL || nvars == 0);
899 assert(coefs != NULL || nvars == 0);
900
901 if( nvars == 0 )
902 return SCIP_OKAY;
903
904 SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nvars) );
905 assert(rowprep->varssize >= rowprep->nvars + nvars);
906
907 /*lint --e{866} */
908 BMScopyMemoryArray(rowprep->vars + rowprep->nvars, vars, nvars);
909 BMScopyMemoryArray(rowprep->coefs + rowprep->nvars, coefs, nvars);
910 rowprep->nvars += nvars;
911
912 return SCIP_OKAY;
913 }
914
915 /** computes violation of rowprep in a given solution
916 *
917 * Can return whether the violation value is reliable from a floating-point accuracy point of view.
918 * The value will not be deemed reliable when its calculation involved the subtraction of large numbers.
919 * To be precise, the violation of an inequality \f$ \sum_i a_ix_i \leq b \f$ in a solution \f$x^*\f$ is deemed
920 * reliable if \f$ |\sum_i a_ix^*_i - b| \geq 2^{-50} \max (|b|, \max_i |a_ix^*_i|) \f$.
921 */
922 SCIP_Real SCIPgetRowprepViolation(
923 SCIP* scip, /**< SCIP data structure */
924 SCIP_ROWPREP* rowprep, /**< rowprep */
925 SCIP_SOL* sol, /**< solution or NULL for LP solution */
926 SCIP_Bool* reliable /**< buffer to store whether computed violation is reliable (numerically), or NULL if not of interest */
927 )
928 {
929 SCIP_Real activity;
930 SCIP_Real maxterm;
931 SCIP_Real term;
932 SCIP_Real violation;
933 SCIP_Real val;
934 int i;
935
936 activity = 0.0;
937 maxterm = REALABS(rowprep->side);
938 for( i = 0; i < rowprep->nvars; ++i )
939 {
940 /* Loose variable have the best bound as LP solution value.
941 * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
942 * When this happens, their LP solution value changes to 0.0!
943 * So when calculating the row activity for an LP solution, we treat loose variable as if they were already column variables.
944 */
945 if( sol != NULL || SCIPvarGetStatus(rowprep->vars[i]) != SCIP_VARSTATUS_LOOSE )
946 {
947 val = SCIPgetSolVal(scip, sol, rowprep->vars[i]);
948
949 /* If a variable is at infinity, then this should lead to an immediate decision.
950 * Having different contradicting infinities is something I would now know how to handle and am ignoring now.
951 */
952 if( SCIPisInfinity(scip, val * (rowprep->coefs[i] >= 0.0 ? 1.0 : -1.0)) )
953 {
954 /* activity = SCIPinfinity(scip); */
955 if( reliable != NULL )
956 *reliable = TRUE;
957 if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
958 return SCIPinfinity(scip); /* infinity <= side -> always violated */
959 else
960 return 0.0; /* infinity >= side -> never violated */
961 }
962 if( SCIPisInfinity(scip, val * (rowprep->coefs[i] >= 0.0 ? -1.0 : 1.0)) )
963 {
964 /* activity = -SCIPinfinity(scip); */
965 if( reliable != NULL )
966 *reliable = TRUE;
967 if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
968 return 0.0; /* -infinity <= side -> never violated */
969 else
970 return SCIPinfinity(scip); /* -infinity >= side -> always violated */
971 }
972
973 term = rowprep->coefs[i] * val;
974 activity += term;
975
976 if( reliable != NULL && REALABS(term) > maxterm )
977 maxterm = REALABS(term);
978 }
979 }
980
981 if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
982 /* cut is activity <= side -> violation is activity - side (if positive) */
983 violation = activity - rowprep->side;
984 else
985 /* cut is activity >= side -> violation is side - activity (if positive) */
986 violation = rowprep->side - activity;
987
988 /* In double precision, the mantissa (or significand) of a floating point number has 52 bit.
989 * Therefore, if the exponent in the violation is 52 (or more) less than the one of maxterm,
990 * then it is essentially random.
991 * We require here that the exponents differ by at most 50.
992 * To be more robust w.r.t. scaling of the row, we look at the exponent of the quotient maxterm/violation
993 * instead of the difference of the exponents of maxterm and violation.
994 */
995 if( reliable != NULL )
996 {
997 if( violation != 0.0 )
998 {
999 int exponent;
1000 (void) frexp(maxterm / violation, &exponent); /* difference in exponents for maxterm and violation */
1001 *reliable = exponent <= 50;
1002 }
1003 else
1004 *reliable = TRUE; /* not clear how to evaluate reliability here, so think positive */
1005 }
1006
1007 return MAX(violation, 0.0);
1008 }
1009
1010 /** computes violation of rowprep in a given solution and reports whether that value seem numerically reliable
1011 *
1012 * @see SCIPgetRowprepViolation()
1013 */
1014 SCIP_Bool SCIPisRowprepViolationReliable(
1015 SCIP* scip, /**< SCIP data structure */
1016 SCIP_ROWPREP* rowprep, /**< rowprep */
1017 SCIP_SOL* sol /**< solution or NULL for LP solution */
1018 )
1019 {
1020 SCIP_Bool reliable;
1021
1022 assert(scip != NULL);
1023 assert(rowprep != NULL);
1024
1025 (void) SCIPgetRowprepViolation(scip, rowprep, sol, &reliable);
1026
1027 return reliable;
1028 }
1029
1030 /** Merge terms that use same variable and eliminate zero coefficients.
1031 *
1032 * Removes a variable if its bounds have a relative difference of below epsilon.
1033 * Local bounds are checked for local rows, otherwise global bounds are used.
1034 * If the bounds are not absolute equal, the bound that relaxes the row is used.
1035 *
1036 * Terms are sorted by variable (see SCIPvarComp()) after return.
1037 */
1038 void SCIPmergeRowprepTerms(
1039 SCIP* scip, /**< SCIP data structure */
1040 SCIP_ROWPREP* rowprep /**< rowprep to be cleaned up */
1041 )
1042 {
1043 int i;
1044 int j;
1045
1046 assert(scip != NULL);
1047 assert(rowprep != NULL);
1048
1049 if( rowprep->nvars <= 1 )
1050 return;
1051
1052 /* sort terms by variable index */
1053 SCIPsortPtrReal((void**)rowprep->vars, rowprep->coefs, SCIPvarComp, rowprep->nvars);
1054
1055 /* merge terms with same variable, drop 0 coefficients */
1056 i = 0;
1057 j = 1;
1058 while( j < rowprep->nvars )
1059 {
1060 if( rowprep->vars[i] == rowprep->vars[j] )
1061 {
1062 /* merge term j into term i */
1063 rowprep->coefs[i] += rowprep->coefs[j];
1064 ++j;
1065 continue;
1066 }
1067
1068 /* move term i into side if fixed */
1069 if( rowprep->local && SCIPisRelEQ(scip, SCIPvarGetLbLocal(rowprep->vars[i]), SCIPvarGetUbLocal(rowprep->vars[i])) )
1070 {
1071 if( (rowprep->coefs[i] > 0.0) == (rowprep->sidetype == SCIP_SIDETYPE_RIGHT) )
1072 rowprep->side -= rowprep->coefs[i] * SCIPvarGetLbLocal(rowprep->vars[i]);
1073 else
1074 rowprep->side -= rowprep->coefs[i] * SCIPvarGetUbLocal(rowprep->vars[i]);
1075 rowprep->coefs[i] = 0.0; /* so will be cleaned out below */
1076 }
1077 else if( !rowprep->local && SCIPisRelEQ(scip, SCIPvarGetLbGlobal(rowprep->vars[i]), SCIPvarGetUbGlobal(rowprep->vars[i])) )
1078 {
1079 if( (rowprep->coefs[i] > 0.0) == (rowprep->sidetype == SCIP_SIDETYPE_RIGHT) )
1080 rowprep->side -= rowprep->coefs[i] * SCIPvarGetLbGlobal(rowprep->vars[i]);
1081 else
1082 rowprep->side -= rowprep->coefs[i] * SCIPvarGetUbGlobal(rowprep->vars[i]);
1083 rowprep->coefs[i] = 0.0; /* so will be cleaned out below */
1084 }
1085
1086 if( rowprep->coefs[i] == 0.0 )
1087 {
1088 /* move term j to position i */
1089 rowprep->coefs[i] = rowprep->coefs[j];
1090 rowprep->vars[i] = rowprep->vars[j];
1091 ++j;
1092 continue;
1093 }
1094
1095 /* move term j to position i+1 and move on */
1096 if( j != i+1 )
1097 {
1098 rowprep->vars[i+1] = rowprep->vars[j];
1099 rowprep->coefs[i+1] = rowprep->coefs[j];
1100 }
1101 ++i;
1102 ++j;
1103 }
1104
1105 /* move term i into side if fixed */
1106 if( rowprep->local && SCIPisRelEQ(scip, SCIPvarGetLbLocal(rowprep->vars[i]), SCIPvarGetUbLocal(rowprep->vars[i])) )
1107 {
1108 if( (rowprep->coefs[i] > 0.0) == (rowprep->sidetype == SCIP_SIDETYPE_RIGHT) )
1109 rowprep->side -= rowprep->coefs[i] * SCIPvarGetLbLocal(rowprep->vars[i]);
1110 else
1111 rowprep->side -= rowprep->coefs[i] * SCIPvarGetUbLocal(rowprep->vars[i]);
1112 rowprep->coefs[i] = 0.0; /* so will be cleaned out below */
1113 }
1114 else if( !rowprep->local && SCIPisRelEQ(scip, SCIPvarGetLbGlobal(rowprep->vars[i]), SCIPvarGetUbGlobal(rowprep->vars[i])) )
1115 {
1116 if( (rowprep->coefs[i] > 0.0) == (rowprep->sidetype == SCIP_SIDETYPE_RIGHT) )
1117 rowprep->side -= rowprep->coefs[i] * SCIPvarGetLbGlobal(rowprep->vars[i]);
1118 else
1119 rowprep->side -= rowprep->coefs[i] * SCIPvarGetUbGlobal(rowprep->vars[i]);
1120 rowprep->coefs[i] = 0.0; /* so will be cleaned out below */
1121 }
1122
1123 /* remaining term can have coef zero -> forget about it */
1124 if( rowprep->coefs[i] == 0.0 )
1125 --i;
1126
1127 /* i points to last term */
1128 rowprep->nvars = i+1;
1129 }
1130
1131 /** Cleans up and attempts to improve rowprep
1132 *
1133 * Drops small or large coefficients if coefrange is too large, if this can be done by relaxing the row.
1134 * Scales coefficients up to reach minimal violation, if possible.
1135 * Scaling is omitted if violation is very small (\ref ROWPREP_SCALEUP_VIOLNONZERO) or
1136 * maximal coefficient would become huge (\ref ROWPREP_SCALEUP_MAXMAXCOEF).
1137 * Scales coefficients and side down if they are large and if the minimal violation is still reached.
1138 * Rounds coefficients close to integral values to integrals, if this can be done by relaxing the row.
1139 * Rounds side within epsilon of 0 to 0.0 or +/-1.1*epsilon, whichever relaxes the row least.
1140 *
1141 * After return, the terms in the rowprep will be sorted by absolute value of coefficient, in decreasing order.
1142 * Thus, the coefrange can be obtained via `REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1])` (if nvars>0).
1143 *
1144 * `success` is set to TRUE if and only if the rowprep satisfies the following:
1145 * - the coefrange is below `maxcoefrange`
1146 * - the violation is at least `minviol`
1147 * - the violation is reliable or `minviol` = 0
1148 * - the absolute value of coefficients are below SCIPinfinity()
1149 * - the absolute value of the side is below SCIPinfinity()
1150 */
1151 SCIP_RETCODE SCIPcleanupRowprep(
1152 SCIP* scip, /**< SCIP data structure */
1153 SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
1154 SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
1155 SCIP_Real minviol, /**< minimal absolute violation the row should achieve (w.r.t. sol) */
1156 SCIP_Real* viol, /**< buffer to store absolute violation of cleaned up cut in sol, or NULL if not of interest */
1157 SCIP_Bool* success /**< buffer to store whether cut cleanup was successful, or NULL if not of interest */
1158 )
1159 {
1160 SCIP_Real myviol;
1161 SCIP_Bool violreliable = TRUE;
1162 SCIP_Real maxcoefrange;
1163 #ifdef SCIP_DEBUG
1164 SCIP_Real mincoef = 1.0;
1165 SCIP_Real maxcoef = 1.0;
1166 #endif
1167
1168 maxcoefrange = SCIPsetGetSepaMaxCoefRatioRowprep(scip->set);
1169
1170 if( rowprep->recordmodifications )
1171 {
1172 /* forget about possible previous modifications */
1173 rowprep->nmodifiedvars = 0;
1174 rowprep->modifiedside = FALSE;
1175 }
1176
1177 /* sort term by absolute value of coef. */
1178 SCIP_CALL( rowprepCleanupSortTerms(scip, rowprep) );
1179
1180 #ifdef SCIP_DEBUG
1181 if( rowprep->nvars > 0 )
1182 {
1183 maxcoef = REALABS(rowprep->coefs[0]);
1184 mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
1185 }
1186
1187 SCIPinfoMessage(scip, NULL, "starting cleanup, coefrange %g: ", maxcoef/mincoef);
1188 SCIPprintRowprep(scip, rowprep, NULL);
1189 #endif
1190
1191 /* improve coefficient range by aggregating out variables */
1192 SCIP_CALL( rowprepCleanupImproveCoefrange(scip, rowprep, sol, maxcoefrange) );
1193
1194 /* get current violation in sol (reliability info only needed if success is not NULL) */
1195 myviol = SCIPgetRowprepViolation(scip, rowprep, sol, success != NULL ? &violreliable : NULL); /*lint !e826*/
1196 assert(myviol >= 0.0);
1197
1198 #ifdef SCIP_DEBUG
1199 if( rowprep->nvars > 0 )
1200 {
1201 maxcoef = REALABS(rowprep->coefs[0]);
1202 mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
1203 }
1204
1205 SCIPinfoMessage(scip, NULL, "improved coefrange to %g, viol %g: ", maxcoef / mincoef, myviol);
1206 SCIPprintRowprep(scip, rowprep, NULL);
1207 #endif
1208
1209 /* if there is interest in achieving some minimal violation, then possibly scale up to increase violation
1210 * this updates myviol; since this is only scaling the cut, it doesn't change anything about the reliability of the violation value */
1211 if( minviol > 0.0 )
1212 {
1213 /* first, try to achieve scip's minefficacy (typically 1e-4) */
1214 if( SCIPgetSepaMinEfficacy(scip) > minviol )
1215 rowprepCleanupScaleup(scip, rowprep, &myviol, SCIPgetSepaMinEfficacy(scip));
1216 /* in case scip minefficacy could not be reached or was smaller than minviol, try with the given minviol */
1217 rowprepCleanupScaleup(scip, rowprep, &myviol, minviol);
1218 }
1219
1220 /* scale down to improve numerics, updates myviol (reliability doesn't change) */
1221 rowprepCleanupScaledown(scip, rowprep, &myviol, MAX(SCIPgetSepaMinEfficacy(scip), minviol)); /*lint !e666*/
1222
1223 #ifdef SCIP_DEBUG
1224 SCIPinfoMessage(scip, NULL, "applied scaling, viol %g: ", myviol);
1225 SCIPprintRowprep(scip, rowprep, NULL);
1226 #endif
1227
1228 /* turn almost-integral coefs to integral values, may set myviol to SCIP_INVALID */
1229 SCIP_CALL( rowprepCleanupIntegralCoefs(scip, rowprep, &myviol) );
1230
1231 /* relax almost-zero side, may set myviol to SCIP_INVALID */
1232 rowprepCleanupSide(scip, rowprep, &myviol);
1233
1234 #ifdef SCIP_DEBUG
1235 SCIPinfoMessage(scip, NULL, "adjusted almost-integral coefs and sides, viol %g: ", myviol);
1236 SCIPprintRowprep(scip, rowprep, NULL);
1237 #endif
1238
1239 #if !1
1240 /* compute final coefrange, if requested by caller */
1241 if( coefrange != NULL )
1242 {
1243 if( rowprep->nvars > 0 )
1244 *coefrange = REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]);
1245 else
1246 *coefrange = 1.0;
1247 }
1248 #endif
1249
1250 /* check whether rowprep could be turned into a reasonable row */
1251 if( success != NULL )
1252 {
1253 *success = TRUE;
1254
1255 /* check whether the coef.range is below maxcoefrange */
1256 if( rowprep->nvars > 0 && REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]) > maxcoefrange )
1257 {
1258 SCIPdebugMsg(scip, "rowprep coefrange %g is above the limit %g\n", REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]), maxcoefrange);
1259 *success = FALSE;
1260 }
1261
1262 /* check whether coefficients are below SCIPinfinity (terms are order by coef value) */
1263 if( *success && rowprep->nvars > 0 && SCIPisInfinity(scip, REALABS(rowprep->coefs[0])) )
1264 {
1265 SCIPdebugMsg(scip, "rowprep coefficient %g is beyond value for infinity\n", rowprep->coefs[0]);
1266 *success = FALSE;
1267 }
1268
1269 /* check whether the absolute value of the side is below SCIPinfinity */
1270 if( *success && SCIPisInfinity(scip, REALABS(rowprep->side)) )
1271 {
1272 SCIPdebugMsg(scip, "rowprep side %g is beyond value for infinity\n", rowprep->side);
1273 *success = FALSE;
1274 }
1275
1276 /* check if violation is at least minviol and reliable, if minviol > 0 */
1277 if( *success && minviol > 0.0 )
1278 {
1279 /* may need to recompute violation if coefs or side was modified above */
1280 if( myviol == SCIP_INVALID ) /*lint !e777 */
1281 myviol = SCIPgetRowprepViolation(scip, rowprep, sol, &violreliable);
1282
1283 if( !violreliable )
1284 {
1285 SCIPdebugMsg(scip, "rowprep violation %g is not reliable\n", myviol);
1286 *success = FALSE;
1287 }
1288 else if( myviol < minviol )
1289 {
1290 SCIPdebugMsg(scip, "rowprep violation %g is below minimal violation %g\n", myviol, minviol);
1291 *success = FALSE;
1292 }
1293 }
1294 }
1295
1296 /* If we updated myviol correctly, then it should coincide with freshly computed violation.
1297 * I leave this assert off for now, since getting the tolerance in the EQ correctly is not trivial. We recompute viol below anyway.
1298 */
1299 /* assert(myviol == SCIP_INVALID || SCIPisEQ(scip, myviol, SCIPgetRowprepViolation(scip, rowprep, sol, NULL))); */
1300
1301 /* compute final violation, if requested by caller */
1302 if( viol != NULL ) /*lint --e{777} */
1303 *viol = myviol == SCIP_INVALID ? SCIPgetRowprepViolation(scip, rowprep, sol, NULL) : myviol;
1304
1305 return SCIP_OKAY;
1306 }
1307
1308 /** Cleans up and attempts to improve rowprep without regard for violation
1309 *
1310 * Drops small or large coefficients if their ratio is beyond separating/maxcoefratiofacrowprep / numerics/feastol,
1311 * if this can be done by relaxing the row.
1312 * Scales coefficients and side to have maximal coefficient in `[1/maxcoefbound,maxcoefbound]`.
1313 * Rounds coefficients close to integral values to integrals, if this can be done by relaxing the row.
1314 * Rounds side within epsilon of 0 to 0.0 or +/-1.1*epsilon, whichever relaxes the row least.
1315 *
1316 * After return, the terms in the rowprep will be sorted by absolute value of coefficient, in decreasing order.
1317 * Thus, the coefratio can be obtained via `REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1])` (if nvars>0).
1318 *
1319 * `success` is set to TRUE if and only if the rowprep satisfies the following:
1320 * - the coefratio is below separating/maxcoefratiofacrowprep / numerics/feastol
1321 * - the absolute value of coefficients are below SCIPinfinity()
1322 * - the absolute value of the side is below SCIPinfinity()
1323 *
1324 * In difference to SCIPcleanupRowprep(), this function does not scale up the row to increase the absolute violation.
1325 */
1326 SCIP_RETCODE SCIPcleanupRowprep2(
1327 SCIP* scip, /**< SCIP data structure */
1328 SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
1329 SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
1330 SCIP_Real maxcoefbound, /**< bound on absolute value of largest coefficient */
1331 SCIP_Bool* success /**< buffer to store whether cut cleanup was successful, or NULL if not of interest */
1332 )
1333 {
1334 SCIP_Real maxcoefrange;
1335 #ifdef SCIP_DEBUG
1336 SCIP_Real mincoef = 1.0;
1337 SCIP_Real maxcoef = 1.0;
1338 #endif
1339
1340 assert(maxcoefbound >= 1.0);
1341
1342 maxcoefrange = SCIPsetGetSepaMaxCoefRatioRowprep(scip->set);
1343
|
(1) Event deref_parm: |
Directly dereferencing parameter "rowprep". |
1344 if( rowprep->recordmodifications )
1345 {
1346 /* forget about possible previous modifications */
1347 rowprep->nmodifiedvars = 0;
1348 rowprep->modifiedside = FALSE;
1349 }
1350
1351 /* sort term by absolute value of coef. */
1352 SCIP_CALL( rowprepCleanupSortTerms(scip, rowprep) );
1353
1354 #ifdef SCIP_DEBUG
1355 if( rowprep->nvars > 0 )
1356 {
1357 maxcoef = REALABS(rowprep->coefs[0]);
1358 mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
1359 }
1360
1361 SCIPinfoMessage(scip, NULL, "starting cleanup, coefrange %g: ", maxcoef/mincoef);
1362 SCIPprintRowprep(scip, rowprep, NULL);
1363 #endif
1364
1365 /* improve coefficient range by aggregating out variables */
1366 SCIP_CALL( rowprepCleanupImproveCoefrange(scip, rowprep, sol, maxcoefrange) );
1367
1368 #ifdef SCIP_DEBUG
1369 if( rowprep->nvars > 0 )
1370 {
1371 maxcoef = REALABS(rowprep->coefs[0]);
1372 mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
1373 }
1374
1375 SCIPinfoMessage(scip, NULL, "improved coefrange to %g: ", maxcoef / mincoef);
1376 SCIPprintRowprep(scip, rowprep, NULL);
1377 #endif
1378
1379 /* scale up or down to improve numerics
1380 * if maximal coef is below 1.0/maxcoefbound, scale up to reach ~ 1.0/maxcoefbound
1381 * if maximal coef is above maxcoefbound, scale down to ~ maxcoefbound
1382 */
1383 if( rowprep->nvars > 0 && !SCIPisInfinity(scip, maxcoefbound) )
1384 {
1385 SCIP_Real expon = 0.0;
1386 if( REALABS(rowprep->coefs[0]) < 1.0/maxcoefbound )
1387 expon = SCIPscaleRowprep(rowprep, (1.0/maxcoefbound) / REALABS(rowprep->coefs[0]));
1388 else if( REALABS(rowprep->coefs[0]) > maxcoefbound )
1389 expon = SCIPscaleRowprep(rowprep, maxcoefbound / REALABS(rowprep->coefs[0]));
1390
1391 #ifdef SCIP_DEBUG
1392 SCIPinfoMessage(scip, NULL, "applied scaling by %g: ", pow(2.0, expon));
1393 SCIPprintRowprep(scip, rowprep, NULL);
1394 #else
1395 (void) expon;
1396 #endif
1397 }
1398
1399 /* turn almost-integral coefs to integral values */
1400 SCIP_CALL( rowprepCleanupIntegralCoefs(scip, rowprep, NULL) );
1401
1402 /* relax almost-zero side */
1403 rowprepCleanupSide(scip, rowprep, NULL);
1404
1405 #ifdef SCIP_DEBUG
1406 SCIPinfoMessage(scip, NULL, "adjusted almost-integral coefs and sides: ");
1407 SCIPprintRowprep(scip, rowprep, NULL);
1408 #endif
1409
1410 /* check whether rowprep could be turned into a reasonable row */
1411 if( success != NULL )
1412 {
1413 *success = TRUE;
1414
1415 /* check whether the coef.range is below maxcoefrange */
1416 if( rowprep->nvars > 0 && REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]) > maxcoefrange )
1417 {
1418 SCIPdebugMsg(scip, "rowprep coefrange %g is above the limit %g\n", REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]), maxcoefrange);
1419 *success = FALSE;
1420 }
1421
1422 /* check whether coefficients are below SCIPinfinity (terms are order by coef value) */
1423 if( *success && rowprep->nvars > 0 && SCIPisInfinity(scip, REALABS(rowprep->coefs[0])) )
1424 {
1425 SCIPdebugMsg(scip, "rowprep coefficient %g is beyond value for infinity\n", rowprep->coefs[0]);
1426 *success = FALSE;
1427 }
1428
1429 /* check whether the absolute value of the side is below SCIPinfinity */
1430 if( *success && SCIPisInfinity(scip, REALABS(rowprep->side)) )
1431 {
1432 SCIPdebugMsg(scip, "rowprep side %g is beyond value for infinity\n", rowprep->side);
1433 *success = FALSE;
1434 }
1435 }
1436
1437 return SCIP_OKAY;
1438 }
1439
1440 /** Scales up a rowprep to increase coefficients/sides that are within epsilon to an integer value, if possible.
1441 *
1442 * Computes the minimal fractionality of all fractional coefficients and the side of the rowprep.
1443 * If this fractionality is below epsilon, the rowprep is scaled up such that the fractionality exceeds epsilon,
1444 * if this will not put any coefficient or side above SCIPhugeValue().
1445 *
1446 * This function does not relax the rowprep.
1447 *
1448 * `success` is set to TRUE if the resulting rowprep can be turned into a SCIP_ROW, that is,
1449 * all coefs and the side is below SCIPinfinity() and fractionalities are above epsilon.
1450 * If `success` is set to FALSE, then the rowprep will not have been modified.
1451 *
1452 * @return The applied scaling factor, if `success` is set to TRUE.
1453 */
1454 SCIP_Real SCIPscaleupRowprep(
1455 SCIP* scip, /**< SCIP data structure */
1456 SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
1457 SCIP_Real minscaleup, /**< minimal factor by which to scale up row, or <= 1.0 if to be ignored */
1458 SCIP_Bool* success /**< buffer to store whether rowprep could be turned into SCIP_ROW without loss, or NULL if not of interest */
1459 )
1460 {
1461 SCIP_Real minfrac = 0.5;
1462 SCIP_Real minfrac0 = 0.5;
1463 SCIP_Real frac;
1464 SCIP_Real maxval;
1465 SCIP_Real factor = 1.0;
1466 SCIP_Bool makeintegral = TRUE;
1467 int i;
1468
1469 /* find the smallest fractionality in rowprep sides and coefficients and the largest absolute coefficient/side */
1470 frac = REALABS(floor(rowprep->side + 0.5) - rowprep->side);
1471 if( frac != 0.0 )
1472 {
1473 if( REALABS(rowprep->side) > 0.5 )
1474 {
1475 if( frac < minfrac )
1476 minfrac = frac;
1477 }
1478 else if( frac < minfrac0 )
1479 minfrac0 = frac;
1480 }
1481 maxval = REALABS(rowprep->side);
1482
1483 for( i = 0; i < rowprep->nvars; ++i )
1484 {
1485 frac = REALABS(floor(rowprep->coefs[i] + 0.5) - rowprep->coefs[i]);
1486 if( frac != 0.0 )
1487 {
1488 if( REALABS(rowprep->coefs[i]) > 0.5 )
1489 {
1490 if( frac < minfrac )
1491 minfrac = frac;
1492 }
1493 else if( frac < minfrac0 )
1494 minfrac0 = frac;
1495 }
1496 if( REALABS(rowprep->coefs[i]) > maxval )
1497 maxval = REALABS(rowprep->coefs[i]);
1498 }
1499
1500 SCIPdebugMsg(scip, "minimal fractional of rowprep coefs and side is %g, max coef/side is %g\n", MIN(minfrac, minfrac0), maxval);
1501
1502 /* in order for SCIP_ROW to not modify the coefs and side, they need to be more than epsilon way from an integer value
1503 *
1504 * If the integer value is 0, then scaling up the rowprep by epsilon/minfrac will increase its minimal fractionality
1505 * above epsilon.
1506 * If the integer value is not zero, then scaling up the rowprep by a well-chosen fractional number alpha will increase
1507 * the minimal fractionality by about alpha*integer-value mod 1. To reduce the chance that alpha*integer-value is integral,
1508 * we use a "very fractional" value for alpha.
1509 *
1510 * If the scaling increases the maximal coef/value beyond SCIPinfinity, then the rowprep would be useless.
1511 * We even check that we don't increase beyond SCIPhugeValue here
1512 */
1513 if( minfrac0 <= SCIPepsilon(scip) )
1514 {
1515 factor = 1.1 * SCIPepsilon(scip) / minfrac0;
1516
1517 if( factor < minscaleup )
1518 factor = minscaleup;
1519 }
1520 else if( minfrac <= SCIPepsilon(scip) )
1521 {
1522 factor = MAX(M_SQRT2, minscaleup);
1523 makeintegral = FALSE;
1524 }
1525 else if( minscaleup > 1.0 )
1526 {
1527 factor = minscaleup;
1528 }
1529 else
1530 {
1531 /* do not scale up, only check whether maxval is already below infinity */
1532 if( success != NULL )
1533 *success = !SCIPisInfinity(scip, maxval);
1534
1535 return 1.0;
1536 }
1537
1538 if( !SCIPisHugeValue(scip, factor * maxval) )
1539 {
1540 if( makeintegral)
1541 {
1542 factor = SCIPscaleRowprep(rowprep, factor);
1543
1544 #ifdef SCIP_DEBUG
1545 factor = pow(2.0, factor); /* SCIPscaleRowprep() actually returned log2 of factor */
1546 #endif
1547 }
1548 else
1549 {
1550 /* multiply each coefficient by factor */
1551 for( i = 0; i < rowprep->nvars; ++i )
1552 rowprep->coefs[i] *= factor;
1553
1554 /* multiply side by factor */
1555 rowprep->side *= factor;
1556 }
1557 #ifdef SCIP_DEBUG
1558 maxval *= factor;
1559 SCIPinfoMessage(scip, NULL, "scaled up rowprep by %g (minfrac=%g, minscaleup=%g), maxval is now %g\n", factor, minfrac, minscaleup, maxval);
1560 SCIPprintRowprep(scip, rowprep, NULL);
1561 #endif
1562
1563 if( success != NULL )
1564 *success = TRUE;
1565 }
1566 else if( success != NULL )
1567 *success = FALSE;
1568
1569 return factor;
1570 }
1571
1572 /** scales a rowprep by given factor (after some rounding)
1573 *
1574 * @return Exponent of actually applied scaling factor, if written as \f$2^x\f$.
1575 */
1576 int SCIPscaleRowprep(
1577 SCIP_ROWPREP* rowprep, /**< rowprep to be scaled */
1578 SCIP_Real factor /**< suggested scale factor */
1579 )
1580 {
1581 double v;
1582 int expon;
1583 int i;
1584
1585 assert(rowprep != NULL);
1586 assert(factor > 0.0);
1587
1588 /* write factor as v*2^expon with v in [0.5,1) */
1589 v = frexp(factor, &expon);
1590 /* adjust to v'*2^expon with v' in (0.5,1] by v'=v if v > 0.5, v'=1 if v=0.5 */
1591 if( v == 0.5 )
1592 --expon;
1593
1594 /* multiply each coefficient by 2^expon */
1595 for( i = 0; i < rowprep->nvars; ++i )
1596 rowprep->coefs[i] = ldexp(rowprep->coefs[i], expon);
1597
1598 /* multiply side by 2^expon */
1599 rowprep->side = ldexp(rowprep->side, expon);
1600
1601 return expon;
1602 }
1603
1604 /** generates a SCIP_ROW from a rowprep, setting its origin to given constraint handler */
1605 SCIP_RETCODE SCIPgetRowprepRowConshdlr(
1606 SCIP* scip, /**< SCIP data structure */
1607 SCIP_ROW** row, /**< buffer to store pointer to new row */
1608 SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
1609 SCIP_CONSHDLR* conshdlr /**< constraint handler */
1610 )
1611 {
1612 assert(scip != NULL);
1613 assert(row != NULL);
1614 assert(rowprep != NULL);
1615 assert(conshdlr != NULL);
1616
1617 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, row, conshdlr, rowprep->name,
1618 rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
1619 rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
1620 rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
1621
1622 SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
1623
1624 return SCIP_OKAY;
1625 }
1626
1627 /** generates a SCIP_ROW from a rowprep, setting its origin to given constraint */
1628 SCIP_RETCODE SCIPgetRowprepRowCons(
1629 SCIP* scip, /**< SCIP data structure */
1630 SCIP_ROW** row, /**< buffer to store pointer to new row */
1631 SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
1632 SCIP_CONS* cons /**< constraint */
1633 )
1634 {
1635 assert(scip != NULL);
1636 assert(row != NULL);
1637 assert(rowprep != NULL);
1638 assert(cons != NULL);
1639
1640 SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, cons, rowprep->name,
1641 rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
1642 rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
1643 rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
1644
1645 SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
1646
1647 return SCIP_OKAY;
1648 }
1649
1650 /** generates a SCIP_ROW from a rowprep, setting its origin to given separator */
1651 SCIP_RETCODE SCIPgetRowprepRowSepa(
1652 SCIP* scip, /**< SCIP data structure */
1653 SCIP_ROW** row, /**< buffer to store pointer to new row */
1654 SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
1655 SCIP_SEPA* sepa /**< separator */
1656 )
1657 {
1658 assert(scip != NULL);
1659 assert(row != NULL);
1660 assert(rowprep != NULL);
1661
1662 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, rowprep->name,
1663 rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
1664 rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
1665 rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
1666
1667 SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
1668
1669 return SCIP_OKAY;
1670 }
1671