Scippy

SCIP

Solving Constraint Integer Programs

sepastore.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file sepastore.c
26 * @ingroup OTHER_CFILES
27 * @brief methods for storing separated cuts
28 * @author Tobias Achterberg
29 * @author Marc Pfetsch
30 * @author Leona Gottwald
31 */
32
33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34
35#include <assert.h>
36
37#include "scip/def.h"
38#include "scip/set.h"
39#include "scip/stat.h"
40#include "scip/lp.h"
41#include "scip/lpexact.h"
42#include "scip/var.h"
43#include "scip/tree.h"
44#include "scip/reopt.h"
45#include "scip/sepastore.h"
46#include "scip/event.h"
47#include "scip/sepa.h"
48#include "scip/cons.h"
49#include "scip/debug.h"
50#include "scip/scip.h"
51#include "scip/cuts.h"
52#include "scip/cutsel.h"
53#include "scip/struct_event.h"
55#include "scip/misc.h"
56#include "scip/pub_lpexact.h"
57#include "scip/scip_lpexact.h"
58
59
60
61/*
62 * dynamic memory arrays
63 */
64
65/** resizes cuts and score arrays to be able to store at least num entries */
66static
68 SCIP_SEPASTORE* sepastore, /**< separation storage */
69 SCIP_SET* set, /**< global SCIP settings */
70 int num /**< minimal number of slots in array */
71 )
72{
73 assert(sepastore != NULL);
74 assert(set != NULL);
75
76 if( num > sepastore->cutssize )
77 {
78 int newsize;
79
80 newsize = SCIPsetCalcMemGrowSize(set, num);
81 SCIP_ALLOC( BMSreallocMemoryArray(&sepastore->cuts, newsize) );
82 sepastore->cutssize = newsize;
83 }
84 assert(num <= sepastore->cutssize);
85
86 return SCIP_OKAY;
87}
88
89/** creates separation storage */
91 SCIP_SEPASTORE** sepastore, /**< pointer to store separation storage */
92 BMS_BLKMEM* blkmem, /**< block memory */
93 SCIP_SET* set /**< global SCIP settings */
94 )
95{
96 assert(sepastore != NULL);
97
98 SCIP_ALLOC( BMSallocMemory(sepastore) );
99
100 (*sepastore)->cuts = NULL;
101 (*sepastore)->cutssize = 0;
102 (*sepastore)->ncuts = 0;
103 (*sepastore)->nforcedcuts = 0;
104 (*sepastore)->ncutsadded = 0;
105 (*sepastore)->ncutsaddedviapool = 0;
106 (*sepastore)->ncutsaddeddirect = 0;
107 (*sepastore)->ncutsfoundround = 0;
108 (*sepastore)->ncutsapplied = 0;
109 (*sepastore)->initiallp = FALSE;
110 (*sepastore)->forcecuts = FALSE;
111
112 SCIP_CALL( SCIPrandomCreate(&(*sepastore)->randnumgen, blkmem, SCIPsetInitializeRandomSeed(set, 0x5EED)) );
113
114 return SCIP_OKAY;
115}
116
117/** frees separation storage */
119 SCIP_SEPASTORE** sepastore, /**< pointer to store separation storage */
120 BMS_BLKMEM* blkmem /**< block memory */
121 )
122{
123 assert(sepastore != NULL);
124 assert(*sepastore != NULL);
125 assert((*sepastore)->ncuts == 0);
126
127 SCIPrandomFree(&(*sepastore)->randnumgen, blkmem);
128 BMSfreeMemoryArrayNull(&(*sepastore)->cuts);
129 BMSfreeMemory(sepastore);
130
131 return SCIP_OKAY;
132}
133
134/** informs separation storage that the setup of the initial LP starts now */
136 SCIP_SEPASTORE* sepastore /**< separation storage */
137 )
138{
139 assert(sepastore != NULL);
140 assert(!sepastore->initiallp);
141 assert(sepastore->ncuts == 0);
142
143 sepastore->initiallp = TRUE;
144}
145
146/** informs separation storage that the setup of the initial LP is now finished */
148 SCIP_SEPASTORE* sepastore /**< separation storage */
149 )
150{
151 assert(sepastore != NULL);
152 assert(sepastore->initiallp);
153 assert(sepastore->ncuts == 0);
154
155 sepastore->initiallp = FALSE;
156}
157
158/** informs separation storage that the following cuts should be used in any case */
160 SCIP_SEPASTORE* sepastore /**< separation storage */
161 )
162{
163 assert(sepastore != NULL);
164 assert(!sepastore->forcecuts);
165
166 sepastore->forcecuts = TRUE;
167}
168
169/** informs separation storage that the following cuts should no longer be used in any case */
171 SCIP_SEPASTORE* sepastore /**< separation storage */
172 )
173{
174 assert(sepastore != NULL);
175 assert(sepastore->forcecuts);
176
177 sepastore->forcecuts = FALSE;
178}
179
180/** checks cut for redundancy due to activity bounds */
181static
183 SCIP_SEPASTORE* sepastore, /**< separation storage */
184 SCIP_SET* set, /**< global SCIP settings */
185 SCIP_STAT* stat, /**< problem statistics data */
186 SCIP_ROW* cut /**< separated cut */
187 )
188{
189 SCIP_Real minactivity;
190 SCIP_Real maxactivity;
191 SCIP_Real lhs;
192 SCIP_Real rhs;
193
194 assert(sepastore != NULL);
195 assert(cut != NULL);
196
197 /* modifiable cuts cannot be declared redundant, since we don't know all coefficients */
198 if( SCIProwIsModifiable(cut) )
199 return FALSE;
200
201 /** @todo implement a safe redundancy check for cuts in exact solving mode */
202 if( set->exact_enable )
203 return FALSE;
204
205 /* check for activity redundancy */
206 lhs = SCIProwGetLhs(cut);
207 rhs = SCIProwGetRhs(cut);
208 minactivity = SCIProwGetMinActivity(cut, set, stat);
209 maxactivity = SCIProwGetMaxActivity(cut, set, stat);
210
211 if( (SCIPsetIsInfinity(set, -lhs) || SCIPsetIsLE(set, lhs, minactivity)) &&
212 (SCIPsetIsInfinity(set, rhs) || SCIPsetIsLE(set, maxactivity, rhs)) )
213 {
214 SCIPsetDebugMsg(set, "ignoring activity redundant cut <%s> (sides=[%g,%g], act=[%g,%g])\n",
215 SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
216 /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
217 return TRUE;
218 }
219
220 return FALSE;
221}
222
223/** checks cut for redundancy or infeasibility due to activity bounds */
224static
226 SCIP_SEPASTORE* sepastore, /**< separation storage */
227 SCIP_SET* set, /**< global SCIP settings */
228 SCIP_STAT* stat, /**< problem statistics data */
229 SCIP_ROW* cut, /**< separated cut */
230 SCIP_Bool* infeasible /**< pointer to store whether the cut has been detected to be infeasible */
231 )
232{
233 SCIP_Real minactivity;
234 SCIP_Real maxactivity;
235 SCIP_Real lhs;
236 SCIP_Real rhs;
237
238 assert(sepastore != NULL);
239 assert(cut != NULL);
240 assert(infeasible != NULL);
241
242 *infeasible = FALSE;
243
244 /** @todo implement a safe redundancy or infeasibility check for cuts in exact solving mode */
245 if( set->exact_enable )
246 return FALSE;
247
248 /* modifiable cuts cannot be declared redundant or infeasible, since we don't know all coefficients */
249 if( SCIProwIsModifiable(cut) )
250 return FALSE;
251
252 /* check for activity redundancy */
253 lhs = SCIProwGetLhs(cut);
254 rhs = SCIProwGetRhs(cut);
255 minactivity = SCIProwGetMinActivity(cut, set, stat);
256 maxactivity = SCIProwGetMaxActivity(cut, set, stat);
257
258 if( (SCIPsetIsInfinity(set, -lhs) || SCIPsetIsLE(set, lhs, minactivity)) &&
259 (SCIPsetIsInfinity(set, rhs) || SCIPsetIsLE(set, maxactivity, rhs)) )
260 {
261 SCIPsetDebugMsg(set, "ignoring activity redundant cut <%s> (sides=[%g,%g], act=[%g,%g])\n",
262 SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
263 /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
264 return TRUE;
265 }
266
267 if( (!SCIPsetIsInfinity(set, rhs) && SCIPsetIsFeasPositive(set, minactivity - rhs)) ||
268 (!SCIPsetIsInfinity(set, -lhs) && SCIPsetIsFeasNegative(set, maxactivity - lhs)) )
269 {
270 SCIPsetDebugMsg(set, "cut <%s> is infeasible (sides=[%g,%g], act=[%g,%g])\n",
271 SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
272 /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
273 *infeasible = TRUE;
274 return TRUE;
275 }
276
277 return FALSE;
278}
279
280/** checks whether a cut with only one variable can be applied as boundchange
281 *
282 * This is the case if the bound change would prove infeasibility (w.r.t feastol), or if the new bound is at least
283 * epsilon better than the old bound. In the latter case, also the opposite bound has to be taken into account.
284 */
285static
287 SCIP_SET* set, /**< global SCIP settings */
288 SCIP_ROW* cut /**< cut with a single variable */
289 )
290{
291 SCIP_COL** cols;
292 SCIP_Real* vals;
293 SCIP_VAR* var;
294 SCIP_Real lhs;
295 SCIP_Real rhs;
296 SCIP_Bool local;
297 SCIP_Real oldlb;
298 SCIP_Real oldub;
299
300 assert(set != NULL);
301 assert(cut != NULL);
302 assert(!SCIProwIsModifiable(cut));
303 assert(SCIProwGetNNonz(cut) == 1);
304
305 /* get the single variable and its coefficient of the cut */
306 cols = SCIProwGetCols(cut);
307 assert(cols != NULL);
308
309 var = SCIPcolGetVar(cols[0]);
310 vals = SCIProwGetVals(cut);
311 assert(vals != NULL);
312 assert(!SCIPsetIsZero(set, vals[0]));
313
314 /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */
315 if( SCIPsetIsFeasZero(set, vals[0]) )
316 return FALSE;
317
318 local = SCIProwIsLocal(cut);
319
320 oldlb = local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
321 oldub = local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
322
323 /* get the left hand side of the cut and convert it to a bound */
324 lhs = SCIProwGetLhs(cut);
325 if( !SCIPsetIsInfinity(set, -lhs) )
326 {
327 lhs -= SCIProwGetConstant(cut);
328 if( vals[0] > 0.0 )
329 {
330 /* coefficient is positive -> lhs corresponds to lower bound */
331 SCIP_Real newlb;
332
333 newlb = lhs/vals[0];
334 SCIPvarAdjustLb(var, set, &newlb);
335
336 /* bound changes that improve the bound sufficiently are applicable */
337 if( SCIPsetIsFeasGT(set, newlb, oldub) || SCIPsetIsGT(set, MIN(newlb, oldub), oldlb) )
338 return TRUE;
339 }
340 else
341 {
342 /* coefficient is negative -> lhs corresponds to upper bound */
343 SCIP_Real newub;
344
345 newub = lhs/vals[0];
346 SCIPvarAdjustUb(var, set, &newub);
347
348 /* bound changes that improve the bound sufficiently are applicable */
349 if( SCIPsetIsFeasLT(set, newub, oldlb) || SCIPsetIsLT(set, MAX(newub, oldlb), oldub) )
350 return TRUE;
351 }
352 }
353
354 /* get the right hand side of the cut and convert it to a bound */
355 rhs = SCIProwGetRhs(cut);
356 if( !SCIPsetIsInfinity(set, rhs) )
357 {
358 rhs -= SCIProwGetConstant(cut);
359 if( vals[0] > 0.0 )
360 {
361 /* coefficient is positive -> rhs corresponds to upper bound */
362 SCIP_Real newub;
363
364 newub = rhs/vals[0];
365 SCIPvarAdjustUb(var, set, &newub);
366
367 /* bound changes that improve the bound sufficiently are applicable */
368 if( SCIPsetIsFeasLT(set, newub, oldlb) || SCIPsetIsLT(set, MAX(newub, oldlb), oldub) )
369 return TRUE;
370 }
371 else
372 {
373 /* coefficient is negative -> rhs corresponds to lower bound */
374 SCIP_Real newlb;
375
376 newlb = rhs/vals[0];
377 SCIPvarAdjustLb(var, set, &newlb);
378
379 /* bound changes that improve the bound sufficiently are applicable */
380 if( SCIPsetIsFeasGT(set, newlb, oldub) || SCIPsetIsGT(set, MIN(newlb, oldub), oldlb) )
381 return TRUE;
382 }
383 }
384
385 return FALSE;
386}
387
388/** removes a non-forced cut from the separation storage */
389static
391 SCIP_SEPASTORE* sepastore, /**< separation storage */
392 BMS_BLKMEM* blkmem, /**< block memory */
393 SCIP_SET* set, /**< global SCIP settings */
394 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
395 SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
396 SCIP_LP* lp, /**< LP data */
397 int pos /**< position of cut to delete */
398 )
399{
400 assert(sepastore != NULL);
401 assert(sepastore->cuts != NULL);
402 assert(sepastore->nforcedcuts <= pos && pos < sepastore->ncuts);
403
404 /* check, if the row deletions from separation storage events are tracked if so, issue ROWDELETEDSEPA event */
405 if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
406 {
407 SCIP_EVENT* event;
408
409 SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[pos]) );
410 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
411 }
412
413 /* release the row */
414 if( !sepastore->initiallp )
415 {
416 sepastore->ncutsadded--;
417 if( sepastore->cuts[pos]->fromcutpool )
418 sepastore->ncutsaddedviapool--;
419 else
420 sepastore->ncutsaddeddirect--;
421
423 {
424 SCIP_SEPA* sepa;
425 sepa = SCIProwGetOriginSepa(sepastore->cuts[pos]);
426 SCIPsepaDecNCutsAdded(sepa, sepastore->cuts[pos]->fromcutpool);
427 }
428 }
429 SCIP_CALL( SCIProwRelease(&sepastore->cuts[pos], blkmem, set, lp) );
430
431 /* move last cut to the empty position */
432 sepastore->cuts[pos] = sepastore->cuts[sepastore->ncuts-1];
433 sepastore->ncuts--;
434
435 return SCIP_OKAY;
436}
437
438/** adds cut to separation storage and captures it */
440 SCIP_SEPASTORE* sepastore, /**< separation storage */
441 BMS_BLKMEM* blkmem, /**< block memory */
442 SCIP_SET* set, /**< global SCIP settings */
443 SCIP_STAT* stat, /**< problem statistics data */
444 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
445 SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
446 SCIP_LP* lp, /**< LP data */
447 SCIP_ROW* cut, /**< separated cut */
448 SCIP_Bool forcecut, /**< should the cut be forced to enter the LP? */
449 SCIP_Bool root, /**< are we at the root node? */
450 SCIP_Bool* infeasible /**< pointer to store whether the cut is infeasible */
451 )
452{
453 SCIP_Bool redundant;
454 int pos;
455
456 assert(sepastore != NULL);
457 assert(sepastore->nforcedcuts <= sepastore->ncuts);
458 assert(set != NULL);
459 assert(cut != NULL);
461 assert(eventqueue != NULL);
462 assert(eventfilter != NULL);
463
464 /* debug: check cut for feasibility */
465 SCIP_CALL( SCIPdebugCheckRow(set, cut) ); /*lint !e506 !e774*/
466
467 /* the cut will be forced to enter the LP if the dual must be collected and the initial LP is being constructed */
468 forcecut = forcecut || (set->lp_alwaysgetduals && sepastore->initiallp);
469
470 /* in the root node, every local cut is a global cut, and global cuts are nicer in many ways ... */
471 if( root && SCIProwIsLocal(cut) )
472 {
473 SCIPsetDebugMsg(set, "change local flag of cut <%s> to FALSE due to addition in root node\n", SCIProwGetName(cut));
474
476
477 assert(!SCIProwIsLocal(cut));
478 }
479
480 /* check cut for redundancy or infeasibility */
481 redundant = sepastoreIsCutRedundantOrInfeasible(sepastore, set, stat, cut, infeasible);
482 /* Note that we add infeasible rows in any case, since we cannot be sure whether the return values are handled
483 * correctly. In this way, the LP becomes infeasible. */
484
485 /* in each separation round, make sure that at least one (even redundant) cut enters the LP to avoid cycling */
486 if( !forcecut && sepastore->ncuts > 0 && redundant )
487 return SCIP_OKAY;
488
489 /* if only one cut is currently present in sepastore, it could be redundant; in this case, it can now be removed
490 * again, because now a non redundant cut enters the sepastore */
491 if( sepastore->ncuts == 1 && sepastoreIsCutRedundant(sepastore, set, stat, sepastore->cuts[0]) )
492 {
493 /* check, if the row deletions from separation storage events are tracked if so, issue ROWDELETEDSEPA event */
494 if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
495 {
496 SCIP_EVENT* event;
497
498 SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[0]) );
499 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
500 }
501 /* update statistics of total number of found cuts */
502 if( !sepastore->initiallp )
503 {
504 sepastore->ncutsadded--;
505 if( sepastore->cuts[0]->fromcutpool )
506 sepastore->ncutsaddedviapool--;
507 else
508 sepastore->ncutsaddeddirect--;
509
511 {
512 SCIP_SEPA* sepa;
513 sepa = SCIProwGetOriginSepa(sepastore->cuts[0]);
514 SCIPsepaDecNCutsAdded(sepa, sepastore->cuts[0]->fromcutpool);
515 }
516 }
517
518 SCIP_CALL( SCIProwRelease(&sepastore->cuts[0], blkmem, set, lp) );
519 sepastore->ncuts = 0;
520 sepastore->nforcedcuts = 0;
521 }
522
523 /* a cut is forced to enter the LP if
524 * - we construct the initial LP, or
525 * - it has infinite score factor, or
526 * - it is a bound change that can be applied
527 * if it is a non-forced cut and no cuts should be added, abort
528 */
529 forcecut = forcecut || sepastore->initiallp || sepastore->forcecuts || (!SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 && sepastoreIsBdchgApplicable(set, cut));
530 if( !forcecut && SCIPsetGetSepaMaxcuts(set, root) == 0 )
531 return SCIP_OKAY;
532
533 /* get enough memory to store the cut */
534 SCIP_CALL( sepastoreEnsureCutsMem(sepastore, set, sepastore->ncuts+1) );
535 assert(sepastore->ncuts < sepastore->cutssize);
536
537 SCIPsetDebugMsg(set, "adding cut <%s> to separation storage of size %d (forcecut=%u, len=%d)\n",
538 SCIProwGetName(cut), sepastore->ncuts, forcecut, SCIProwGetNNonz(cut));
539 /*SCIP_CALL( SCIPprintRow(set->scip, cut, NULL) );*/
540
541 /* capture the cut */
542 SCIProwCapture(cut);
543
544 /* add cut to arrays */
545 if( forcecut )
546 {
547 /* make room at the beginning of the array for forced cut */
548 pos = sepastore->nforcedcuts;
549 sepastore->cuts[sepastore->ncuts] = sepastore->cuts[pos];
550 sepastore->nforcedcuts++;
551 }
552 else
553 pos = sepastore->ncuts;
554
555 sepastore->cuts[pos] = cut;
556
557 /* update statistics of total number of found cuts */
558 if( !sepastore->initiallp )
559 {
560 sepastore->ncutsadded++;
561 sepastore->ncutsfoundround++;
562 if( cut->fromcutpool )
563 sepastore->ncutsaddedviapool++;
564 else
565 sepastore->ncutsaddeddirect++;
566
568 {
569 SCIP_SEPA* sepa;
570
571 sepa = SCIProwGetOriginSepa(cut);
573 }
574 }
575 sepastore->ncuts++;
576
577 /* check, if the row addition to separation storage events are tracked if so, issue ROWADDEDSEPA event */
578 if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWADDEDSEPA) != 0 )
579 {
580 SCIP_EVENT* event;
581
582 SCIP_CALL( SCIPeventCreateRowAddedSepa(&event, blkmem, cut) );
583 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
584 }
585
586 /* If the duals need to be collected, then the infeasible flag is set to FALSE. This ensures that the LP is solved */
587 if( set->lp_alwaysgetduals && sepastore->initiallp )
588 (*infeasible) = FALSE;
589
590 return SCIP_OKAY;
591}
592
593/** applies a lower bound change */
594static
596 SCIP_SEPASTORE* sepastore, /**< separation storage */
597 BMS_BLKMEM* blkmem, /**< block memory */
598 SCIP_SET* set, /**< global SCIP settings */
599 SCIP_STAT* stat, /**< problem statistics */
600 SCIP_PROB* transprob, /**< transformed problem */
601 SCIP_PROB* origprob, /**< original problem */
602 SCIP_TREE* tree, /**< branch and bound tree */
603 SCIP_REOPT* reopt, /**< reoptimization data structure */
604 SCIP_LP* lp, /**< LP data */
605 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
606 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
607 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
608 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
609 SCIP_VAR* var, /**< problem variable */
610 SCIP_Real bound, /**< new lower bound of variable */
611 SCIP_Bool local, /**< is it a local bound change? (otherwise global) */
612 SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
613 SCIP_Bool* cutoff /**< pointer to store TRUE, if an infeasibility has been detected */
614 )
615{
616 assert(sepastore != NULL);
617 assert(cutoff != NULL);
618 assert(applied != NULL);
619
620 /* adjust bound to the one that would be applied, so the SCIPsetIsGT check below is more reliable */
621 SCIPvarAdjustLb(var, set, &bound);
622
623 if( local )
624 {
625 /* apply the local bound change or detect a cutoff */
627 {
628 SCIPsetDebugMsg(set, " -> applying bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
630
631 /* changing the lower bound to a value >= SCIPinfinity should result in a cutoff,
632 * since "infinite" values in solutions are reserved for another meaning
633 */
635 {
636 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob, tree,
637 reopt, lp, branchcand, eventqueue, eventfilter, cliquetable, var, bound, SCIP_BOUNDTYPE_LOWER, FALSE) );
638 }
639 else
640 *cutoff = TRUE;
641
642 *applied = TRUE;
643 }
644 else
645 {
646 SCIPsetDebugMsg(set, " -> ignoring bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
648 }
649 }
650 else
651 {
652 /* apply the global bound change or detect a global cutoff which means we can cutoff the root node */
654 {
655 SCIPsetDebugMsg(set, " -> applying global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
657
658 /* changing the lower bound to a value >= SCIPinfinity should result in a cutoff,
659 * since "infinite" values in solutions are reserved for another meaning
660 */
662 {
663 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, tree, reopt,
664 lp, branchcand, eventqueue, eventfilter, cliquetable, var, bound, SCIP_BOUNDTYPE_LOWER, FALSE) );
665 }
666 else
667 {
668 /* we are done with solving since a global bound change is infeasible */
669 SCIP_CALL( SCIPnodeCutoff(SCIPtreeGetRootNode(tree), set, stat, eventfilter, tree, transprob, origprob, reopt, lp, blkmem) );
670 *cutoff = TRUE;
671 }
672
673 *applied = TRUE;
674 }
675 else
676 {
677 SCIPsetDebugMsg(set, " -> ignoring global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
679 }
680 }
681
682 return SCIP_OKAY;
683}
684
685/** applies an upper bound change */
686static
688 SCIP_SEPASTORE* sepastore, /**< separation storage */
689 BMS_BLKMEM* blkmem, /**< block memory */
690 SCIP_SET* set, /**< global SCIP settings */
691 SCIP_STAT* stat, /**< problem statistics */
692 SCIP_PROB* transprob, /**< transformed problem */
693 SCIP_PROB* origprob, /**< original problem */
694 SCIP_TREE* tree, /**< branch and bound tree */
695 SCIP_REOPT* reopt, /**< reoptimization data structure */
696 SCIP_LP* lp, /**< LP data */
697 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
698 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
699 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
700 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
701 SCIP_VAR* var, /**< problem variable */
702 SCIP_Real bound, /**< new upper bound of variable */
703 SCIP_Bool local, /**< is it a local bound change? (otherwise global) */
704 SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
705 SCIP_Bool* cutoff /**< pointer to store TRUE, if an infeasibility has been detected */
706 )
707{
708 assert(sepastore != NULL);
709 assert(cutoff != NULL);
710 assert(applied != NULL);
711
712 /* adjust bound to the one that would be applied, so the SCIPsetIsGT check below is more reliable */
713 SCIPvarAdjustUb(var, set, &bound);
714
715 if( local )
716 {
717 /* apply the local bound change or detect a cutoff */
719 {
720 SCIPsetDebugMsg(set, " -> applying bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
722
723 /* changing the upper bound to a value <= -SCIPinfinity should result in a cutoff,
724 * since "infinite" values in solutions are reserved for another meaning
725 */
727 {
728 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob, tree,
729 reopt, lp, branchcand, eventqueue, eventfilter, cliquetable, var, bound, SCIP_BOUNDTYPE_UPPER, FALSE) );
730 }
731 else
732 *cutoff = TRUE;
733
734 *applied = TRUE;
735 }
736 else
737 {
738 SCIPsetDebugMsg(set, " -> ignoring bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
740 }
741 }
742 else
743 {
744 /* apply the global bound change or detect a global cutoff which means we can cutoff the root node */
746 {
747 SCIPsetDebugMsg(set, " -> applying global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
749
750 /* changing the upper bound to a value <= -SCIPinfinity should result in a cutoff,
751 * since "infinite" values in solutions are reserved for another meaning
752 */
754 {
755 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, tree, reopt,
756 lp, branchcand, eventqueue, eventfilter, cliquetable, var, bound, SCIP_BOUNDTYPE_UPPER, FALSE) );
757 }
758 else
759 {
760 /* we are done with solving since a global bound change is infeasible */
761 SCIP_CALL( SCIPnodeCutoff(SCIPtreeGetRootNode(tree), set, stat, eventfilter, tree, transprob, origprob, reopt, lp, blkmem) );
762 *cutoff = TRUE;
763 }
764
765 *applied = TRUE;
766 }
767 else
768 {
769 SCIPsetDebugMsg(set, " -> ignoring global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
771 }
772 }
773
774 return SCIP_OKAY;
775}
776
777/** applies a cut that is a bound change directly as bound change instead of adding it as row to the LP */
778static
780 SCIP_SEPASTORE* sepastore, /**< separation storage */
781 BMS_BLKMEM* blkmem, /**< block memory */
782 SCIP_SET* set, /**< global SCIP settings */
783 SCIP_STAT* stat, /**< problem statistics */
784 SCIP_PROB* transprob, /**< transformed problem */
785 SCIP_PROB* origprob, /**< original problem */
786 SCIP_TREE* tree, /**< branch and bound tree */
787 SCIP_REOPT* reopt, /**< reoptimization data structure */
788 SCIP_LP* lp, /**< LP data */
789 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
790 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
791 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
792 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
793 SCIP_ROW* cut, /**< cut with a single variable */
794 SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
795 SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */
796 )
797{
798 SCIP_COL** cols;
799 SCIP_Real* vals;
800 SCIP_VAR* var;
801 SCIP_Real lhs;
802 SCIP_Real rhs;
803 SCIP_Bool local;
804
805 assert(sepastore != NULL);
806 assert(!SCIProwIsModifiable(cut));
807 assert(SCIProwGetNNonz(cut) == 1);
808 assert(cutoff != NULL);
809 assert(applied != NULL);
810
811 *applied = FALSE;
812 *cutoff = FALSE;
813
814 /* get the single variable and its coefficient of the cut */
815 cols = SCIProwGetCols(cut);
816 assert(cols != NULL);
817
818 var = SCIPcolGetVar(cols[0]);
819 vals = SCIProwGetVals(cut);
820 assert(vals != NULL);
821 assert(!SCIPsetIsZero(set, vals[0]));
822
823 /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */
824 if( SCIPsetIsFeasZero(set, vals[0]) )
825 return SCIP_OKAY;
826
827 local = SCIProwIsLocal(cut);
828
829 /* get the left hand side of the cut and convert it to a bound */
830 lhs = SCIProwGetLhs(cut);
831 if( !SCIPsetIsInfinity(set, -lhs) )
832 {
833 lhs -= SCIProwGetConstant(cut);
834 if( vals[0] > 0.0 )
835 {
836 /* coefficient is positive -> lhs corresponds to lower bound */
837 SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
838 eventfilter, cliquetable, var, lhs/vals[0], local, applied, cutoff) );
839 }
840 else
841 {
842 /* coefficient is negative -> lhs corresponds to upper bound */
843 SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
844 eventfilter, cliquetable, var, lhs/vals[0], local, applied, cutoff) );
845 }
846 }
847
848 /* get the right hand side of the cut and convert it to a bound */
849 rhs = SCIProwGetRhs(cut);
850 if( !SCIPsetIsInfinity(set, rhs) )
851 {
852 rhs -= SCIProwGetConstant(cut);
853 if( vals[0] > 0.0 )
854 {
855 /* coefficient is positive -> rhs corresponds to upper bound */
856 SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
857 eventfilter, cliquetable, var, rhs/vals[0], local, applied, cutoff) );
858 }
859 else
860 {
861 /* coefficient is negative -> rhs corresponds to lower bound */
862 SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
863 eventfilter, cliquetable, var, rhs/vals[0], local, applied, cutoff) );
864 }
865 }
866
867 /* count the bound change as applied cut */
868 if( *applied && !sepastore->initiallp )
869 sepastore->ncutsapplied++;
870
871 return SCIP_OKAY;
872}
873
874/** applies the given cut to the LP and updates the orthogonalities and scores of remaining cuts */
875static
877 SCIP_SEPASTORE* sepastore, /**< separation storage */
878 BMS_BLKMEM* blkmem, /**< block memory */
879 SCIP_SET* set, /**< global SCIP settings */
880 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
881 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
882 SCIP_LP* lp, /**< LP data */
883 SCIP_ROW* cut, /**< cut to apply to the LP */
884 int depth, /**< depth of current node */
885 int* ncutsapplied /**< pointer to count the number of applied cuts */
886 )
887{
888 assert(sepastore != NULL);
889 assert(ncutsapplied != NULL);
890
891 /* a row could have been added twice to the separation store; add it only once! */
892 if( !SCIProwIsInLP(cut) )
893 {
894 /* add cut to the LP and capture it */
895 SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, cut, depth) );
896
897 /* update statistics -> only if we are not in the initial lp (cuts are only counted if added during run) */
898 if( !sepastore->initiallp )
899 {
900 sepastore->ncutsapplied++;
901
902 /* increase count of applied cuts for origins of row */
903 /* TODO: adjust conshdlr statistics to mirror cut statistics */
904 switch ( (SCIP_ROWORIGINTYPE) cut->origintype )
905 {
907 assert( cut->origin != NULL );
909 break;
911 assert( cut->origin != NULL );
913 break;
915 assert( cut->origin != NULL );
917 break;
920 /* do nothing - cannot update statistics */
921 break;
922 default:
923 SCIPerrorMessage("unknown type of row origin.\n");
924 return SCIP_INVALIDDATA;
925 }
926 }
927
928 (*ncutsapplied)++;
929 }
930
931 return SCIP_OKAY;
932}
933
934/** adds cuts to the LP and clears separation storage */
936 SCIP_SEPASTORE* sepastore, /**< separation storage */
937 BMS_BLKMEM* blkmem, /**< block memory */
938 SCIP_SET* set, /**< global SCIP settings */
939 SCIP_STAT* stat, /**< problem statistics */
940 SCIP_PROB* transprob, /**< transformed problem */
941 SCIP_PROB* origprob, /**< original problem */
942 SCIP_TREE* tree, /**< branch and bound tree */
943 SCIP_REOPT* reopt, /**< reoptimization data structure */
944 SCIP_LP* lp, /**< LP data */
945 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
946 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
947 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
948 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
949 SCIP_Bool root, /**< are we at the root node? */
950 SCIP_EFFICIACYCHOICE efficiacychoice, /**< type of solution to base efficiacy computation on */
951 SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */
952 )
953{
954 SCIP_NODE* node;
955 int maxsepacuts;
956 int ncutsapplied;
957 int nselectedcuts;
958 int depth;
959 int i;
960
961 assert(sepastore != NULL);
962 assert(set != NULL);
963 assert(tree != NULL);
964 assert(lp != NULL);
965 assert(cutoff != NULL);
966
967 SCIP_UNUSED(efficiacychoice);
968
969 SCIPsetDebugMsg(set, "selecting from %d cuts\n", sepastore->ncuts);
970
971 /* get maximal number of cuts to add to the LP */
972 maxsepacuts = SCIPsetGetSepaMaxcuts(set, root);
973
974 /* if all cuts are forced cuts, no selection is required */
975 if( sepastore->nforcedcuts >= MIN(sepastore->ncuts, maxsepacuts) )
976 {
977 nselectedcuts = sepastore->nforcedcuts;
978 }
979 else
980 {
981 /* call cut selection algorithms */
982 nselectedcuts = 0;
983 SCIP_CALL( SCIPcutselsSelect(set, sepastore->cuts, sepastore->ncuts, sepastore->nforcedcuts, root, sepastore->initiallp, maxsepacuts,
984 &nselectedcuts) );
985 assert(nselectedcuts + sepastore->nforcedcuts <= maxsepacuts);
986
987 /* note that cut selector statistics are updated here also when in probing mode; this may lead to an offset with
988 * separator/constraint handler statistics */
989 /* @todo do not update cutselector statistics if SCIPtreeProbing(scip->tree) */
990 nselectedcuts += sepastore->nforcedcuts;
991 }
992
993 /*
994 * apply all selected cuts
995 */
996 ncutsapplied = 0;
997 *cutoff = FALSE;
998
999 node = SCIPtreeGetCurrentNode(tree);
1000 assert(node != NULL);
1001
1002 /* get depth of current node */
1003 depth = SCIPnodeGetDepth(node);
1004
1005 for( i = 0; i < nselectedcuts && !(*cutoff); i++ )
1006 {
1007 SCIP_ROW* cut;
1008
1009 cut = sepastore->cuts[i];
1010
1011 if( i < sepastore->nforcedcuts || SCIPsetIsFeasPositive(set, SCIProwGetLPEfficacy(cut, set, stat, lp)) )
1012 {
1013 SCIP_Bool applied = FALSE;
1014
1015 /* if the cut is a bound change (i.e. a row with only one variable), add it as bound change instead of LP row */
1016 if( !SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 && !set->exact_enable )
1017 {
1018 SCIPsetDebugMsg(set, " -> applying forced cut <%s> as boundchange\n", SCIProwGetName(cut));
1019 SCIP_CALL( sepastoreApplyBdchg(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
1020 eventqueue, eventfilter, cliquetable, cut, &applied, cutoff) );
1021 assert(applied || !sepastoreIsBdchgApplicable(set, cut));
1022 }
1023
1024 if( !applied )
1025 {
1026 /* create rational representation of the cut; note that this may slightly change the floating-point
1027 * coefficients
1028 */
1029 if( set->exact_enable && SCIProwGetRowExact(cut) == NULL )
1030 {
1031 SCIP_Bool poolcut = FALSE;
1032 if( !SCIProwIsLocal(cut) && !(SCIPisCutNew(set->scip, cut)) )
1033 {
1034 poolcut = TRUE;
1035 SCIP_CALL( SCIPdelPoolCut(set->scip, cut) );
1036 }
1037 SCIP_CALL( SCIProwExactCreateFromRow(cut, blkmem, set, stat, eventqueue, transprob, lp->lpexact) );
1038 if( poolcut )
1039 {
1040 SCIP_CALL( SCIPaddPoolCut(set->scip, cut) );
1041 }
1042
1043 SCIP_CALL( SCIPaddRowExact(set->scip, cut->rowexact) );
1044 }
1045
1046 /* add cut to the LP and update orthogonalities */
1047 SCIPsetDebugMsg(set, " -> applying%s cut <%s>\n", (i < sepastore->nforcedcuts) ? " forced" : "", SCIProwGetName(cut));
1048 /*SCIPdebug( SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
1049 SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, depth, &ncutsapplied) );
1050 }
1051 }
1052 }
1053
1054 /* clear the separation storage and reset statistics for separation round */
1055 SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );
1056
1057 return SCIP_OKAY;
1058}
1059
1060/** clears the separation storage without adding the cuts to the LP */
1062 SCIP_SEPASTORE* sepastore, /**< separation storage */
1063 BMS_BLKMEM* blkmem, /**< block memory */
1064 SCIP_SET* set, /**< global SCIP settings */
1065 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1066 SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
1067 SCIP_LP* lp /**< LP data */
1068 )
1069{
1070 int c;
1071
1072 assert(sepastore != NULL);
1073
1074 SCIPsetDebugMsg(set, "clearing %d cuts\n", sepastore->ncuts);
1075
1076 /* release cuts */
1077 for( c = 0; c < sepastore->ncuts; ++c )
1078 {
1079 /* check, if the row deletions from separation storage events are tracked if so, issue ROWDELETEDSEPA event */
1080 if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
1081 {
1082 SCIP_EVENT* event;
1083
1084 SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[c]) );
1085 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
1086 }
1087
1088 SCIP_CALL( SCIProwRelease(&sepastore->cuts[c], blkmem, set, lp) );
1089 }
1090
1091 /* reset counters */
1092 sepastore->ncuts = 0;
1093 sepastore->nforcedcuts = 0;
1094 sepastore->ncutsfoundround = 0;
1095
1096 /* if we have just finished the initial LP construction, free the (potentially large) cuts array */
1097 if( sepastore->initiallp )
1098 {
1099 BMSfreeMemoryArrayNull(&sepastore->cuts);
1100 sepastore->cutssize = 0;
1101 }
1102
1103 return SCIP_OKAY;
1104}
1105
1106/** removes cuts that are inefficacious w.r.t. the current LP solution from separation storage without adding the cuts to the LP */
1108 SCIP_SEPASTORE* sepastore, /**< separation storage */
1109 BMS_BLKMEM* blkmem, /**< block memory */
1110 SCIP_SET* set, /**< global SCIP settings */
1111 SCIP_STAT* stat, /**< problem statistics data */
1112 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1113 SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
1114 SCIP_LP* lp, /**< LP data */
1115 SCIP_Bool root, /**< are we at the root node? */
1116 SCIP_EFFICIACYCHOICE efficiacychoice /**< type of solution to base efficiacy computation on */
1117 )
1118{
1119 int cnt = 0;
1120 int c;
1121
1122 assert( sepastore != NULL );
1123
1124 /* check non-forced cuts only */
1125 c = sepastore->nforcedcuts;
1126 while( c < sepastore->ncuts )
1127 {
1128 SCIP_Real cutefficacy;
1129
1130 /* calculate cut's efficacy */
1131 switch ( efficiacychoice )
1132 {
1134 cutefficacy = SCIProwGetLPEfficacy(sepastore->cuts[c], set, stat, lp);
1135 break;
1137 cutefficacy = SCIProwGetRelaxEfficacy(sepastore->cuts[c], set, stat);
1138 break;
1140 cutefficacy = SCIProwGetNLPEfficacy(sepastore->cuts[c], set, stat);
1141 break;
1142 default:
1143 SCIPerrorMessage("Invalid efficiacy choice.\n");
1144 return SCIP_INVALIDCALL;
1145 }
1146
1147 if( !SCIPsetIsEfficacious(set, root, cutefficacy) )
1148 {
1149 SCIP_CALL( sepastoreDelCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, c) );
1150 ++cnt;
1151 }
1152 else
1153 ++c;
1154 }
1155 SCIPsetDebugMsg(set, "removed %d non-efficacious cuts\n", cnt);
1156
1157 return SCIP_OKAY;
1158}
1159
1160/** indicates whether a cut is applicable
1161 *
1162 * A cut is applicable if it is modifiable, not a bound change, or a bound change that changes bounds by at least epsilon.
1163 */
1165 SCIP_SET* set, /**< global SCIP settings */
1166 SCIP_ROW* cut /**< cut to check */
1167 )
1168{
1169 return SCIProwIsModifiable(cut) || SCIProwGetNNonz(cut) != 1 || sepastoreIsBdchgApplicable(set, cut);
1170}
1171
1172/** get cuts in the separation storage */
1174 SCIP_SEPASTORE* sepastore /**< separation storage */
1175 )
1176{
1177 assert(sepastore != NULL);
1178
1179 return sepastore->cuts;
1180}
1181
1182/** get number of cuts in the separation storage */
1184 SCIP_SEPASTORE* sepastore /**< separation storage */
1185 )
1186{
1187 assert(sepastore != NULL);
1188
1189 return sepastore->ncuts;
1190}
1191
1192/** gets the total number of cutting planes added to the separation storage;
1193 * this is equal to the sum of added cuts directly and via the pool. */
1195 SCIP_SEPASTORE* sepastore /**< separation storage */
1196 )
1197{
1198 assert(sepastore != NULL);
1199
1200 return sepastore->ncutsadded;
1201}
1202
1203/** gets the number of cutting planes added to the separation storage from the cut pool */
1205 SCIP_SEPASTORE* sepastore /**< separation storage */
1206 )
1207{
1208 assert(sepastore != NULL);
1209
1210 return sepastore->ncutsaddedviapool;
1211}
1212
1213/** gets the number of cutting planes added to the separation storage directly */
1215 SCIP_SEPASTORE* sepastore /**< separation storage */
1216 )
1217{
1218 assert(sepastore != NULL);
1219
1220 return sepastore->ncutsaddeddirect;
1221}
1222
1223/** get number of cuts found so far in current separation round */
1225 SCIP_SEPASTORE* sepastore /**< separation storage */
1226 )
1227{
1228 assert(sepastore != NULL);
1229
1230 return sepastore->ncutsfoundround;
1231}
1232
1233/** gets the total number of cutting planes applied to the LP */
1235 SCIP_SEPASTORE* sepastore /**< separation storage */
1236 )
1237{
1238 assert(sepastore != NULL);
1239
1240 return sepastore->ncutsapplied;
1241}
static long bound
void SCIPconshdlrIncNAppliedCuts(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5062
internal methods for constraints and constraint handlers
methods for the aggregation rows
SCIP_RETCODE SCIPcutselsSelect(SCIP_SET *set, SCIP_ROW **cuts, int ncuts, int nforcedcuts, SCIP_Bool root, SCIP_Bool initiallp, int maxnselectedcuts, int *nselectedcuts)
Definition: cutsel.c:169
internal methods for cut selectors
methods for debugging
#define SCIPdebugCheckRow(set, row)
Definition: debug.h:297
common defines and data types used in all packages of SCIP
#define NULL
Definition: def.h:248
#define SCIP_UNUSED(x)
Definition: def.h:409
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_ALLOC(x)
Definition: def.h:366
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPeventqueueAdd(SCIP_EVENTQUEUE *eventqueue, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENT **event)
Definition: event.c:2561
SCIP_RETCODE SCIPeventCreateRowAddedSepa(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_ROW *row)
Definition: event.c:998
SCIP_RETCODE SCIPeventCreateRowDeletedSepa(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_ROW *row)
Definition: event.c:1017
internal methods for managing events
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17425
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:336
SCIP_Bool SCIPisCutNew(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:318
SCIP_RETCODE SCIPdelPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:356
SCIP_RETCODE SCIPaddRowExact(SCIP *scip, SCIP_ROWEXACT *rowexact)
Definition: scip_exact.c:257
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:8493
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17686
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17805
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17607
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17632
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17696
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17795
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17745
SCIP_SEPA * SCIProwGetOriginSepa(SCIP_ROW *row)
Definition: lp.c:17870
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:17652
SCIP_ROWEXACT * SCIProwGetRowExact(SCIP_ROW *row)
Definition: lp.c:17959
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17917
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17642
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_Real SCIProwGetRelaxEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:7170
void SCIProwCapture(SCIP_ROW *row)
Definition: lp.c:5554
SCIP_Real SCIProwGetMaxActivity(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6849
SCIP_Real SCIProwGetNLPEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:7210
SCIP_RETCODE SCIProwChgLocal(SCIP_ROW *row, SCIP_Bool local)
Definition: lp.c:5946
SCIP_Real SCIProwGetLPEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp)
Definition: lp.c:7054
SCIP_RETCODE SCIPlpAddRow(SCIP_LP *lp, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_ROW *row, int depth)
Definition: lp.c:9759
SCIP_Real SCIProwGetMinActivity(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6828
SCIP_RETCODE SCIProwRelease(SCIP_ROW **row, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp)
Definition: lp.c:5567
internal methods for LP management
SCIP_RETCODE SCIProwExactCreateFromRow(SCIP_ROW *fprow, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_PROB *prob, SCIP_LPEXACT *lpexact)
Definition: lpexact.c:3373
internal methods for exact LP management
#define BMSfreeMemory(ptr)
Definition: memory.h:145
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:127
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:148
#define BMSallocMemory(ptr)
Definition: memory.h:118
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem)
Definition: misc.c:10209
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:10193
internal miscellaneous methods
public methods for LP management
#define SCIPerrorMessage
Definition: pub_message.h:64
data structures and methods for collecting reoptimization information
SCIP callable library.
public methods for the LP relaxation, rows and columns
void SCIPsepaDecNCutsAdded(SCIP_SEPA *sepa, SCIP_Bool fromcutpool)
Definition: sepa.c:1029
void SCIPsepaIncNCutsApplied(SCIP_SEPA *sepa, SCIP_Bool fromcutpool)
Definition: sepa.c:984
void SCIPsepaIncNCutsAdded(SCIP_SEPA *sepa, SCIP_Bool fromcutpool)
Definition: sepa.c:1006
internal methods for separators
static SCIP_Bool sepastoreIsBdchgApplicable(SCIP_SET *set, SCIP_ROW *cut)
Definition: sepastore.c:286
int SCIPsepastoreGetNCutsFoundRound(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1224
void SCIPsepastoreEndInitialLP(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:147
static SCIP_RETCODE sepastoreApplyBdchg(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_CLIQUETABLE *cliquetable, SCIP_ROW *cut, SCIP_Bool *applied, SCIP_Bool *cutoff)
Definition: sepastore.c:779
SCIP_RETCODE SCIPsepastoreCreate(SCIP_SEPASTORE **sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set)
Definition: sepastore.c:90
SCIP_RETCODE SCIPsepastoreClearCuts(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp)
Definition: sepastore.c:1061
int SCIPsepastoreGetNCutsAddedViaPool(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1204
int SCIPsepastoreGetNCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1183
SCIP_RETCODE SCIPsepastoreAddCut(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool root, SCIP_Bool *infeasible)
Definition: sepastore.c:439
static SCIP_RETCODE sepastoreApplyUb(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Real bound, SCIP_Bool local, SCIP_Bool *applied, SCIP_Bool *cutoff)
Definition: sepastore.c:687
void SCIPsepastoreStartForceCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:159
void SCIPsepastoreEndForceCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:170
static SCIP_RETCODE sepastoreApplyLb(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Real bound, SCIP_Bool local, SCIP_Bool *applied, SCIP_Bool *cutoff)
Definition: sepastore.c:595
static SCIP_Bool sepastoreIsCutRedundant(SCIP_SEPASTORE *sepastore, SCIP_SET *set, SCIP_STAT *stat, SCIP_ROW *cut)
Definition: sepastore.c:182
SCIP_RETCODE SCIPsepastoreRemoveInefficaciousCuts(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_Bool root, SCIP_EFFICIACYCHOICE efficiacychoice)
Definition: sepastore.c:1107
void SCIPsepastoreStartInitialLP(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:135
static SCIP_RETCODE sepastoreApplyCut(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_ROW *cut, int depth, int *ncutsapplied)
Definition: sepastore.c:876
static SCIP_Bool sepastoreIsCutRedundantOrInfeasible(SCIP_SEPASTORE *sepastore, SCIP_SET *set, SCIP_STAT *stat, SCIP_ROW *cut, SCIP_Bool *infeasible)
Definition: sepastore.c:225
SCIP_RETCODE SCIPsepastoreFree(SCIP_SEPASTORE **sepastore, BMS_BLKMEM *blkmem)
Definition: sepastore.c:118
SCIP_RETCODE SCIPsepastoreApplyCuts(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool root, SCIP_EFFICIACYCHOICE efficiacychoice, SCIP_Bool *cutoff)
Definition: sepastore.c:935
static SCIP_RETCODE sepastoreDelCut(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, int pos)
Definition: sepastore.c:390
int SCIPsepastoreGetNCutsApplied(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1234
SCIP_ROW ** SCIPsepastoreGetCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1173
int SCIPsepastoreGetNCutsAddedDirect(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1214
static SCIP_RETCODE sepastoreEnsureCutsMem(SCIP_SEPASTORE *sepastore, SCIP_SET *set, int num)
Definition: sepastore.c:67
SCIP_Bool SCIPsepastoreIsCutApplicable(SCIP_SET *set, SCIP_ROW *cut)
Definition: sepastore.c:1164
int SCIPsepastoreGetNCutsAdded(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1194
internal methods for storing separated cuts
SCIP_Bool SCIPsetIsEfficacious(SCIP_SET *set, SCIP_Bool root, SCIP_Real efficacy)
Definition: set.c:7447
SCIP_Bool SCIPsetIsFeasPositive(SCIP_SET *set, SCIP_Real val)
Definition: set.c:7076
SCIP_Bool SCIPsetIsFeasNegative(SCIP_SET *set, SCIP_Real val)
Definition: set.c:7087
int SCIPsetGetSepaMaxcuts(SCIP_SET *set, SCIP_Bool root)
Definition: set.c:6233
SCIP_Bool SCIPsetIsFeasGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:7017
SCIP_Bool SCIPsetIsFeasLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6993
SCIP_Bool SCIPsetIsLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6577
SCIP_Bool SCIPsetIsFeasZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:7065
SCIP_Bool SCIPsetIsFeasLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6969
SCIP_Bool SCIPsetIsLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6557
SCIP_Bool SCIPsetIsInfinity(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6515
SCIP_Bool SCIPsetIsGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6597
SCIP_Bool SCIPsetIsZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6637
SCIP_Bool SCIPsetIsFeasGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:7041
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:6080
unsigned int SCIPsetInitializeRandomSeed(SCIP_SET *set, unsigned int initialseedvalue)
Definition: set.c:7800
internal methods for global SCIP settings
#define SCIPsetDebugMsg
Definition: set.h:1811
internal methods for problem statistics
SCIP_EVENTTYPE eventmask
Definition: struct_event.h:211
SCIP_LPEXACT * lpexact
Definition: struct_lp.h:309
unsigned int origintype
Definition: struct_lp.h:270
SCIP_ROWEXACT * rowexact
Definition: struct_lp.h:235
void * origin
Definition: struct_lp.h:228
unsigned int fromcutpool
Definition: struct_lp.h:254
SCIP_Bool initiallp
SCIP_Bool forcecuts
SCIP_ROW ** cuts
datastructures for managing events
datastructures for storing conflicts
Definition: heur_padm.c:135
SCIP_RETCODE SCIPnodeAddBoundchg(SCIP_NODE *node, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Real newbound, SCIP_BOUNDTYPE boundtype, SCIP_Bool probingchange)
Definition: tree.c:2539
SCIP_RETCODE SCIPnodeCutoff(SCIP_NODE *node, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTFILTER *eventfilter, SCIP_TREE *tree, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_REOPT *reopt, SCIP_LP *lp, BMS_BLKMEM *blkmem)
Definition: tree.c:1259
SCIP_NODE * SCIPtreeGetCurrentNode(SCIP_TREE *tree)
Definition: tree.c:9462
SCIP_NODE * SCIPtreeGetRootNode(SCIP_TREE *tree)
Definition: tree.c:9529
internal methods for branch and bound tree
#define SCIP_EVENTTYPE_ROWDELETEDSEPA
Definition: type_event.h:110
#define SCIP_EVENTTYPE_ROWADDEDSEPA
Definition: type_event.h:109
enum SCIP_RowOriginType SCIP_ROWORIGINTYPE
Definition: type_lp.h:79
@ SCIP_ROWORIGINTYPE_CONSHDLR
Definition: type_lp.h:74
@ SCIP_ROWORIGINTYPE_REOPT
Definition: type_lp.h:77
@ SCIP_ROWORIGINTYPE_UNSPEC
Definition: type_lp.h:73
@ SCIP_ROWORIGINTYPE_SEPA
Definition: type_lp.h:76
@ SCIP_ROWORIGINTYPE_CONS
Definition: type_lp.h:75
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition: type_lp.h:57
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_EFFICIACYCHOICE_LP
@ SCIP_EFFICIACYCHOICE_RELAX
@ SCIP_EFFICIACYCHOICE_NLP
enum SCIP_Efficiacychoice SCIP_EFFICIACYCHOICE
void SCIPvarAdjustLb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *lb)
Definition: var.c:9910
void SCIPvarAdjustUb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *ub)
Definition: var.c:9961
internal methods for problem variables