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