1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 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   event.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods and datastructures for managing events
19  * @author Tobias Achterberg
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include <assert.h>
25 #include <string.h>
26 
27 #include "scip/branch.h"
28 #include "scip/clock.h"
29 #include "scip/event.h"
30 #include "scip/lp.h"
31 #include "scip/primal.h"
32 #include "scip/pub_event.h"
33 #include "scip/pub_message.h"
34 #include "scip/pub_var.h"
35 #include "scip/set.h"
36 #include "scip/struct_event.h"
37 #include "scip/struct_lp.h"
38 #include "scip/struct_set.h"
39 #include "scip/struct_var.h"
40 #include "scip/var.h"
41 
42 /* timing the execution methods for event handling takes a lot of time, so it is disabled */
43 /* #define TIMEEVENTEXEC */
44 
45 
46 /*
47  * Event handler methods
48  */
49 
50 /** copies the given event handler to a new scip */
SCIPeventhdlrCopyInclude(SCIP_EVENTHDLR * eventhdlr,SCIP_SET * set)51 SCIP_RETCODE SCIPeventhdlrCopyInclude(
52    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
53    SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
54    )
55 {
56    assert(eventhdlr != NULL);
57    assert(set != NULL);
58    assert(set->scip != NULL);
59 
60    if( eventhdlr->eventcopy != NULL )
61    {
62       SCIPsetDebugMsg(set, "including event handler %s in subscip %p\n", SCIPeventhdlrGetName(eventhdlr), (void*)set->scip);
63       SCIP_CALL( eventhdlr->eventcopy(set->scip, eventhdlr) );
64    }
65 
66    return SCIP_OKAY;
67 }
68 
69 /** internal method for creating an event handler */
70 static
doEventhdlrCreate(SCIP_EVENTHDLR ** eventhdlr,const char * name,const char * desc,SCIP_DECL_EVENTCOPY ((* eventcopy)),SCIP_DECL_EVENTFREE ((* eventfree)),SCIP_DECL_EVENTINIT ((* eventinit)),SCIP_DECL_EVENTEXIT ((* eventexit)),SCIP_DECL_EVENTINITSOL ((* eventinitsol)),SCIP_DECL_EVENTEXITSOL ((* eventexitsol)),SCIP_DECL_EVENTDELETE ((* eventdelete)),SCIP_DECL_EVENTEXEC ((* eventexec)),SCIP_EVENTHDLRDATA * eventhdlrdata)71 SCIP_RETCODE doEventhdlrCreate(
72    SCIP_EVENTHDLR**      eventhdlr,          /**< pointer to event handler data structure */
73    const char*           name,               /**< name of event handler */
74    const char*           desc,               /**< description of event handler */
75    SCIP_DECL_EVENTCOPY   ((*eventcopy)),     /**< copy method of event handler or NULL if you don't want to copy your plugin into sub-SCIPs */
76    SCIP_DECL_EVENTFREE   ((*eventfree)),     /**< destructor of event handler */
77    SCIP_DECL_EVENTINIT   ((*eventinit)),     /**< initialize event handler */
78    SCIP_DECL_EVENTEXIT   ((*eventexit)),     /**< deinitialize event handler */
79    SCIP_DECL_EVENTINITSOL((*eventinitsol)),  /**< solving process initialization method of event handler */
80    SCIP_DECL_EVENTEXITSOL((*eventexitsol)),  /**< solving process deinitialization method of event handler */
81    SCIP_DECL_EVENTDELETE ((*eventdelete)),   /**< free specific event data */
82    SCIP_DECL_EVENTEXEC   ((*eventexec)),     /**< execute event handler */
83    SCIP_EVENTHDLRDATA*   eventhdlrdata       /**< event handler data */
84    )
85 {
86    assert(eventhdlr != NULL);
87    assert(name != NULL);
88    assert(desc != NULL);
89    assert(eventexec != NULL);
90 
91    SCIP_ALLOC( BMSallocMemory(eventhdlr) );
92    BMSclearMemory(*eventhdlr);
93    SCIP_ALLOC( BMSduplicateMemoryArray(&(*eventhdlr)->name, name, strlen(name)+1) );
94    SCIP_ALLOC( BMSduplicateMemoryArray(&(*eventhdlr)->desc, desc, strlen(desc)+1) );
95    (*eventhdlr)->eventcopy = eventcopy;
96    (*eventhdlr)->eventfree = eventfree;
97    (*eventhdlr)->eventinit = eventinit;
98    (*eventhdlr)->eventexit = eventexit;
99    (*eventhdlr)->eventinitsol = eventinitsol;
100    (*eventhdlr)->eventexitsol = eventexitsol;
101    (*eventhdlr)->eventdelete = eventdelete;
102    (*eventhdlr)->eventexec = eventexec;
103    (*eventhdlr)->eventhdlrdata = eventhdlrdata;
104    (*eventhdlr)->initialized = FALSE;
105 
106    /* create clocks */
107    SCIP_CALL( SCIPclockCreate(&(*eventhdlr)->setuptime, SCIP_CLOCKTYPE_DEFAULT) );
108    SCIP_CALL( SCIPclockCreate(&(*eventhdlr)->eventtime, SCIP_CLOCKTYPE_DEFAULT) );
109 
110    return SCIP_OKAY;
111 }
112 
113 /** creates an event handler */
SCIPeventhdlrCreate(SCIP_EVENTHDLR ** eventhdlr,SCIP_SET * set,const char * name,const char * desc,SCIP_DECL_EVENTCOPY ((* eventcopy)),SCIP_DECL_EVENTFREE ((* eventfree)),SCIP_DECL_EVENTINIT ((* eventinit)),SCIP_DECL_EVENTEXIT ((* eventexit)),SCIP_DECL_EVENTINITSOL ((* eventinitsol)),SCIP_DECL_EVENTEXITSOL ((* eventexitsol)),SCIP_DECL_EVENTDELETE ((* eventdelete)),SCIP_DECL_EVENTEXEC ((* eventexec)),SCIP_EVENTHDLRDATA * eventhdlrdata)114 SCIP_RETCODE SCIPeventhdlrCreate(
115    SCIP_EVENTHDLR**      eventhdlr,          /**< pointer to event handler data structure */
116    SCIP_SET*             set,                /**< global SCIP settings */
117    const char*           name,               /**< name of event handler */
118    const char*           desc,               /**< description of event handler */
119    SCIP_DECL_EVENTCOPY   ((*eventcopy)),     /**< copy method of event handler or NULL if you don't want to copy your plugin into sub-SCIPs */
120    SCIP_DECL_EVENTFREE   ((*eventfree)),     /**< destructor of event handler */
121    SCIP_DECL_EVENTINIT   ((*eventinit)),     /**< initialize event handler */
122    SCIP_DECL_EVENTEXIT   ((*eventexit)),     /**< deinitialize event handler */
123    SCIP_DECL_EVENTINITSOL((*eventinitsol)),  /**< solving process initialization method of event handler */
124    SCIP_DECL_EVENTEXITSOL((*eventexitsol)),  /**< solving process deinitialization method of event handler */
125    SCIP_DECL_EVENTDELETE ((*eventdelete)),   /**< free specific event data */
126    SCIP_DECL_EVENTEXEC   ((*eventexec)),     /**< execute event handler */
127    SCIP_EVENTHDLRDATA*   eventhdlrdata       /**< event handler data */
128    )
129 {
130    assert(eventhdlr != NULL);
131    assert(set != NULL);
132 
133    SCIP_CALL_FINALLY( doEventhdlrCreate(eventhdlr, name, desc, eventcopy, eventfree, eventinit, eventexit,
134       eventinitsol, eventexitsol, eventdelete, eventexec, eventhdlrdata), (void) SCIPeventhdlrFree(eventhdlr, set) );
135 
136    return SCIP_OKAY;
137 }
138 
139 /** calls destructor and frees memory of event handler */
SCIPeventhdlrFree(SCIP_EVENTHDLR ** eventhdlr,SCIP_SET * set)140 SCIP_RETCODE SCIPeventhdlrFree(
141    SCIP_EVENTHDLR**      eventhdlr,          /**< pointer to event handler data structure */
142    SCIP_SET*             set                 /**< global SCIP settings */
143    )
144 {
145    assert(eventhdlr != NULL);
146    assert(set != NULL);
147 
148    if( *eventhdlr == NULL )
149       return SCIP_OKAY;
150 
151    assert(!(*eventhdlr)->initialized);
152 
153    /* call destructor of event handler */
154    if( (*eventhdlr)->eventfree != NULL )
155    {
156       SCIP_CALL( (*eventhdlr)->eventfree(set->scip, *eventhdlr) );
157    }
158 
159    /* free clocks */
160    SCIPclockFree(&(*eventhdlr)->eventtime);
161    SCIPclockFree(&(*eventhdlr)->setuptime);
162 
163    BMSfreeMemoryArrayNull(&(*eventhdlr)->name);
164    BMSfreeMemoryArrayNull(&(*eventhdlr)->desc);
165    BMSfreeMemory(eventhdlr);
166 
167    return SCIP_OKAY;
168 }
169 
170 /** initializes event handler */
SCIPeventhdlrInit(SCIP_EVENTHDLR * eventhdlr,SCIP_SET * set)171 SCIP_RETCODE SCIPeventhdlrInit(
172    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler for this event */
173    SCIP_SET*             set                 /**< global SCIP settings */
174    )
175 {
176    assert(eventhdlr != NULL);
177    assert(set != NULL);
178 
179    if( eventhdlr->initialized )
180    {
181       SCIPerrorMessage("event handler <%s> already initialized\n", eventhdlr->name);
182       return SCIP_INVALIDCALL;
183    }
184 
185    if( set->misc_resetstat )
186    {
187       SCIPclockReset(eventhdlr->setuptime);
188       SCIPclockReset(eventhdlr->eventtime);
189    }
190 
191    if( eventhdlr->eventinit != NULL )
192    {
193       /* start timing */
194       SCIPclockStart(eventhdlr->setuptime, set);
195 
196       SCIP_CALL( eventhdlr->eventinit(set->scip, eventhdlr) );
197 
198       /* stop timing */
199       SCIPclockStop(eventhdlr->setuptime, set);
200    }
201    eventhdlr->initialized = TRUE;
202 
203    return SCIP_OKAY;
204 }
205 
206 /** calls exit method of event handler */
SCIPeventhdlrExit(SCIP_EVENTHDLR * eventhdlr,SCIP_SET * set)207 SCIP_RETCODE SCIPeventhdlrExit(
208    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler for this event */
209    SCIP_SET*             set                 /**< global SCIP settings */
210    )
211 {
212    assert(eventhdlr != NULL);
213    assert(set != NULL);
214 
215    if( !eventhdlr->initialized )
216    {
217       SCIPerrorMessage("event handler <%s> not initialized\n", eventhdlr->name);
218       return SCIP_INVALIDCALL;
219    }
220 
221    if( eventhdlr->eventexit != NULL )
222    {
223       /* start timing */
224       SCIPclockStart(eventhdlr->setuptime, set);
225 
226       SCIP_CALL( eventhdlr->eventexit(set->scip, eventhdlr) );
227 
228       /* stop timing */
229       SCIPclockStop(eventhdlr->setuptime, set);
230    }
231    eventhdlr->initialized = FALSE;
232 
233    return SCIP_OKAY;
234 }
235 
236 /** informs event handler that the branch and bound process is being started */
SCIPeventhdlrInitsol(SCIP_EVENTHDLR * eventhdlr,SCIP_SET * set)237 SCIP_RETCODE SCIPeventhdlrInitsol(
238    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
239    SCIP_SET*             set                 /**< global SCIP settings */
240    )
241 {
242    assert(eventhdlr != NULL);
243    assert(set != NULL);
244 
245    /* call solving process initialization method of event handler */
246    if( eventhdlr->eventinitsol != NULL )
247    {
248       /* start timing */
249       SCIPclockStart(eventhdlr->setuptime, set);
250 
251       SCIP_CALL( eventhdlr->eventinitsol(set->scip, eventhdlr) );
252 
253       /* stop timing */
254       SCIPclockStop(eventhdlr->setuptime, set);
255    }
256 
257    return SCIP_OKAY;
258 }
259 
260 /** informs event handler that the branch and bound process data is being freed */
SCIPeventhdlrExitsol(SCIP_EVENTHDLR * eventhdlr,SCIP_SET * set)261 SCIP_RETCODE SCIPeventhdlrExitsol(
262    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
263    SCIP_SET*             set                 /**< global SCIP settings */
264    )
265 {
266    assert(eventhdlr != NULL);
267    assert(set != NULL);
268 
269    /* call solving process deinitialization method of event handler */
270    if( eventhdlr->eventexitsol != NULL )
271    {
272       /* start timing */
273       SCIPclockStart(eventhdlr->setuptime, set);
274 
275       SCIP_CALL( eventhdlr->eventexitsol(set->scip, eventhdlr) );
276 
277       /* stop timing */
278       SCIPclockStop(eventhdlr->setuptime, set);
279    }
280 
281    return SCIP_OKAY;
282 }
283 
284 /** calls execution method of event handler */
SCIPeventhdlrExec(SCIP_EVENTHDLR * eventhdlr,SCIP_SET * set,SCIP_EVENT * event,SCIP_EVENTDATA * eventdata)285 SCIP_RETCODE SCIPeventhdlrExec(
286    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
287    SCIP_SET*             set,                /**< global SCIP settings */
288    SCIP_EVENT*           event,              /**< event to call event handler with */
289    SCIP_EVENTDATA*       eventdata           /**< user data for the issued event */
290    )
291 {
292    assert(eventhdlr != NULL);
293    assert(eventhdlr->eventexec != NULL);
294    assert(set != NULL);
295    assert(event != NULL);
296 
297    SCIPsetDebugMsg(set, "execute event of handler <%s> with event %p of type 0x%" SCIP_EVENTTYPE_FORMAT "\n", eventhdlr->name, (void*)event, event->eventtype);
298 
299 #ifdef TIMEEVENTEXEC
300    /* start timing */
301    SCIPclockStart(eventhdlr->eventtime, set);
302 #endif
303 
304    SCIP_CALL( eventhdlr->eventexec(set->scip, eventhdlr, event, eventdata) );
305 
306 #ifdef TIMEEVENTEXEC
307    /* stop timing */
308    SCIPclockStop(eventhdlr->eventtime, set);
309 #endif
310 
311    return SCIP_OKAY;
312 }
313 
314 /** gets name of event handler */
SCIPeventhdlrGetName(SCIP_EVENTHDLR * eventhdlr)315 const char* SCIPeventhdlrGetName(
316    SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
317    )
318 {
319    assert(eventhdlr != NULL);
320 
321    return eventhdlr->name;
322 }
323 
324 /** gets user data of event handler */
SCIPeventhdlrGetData(SCIP_EVENTHDLR * eventhdlr)325 SCIP_EVENTHDLRDATA* SCIPeventhdlrGetData(
326    SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
327    )
328 {
329    assert(eventhdlr != NULL);
330 
331    return eventhdlr->eventhdlrdata;
332 }
333 
334 /** sets user data of event handler; user has to free old data in advance! */
SCIPeventhdlrSetData(SCIP_EVENTHDLR * eventhdlr,SCIP_EVENTHDLRDATA * eventhdlrdata)335 void SCIPeventhdlrSetData(
336    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
337    SCIP_EVENTHDLRDATA*   eventhdlrdata       /**< new event handler user data */
338    )
339 {
340    assert(eventhdlr != NULL);
341 
342    eventhdlr->eventhdlrdata = eventhdlrdata;
343 }
344 
345 /** sets copy callback for all events of this event handler */
SCIPeventhdlrSetCopy(SCIP_EVENTHDLR * eventhdlr,SCIP_DECL_EVENTCOPY ((* eventcopy)))346 void SCIPeventhdlrSetCopy(
347    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
348    SCIP_DECL_EVENTCOPY   ((*eventcopy))      /**< copy callback for events */
349    )
350 {
351    assert(eventhdlr != NULL);
352 
353    eventhdlr->eventcopy = eventcopy;
354 }
355 
356 /** sets destructor callback of this event handler */
SCIPeventhdlrSetFree(SCIP_EVENTHDLR * eventhdlr,SCIP_DECL_EVENTFREE ((* eventfree)))357 void SCIPeventhdlrSetFree(
358    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
359    SCIP_DECL_EVENTFREE   ((*eventfree))      /**< destructor callback of event handler */
360    )
361 {
362    assert(eventhdlr != NULL);
363 
364    eventhdlr->eventfree = eventfree;
365 }
366 
367 /** sets initialization callback of this event handler */
SCIPeventhdlrSetInit(SCIP_EVENTHDLR * eventhdlr,SCIP_DECL_EVENTINIT ((* eventinit)))368 void SCIPeventhdlrSetInit(
369    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
370    SCIP_DECL_EVENTINIT   ((*eventinit))      /**< initialization callback of event handler */
371    )
372 {
373    assert(eventhdlr != NULL);
374 
375    eventhdlr->eventinit = eventinit;
376 }
377 
378 /** sets deinitialization callback of this event handler */
SCIPeventhdlrSetExit(SCIP_EVENTHDLR * eventhdlr,SCIP_DECL_EVENTEXIT ((* eventexit)))379 void SCIPeventhdlrSetExit(
380    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
381    SCIP_DECL_EVENTEXIT   ((*eventexit))      /**< deinitialization callback of event handler */
382    )
383 {
384    assert(eventhdlr != NULL);
385 
386    eventhdlr->eventexit = eventexit;
387 }
388 
389 /** sets solving process initialization callback of this event handler */
SCIPeventhdlrSetInitsol(SCIP_EVENTHDLR * eventhdlr,SCIP_DECL_EVENTINITSOL ((* eventinitsol)))390 void SCIPeventhdlrSetInitsol(
391    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
392    SCIP_DECL_EVENTINITSOL((*eventinitsol))   /**< solving process initialization callback of event handler */
393    )
394 {
395    assert(eventhdlr != NULL);
396 
397    eventhdlr->eventinitsol = eventinitsol;
398 }
399 
400 /** sets solving process deinitialization callback of this event handler */
SCIPeventhdlrSetExitsol(SCIP_EVENTHDLR * eventhdlr,SCIP_DECL_EVENTEXITSOL ((* eventexitsol)))401 void SCIPeventhdlrSetExitsol(
402    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
403    SCIP_DECL_EVENTEXITSOL((*eventexitsol))   /**< solving process deinitialization callback of event handler */
404    )
405 {
406    assert(eventhdlr != NULL);
407 
408    eventhdlr->eventexitsol = eventexitsol;
409 }
410 
411 /** sets callback to free specific event data */
SCIPeventhdlrSetDelete(SCIP_EVENTHDLR * eventhdlr,SCIP_DECL_EVENTDELETE ((* eventdelete)))412 void SCIPeventhdlrSetDelete(
413    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
414    SCIP_DECL_EVENTDELETE ((*eventdelete))    /**< callback to free specific event data */
415    )
416 {
417    assert(eventhdlr != NULL);
418 
419    eventhdlr->eventdelete = eventdelete;
420 }
421 
422 /** is event handler initialized? */
SCIPeventhdlrIsInitialized(SCIP_EVENTHDLR * eventhdlr)423 SCIP_Bool SCIPeventhdlrIsInitialized(
424    SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
425    )
426 {
427    assert(eventhdlr != NULL);
428 
429    return eventhdlr->initialized;
430 }
431 
432 /** enables or disables all clocks of \p eventhdlr, depending on the value of the flag */
SCIPeventhdlrEnableOrDisableClocks(SCIP_EVENTHDLR * eventhdlr,SCIP_Bool enable)433 void SCIPeventhdlrEnableOrDisableClocks(
434    SCIP_EVENTHDLR*       eventhdlr,          /**< the event handler for which all clocks should be enabled or disabled */
435    SCIP_Bool             enable              /**< should the clocks of the event handler be enabled? */
436    )
437 {
438    assert(eventhdlr != NULL);
439 
440    SCIPclockEnableOrDisable(eventhdlr->setuptime, enable);
441    SCIPclockEnableOrDisable(eventhdlr->eventtime, enable);
442 }
443 
444 /** gets time in seconds used in this event handler for setting up for next stages */
SCIPeventhdlrGetSetupTime(SCIP_EVENTHDLR * eventhdlr)445 SCIP_Real SCIPeventhdlrGetSetupTime(
446    SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
447    )
448 {
449    assert(eventhdlr != NULL);
450 
451    return SCIPclockGetTime(eventhdlr->setuptime);
452 }
453 
454 /** gets time in seconds used in this event handler, this measurement is currently disabled so this method will return
455  *  0, define TIMEEVENTEXEC in the beginning of this file to enable
456  */
SCIPeventhdlrGetTime(SCIP_EVENTHDLR * eventhdlr)457 SCIP_Real SCIPeventhdlrGetTime(
458    SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
459    )
460 {
461    assert(eventhdlr != NULL);
462 
463    return SCIPclockGetTime(eventhdlr->eventtime);
464 }
465 
466 
467 
468 /*
469  * Event methods
470  */
471 
472 
473 /** creates a synchronization event */
SCIPeventCreateSync(SCIP_EVENT ** event,BMS_BLKMEM * blkmem)474 SCIP_RETCODE SCIPeventCreateSync(
475    SCIP_EVENT**          event,              /**< pointer to store the event */
476    BMS_BLKMEM*           blkmem              /**< block memory */
477    )
478 {
479    assert(event != NULL);
480 
481    /* create event data */
482    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
483    (*event)->eventtype = SCIP_EVENTTYPE_SYNC;
484 
485    return SCIP_OKAY;
486 }
487 
488 /*
489  * simple functions implemented as defines
490  */
491 
492 /* In debug mode, the following methods are implemented as function calls to ensure
493  * type validity.
494  * In optimized mode, the methods are implemented as defines to improve performance.
495  * However, we want to have them in the library anyways, so we have to undef the defines.
496  */
497 
498 #undef SCIPeventGetType
499 #undef SCIPeventGetOldobj
500 #undef SCIPeventGetNewobj
501 #undef SCIPeventGetOldtype
502 #undef SCIPeventGetNewtype
503 #undef SCIPeventGetOldbound
504 #undef SCIPeventGetNewbound
505 #undef SCIPeventGetNode
506 #undef SCIPeventGetSol
507 #undef SCIPeventGetRowCol
508 #undef SCIPeventGetRowOldCoefVal
509 #undef SCIPeventGetRowNewCoefVal
510 #undef SCIPeventGetRowOldConstVal
511 #undef SCIPeventGetRowNewConstVal
512 #undef SCIPeventGetRowSide
513 #undef SCIPeventGetRowOldSideVal
514 #undef SCIPeventGetRowNewSideVal
515 
516 /** creates an event for an addition of a variable to the problem */
SCIPeventCreateVarAdded(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var)517 SCIP_RETCODE SCIPeventCreateVarAdded(
518    SCIP_EVENT**          event,              /**< pointer to store the event */
519    BMS_BLKMEM*           blkmem,             /**< block memory */
520    SCIP_VAR*             var                 /**< variable that was added to the problem */
521    )
522 {
523    assert(event != NULL);
524    assert(blkmem != NULL);
525 
526    /* create event data */
527    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
528    (*event)->eventtype = SCIP_EVENTTYPE_VARADDED;
529    (*event)->data.eventvaradded.var = var;
530 
531    return SCIP_OKAY;
532 }
533 
534 /** creates an event for a deletion of a variable from the problem */
SCIPeventCreateVarDeleted(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var)535 SCIP_RETCODE SCIPeventCreateVarDeleted(
536    SCIP_EVENT**          event,              /**< pointer to store the event */
537    BMS_BLKMEM*           blkmem,             /**< block memory */
538    SCIP_VAR*             var                 /**< variable that is to be deleted from the problem */
539    )
540 {
541    assert(event != NULL);
542    assert(blkmem != NULL);
543 
544    /* create event data */
545    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
546    (*event)->eventtype = SCIP_EVENTTYPE_VARDELETED;
547    (*event)->data.eventvardeleted.var = var;
548 
549    return SCIP_OKAY;
550 }
551 
552 /** creates an event for a fixing of a variable */
SCIPeventCreateVarFixed(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var)553 SCIP_RETCODE SCIPeventCreateVarFixed(
554    SCIP_EVENT**          event,              /**< pointer to store the event */
555    BMS_BLKMEM*           blkmem,             /**< block memory */
556    SCIP_VAR*             var                 /**< variable that was fixed */
557    )
558 {
559    assert(event != NULL);
560    assert(blkmem != NULL);
561    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED
562       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED
563       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR
564       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED);
565 
566    /* create event data */
567    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
568    (*event)->eventtype = SCIP_EVENTTYPE_VARFIXED;
569    (*event)->data.eventvarfixed.var = var;
570 
571    return SCIP_OKAY;
572 }
573 
574 /** creates an event for a change in the number of locks of a variable down to zero or one */
SCIPeventCreateVarUnlocked(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var)575 SCIP_RETCODE SCIPeventCreateVarUnlocked(
576    SCIP_EVENT**          event,              /**< pointer to store the event */
577    BMS_BLKMEM*           blkmem,             /**< block memory */
578    SCIP_VAR*             var                 /**< variable that changed the number of locks */
579    )
580 {
581    assert(event != NULL);
582    assert(blkmem != NULL);
583    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
584       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN
585       || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED);
586 
587    /* create event data */
588    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
589    (*event)->eventtype = SCIP_EVENTTYPE_VARUNLOCKED;
590    (*event)->data.eventvarunlocked.var = var;
591 
592    return SCIP_OKAY;
593 }
594 
595 /** creates an event for a change in the objective value of a variable */
SCIPeventCreateObjChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real oldobj,SCIP_Real newobj)596 SCIP_RETCODE SCIPeventCreateObjChanged(
597    SCIP_EVENT**          event,              /**< pointer to store the event */
598    BMS_BLKMEM*           blkmem,             /**< block memory */
599    SCIP_VAR*             var,                /**< variable whose objective value changed */
600    SCIP_Real             oldobj,             /**< old objective value before value changed */
601    SCIP_Real             newobj              /**< new objective value after value changed */
602    )
603 {
604    assert(event != NULL);
605    assert(blkmem != NULL);
606    assert(oldobj != newobj); /*lint !e777*/
607 
608    /* create event data */
609    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
610    (*event)->eventtype = SCIP_EVENTTYPE_OBJCHANGED;
611    (*event)->data.eventobjchg.var = var;
612    (*event)->data.eventobjchg.oldobj = oldobj;
613    (*event)->data.eventobjchg.newobj = newobj;
614 
615    return SCIP_OKAY;
616 }
617 
618 /** creates an event for a change in the global lower bound of a variable */
SCIPeventCreateGlbChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real oldbound,SCIP_Real newbound)619 SCIP_RETCODE SCIPeventCreateGlbChanged(
620    SCIP_EVENT**          event,              /**< pointer to store the event */
621    BMS_BLKMEM*           blkmem,             /**< block memory */
622    SCIP_VAR*             var,                /**< variable whose bound changed */
623    SCIP_Real             oldbound,           /**< old bound before bound changed */
624    SCIP_Real             newbound            /**< new bound after bound changed */
625    )
626 {
627    assert(event != NULL);
628    assert(blkmem != NULL);
629    assert(oldbound != newbound); /*lint !e777*/
630 
631    /* create event data */
632    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
633    (*event)->eventtype = SCIP_EVENTTYPE_GLBCHANGED;
634    (*event)->data.eventbdchg.var = var;
635    (*event)->data.eventbdchg.oldbound = oldbound;
636    (*event)->data.eventbdchg.newbound = newbound;
637 
638    return SCIP_OKAY;
639 }
640 
641 /** creates an event for a change in the global upper bound of a variable */
SCIPeventCreateGubChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real oldbound,SCIP_Real newbound)642 SCIP_RETCODE SCIPeventCreateGubChanged(
643    SCIP_EVENT**          event,              /**< pointer to store the event */
644    BMS_BLKMEM*           blkmem,             /**< block memory */
645    SCIP_VAR*             var,                /**< variable whose bound changed */
646    SCIP_Real             oldbound,           /**< old bound before bound changed */
647    SCIP_Real             newbound            /**< new bound after bound changed */
648    )
649 {
650    assert(event != NULL);
651    assert(blkmem != NULL);
652    assert(oldbound != newbound); /*lint !e777*/
653 
654    /* create event data */
655    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
656    (*event)->eventtype = SCIP_EVENTTYPE_GUBCHANGED;
657    (*event)->data.eventbdchg.var = var;
658    (*event)->data.eventbdchg.oldbound = oldbound;
659    (*event)->data.eventbdchg.newbound = newbound;
660 
661    return SCIP_OKAY;
662 }
663 
664 /** creates an event for a change in the lower bound of a variable */
SCIPeventCreateLbChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real oldbound,SCIP_Real newbound)665 SCIP_RETCODE SCIPeventCreateLbChanged(
666    SCIP_EVENT**          event,              /**< pointer to store the event */
667    BMS_BLKMEM*           blkmem,             /**< block memory */
668    SCIP_VAR*             var,                /**< variable whose bound changed */
669    SCIP_Real             oldbound,           /**< old bound before bound changed */
670    SCIP_Real             newbound            /**< new bound after bound changed */
671    )
672 {
673    assert(event != NULL);
674    assert(blkmem != NULL);
675    assert(oldbound != newbound); /*lint !e777*/
676 
677    /* create event data */
678    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
679    if( newbound > oldbound )
680       (*event)->eventtype = SCIP_EVENTTYPE_LBTIGHTENED;
681    else
682       (*event)->eventtype = SCIP_EVENTTYPE_LBRELAXED;
683    (*event)->data.eventbdchg.var = var;
684    (*event)->data.eventbdchg.oldbound = oldbound;
685    (*event)->data.eventbdchg.newbound = newbound;
686 
687    return SCIP_OKAY;
688 }
689 
690 /** creates an event for a change in the upper bound of a variable */
SCIPeventCreateUbChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real oldbound,SCIP_Real newbound)691 SCIP_RETCODE SCIPeventCreateUbChanged(
692    SCIP_EVENT**          event,              /**< pointer to store the event */
693    BMS_BLKMEM*           blkmem,             /**< block memory */
694    SCIP_VAR*             var,                /**< variable whose bound changed */
695    SCIP_Real             oldbound,           /**< old bound before bound changed */
696    SCIP_Real             newbound            /**< new bound after bound changed */
697    )
698 {
699    assert(event != NULL);
700    assert(blkmem != NULL);
701    assert(oldbound != newbound); /*lint !e777*/
702 
703    /* create event data */
704    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
705    if( newbound < oldbound )
706       (*event)->eventtype = SCIP_EVENTTYPE_UBTIGHTENED;
707    else
708       (*event)->eventtype = SCIP_EVENTTYPE_UBRELAXED;
709    (*event)->data.eventbdchg.var = var;
710    (*event)->data.eventbdchg.oldbound = oldbound;
711    (*event)->data.eventbdchg.newbound = newbound;
712 
713    return SCIP_OKAY;
714 }
715 
716 /** creates an event for an addition of a domain hole to a variable */
SCIPeventCreateGholeAdded(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real left,SCIP_Real right)717 SCIP_RETCODE SCIPeventCreateGholeAdded(
718    SCIP_EVENT**          event,              /**< pointer to store the event */
719    BMS_BLKMEM*           blkmem,             /**< block memory */
720    SCIP_VAR*             var,                /**< variable whose bound changed */
721    SCIP_Real             left,               /**< left bound of open interval in new hole */
722    SCIP_Real             right               /**< right bound of open interval in new hole */
723    )
724 {
725    assert(event != NULL);
726    assert(blkmem != NULL);
727 
728    /* create event data */
729    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
730    (*event)->eventtype = SCIP_EVENTTYPE_GHOLEADDED;
731    (*event)->data.eventhole.var = var;
732    (*event)->data.eventhole.left = left;
733    (*event)->data.eventhole.right = right;
734 
735    return SCIP_OKAY;
736 }
737 
738 /** creates an event for removing a domain hole of a variable */
SCIPeventCreateGholeRemoved(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real left,SCIP_Real right)739 SCIP_RETCODE SCIPeventCreateGholeRemoved(
740    SCIP_EVENT**          event,              /**< pointer to store the event */
741    BMS_BLKMEM*           blkmem,             /**< block memory */
742    SCIP_VAR*             var,                /**< variable whose bound changed */
743    SCIP_Real             left,               /**< left bound of open interval in hole */
744    SCIP_Real             right               /**< right bound of open interval in hole */
745    )
746 {
747    assert(event != NULL);
748    assert(blkmem != NULL);
749 
750    /* create event data */
751    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
752    (*event)->eventtype = SCIP_EVENTTYPE_GHOLEREMOVED;
753    (*event)->data.eventhole.var = var;
754    (*event)->data.eventhole.left = left;
755    (*event)->data.eventhole.right = right;
756 
757    return SCIP_OKAY;
758 }
759 
760 /** creates an event for an addition of a domain hole to a variable */
SCIPeventCreateLholeAdded(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real left,SCIP_Real right)761 SCIP_RETCODE SCIPeventCreateLholeAdded(
762    SCIP_EVENT**          event,              /**< pointer to store the event */
763    BMS_BLKMEM*           blkmem,             /**< block memory */
764    SCIP_VAR*             var,                /**< variable whose bound changed */
765    SCIP_Real             left,               /**< left bound of open interval in new hole */
766    SCIP_Real             right               /**< right bound of open interval in new hole */
767    )
768 {
769    assert(event != NULL);
770    assert(blkmem != NULL);
771 
772    /* create event data */
773    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
774    (*event)->eventtype = SCIP_EVENTTYPE_LHOLEADDED;
775    (*event)->data.eventhole.var = var;
776    (*event)->data.eventhole.left = left;
777    (*event)->data.eventhole.right = right;
778 
779    return SCIP_OKAY;
780 }
781 
782 /** creates an event for removing a domain hole of a variable */
SCIPeventCreateLholeRemoved(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_Real left,SCIP_Real right)783 SCIP_RETCODE SCIPeventCreateLholeRemoved(
784    SCIP_EVENT**          event,              /**< pointer to store the event */
785    BMS_BLKMEM*           blkmem,             /**< block memory */
786    SCIP_VAR*             var,                /**< variable whose bound changed */
787    SCIP_Real             left,               /**< left bound of open interval in hole */
788    SCIP_Real             right               /**< right bound of open interval in hole */
789    )
790 {
791    assert(event != NULL);
792    assert(blkmem != NULL);
793 
794    /* create event data */
795    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
796    (*event)->eventtype = SCIP_EVENTTYPE_LHOLEREMOVED;
797    (*event)->data.eventhole.var = var;
798    (*event)->data.eventhole.left = left;
799    (*event)->data.eventhole.right = right;
800 
801    return SCIP_OKAY;
802 }
803 
804 /** creates an event for an addition to the variable's implications list, clique or variable bounds information */
SCIPeventCreateImplAdded(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var)805 SCIP_RETCODE SCIPeventCreateImplAdded(
806    SCIP_EVENT**          event,              /**< pointer to store the event */
807    BMS_BLKMEM*           blkmem,             /**< block memory */
808    SCIP_VAR*             var                 /**< variable that was fixed */
809    )
810 {
811    assert(event != NULL);
812    assert(blkmem != NULL);
813    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
814 
815    /* create event data */
816    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
817    (*event)->eventtype = SCIP_EVENTTYPE_IMPLADDED;
818    (*event)->data.eventimpladd.var = var;
819 
820    return SCIP_OKAY;
821 }
822 
823 /** creates an event for a changeing the type of a variable */
SCIPeventCreateTypeChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_VARTYPE oldtype,SCIP_VARTYPE newtype)824 SCIP_RETCODE SCIPeventCreateTypeChanged(
825    SCIP_EVENT**          event,              /**< pointer to store the event */
826    BMS_BLKMEM*           blkmem,             /**< block memory */
827    SCIP_VAR*             var,                /**< variable whose objective value changed */
828    SCIP_VARTYPE          oldtype,            /**< old variable type */
829    SCIP_VARTYPE          newtype             /**< new variable type */
830    )
831 {
832    assert(event != NULL);
833    assert(blkmem != NULL);
834    assert(oldtype != newtype);
835 
836    /* create event data */
837    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
838    (*event)->eventtype = SCIP_EVENTTYPE_TYPECHANGED;
839    (*event)->data.eventtypechg.var = var;
840    (*event)->data.eventtypechg.oldtype = oldtype;
841    (*event)->data.eventtypechg.newtype = newtype;
842 
843    return SCIP_OKAY;
844 }
845 
846 /** creates an event for the addition of a linear row to the separation storage */
SCIPeventCreateRowAddedSepa(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_ROW * row)847 SCIP_RETCODE SCIPeventCreateRowAddedSepa(
848    SCIP_EVENT**          event,              /**< pointer to store the event */
849    BMS_BLKMEM*           blkmem,             /**< block memory */
850    SCIP_ROW*             row                 /**< row that was added to the separation storage*/
851    )
852 {
853    assert(event != NULL);
854    assert(blkmem != NULL);
855    assert(row != NULL);
856 
857    /* create event data */
858    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
859    (*event)->eventtype = SCIP_EVENTTYPE_ROWADDEDSEPA;
860    (*event)->data.eventrowaddedsepa.row = row;
861 
862    return SCIP_OKAY;
863 }
864 
865 /** creates an event for the deletion of a linear row from the separation storage */
SCIPeventCreateRowDeletedSepa(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_ROW * row)866 SCIP_RETCODE SCIPeventCreateRowDeletedSepa(
867    SCIP_EVENT**          event,              /**< pointer to store the event */
868    BMS_BLKMEM*           blkmem,             /**< block memory */
869    SCIP_ROW*             row                 /**< row that was deleted from the separation storage */
870    )
871 {
872    assert(event != NULL);
873    assert(blkmem != NULL);
874    assert(row != NULL);
875 
876    /* create event data */
877    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
878    (*event)->eventtype = SCIP_EVENTTYPE_ROWDELETEDSEPA;
879    (*event)->data.eventrowdeletedsepa.row = row;
880 
881    return SCIP_OKAY;
882 }
883 
884 /** creates an event for the addition of a linear row to the LP */
SCIPeventCreateRowAddedLP(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_ROW * row)885 SCIP_RETCODE SCIPeventCreateRowAddedLP(
886    SCIP_EVENT**          event,              /**< pointer to store the event */
887    BMS_BLKMEM*           blkmem,             /**< block memory */
888    SCIP_ROW*             row                 /**< row that was added to the LP */
889    )
890 {
891    assert(event != NULL);
892    assert(blkmem != NULL);
893    assert(row != NULL);
894 
895    /* create event data */
896    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
897    (*event)->eventtype = SCIP_EVENTTYPE_ROWADDEDLP;
898    (*event)->data.eventrowaddedlp.row = row;
899 
900    return SCIP_OKAY;
901 }
902 
903 /** creates an event for the deletion of a linear row from the LP */
SCIPeventCreateRowDeletedLP(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_ROW * row)904 SCIP_RETCODE SCIPeventCreateRowDeletedLP(
905    SCIP_EVENT**          event,              /**< pointer to store the event */
906    BMS_BLKMEM*           blkmem,             /**< block memory */
907    SCIP_ROW*             row                 /**< row that was deleted from the LP */
908    )
909 {
910    assert(event != NULL);
911    assert(blkmem != NULL);
912    assert(row != NULL);
913 
914    /* create event data */
915    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
916    (*event)->eventtype = SCIP_EVENTTYPE_ROWDELETEDLP;
917    (*event)->data.eventrowdeletedlp.row = row;
918 
919    return SCIP_OKAY;
920 }
921 
922 /** creates an event for the change of a coefficient in a linear row */
SCIPeventCreateRowCoefChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_ROW * row,SCIP_COL * col,SCIP_Real oldval,SCIP_Real newval)923 SCIP_RETCODE SCIPeventCreateRowCoefChanged(
924    SCIP_EVENT**          event,              /**< pointer to store the event */
925    BMS_BLKMEM*           blkmem,             /**< block memory */
926    SCIP_ROW*             row,                /**< row in which a coefficient changed */
927    SCIP_COL*             col,                /**< column which coefficient changed */
928    SCIP_Real             oldval,             /**< old value of coefficient */
929    SCIP_Real             newval              /**< new value of coefficient */
930    )
931 {
932    assert(event != NULL);
933    assert(blkmem != NULL);
934    assert(row != NULL);
935 
936    /* create event data */
937    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
938    (*event)->eventtype = SCIP_EVENTTYPE_ROWCOEFCHANGED;
939    (*event)->data.eventrowcoefchanged.row = row;
940    (*event)->data.eventrowcoefchanged.col = col;
941    (*event)->data.eventrowcoefchanged.oldval = oldval;
942    (*event)->data.eventrowcoefchanged.newval = newval;
943 
944    return SCIP_OKAY;
945 }
946 
947 /** creates an event for the change of a constant in a linear row */
SCIPeventCreateRowConstChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_ROW * row,SCIP_Real oldval,SCIP_Real newval)948 SCIP_RETCODE SCIPeventCreateRowConstChanged(
949    SCIP_EVENT**          event,              /**< pointer to store the event */
950    BMS_BLKMEM*           blkmem,             /**< block memory */
951    SCIP_ROW*             row,                /**< row in which the constant changed */
952    SCIP_Real             oldval,             /**< old value of constant */
953    SCIP_Real             newval              /**< new value of constant */
954    )
955 {
956    assert(event != NULL);
957    assert(blkmem != NULL);
958    assert(row != NULL);
959 
960    /* create event data */
961    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
962    (*event)->eventtype = SCIP_EVENTTYPE_ROWCONSTCHANGED;
963    (*event)->data.eventrowconstchanged.row = row;
964    (*event)->data.eventrowconstchanged.oldval = oldval;
965    (*event)->data.eventrowconstchanged.newval = newval;
966 
967    return SCIP_OKAY;
968 }
969 
970 /** creates an event for the change of a side of a linear row */
SCIPeventCreateRowSideChanged(SCIP_EVENT ** event,BMS_BLKMEM * blkmem,SCIP_ROW * row,SCIP_SIDETYPE side,SCIP_Real oldval,SCIP_Real newval)971 SCIP_RETCODE SCIPeventCreateRowSideChanged(
972    SCIP_EVENT**          event,              /**< pointer to store the event */
973    BMS_BLKMEM*           blkmem,             /**< block memory */
974    SCIP_ROW*             row,                /**< row which side has changed */
975    SCIP_SIDETYPE         side,               /**< which side has changed */
976    SCIP_Real             oldval,             /**< old value of side */
977    SCIP_Real             newval              /**< new value of side */
978    )
979 {
980    assert(event != NULL);
981    assert(blkmem != NULL);
982    assert(row != NULL);
983 
984    /* create event data */
985    SCIP_ALLOC( BMSallocBlockMemory(blkmem, event) );
986    (*event)->eventtype = SCIP_EVENTTYPE_ROWSIDECHANGED;
987    (*event)->data.eventrowsidechanged.row = row;
988    (*event)->data.eventrowsidechanged.side = side;
989    (*event)->data.eventrowsidechanged.oldval = oldval;
990    (*event)->data.eventrowsidechanged.newval = newval;
991 
992    return SCIP_OKAY;
993 }
994 
995 /** frees an event */
SCIPeventFree(SCIP_EVENT ** event,BMS_BLKMEM * blkmem)996 SCIP_RETCODE SCIPeventFree(
997    SCIP_EVENT**          event,              /**< event to free */
998    BMS_BLKMEM*           blkmem              /**< block memory buffer */
999    )
1000 {
1001    assert(event != NULL);
1002    assert(blkmem != NULL);
1003 
1004    BMSfreeBlockMemory(blkmem, event);
1005 
1006    return SCIP_OKAY;
1007 }
1008 
1009 /** disables an event */
1010 static
eventDisable(SCIP_EVENT * event)1011 void eventDisable(
1012    SCIP_EVENT*           event               /**< event to disable */
1013    )
1014 {
1015    assert(event != NULL);
1016 
1017    event->eventtype = SCIP_EVENTTYPE_DISABLED;
1018 }
1019 
1020 /** gets type of event */
SCIPeventGetType(SCIP_EVENT * event)1021 SCIP_EVENTTYPE SCIPeventGetType(
1022    SCIP_EVENT*           event               /**< event */
1023    )
1024 {
1025    assert(event != NULL);
1026 
1027    return event->eventtype;
1028 }
1029 
1030 /** sets type of event */
SCIPeventChgType(SCIP_EVENT * event,SCIP_EVENTTYPE eventtype)1031 SCIP_RETCODE SCIPeventChgType(
1032    SCIP_EVENT*           event,              /**< event */
1033    SCIP_EVENTTYPE        eventtype           /**< new event type */
1034    )
1035 {
1036    assert(event != NULL);
1037 
1038    event->eventtype = eventtype;
1039 
1040    return SCIP_OKAY;
1041 }
1042 
1043 /** gets variable for a variable event (var added, var deleted, var fixed, objective value or domain change) */
SCIPeventGetVar(SCIP_EVENT * event)1044 SCIP_VAR* SCIPeventGetVar(
1045    SCIP_EVENT*           event               /**< event */
1046    )
1047 {
1048    assert(event != NULL);
1049 
1050    switch( event->eventtype )
1051    {
1052    case SCIP_EVENTTYPE_VARADDED:
1053       assert(event->data.eventvaradded.var != NULL);
1054       return event->data.eventvaradded.var;
1055 
1056    case SCIP_EVENTTYPE_VARDELETED:
1057       assert(event->data.eventvardeleted.var != NULL);
1058       return event->data.eventvardeleted.var;
1059 
1060    case SCIP_EVENTTYPE_VARFIXED:
1061       assert(event->data.eventvarfixed.var != NULL);
1062       return event->data.eventvarfixed.var;
1063 
1064    case SCIP_EVENTTYPE_VARUNLOCKED:
1065       assert(event->data.eventvarunlocked.var != NULL);
1066       return event->data.eventvarunlocked.var;
1067 
1068    case SCIP_EVENTTYPE_OBJCHANGED:
1069       assert(event->data.eventobjchg.var != NULL);
1070       return event->data.eventobjchg.var;
1071 
1072    case SCIP_EVENTTYPE_GLBCHANGED:
1073    case SCIP_EVENTTYPE_GUBCHANGED:
1074    case SCIP_EVENTTYPE_LBTIGHTENED:
1075    case SCIP_EVENTTYPE_LBRELAXED:
1076    case SCIP_EVENTTYPE_UBTIGHTENED:
1077    case SCIP_EVENTTYPE_UBRELAXED:
1078       assert(event->data.eventbdchg.var != NULL);
1079       return event->data.eventbdchg.var;
1080 
1081    case SCIP_EVENTTYPE_GHOLEADDED:
1082    case SCIP_EVENTTYPE_GHOLEREMOVED:
1083    case SCIP_EVENTTYPE_LHOLEADDED:
1084    case SCIP_EVENTTYPE_LHOLEREMOVED:
1085       assert(event->data.eventhole.var != NULL);
1086       return event->data.eventhole.var;
1087 
1088    case SCIP_EVENTTYPE_IMPLADDED:
1089       assert(event->data.eventimpladd.var != NULL);
1090       return event->data.eventimpladd.var;
1091 
1092    case SCIP_EVENTTYPE_TYPECHANGED:
1093       assert(event->data.eventtypechg.var != NULL);
1094       return event->data.eventtypechg.var;
1095 
1096    default:
1097       SCIPerrorMessage("event does not belong to a variable\n");
1098       SCIPABORT();
1099       return NULL; /*lint !e527*/
1100    }  /*lint !e788*/
1101 }
1102 
1103 /** sets variable for a variable event */
SCIPeventChgVar(SCIP_EVENT * event,SCIP_VAR * var)1104 SCIP_RETCODE SCIPeventChgVar(
1105    SCIP_EVENT*           event,              /**< event */
1106    SCIP_VAR*             var                 /**< new variable */
1107    )
1108 {
1109    assert(event != NULL);
1110 
1111    switch( event->eventtype )
1112    {
1113    case SCIP_EVENTTYPE_VARADDED:
1114       assert(event->data.eventvaradded.var != NULL);
1115       event->data.eventvaradded.var = var;
1116       break;
1117 
1118    case SCIP_EVENTTYPE_VARDELETED:
1119       assert(event->data.eventvardeleted.var != NULL);
1120       event->data.eventvardeleted.var = var;
1121       break;
1122 
1123    case SCIP_EVENTTYPE_VARFIXED:
1124       assert(event->data.eventvarfixed.var != NULL);
1125       event->data.eventvarfixed.var = var;
1126       break;
1127 
1128    case SCIP_EVENTTYPE_VARUNLOCKED:
1129       assert(event->data.eventvarunlocked.var != NULL);
1130       event->data.eventvarunlocked.var = var;
1131       break;
1132 
1133    case SCIP_EVENTTYPE_OBJCHANGED:
1134       assert(event->data.eventobjchg.var != NULL);
1135       event->data.eventobjchg.var = var;
1136       break;
1137 
1138    case SCIP_EVENTTYPE_GLBCHANGED:
1139    case SCIP_EVENTTYPE_GUBCHANGED:
1140    case SCIP_EVENTTYPE_LBTIGHTENED:
1141    case SCIP_EVENTTYPE_LBRELAXED:
1142    case SCIP_EVENTTYPE_UBTIGHTENED:
1143    case SCIP_EVENTTYPE_UBRELAXED:
1144       assert(event->data.eventbdchg.var != NULL);
1145       event->data.eventbdchg.var = var;
1146       break;
1147 
1148    case SCIP_EVENTTYPE_GHOLEADDED:
1149    case SCIP_EVENTTYPE_GHOLEREMOVED:
1150    case SCIP_EVENTTYPE_LHOLEADDED:
1151    case SCIP_EVENTTYPE_LHOLEREMOVED:
1152       assert(event->data.eventhole.var != NULL);
1153       event->data.eventhole.var = var;
1154       break;
1155 
1156    case SCIP_EVENTTYPE_IMPLADDED:
1157       assert(event->data.eventimpladd.var != NULL);
1158       event->data.eventimpladd.var = var;
1159       break;
1160 
1161    case SCIP_EVENTTYPE_TYPECHANGED:
1162       assert(event->data.eventtypechg.var != NULL);
1163       event->data.eventtypechg.var = var;
1164       break;
1165 
1166    default:
1167       SCIPerrorMessage("event does not belong to a variable\n");
1168       return SCIP_INVALIDDATA;
1169    }  /*lint !e788*/
1170 
1171    return SCIP_OKAY;
1172 }
1173 
1174 /** gets old objective value for an objective value change event */
SCIPeventGetOldobj(SCIP_EVENT * event)1175 SCIP_Real SCIPeventGetOldobj(
1176    SCIP_EVENT*           event               /**< event */
1177    )
1178 {
1179    assert(event != NULL);
1180 
1181    if( event->eventtype != SCIP_EVENTTYPE_OBJCHANGED )
1182    {
1183       SCIPerrorMessage("event is not an objective value change event\n");
1184       SCIPABORT();
1185       return SCIP_INVALID;  /*lint !e527*/
1186    }
1187 
1188    return event->data.eventobjchg.oldobj;
1189 }
1190 
1191 /** gets new objective value for an objective value change event */
SCIPeventGetNewobj(SCIP_EVENT * event)1192 SCIP_Real SCIPeventGetNewobj(
1193    SCIP_EVENT*           event               /**< event */
1194    )
1195 {
1196    assert(event != NULL);
1197 
1198    if( event->eventtype != SCIP_EVENTTYPE_OBJCHANGED )
1199    {
1200       SCIPerrorMessage("event is not an objective value change event\n");
1201       SCIPABORT();
1202       return SCIP_INVALID;  /*lint !e527*/
1203    }
1204 
1205    return event->data.eventobjchg.newobj;
1206 }
1207 
1208 /** gets old bound for a bound change event */
SCIPeventGetOldbound(SCIP_EVENT * event)1209 SCIP_Real SCIPeventGetOldbound(
1210    SCIP_EVENT*           event               /**< event */
1211    )
1212 {
1213    assert(event != NULL);
1214 
1215    switch( event->eventtype )
1216    {
1217    case SCIP_EVENTTYPE_GLBCHANGED:
1218    case SCIP_EVENTTYPE_GUBCHANGED:
1219    case SCIP_EVENTTYPE_LBTIGHTENED:
1220    case SCIP_EVENTTYPE_LBRELAXED:
1221    case SCIP_EVENTTYPE_UBTIGHTENED:
1222    case SCIP_EVENTTYPE_UBRELAXED:
1223       return event->data.eventbdchg.oldbound;
1224 
1225    default:
1226       SCIPerrorMessage("event is not a bound change event\n");
1227       SCIPABORT();
1228       return 0.0; /*lint !e527*/
1229    }  /*lint !e788*/
1230 }
1231 
1232 /** gets new bound for a bound change event */
SCIPeventGetNewbound(SCIP_EVENT * event)1233 SCIP_Real SCIPeventGetNewbound(
1234    SCIP_EVENT*           event               /**< event */
1235    )
1236 {
1237    assert(event != NULL);
1238 
1239    switch( event->eventtype )
1240    {
1241    case SCIP_EVENTTYPE_GLBCHANGED:
1242    case SCIP_EVENTTYPE_GUBCHANGED:
1243    case SCIP_EVENTTYPE_LBTIGHTENED:
1244    case SCIP_EVENTTYPE_LBRELAXED:
1245    case SCIP_EVENTTYPE_UBTIGHTENED:
1246    case SCIP_EVENTTYPE_UBRELAXED:
1247       return event->data.eventbdchg.newbound;
1248 
1249    default:
1250       SCIPerrorMessage("event is not a bound change event\n");
1251       SCIPABORT();
1252       return 0.0; /*lint !e527*/
1253    }  /*lint !e788*/
1254 }
1255 
1256 /** gets old variable type for a variable type change event */
SCIPeventGetOldtype(SCIP_EVENT * event)1257 SCIP_VARTYPE SCIPeventGetOldtype(
1258    SCIP_EVENT*           event               /**< event */
1259    )
1260 {
1261    assert(event != NULL);
1262 
1263    if( event->eventtype != SCIP_EVENTTYPE_TYPECHANGED )
1264    {
1265       SCIPerrorMessage("event is not an variable type change event\n");
1266       SCIPABORT();
1267       return SCIP_VARTYPE_CONTINUOUS;  /*lint !e527*/
1268    }
1269 
1270    return event->data.eventtypechg.oldtype;
1271 }
1272 
1273 /** gets new variable type for a variable type change event */
SCIPeventGetNewtype(SCIP_EVENT * event)1274 SCIP_VARTYPE SCIPeventGetNewtype(
1275    SCIP_EVENT*           event               /**< event */
1276    )
1277 {
1278    assert(event != NULL);
1279 
1280    if( event->eventtype != SCIP_EVENTTYPE_TYPECHANGED )
1281    {
1282       SCIPerrorMessage("event is not an variable type change event\n");
1283       SCIPABORT();
1284       return SCIP_VARTYPE_CONTINUOUS;  /*lint !e527*/
1285    }
1286 
1287    return event->data.eventtypechg.newtype;
1288 }
1289 
1290 /** gets node for a node or LP event */
SCIPeventGetNode(SCIP_EVENT * event)1291 SCIP_NODE* SCIPeventGetNode(
1292    SCIP_EVENT*           event               /**< event */
1293    )
1294 {
1295    assert(event != NULL);
1296 
1297    if( (event->eventtype & (SCIP_EVENTTYPE_NODEEVENT | SCIP_EVENTTYPE_NODEDELETE | SCIP_EVENTTYPE_LPEVENT)) == 0 )
1298    {
1299       SCIPerrorMessage("event is neither node nor LP event\n");
1300       SCIPABORT();
1301       return NULL;  /*lint !e527*/
1302    }
1303 
1304    return event->data.node;
1305 }
1306 
1307 /** sets node for a node or LP event */
SCIPeventChgNode(SCIP_EVENT * event,SCIP_NODE * node)1308 SCIP_RETCODE SCIPeventChgNode(
1309    SCIP_EVENT*           event,              /**< event */
1310    SCIP_NODE*            node                /**< new node */
1311    )
1312 {
1313    assert(event != NULL);
1314 
1315    if( (event->eventtype & (SCIP_EVENTTYPE_NODEEVENT |  SCIP_EVENTTYPE_NODEDELETE | SCIP_EVENTTYPE_LPEVENT)) == 0 )
1316    {
1317       SCIPerrorMessage("event is neither node nor LP event\n");
1318       SCIPABORT();
1319       return SCIP_INVALIDDATA;  /*lint !e527*/
1320    }
1321 
1322    event->data.node = node;
1323 
1324    return SCIP_OKAY;
1325 }
1326 
1327 /** gets solution for a primal solution event */
SCIPeventGetSol(SCIP_EVENT * event)1328 SCIP_SOL* SCIPeventGetSol(
1329    SCIP_EVENT*           event               /**< event */
1330    )
1331 {
1332    assert(event != NULL);
1333 
1334    if( (event->eventtype & SCIP_EVENTTYPE_SOLEVENT) == 0 )
1335    {
1336       SCIPerrorMessage("event is not a primal solution event\n");
1337       SCIPABORT();
1338       return NULL;  /*lint !e527*/
1339    }
1340 
1341    return event->data.sol;
1342 }
1343 
1344 /** sets solution for a primal solution event */
SCIPeventChgSol(SCIP_EVENT * event,SCIP_SOL * sol)1345 SCIP_RETCODE SCIPeventChgSol(
1346    SCIP_EVENT*           event,              /**< event */
1347    SCIP_SOL*             sol                 /**< new primal solution */
1348    )
1349 {
1350    assert(event != NULL);
1351 
1352    if( (event->eventtype & SCIP_EVENTTYPE_SOLEVENT) == 0 )
1353    {
1354       SCIPerrorMessage("event is not a primal solution event\n");
1355       SCIPABORT();
1356       return SCIP_INVALIDDATA;  /*lint !e527*/
1357    }
1358 
1359    event->data.sol = sol;
1360 
1361    return SCIP_OKAY;
1362 }
1363 
1364 /** gets the left bound of open interval in the hole */
SCIPeventGetHoleLeft(SCIP_EVENT * event)1365 SCIP_Real SCIPeventGetHoleLeft(
1366    SCIP_EVENT*           event               /**< event */
1367    )
1368 {
1369    assert(event != NULL);
1370 
1371    if( (event->eventtype & SCIP_EVENTTYPE_HOLECHANGED) == 0 )
1372    {
1373       SCIPerrorMessage("event is not a hole added or removed event\n");
1374       SCIPABORT();
1375       return SCIP_INVALID;  /*lint !e527*/
1376    }
1377 
1378    return event->data.eventhole.left;
1379 }
1380 
1381 /** gets the right bound of open interval in the hole */
SCIPeventGetHoleRight(SCIP_EVENT * event)1382 SCIP_Real SCIPeventGetHoleRight(
1383    SCIP_EVENT*           event               /**< event */
1384    )
1385 {
1386    assert(event != NULL);
1387 
1388    if( (event->eventtype & SCIP_EVENTTYPE_HOLECHANGED) == 0 )
1389    {
1390       SCIPerrorMessage("event is not a hole added or removed event\n");
1391       SCIPABORT();
1392       return SCIP_INVALID;  /*lint !e527*/
1393    }
1394 
1395    return event->data.eventhole.right;
1396 }
1397 
1398 /** gets row for a row event */
SCIPeventGetRow(SCIP_EVENT * event)1399 SCIP_ROW* SCIPeventGetRow(
1400    SCIP_EVENT*           event               /**< event */
1401    )
1402 {
1403    assert(event != NULL);
1404 
1405    switch( event->eventtype )
1406    {
1407       case SCIP_EVENTTYPE_ROWADDEDSEPA:
1408          return event->data.eventrowaddedsepa.row;
1409       case SCIP_EVENTTYPE_ROWDELETEDSEPA:
1410          return event->data.eventrowdeletedsepa.row;
1411       case SCIP_EVENTTYPE_ROWADDEDLP:
1412          return event->data.eventrowaddedlp.row;
1413       case SCIP_EVENTTYPE_ROWDELETEDLP:
1414          return event->data.eventrowdeletedlp.row;
1415       case SCIP_EVENTTYPE_ROWCOEFCHANGED:
1416          return event->data.eventrowcoefchanged.row;
1417       case SCIP_EVENTTYPE_ROWCONSTCHANGED: /*lint !e30 !e142*/
1418          return event->data.eventrowconstchanged.row;
1419       case SCIP_EVENTTYPE_ROWSIDECHANGED: /*lint !e30 !e142*/
1420          return event->data.eventrowsidechanged.row;
1421       default:
1422          SCIPerrorMessage("event does not belong to a row\n");
1423          SCIPABORT();
1424          return NULL;  /*lint !e527*/
1425    }
1426 }
1427 
1428 /** gets column for a row change coefficient event */
SCIPeventGetRowCol(SCIP_EVENT * event)1429 SCIP_COL* SCIPeventGetRowCol(
1430    SCIP_EVENT*           event               /**< event */
1431    )
1432 {
1433    assert(event != NULL);
1434 
1435    if( (event->eventtype & SCIP_EVENTTYPE_ROWCOEFCHANGED) == 0 )
1436    {
1437       SCIPerrorMessage("event is not a row coefficient changed event\n");
1438       SCIPABORT();
1439       return NULL;  /*lint !e527*/
1440    }
1441 
1442    return event->data.eventrowcoefchanged.col;
1443 }
1444 
1445 /** gets old coefficient value for a row change coefficient event */
SCIPeventGetRowOldCoefVal(SCIP_EVENT * event)1446 SCIP_Real SCIPeventGetRowOldCoefVal(
1447    SCIP_EVENT*           event               /**< event */
1448    )
1449 {
1450    assert(event != NULL);
1451 
1452    if( (event->eventtype & SCIP_EVENTTYPE_ROWCOEFCHANGED) == 0 )
1453    {
1454       SCIPerrorMessage("event is not a row coefficient changed event\n");
1455       SCIPABORT();
1456       return SCIP_INVALID;  /*lint !e527*/
1457    }
1458 
1459    return event->data.eventrowcoefchanged.oldval;
1460 }
1461 
1462 /** gets new coefficient value for a row change coefficient event */
SCIPeventGetRowNewCoefVal(SCIP_EVENT * event)1463 SCIP_Real SCIPeventGetRowNewCoefVal(
1464    SCIP_EVENT*           event               /**< event */
1465    )
1466 {
1467    assert(event != NULL);
1468 
1469    if( (event->eventtype & SCIP_EVENTTYPE_ROWCOEFCHANGED) == 0 )
1470    {
1471       SCIPerrorMessage("event is not a row coefficient changed event\n");
1472       SCIPABORT();
1473       return SCIP_INVALID;  /*lint !e527*/
1474    }
1475 
1476    return event->data.eventrowcoefchanged.newval;
1477 }
1478 
1479 /** gets old constant value for a row change constant event */
SCIPeventGetRowOldConstVal(SCIP_EVENT * event)1480 SCIP_Real SCIPeventGetRowOldConstVal(
1481    SCIP_EVENT*           event               /**< event */
1482    )
1483 {
1484    assert(event != NULL);
1485 
1486    if( !(event->eventtype & SCIP_EVENTTYPE_ROWCONSTCHANGED) )
1487    {
1488       SCIPerrorMessage("event is not a row coefficient changed event\n");
1489       SCIPABORT();
1490       return SCIP_INVALID;  /*lint !e527*/
1491    }
1492 
1493    return event->data.eventrowconstchanged.oldval;
1494 }
1495 
1496 /** gets new constant value for a row change constant event */
SCIPeventGetRowNewConstVal(SCIP_EVENT * event)1497 SCIP_Real SCIPeventGetRowNewConstVal(
1498    SCIP_EVENT*           event               /**< event */
1499    )
1500 {
1501    assert(event != NULL);
1502 
1503    if( !(event->eventtype & SCIP_EVENTTYPE_ROWCONSTCHANGED) )
1504    {
1505       SCIPerrorMessage("event is not a row coefficient changed event\n");
1506       SCIPABORT();
1507       return SCIP_INVALID;  /*lint !e527*/
1508    }
1509 
1510    return event->data.eventrowconstchanged.newval;
1511 }
1512 
1513 /** gets side for a row change side event */
SCIPeventGetRowSide(SCIP_EVENT * event)1514 SCIP_SIDETYPE SCIPeventGetRowSide(
1515    SCIP_EVENT*           event               /**< event */
1516    )
1517 {
1518    assert(event != NULL);
1519 
1520    if( !(event->eventtype & SCIP_EVENTTYPE_ROWSIDECHANGED) )
1521    {
1522       SCIPerrorMessage("event is not a row side changed event\n");
1523       SCIPABORT();
1524       return SCIP_SIDETYPE_LEFT;  /*lint !e527*/
1525    }
1526 
1527    return event->data.eventrowsidechanged.side;
1528 }
1529 
1530 /** gets old side value for a row change side event */
SCIPeventGetRowOldSideVal(SCIP_EVENT * event)1531 SCIP_Real SCIPeventGetRowOldSideVal(
1532    SCIP_EVENT*           event               /**< event */
1533    )
1534 {
1535    assert(event != NULL);
1536 
1537    if( !(event->eventtype & SCIP_EVENTTYPE_ROWSIDECHANGED) )
1538    {
1539       SCIPerrorMessage("event is not a row side changed event\n");
1540       SCIPABORT();
1541       return SCIP_INVALID;  /*lint !e527*/
1542    }
1543 
1544    return event->data.eventrowsidechanged.oldval;
1545 }
1546 
1547 /** gets new side value for a row change side event */
SCIPeventGetRowNewSideVal(SCIP_EVENT * event)1548 SCIP_Real SCIPeventGetRowNewSideVal(
1549    SCIP_EVENT*           event               /**< event */
1550    )
1551 {
1552    assert(event != NULL);
1553 
1554    if( !(event->eventtype & SCIP_EVENTTYPE_ROWSIDECHANGED) )
1555    {
1556       SCIPerrorMessage("event is not a row side changed event\n");
1557       SCIPABORT();
1558       return SCIP_INVALID;  /*lint !e527*/
1559    }
1560 
1561    return event->data.eventrowsidechanged.newval;
1562 }
1563 
1564 /** processes event by calling the appropriate event handlers */
SCIPeventProcess(SCIP_EVENT * event,SCIP_SET * set,SCIP_PRIMAL * primal,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTFILTER * eventfilter)1565 SCIP_RETCODE SCIPeventProcess(
1566    SCIP_EVENT*           event,              /**< event */
1567    SCIP_SET*             set,                /**< global SCIP settings */
1568    SCIP_PRIMAL*          primal,             /**< primal data; only needed for objchanged events, or NULL */
1569    SCIP_LP*              lp,                 /**< current LP data; only needed for obj/boundchanged events, or NULL */
1570    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage; only needed for bound change events, or NULL */
1571    SCIP_EVENTFILTER*     eventfilter         /**< event filter for global events; not needed for variable specific events */
1572    )
1573 {
1574    SCIP_VAR* var;
1575 
1576    assert(event != NULL);
1577    assert((event->eventtype & SCIP_EVENTTYPE_OBJCHANGED) == 0 || primal != NULL);
1578    assert((event->eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED)) == 0 || lp != NULL);
1579    assert((event->eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) == 0 || branchcand != NULL);
1580 
1581    SCIPsetDebugMsg(set, "processing event of type 0x%" SCIP_EVENTTYPE_FORMAT "\n", event->eventtype);
1582 
1583    switch( event->eventtype )
1584    {
1585    case SCIP_EVENTTYPE_DISABLED:
1586       break;
1587 
1588    case SCIP_EVENTTYPE_VARADDED:
1589    case SCIP_EVENTTYPE_PRESOLVEROUND:
1590    case SCIP_EVENTTYPE_NODEFOCUSED:
1591    case SCIP_EVENTTYPE_NODEFEASIBLE:
1592    case SCIP_EVENTTYPE_NODEINFEASIBLE:
1593    case SCIP_EVENTTYPE_NODEBRANCHED:
1594    case SCIP_EVENTTYPE_NODEDELETE:
1595    case SCIP_EVENTTYPE_FIRSTLPSOLVED:
1596    case SCIP_EVENTTYPE_LPSOLVED:
1597    case SCIP_EVENTTYPE_POORSOLFOUND:
1598    case SCIP_EVENTTYPE_BESTSOLFOUND:
1599    case SCIP_EVENTTYPE_ROWADDEDSEPA:
1600    case SCIP_EVENTTYPE_ROWDELETEDSEPA:
1601    case SCIP_EVENTTYPE_ROWADDEDLP:
1602    case SCIP_EVENTTYPE_ROWDELETEDLP:
1603    case SCIP_EVENTTYPE_ROWCOEFCHANGED:
1604    case SCIP_EVENTTYPE_ROWCONSTCHANGED: /*lint !e30 !e142*/
1605    case SCIP_EVENTTYPE_ROWSIDECHANGED: /*lint !e30 !e142*/
1606    case SCIP_EVENTTYPE_SYNC: /*lint !e30 !e142*/
1607       SCIP_CALL( SCIPeventfilterProcess(eventfilter, set, event) );
1608       break;
1609 
1610    case SCIP_EVENTTYPE_VARDELETED:
1611       var = event->data.eventvardeleted.var;
1612       assert(var != NULL);
1613 
1614       /* process variable's event filter */
1615       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1616       break;
1617 
1618    case SCIP_EVENTTYPE_VARFIXED:
1619       var = event->data.eventvarfixed.var;
1620       assert(var != NULL);
1621 
1622       /* process variable's event filter */
1623       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1624       break;
1625 
1626    case SCIP_EVENTTYPE_VARUNLOCKED:
1627       var = event->data.eventvarunlocked.var;
1628       assert(var != NULL);
1629 
1630       /* process variable's event filter */
1631       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1632       break;
1633 
1634    case SCIP_EVENTTYPE_OBJCHANGED:
1635       var = event->data.eventobjchg.var;
1636       assert(var != NULL);
1637       assert(var->eventqueueindexobj == -1);
1638       assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
1639 
1640       /* inform LP about the objective change */
1641       if( SCIPvarGetProbindex(var) >= 0 )
1642       {
1643          if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
1644          {
1645             SCIP_CALL( SCIPcolChgObj(SCIPvarGetCol(var), set, lp, event->data.eventobjchg.newobj) );
1646          }
1647          SCIP_CALL( SCIPlpUpdateVarObj(lp, set, var, event->data.eventobjchg.oldobj, event->data.eventobjchg.newobj) );
1648       }
1649 
1650       /* inform all existing primal solutions about the objective change (only if this is not a temporary change in
1651        * probing mode)
1652        */
1653       if( ! lp->divingobjchg )
1654       {
1655          SCIPprimalUpdateVarObj(primal, var, event->data.eventobjchg.oldobj, event->data.eventobjchg.newobj);
1656       }
1657 
1658       /* process variable's event filter */
1659       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1660       break;
1661 
1662    case SCIP_EVENTTYPE_GLBCHANGED:
1663       var = event->data.eventbdchg.var;
1664       assert(var != NULL);
1665 
1666       /* inform LP about global bound change */
1667       if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
1668       {
1669          assert(SCIPvarGetProbindex(var) >= 0);
1670          SCIP_CALL( SCIPlpUpdateVarLbGlobal(lp, set, var, event->data.eventbdchg.oldbound,
1671                event->data.eventbdchg.newbound) );
1672       }
1673 
1674       /* process variable's event filter */
1675       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1676       break;
1677 
1678    case SCIP_EVENTTYPE_GUBCHANGED:
1679       var = event->data.eventbdchg.var;
1680       assert(var != NULL);
1681 
1682       /* inform LP about global bound change */
1683       if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
1684       {
1685          assert(SCIPvarGetProbindex(var) >= 0);
1686          SCIP_CALL( SCIPlpUpdateVarUbGlobal(lp, set, var, event->data.eventbdchg.oldbound,
1687                event->data.eventbdchg.newbound) );
1688       }
1689 
1690       /* process variable's event filter */
1691       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1692       break;
1693 
1694    case SCIP_EVENTTYPE_LBTIGHTENED:
1695    case SCIP_EVENTTYPE_LBRELAXED:
1696       var = event->data.eventbdchg.var;
1697       assert(var != NULL);
1698       assert(var->eventqueueindexlb == -1);
1699 
1700       /* inform LP about bound change and update branching candidates */
1701       if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
1702       {
1703          assert(SCIPvarGetProbindex(var) >= 0);
1704          if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
1705          {
1706             SCIP_CALL( SCIPcolChgLb(SCIPvarGetCol(var), set, lp, event->data.eventbdchg.newbound) );
1707          }
1708          SCIP_CALL( SCIPlpUpdateVarLb(lp, set, var, event->data.eventbdchg.oldbound,
1709                event->data.eventbdchg.newbound) );
1710          SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) );
1711       }
1712 
1713       /* process variable's event filter */
1714       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1715       break;
1716 
1717    case SCIP_EVENTTYPE_UBTIGHTENED:
1718    case SCIP_EVENTTYPE_UBRELAXED:
1719       var = event->data.eventbdchg.var;
1720       assert(var != NULL);
1721       assert(var->eventqueueindexub == -1);
1722 
1723       /* inform LP about bound change and update branching candidates */
1724       if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
1725       {
1726          assert(SCIPvarGetProbindex(var) >= 0);
1727          if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
1728          {
1729             SCIP_CALL( SCIPcolChgUb(SCIPvarGetCol(var), set, lp, event->data.eventbdchg.newbound) );
1730          }
1731          SCIP_CALL( SCIPlpUpdateVarUb(lp, set, var, event->data.eventbdchg.oldbound,
1732                event->data.eventbdchg.newbound) );
1733          SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) );
1734       }
1735 
1736       /* process variable's event filter */
1737       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1738       break;
1739 
1740    case SCIP_EVENTTYPE_GHOLEADDED:
1741    case SCIP_EVENTTYPE_GHOLEREMOVED:
1742    case SCIP_EVENTTYPE_LHOLEADDED:
1743    case SCIP_EVENTTYPE_LHOLEREMOVED:
1744       var = event->data.eventhole.var;
1745       assert(var != NULL);
1746 
1747       /* process variable's event filter */
1748       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1749       break;
1750 
1751    case SCIP_EVENTTYPE_IMPLADDED:
1752       var = event->data.eventimpladd.var;
1753       assert(var != NULL);
1754       assert(!var->eventqueueimpl);
1755 
1756       /* process variable's event filter */
1757       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1758       break;
1759 
1760    case SCIP_EVENTTYPE_TYPECHANGED:
1761       var = event->data.eventtypechg.var;
1762       assert(var != NULL);
1763 
1764       /* process variable's event filter */
1765       SCIP_CALL( SCIPeventfilterProcess(var->eventfilter, set, event) );
1766       break;
1767 
1768    default:
1769       SCIPerrorMessage("unknown event type <%ld>\n", event->eventtype);
1770       return SCIP_INVALIDDATA;
1771    }
1772 
1773    return SCIP_OKAY;
1774 }
1775 
1776 
1777 
1778 /*
1779  * Event filter methods
1780  */
1781 
1782 /** resizes eventfilter arrays to be able to store at least num entries */
1783 static
eventfilterEnsureMem(SCIP_EVENTFILTER * eventfilter,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)1784 SCIP_RETCODE eventfilterEnsureMem(
1785    SCIP_EVENTFILTER*     eventfilter,        /**< event filter */
1786    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
1787    SCIP_SET*             set,                /**< global SCIP settings */
1788    int                   num                 /**< minimal number of node slots in array */
1789    )
1790 {
1791    assert(eventfilter != NULL);
1792    assert(blkmem != NULL);
1793    assert(set != NULL);
1794 
1795    if( num > eventfilter->size )
1796    {
1797       int newsize;
1798 
1799       newsize = SCIPsetCalcMemGrowSize(set, num);
1800       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &eventfilter->eventtypes, eventfilter->size, newsize) );
1801       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &eventfilter->eventhdlrs, eventfilter->size, newsize) );
1802       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &eventfilter->eventdata, eventfilter->size, newsize) );
1803       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &eventfilter->nextpos, eventfilter->size, newsize) );
1804       eventfilter->size = newsize;
1805    }
1806    assert(num <= eventfilter->size);
1807 
1808    return SCIP_OKAY;
1809 }
1810 
1811 /** creates an event filter */
SCIPeventfilterCreate(SCIP_EVENTFILTER ** eventfilter,BMS_BLKMEM * blkmem)1812 SCIP_RETCODE SCIPeventfilterCreate(
1813    SCIP_EVENTFILTER**    eventfilter,        /**< pointer to store the event filter */
1814    BMS_BLKMEM*           blkmem              /**< block memory buffer */
1815    )
1816 {
1817    assert(eventfilter != NULL);
1818    assert(blkmem != NULL);
1819 
1820    SCIP_ALLOC( BMSallocBlockMemory(blkmem, eventfilter) );
1821    (*eventfilter)->eventtypes = NULL;
1822    (*eventfilter)->eventhdlrs = NULL;
1823    (*eventfilter)->eventdata = NULL;
1824    (*eventfilter)->nextpos = NULL;
1825    (*eventfilter)->size = 0;
1826    (*eventfilter)->len = 0;
1827    (*eventfilter)->firstfreepos = -1;
1828    (*eventfilter)->firstdeletedpos = -1;
1829    (*eventfilter)->eventmask = SCIP_EVENTTYPE_DISABLED;
1830    (*eventfilter)->delayedeventmask = SCIP_EVENTTYPE_DISABLED;
1831    (*eventfilter)->delayupdates = FALSE;
1832 
1833    return SCIP_OKAY;
1834 }
1835 
1836 /** frees an event filter and the associated event data entries */
SCIPeventfilterFree(SCIP_EVENTFILTER ** eventfilter,BMS_BLKMEM * blkmem,SCIP_SET * set)1837 SCIP_RETCODE SCIPeventfilterFree(
1838    SCIP_EVENTFILTER**    eventfilter,        /**< pointer to store the event filter */
1839    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
1840    SCIP_SET*             set                 /**< global SCIP settings */
1841    )
1842 {
1843    int i;
1844 
1845    assert(eventfilter != NULL);
1846    assert(*eventfilter != NULL);
1847    assert(!(*eventfilter)->delayupdates);
1848    assert(blkmem != NULL);
1849    assert(set != NULL);
1850    assert(set->scip != NULL);
1851 
1852    /* free event data */
1853    for( i = 0; i < (*eventfilter)->len; ++i )
1854    {
1855       if( (*eventfilter)->eventtypes[i] != SCIP_EVENTTYPE_DISABLED )
1856       {
1857          assert((*eventfilter)->eventhdlrs[i] != NULL);
1858          if( (*eventfilter)->eventhdlrs[i]->eventdelete != NULL )
1859          {
1860             SCIP_CALL( (*eventfilter)->eventhdlrs[i]->eventdelete(set->scip, (*eventfilter)->eventhdlrs[i],
1861                   &(*eventfilter)->eventdata[i]) );
1862          }
1863       }
1864    }
1865 
1866    /* free event filter data */
1867    BMSfreeBlockMemoryArrayNull(blkmem, &(*eventfilter)->eventtypes, (*eventfilter)->size);
1868    BMSfreeBlockMemoryArrayNull(blkmem, &(*eventfilter)->eventhdlrs, (*eventfilter)->size);
1869    BMSfreeBlockMemoryArrayNull(blkmem, &(*eventfilter)->eventdata, (*eventfilter)->size);
1870    BMSfreeBlockMemoryArrayNull(blkmem, &(*eventfilter)->nextpos, (*eventfilter)->size);
1871    BMSfreeBlockMemory(blkmem, eventfilter);
1872 
1873    return SCIP_OKAY;
1874 }
1875 
1876 /** adds element to event filter */
SCIPeventfilterAdd(SCIP_EVENTFILTER * eventfilter,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTTYPE eventtype,SCIP_EVENTHDLR * eventhdlr,SCIP_EVENTDATA * eventdata,int * filterpos)1877 SCIP_RETCODE SCIPeventfilterAdd(
1878    SCIP_EVENTFILTER*     eventfilter,        /**< event filter */
1879    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
1880    SCIP_SET*             set,                /**< global SCIP settings */
1881    SCIP_EVENTTYPE        eventtype,          /**< event type to catch */
1882    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
1883    SCIP_EVENTDATA*       eventdata,          /**< event data to pass to the event handler for the event processing */
1884    int*                  filterpos           /**< pointer to store position of event filter entry, or NULL */
1885    )
1886 {
1887    int pos;
1888 
1889    assert(eventfilter != NULL);
1890    assert(blkmem != NULL);
1891    assert(set != NULL);
1892    assert(eventhdlr != NULL);
1893 
1894    if( eventfilter->delayupdates )
1895    {
1896       /* insert addition to the end of the arrays;
1897        * in delayed addition we have to add to the end of the arrays, in order to not destroy the validity of the
1898        * arrays we are currently iterating over
1899        */
1900       SCIP_CALL( eventfilterEnsureMem(eventfilter, blkmem, set, eventfilter->len + 1) );
1901       pos = eventfilter->len;
1902       eventfilter->len++;
1903 
1904       /* update delayed event filter mask */
1905       eventfilter->delayedeventmask |= eventtype;
1906    }
1907    else
1908    {
1909       if( eventfilter->firstfreepos == -1 )
1910       {
1911          /* insert addition to the end of the arrays */
1912          SCIP_CALL( eventfilterEnsureMem(eventfilter, blkmem, set, eventfilter->len + 1) );
1913          pos = eventfilter->len;
1914          eventfilter->len++;
1915       }
1916       else
1917       {
1918          /* use the first free slot to store the added event filter entry */
1919          pos = eventfilter->firstfreepos;
1920          assert(0 <= pos && pos < eventfilter->len);
1921          assert(eventfilter->eventtypes[pos] == SCIP_EVENTTYPE_DISABLED);
1922          eventfilter->firstfreepos = eventfilter->nextpos[pos];
1923          assert(-1 <= eventfilter->firstfreepos && eventfilter->firstfreepos < eventfilter->len);
1924       }
1925 
1926       /* update event filter mask */
1927       eventfilter->eventmask |= eventtype;
1928    }
1929    assert(0 <= pos && pos < eventfilter->len);
1930 
1931    eventfilter->eventtypes[pos] = eventtype;
1932    eventfilter->eventhdlrs[pos] = eventhdlr;
1933    eventfilter->eventdata[pos] = eventdata;
1934    eventfilter->nextpos[pos] = -2;
1935 
1936    if( filterpos != NULL )
1937       *filterpos = pos;
1938 
1939    return SCIP_OKAY;
1940 }
1941 
1942 /** linear search for the given entry in event filter */
1943 static
eventfilterSearch(SCIP_EVENTFILTER * const eventfilter,SCIP_EVENTTYPE const eventtype,SCIP_EVENTHDLR * const eventhdlr,SCIP_EVENTDATA * const eventdata)1944 int eventfilterSearch(
1945    SCIP_EVENTFILTER*const eventfilter,       /**< event filter */
1946    SCIP_EVENTTYPE const  eventtype,          /**< event type */
1947    SCIP_EVENTHDLR*const  eventhdlr,          /**< event handler to call for the event processing */
1948    SCIP_EVENTDATA*const  eventdata           /**< event data to pass to the event handler for the event processing */
1949    )
1950 {
1951    int i;
1952 
1953    assert(eventfilter != NULL);
1954    assert(eventtype != SCIP_EVENTTYPE_DISABLED);
1955    assert(eventhdlr != NULL);
1956 
1957    for( i = eventfilter->len - 1; i >= 0; --i )
1958    {
1959       if( eventdata == eventfilter->eventdata[i]
1960          && eventhdlr == eventfilter->eventhdlrs[i]
1961          && eventtype == eventfilter->eventtypes[i]
1962          && eventfilter->nextpos[i] == -2 )
1963          return i;
1964    }
1965 
1966    return -1;
1967 }
1968 
1969 /** deletes element from event filter */
SCIPeventfilterDel(SCIP_EVENTFILTER * eventfilter,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTTYPE eventtype,SCIP_EVENTHDLR * eventhdlr,SCIP_EVENTDATA * eventdata,int filterpos)1970 SCIP_RETCODE SCIPeventfilterDel(
1971    SCIP_EVENTFILTER*     eventfilter,        /**< event filter */
1972    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
1973    SCIP_SET*             set,                /**< global SCIP settings */
1974    SCIP_EVENTTYPE        eventtype,          /**< event type */
1975    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
1976    SCIP_EVENTDATA*       eventdata,          /**< event data to pass to the event handler for the event processing */
1977    int                   filterpos           /**< position of event filter entry, or -1 if unknown */
1978    )
1979 {
1980    assert(eventfilter != NULL);
1981    assert(blkmem != NULL);
1982    assert(set != NULL);
1983    assert(eventtype != SCIP_EVENTTYPE_DISABLED);
1984    assert(eventhdlr != NULL);
1985    assert(-1 <= filterpos && filterpos < eventfilter->len);
1986 
1987    /* search position of event filter entry, if not given by the user */
1988    if( filterpos == -1 )
1989       filterpos = eventfilterSearch(eventfilter, eventtype, eventhdlr, eventdata);
1990    if( filterpos == -1 )
1991    {
1992       SCIPerrorMessage("no event for event handler %p with data %p and event mask 0x%lx found in event filter %p\n",
1993          (void*)eventhdlr, (void*)eventdata, eventtype, (void*)eventfilter);
1994       return SCIP_INVALIDDATA;
1995    }
1996    assert(0 <= filterpos && filterpos < eventfilter->len);
1997    assert(eventfilter->eventtypes[filterpos] == eventtype);
1998    assert(eventfilter->eventhdlrs[filterpos] == eventhdlr);
1999    assert(eventfilter->eventdata[filterpos] == eventdata);
2000    assert(eventfilter->nextpos[filterpos] == -2);
2001 
2002    /* if updates are delayed, insert entry into the list of delayed deletions;
2003     * otherwise, delete the entry from the filter directly and add the slot to the free list
2004     */
2005    if( eventfilter->delayupdates )
2006    {
2007       /* append filterpos to the list of deleted entries */
2008       eventfilter->nextpos[filterpos] = eventfilter->firstdeletedpos;
2009       eventfilter->firstdeletedpos = filterpos;
2010    }
2011    else
2012    {
2013       /* disable the entry in the filter and add the slot to the free list */
2014       assert(eventfilter->nextpos[filterpos] == -2);
2015       eventfilter->eventtypes[filterpos] = SCIP_EVENTTYPE_DISABLED;
2016       eventfilter->nextpos[filterpos] = eventfilter->firstfreepos;
2017       eventfilter->firstfreepos = filterpos;
2018    }
2019 
2020    return SCIP_OKAY;
2021 }
2022 
2023 /** makes the event filter to delay and buffer all updates until eventfilterProcessUpdates() is called */
2024 static
eventfilterDelayUpdates(SCIP_EVENTFILTER * eventfilter)2025 void eventfilterDelayUpdates(
2026    SCIP_EVENTFILTER*     eventfilter         /**< event filter */
2027    )
2028 {
2029    assert(eventfilter != NULL);
2030    assert(!eventfilter->delayupdates);
2031    assert(eventfilter->delayedeventmask == SCIP_EVENTTYPE_DISABLED);
2032 
2033    eventfilter->delayupdates = TRUE;
2034 }
2035 
2036 /** processes all delayed additions and deletions */
2037 static
eventfilterProcessUpdates(SCIP_EVENTFILTER * eventfilter)2038 void eventfilterProcessUpdates(
2039    SCIP_EVENTFILTER*     eventfilter         /**< event filter */
2040    )
2041 {
2042    int pos;
2043    int nextpos;
2044 
2045    assert(eventfilter != NULL);
2046    assert(eventfilter->delayupdates);
2047 
2048    /* move deleted entries into the free list and disable them */
2049    pos = eventfilter->firstdeletedpos;
2050    while( pos != -1 )
2051    {
2052       assert(0 <= pos && pos < eventfilter->len);
2053       assert(eventfilter->eventtypes[pos] != SCIP_EVENTTYPE_DISABLED);
2054       assert(eventfilter->nextpos[pos] >= -1);
2055 
2056       nextpos = eventfilter->nextpos[pos];
2057       eventfilter->nextpos[pos] = eventfilter->firstfreepos;
2058       eventfilter->firstfreepos = pos;
2059       eventfilter->eventtypes[pos] = SCIP_EVENTTYPE_DISABLED;
2060       pos = nextpos;
2061    }
2062    eventfilter->firstdeletedpos = -1;
2063 
2064    /* update event mask */
2065    eventfilter->eventmask |= eventfilter->delayedeventmask;
2066    eventfilter->delayedeventmask = SCIP_EVENTTYPE_DISABLED;
2067 
2068    /* mark the event filter updates to be no longer delayed */
2069    eventfilter->delayupdates = FALSE;
2070 }
2071 
2072 /** processes the event with all event handlers with matching filter setting */
SCIPeventfilterProcess(SCIP_EVENTFILTER * eventfilter,SCIP_SET * set,SCIP_EVENT * event)2073 SCIP_RETCODE SCIPeventfilterProcess(
2074    SCIP_EVENTFILTER*     eventfilter,        /**< event filter */
2075    SCIP_SET*             set,                /**< global SCIP settings */
2076    SCIP_EVENT*           event               /**< event to process */
2077    )
2078 {
2079    SCIP_EVENTTYPE eventtype;
2080    SCIP_EVENTTYPE* eventtypes;
2081    SCIP_Bool processed;
2082    int len;
2083    int i;
2084 
2085    assert(eventfilter != NULL);
2086    assert(set != NULL);
2087    assert(event != NULL);
2088 
2089    SCIPsetDebugMsg(set, "processing event filter %p (len %d, mask 0x%" SCIP_EVENTTYPE_FORMAT ") with event type 0x%" SCIP_EVENTTYPE_FORMAT "\n",
2090       (void*)eventfilter, eventfilter->len, eventfilter->eventmask, event->eventtype);
2091 
2092    eventtype = event->eventtype;
2093 
2094    /* check, if there may be any event handler for specific event */
2095    if( (eventtype & eventfilter->eventmask) == 0 )
2096       return SCIP_OKAY;
2097 
2098    /* delay the updates on this eventfilter, such that changes during event processing to the event filter
2099     * don't destroy necessary information of the arrays we are currently using
2100     */
2101    eventfilterDelayUpdates(eventfilter);
2102 
2103    /* process the event by calling the event handlers */
2104    processed = FALSE;
2105    len = eventfilter->len;
2106    eventtypes = eventfilter->eventtypes;
2107    for( i = 0; i < len; ++i )
2108    {
2109       /* check, if event is applicable for the filter element */
2110       if( (eventtype & eventtypes[i]) != 0 )
2111       {
2112          /* call event handler */
2113          SCIP_CALL( SCIPeventhdlrExec(eventfilter->eventhdlrs[i], set, event, eventfilter->eventdata[i]) );
2114          processed = TRUE;
2115       }
2116    }
2117 
2118    /* update eventfilter mask, if event was not processed by any event handler */
2119    if( !processed )
2120    {
2121       eventfilter->eventmask &= ~event->eventtype;
2122       SCIPsetDebugMsg(set, " -> event type 0x%" SCIP_EVENTTYPE_FORMAT " not processed. new mask of event filter %p: 0x%" SCIP_EVENTTYPE_FORMAT "\n",
2123          event->eventtype, (void*)eventfilter, eventfilter->eventmask);
2124    }
2125 
2126    /* process delayed events on this eventfilter */
2127    eventfilterProcessUpdates(eventfilter);
2128 
2129    return SCIP_OKAY;
2130 }
2131 
2132 
2133 
2134 /*
2135  * Event queue methods
2136  */
2137 
2138 /*
2139  * simple functions implemented as defines
2140  */
2141 
2142 /* In debug mode, the following methods are implemented as function calls to ensure
2143  * type validity.
2144  * In optimized mode, the methods are implemented as defines to improve performance.
2145  * However, we want to have them in the library anyways, so we have to undef the defines.
2146  */
2147 
2148 #undef SCIPeventqueueIsDelayed
2149 
2150 /** resizes events array to be able to store at least num entries */
2151 static
eventqueueEnsureEventsMem(SCIP_EVENTQUEUE * eventqueue,SCIP_SET * set,int num)2152 SCIP_RETCODE eventqueueEnsureEventsMem(
2153    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2154    SCIP_SET*             set,                /**< global SCIP settings */
2155    int                   num                 /**< minimal number of node slots in array */
2156    )
2157 {
2158    assert(eventqueue != NULL);
2159    assert(set != NULL);
2160 
2161    if( num > eventqueue->eventssize )
2162    {
2163       int newsize;
2164 
2165       newsize = SCIPsetCalcMemGrowSize(set, num);
2166       SCIP_ALLOC( BMSreallocMemoryArray(&eventqueue->events, newsize) );
2167       eventqueue->eventssize = newsize;
2168    }
2169    assert(num <= eventqueue->eventssize);
2170 
2171    return SCIP_OKAY;
2172 }
2173 
2174 /** creates an event queue */
SCIPeventqueueCreate(SCIP_EVENTQUEUE ** eventqueue)2175 SCIP_RETCODE SCIPeventqueueCreate(
2176    SCIP_EVENTQUEUE**     eventqueue          /**< pointer to store the event queue */
2177    )
2178 {
2179    assert(eventqueue != NULL);
2180 
2181    SCIP_ALLOC( BMSallocMemory(eventqueue) );
2182    (*eventqueue)->events = NULL;
2183    (*eventqueue)->eventssize = 0;
2184    (*eventqueue)->nevents = 0;
2185    (*eventqueue)->delayevents = FALSE;
2186 
2187    return SCIP_OKAY;
2188 }
2189 
2190 /** frees event queue; there must not be any unprocessed events in the queue! */
SCIPeventqueueFree(SCIP_EVENTQUEUE ** eventqueue)2191 SCIP_RETCODE SCIPeventqueueFree(
2192    SCIP_EVENTQUEUE**     eventqueue          /**< pointer to the event queue */
2193    )
2194 {
2195    assert(eventqueue != NULL);
2196    assert(*eventqueue != NULL);
2197    assert((*eventqueue)->nevents == 0);
2198 
2199    BMSfreeMemoryArrayNull(&(*eventqueue)->events);
2200    BMSfreeMemory(eventqueue);
2201 
2202    return SCIP_OKAY;
2203 }
2204 
2205 /** appends event to the event queue; sets event to NULL afterwards */
2206 static
eventqueueAppend(SCIP_EVENTQUEUE * eventqueue,SCIP_SET * set,SCIP_EVENT ** event)2207 SCIP_RETCODE eventqueueAppend(
2208    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2209    SCIP_SET*             set,                /**< global SCIP settings */
2210    SCIP_EVENT**          event               /**< pointer to event to append to the queue */
2211    )
2212 {
2213    assert(eventqueue != NULL);
2214    assert(eventqueue->delayevents);
2215    assert(event != NULL);
2216    assert(*event != NULL);
2217 
2218    SCIPsetDebugMsg(set, "appending event %p of type 0x%" SCIP_EVENTTYPE_FORMAT " to event queue %p at position %d\n",
2219       (void*)*event, (*event)->eventtype, (void*)eventqueue, eventqueue->nevents);
2220 
2221    SCIP_CALL( eventqueueEnsureEventsMem(eventqueue, set, eventqueue->nevents+1) );
2222    eventqueue->events[eventqueue->nevents] = *event;
2223    eventqueue->nevents++;
2224 
2225    *event = NULL;
2226 
2227    return SCIP_OKAY;
2228 }
2229 
2230 /** processes event or adds event to the event queue */
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)2231 SCIP_RETCODE SCIPeventqueueAdd(
2232    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2233    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
2234    SCIP_SET*             set,                /**< global SCIP settings */
2235    SCIP_PRIMAL*          primal,             /**< primal data; only needed for objchanged events, or NULL */
2236    SCIP_LP*              lp,                 /**< current LP data; only needed for obj/boundchanged events, or NULL */
2237    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage; only needed for bound change events, or NULL */
2238    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global events; not needed for variable specific events */
2239    SCIP_EVENT**          event               /**< pointer to event to add to the queue; will be NULL after queue addition */
2240    )
2241 {
2242    SCIP_VAR* var;
2243    SCIP_EVENT* qevent;
2244    int pos;
2245 
2246    assert(eventqueue != NULL);
2247    assert(event != NULL);
2248    assert(*event != NULL);
2249    assert(((*event)->eventtype & SCIP_EVENTTYPE_OBJCHANGED) == 0 || primal != NULL);
2250    assert(((*event)->eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_OBJCHANGED)) == 0 || lp != NULL);
2251    assert(((*event)->eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) == 0 || branchcand != NULL);
2252 
2253    if( !eventqueue->delayevents )
2254    {
2255       SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
2256 
2257       /* immediately process event */
2258       SCIP_CALL( SCIPeventProcess(*event, set, primal, lp, branchcand, eventfilter) );
2259       SCIP_CALL( SCIPeventFree(event, blkmem) );
2260 
2261       SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, primal, lp, branchcand, eventfilter) );
2262    }
2263    else
2264    {
2265       /* delay processing of event by appending it to the event queue */
2266       SCIPsetDebugMsg(set, "adding event %p of type 0x%" SCIP_EVENTTYPE_FORMAT " to event queue %p\n", (void*)*event, (*event)->eventtype, (void*)eventqueue);
2267 
2268       switch( (*event)->eventtype )
2269       {
2270       case SCIP_EVENTTYPE_DISABLED:
2271          SCIPerrorMessage("cannot add a disabled event to the event queue\n");
2272          return SCIP_INVALIDDATA;
2273 
2274       case SCIP_EVENTTYPE_VARADDED:
2275       case SCIP_EVENTTYPE_VARDELETED:
2276       case SCIP_EVENTTYPE_VARFIXED:
2277       case SCIP_EVENTTYPE_VARUNLOCKED:
2278       case SCIP_EVENTTYPE_GLBCHANGED:
2279       case SCIP_EVENTTYPE_GUBCHANGED:
2280       case SCIP_EVENTTYPE_PRESOLVEROUND:
2281       case SCIP_EVENTTYPE_NODEFOCUSED:
2282       case SCIP_EVENTTYPE_NODEFEASIBLE:
2283       case SCIP_EVENTTYPE_NODEINFEASIBLE:
2284       case SCIP_EVENTTYPE_NODEBRANCHED:
2285       case SCIP_EVENTTYPE_NODEDELETE:
2286       case SCIP_EVENTTYPE_FIRSTLPSOLVED:
2287       case SCIP_EVENTTYPE_LPSOLVED:
2288       case SCIP_EVENTTYPE_POORSOLFOUND:
2289       case SCIP_EVENTTYPE_BESTSOLFOUND:
2290       case SCIP_EVENTTYPE_GHOLEADDED:
2291       case SCIP_EVENTTYPE_GHOLEREMOVED:
2292       case SCIP_EVENTTYPE_LHOLEADDED:
2293       case SCIP_EVENTTYPE_LHOLEREMOVED:
2294       case SCIP_EVENTTYPE_ROWADDEDSEPA: /* @todo remove previous DELETEDSEPA event */
2295       case SCIP_EVENTTYPE_ROWDELETEDSEPA: /* @todo remove previous ADDEDSEPA event */
2296       case SCIP_EVENTTYPE_ROWADDEDLP: /* @todo remove previous DELETEDLP event */
2297       case SCIP_EVENTTYPE_ROWDELETEDLP: /* @todo remove previous ADDEDLP event */
2298       case SCIP_EVENTTYPE_ROWCOEFCHANGED: /* @todo merge? */
2299       case SCIP_EVENTTYPE_ROWCONSTCHANGED: /* @todo merge with previous constchanged event */ /*lint !e30 !e142*/
2300       case SCIP_EVENTTYPE_ROWSIDECHANGED: /* @todo merge with previous sidechanged event */ /*lint !e30 !e142*/
2301       case SCIP_EVENTTYPE_SYNC: /*lint !e30 !e142*/
2302          /* these events cannot (or need not) be merged; just add them to the queue */
2303          SCIP_CALL( eventqueueAppend(eventqueue, set, event) );
2304          break;
2305 
2306       case SCIP_EVENTTYPE_OBJCHANGED:
2307          /* changes in objective value may be merged with older changes in objective value */
2308          var = (*event)->data.eventobjchg.var;
2309          assert(var != NULL);
2310          pos = var->eventqueueindexobj;
2311          if( pos >= 0 )
2312          {
2313             /* the objective value change event already exists -> modify it accordingly */
2314             assert(pos < eventqueue->nevents);
2315             qevent = eventqueue->events[pos];
2316             assert(qevent != NULL);
2317             assert(qevent->eventtype == SCIP_EVENTTYPE_OBJCHANGED);
2318             assert(qevent->data.eventobjchg.var == var);
2319             assert(SCIPsetIsEQ(set, (*event)->data.eventobjchg.oldobj, qevent->data.eventobjchg.newobj));
2320 
2321             SCIPsetDebugMsg(set, " -> merging OBJ event (<%s>,%g -> %g) with event at position %d (<%s>,%g -> %g)\n",
2322                SCIPvarGetName((*event)->data.eventobjchg.var), (*event)->data.eventobjchg.oldobj,
2323                (*event)->data.eventobjchg.newobj,
2324                pos, SCIPvarGetName(qevent->data.eventobjchg.var), qevent->data.eventobjchg.oldobj,
2325                qevent->data.eventobjchg.newobj);
2326 
2327             qevent->data.eventobjchg.newobj = (*event)->data.eventobjchg.newobj;
2328             if( qevent->data.eventobjchg.newobj == qevent->data.eventobjchg.oldobj ) /*lint !e777*/
2329             {
2330                /* the queued objective value change was reversed -> disable the event in the queue */
2331                eventDisable(qevent);
2332                var->eventqueueindexobj = -1;
2333                SCIPsetDebugMsg(set, " -> event disabled\n");
2334             }
2335 
2336             /* free the event that is of no use any longer */
2337             SCIP_CALL( SCIPeventFree(event, blkmem) );
2338          }
2339          else
2340          {
2341             /* the objective value change event doesn't exist -> add it to the queue, and remember the array index */
2342             var->eventqueueindexobj = eventqueue->nevents;
2343             SCIP_CALL( eventqueueAppend(eventqueue, set, event) );
2344          }
2345          break;
2346 
2347       case SCIP_EVENTTYPE_LBTIGHTENED:
2348       case SCIP_EVENTTYPE_LBRELAXED:
2349          /* changes in lower bound may be merged with older changes in lower bound */
2350          var = (*event)->data.eventbdchg.var;
2351          assert(var != NULL);
2352          pos = var->eventqueueindexlb;
2353          if( pos >= 0 )
2354          {
2355             /* the lower bound change event already exists -> modify it accordingly */
2356             assert(pos < eventqueue->nevents);
2357             qevent = eventqueue->events[pos];
2358             assert(qevent != NULL);
2359             assert(qevent->eventtype == SCIP_EVENTTYPE_LBTIGHTENED || qevent->eventtype == SCIP_EVENTTYPE_LBRELAXED);
2360             assert(qevent->data.eventbdchg.var == var);
2361             assert(SCIPsetIsEQ(set, (*event)->data.eventbdchg.oldbound, qevent->data.eventbdchg.newbound));
2362 
2363             SCIPsetDebugMsg(set, " -> merging LB event (<%s>,%g -> %g) with event at position %d (<%s>,%g -> %g)\n",
2364                SCIPvarGetName((*event)->data.eventbdchg.var), (*event)->data.eventbdchg.oldbound,
2365                (*event)->data.eventbdchg.newbound,
2366                pos, SCIPvarGetName(qevent->data.eventbdchg.var), qevent->data.eventbdchg.oldbound,
2367                qevent->data.eventbdchg.newbound);
2368 
2369             qevent->data.eventbdchg.newbound = (*event)->data.eventbdchg.newbound;
2370             /*if( SCIPsetIsLT(set, qevent->data.eventbdchg.newbound, qevent->data.eventbdchg.oldbound) )*/
2371             if( qevent->data.eventbdchg.newbound < qevent->data.eventbdchg.oldbound )
2372                qevent->eventtype = SCIP_EVENTTYPE_LBRELAXED;
2373             /*else if( SCIPsetIsGT(set, qevent->data.eventbdchg.newbound, qevent->data.eventbdchg.oldbound) )*/
2374             else if( qevent->data.eventbdchg.newbound > qevent->data.eventbdchg.oldbound )
2375                qevent->eventtype = SCIP_EVENTTYPE_LBTIGHTENED;
2376             else
2377             {
2378                /* the queued bound change was reversed -> disable the event in the queue */
2379                assert(qevent->data.eventbdchg.newbound == qevent->data.eventbdchg.oldbound); /*lint !e777*/
2380                eventDisable(qevent);
2381                var->eventqueueindexlb = -1;
2382                SCIPsetDebugMsg(set, " -> event disabled\n");
2383             }
2384 
2385             /* free the event that is of no use any longer */
2386             SCIP_CALL( SCIPeventFree(event, blkmem) );
2387          }
2388          else
2389          {
2390             /* the lower bound change event doesn't exist -> add it to the queue, and remember the array index */
2391             var->eventqueueindexlb = eventqueue->nevents;
2392             SCIP_CALL( eventqueueAppend(eventqueue, set, event) );
2393          }
2394          break;
2395 
2396       case SCIP_EVENTTYPE_UBTIGHTENED:
2397       case SCIP_EVENTTYPE_UBRELAXED:
2398          /* changes in upper bound may be merged with older changes in upper bound */
2399          var = (*event)->data.eventbdchg.var;
2400          assert(var != NULL);
2401          pos = var->eventqueueindexub;
2402          if( pos >= 0 )
2403          {
2404             /* the upper bound change event already exists -> modify it accordingly */
2405             assert(pos < eventqueue->nevents);
2406             qevent = eventqueue->events[pos];
2407             assert(qevent != NULL);
2408             assert(qevent->eventtype == SCIP_EVENTTYPE_UBTIGHTENED || qevent->eventtype == SCIP_EVENTTYPE_UBRELAXED);
2409             assert(qevent->data.eventbdchg.var == var);
2410             assert(SCIPsetIsEQ(set, (*event)->data.eventbdchg.oldbound, qevent->data.eventbdchg.newbound));
2411 
2412             SCIPsetDebugMsg(set, " -> merging UB event (<%s>,%g -> %g) with event at position %d (<%s>,%g -> %g)\n",
2413                SCIPvarGetName((*event)->data.eventbdchg.var), (*event)->data.eventbdchg.oldbound,
2414                (*event)->data.eventbdchg.newbound,
2415                pos, SCIPvarGetName(qevent->data.eventbdchg.var), qevent->data.eventbdchg.oldbound,
2416                qevent->data.eventbdchg.newbound);
2417 
2418             qevent->data.eventbdchg.newbound = (*event)->data.eventbdchg.newbound;
2419             /*if( SCIPsetIsLT(set, qevent->data.eventbdchg.newbound, qevent->data.eventbdchg.oldbound) )*/
2420             if( qevent->data.eventbdchg.newbound < qevent->data.eventbdchg.oldbound )
2421                qevent->eventtype = SCIP_EVENTTYPE_UBTIGHTENED;
2422             /*else if( SCIPsetIsGT(set, qevent->data.eventbdchg.newbound, qevent->data.eventbdchg.oldbound) )*/
2423             else if( qevent->data.eventbdchg.newbound > qevent->data.eventbdchg.oldbound )
2424                qevent->eventtype = SCIP_EVENTTYPE_UBRELAXED;
2425             else
2426             {
2427                /* the queued bound change was reversed -> disable the event in the queue */
2428                assert(qevent->data.eventbdchg.newbound == qevent->data.eventbdchg.oldbound); /*lint !e777*/
2429                eventDisable(qevent);
2430                var->eventqueueindexub = -1;
2431                SCIPsetDebugMsg(set, " -> event disabled\n");
2432             }
2433 
2434             /* free the event that is of no use any longer */
2435             SCIP_CALL( SCIPeventFree(event, blkmem) );
2436          }
2437          else
2438          {
2439             /* the upper bound change event doesn't exist -> add it to the queue, and remember the array index */
2440             var->eventqueueindexub = eventqueue->nevents;
2441             SCIP_CALL( eventqueueAppend(eventqueue, set, event) );
2442          }
2443          break;
2444 
2445       case SCIP_EVENTTYPE_IMPLADDED:
2446          var = (*event)->data.eventimpladd.var;
2447          assert(var != NULL);
2448          if( var->eventqueueimpl )
2449          {
2450             /* free the event that is of no use any longer */
2451             SCIP_CALL( SCIPeventFree(event, blkmem) );
2452          }
2453          else
2454          {
2455             var->eventqueueimpl = TRUE;
2456             SCIP_CALL( eventqueueAppend(eventqueue, set, event) );
2457          }
2458          break;
2459 
2460       default:
2461          SCIPerrorMessage("unknown event type <%ld>\n", (*event)->eventtype);
2462          return SCIP_INVALIDDATA;
2463       }
2464    }
2465 
2466    assert(*event == NULL);
2467 
2468    return SCIP_OKAY;
2469 }
2470 
2471 /** marks queue to delay incoming events until a call to SCIPeventqueueProcess() */
SCIPeventqueueDelay(SCIP_EVENTQUEUE * eventqueue)2472 SCIP_RETCODE SCIPeventqueueDelay(
2473    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
2474    )
2475 {
2476    assert(eventqueue != NULL);
2477    assert(!eventqueue->delayevents);
2478 
2479    SCIPdebugMessage("event processing is delayed\n");
2480 
2481    eventqueue->delayevents = TRUE;
2482 
2483    return SCIP_OKAY;
2484 }
2485 
2486 /** processes all delayed events, marks queue to process events immediately */
SCIPeventqueueProcess(SCIP_EVENTQUEUE * eventqueue,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_PRIMAL * primal,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTFILTER * eventfilter)2487 SCIP_RETCODE SCIPeventqueueProcess(
2488    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2489    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
2490    SCIP_SET*             set,                /**< global SCIP settings */
2491    SCIP_PRIMAL*          primal,             /**< primal data */
2492    SCIP_LP*              lp,                 /**< current LP data */
2493    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
2494    SCIP_EVENTFILTER*     eventfilter         /**< event filter for global (not variable dependent) events */
2495    )
2496 {
2497    SCIP_EVENT* event;
2498    int i;
2499 
2500    assert(eventqueue != NULL);
2501    assert(eventqueue->delayevents);
2502 
2503    SCIPsetDebugMsg(set, "processing %d queued events\n", eventqueue->nevents);
2504 
2505    /* pass events to the responsible event filters
2506     * During event processing, new events may be raised. We have to loop to the mutable eventqueue->nevents.
2507     * A loop to something like "nevents = eventqueue->nevents; for(...; i < nevents; ...)" would miss the
2508     * newly created events. The same holds for eventqueue->events, which can be moved in memory due to
2509     * memory reallocation in eventqueueAppend().
2510     */
2511    for( i = 0; i < eventqueue->nevents; ++i )
2512    {
2513       event = eventqueue->events[i];
2514       assert(event != NULL);
2515 
2516       SCIPsetDebugMsg(set, "processing event %d of %d events in queue: eventtype=0x%" SCIP_EVENTTYPE_FORMAT "\n", i, eventqueue->nevents, event->eventtype);
2517 
2518       /* unmark the event queue index of a variable with changed objective value or bounds, and unmark the event queue
2519        * member flag of a variable with added implication
2520        */
2521       if( (event->eventtype & SCIP_EVENTTYPE_OBJCHANGED) != 0 )
2522       {
2523          assert(event->data.eventobjchg.var->eventqueueindexobj == i);
2524          event->data.eventobjchg.var->eventqueueindexobj = -1;
2525       }
2526       else if( (event->eventtype & SCIP_EVENTTYPE_LBCHANGED) != 0 )
2527       {
2528          assert(event->data.eventbdchg.var->eventqueueindexlb == i);
2529          event->data.eventbdchg.var->eventqueueindexlb = -1;
2530       }
2531       else if( (event->eventtype & SCIP_EVENTTYPE_UBCHANGED) != 0 )
2532       {
2533          assert(event->data.eventbdchg.var->eventqueueindexub == i);
2534          event->data.eventbdchg.var->eventqueueindexub = -1;
2535       }
2536       else if( (event->eventtype & SCIP_EVENTTYPE_IMPLADDED) != 0 )
2537       {
2538          assert(event->data.eventimpladd.var->eventqueueimpl);
2539          event->data.eventimpladd.var->eventqueueimpl = FALSE;
2540       }
2541 
2542       /* process event */
2543       SCIP_CALL( SCIPeventProcess(event, set, primal, lp, branchcand, eventfilter) );
2544 
2545       /* free the event immediately, because additionally raised events during event processing
2546        * can lead to a large event queue
2547        */
2548       SCIP_CALL( SCIPeventFree(&eventqueue->events[i], blkmem) );
2549    }
2550 
2551    assert(i == eventqueue->nevents);
2552    eventqueue->nevents = 0;
2553    eventqueue->delayevents = FALSE;
2554 
2555    return SCIP_OKAY;
2556 }
2557 
2558 /** returns TRUE iff events of the queue are delayed until the next SCIPeventqueueProcess() call */
SCIPeventqueueIsDelayed(SCIP_EVENTQUEUE * eventqueue)2559 SCIP_Bool SCIPeventqueueIsDelayed(
2560    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
2561    )
2562 {
2563    assert(eventqueue != NULL);
2564 
2565    return eventqueue->delayevents;
2566 }
2567