Scippy

SCIP

Solving Constraint Integer Programs

Author
Stefan Heinz

This example illustrates the use of an event handler within SCIP. It extends the default plugins of SCIP by two additional plugins, namely an event handler which reacts on new best solutions and an event handler acting on processed nodes. You should also read the section How to add event handler which explains event handling in general.

The event handlers event_bestsol.c and event_boundwriting.c show how the create a customized event handler in SCIP. In case of an event handler, there are two important questions to answer:

  1. When to install the event handler and
  2. When to remove the event handler.

Note: You can replace the event type in this example with any none-variable event. See in the type_event.h in the SCIP documentation for a complete list.

The remainder of this page focusses on the best solution event handler. See event_boundwriting.c for a documentation of the bound writing event handler.

Installing the event handler

In the following we describe the use of the callback methods of all event handler for the installation of our event handler.

In this example, we want to install an event handler which reacts on a new best solution.

Our goal is to specify that our event_bestsol.c event handler reacts on the SCIP_EVENTTYPE_BESTSOLFOUND which already exists in SCIP. The main methods for changing the way SCIP notifies the event handler about an event are

The right callback event handler in the callback SCIP_DECL_EVENTINIT. At that point the problem was tranformed. Note that there are heuristics which are called before even the presolving starts as for example the trivial heuristic. This means the callback SCIP_DECL_EVENTINTSOL is too late to install the solution event because at that stage, we might have already missed several solutions.

static
SCIP_DECL_EVENTINIT(eventInitBestsol)
{
assert(scip != NULL);
assert(eventhdlr != NULL);
assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
return SCIP_OKAY;
}

The method SCIPcatchEvent() notifies SCIP that we want to react on the event type best solution found.

Remove the event handler

With respect to dropping the event handling, we perform that action in SCIP_DECL_EVENTEXIT which is the counter part of SCIP_DECL_EVENTINIT. The callback SCIP_DECL_EVENTEXITSOL which is the counter part to SCIP_DECL_EVENTINTSOL does not work because it will be called before the branch-and-bound process is freed. This, however, is not only done after the problem is solved. It also happens when a restart is performed. Dropping the event handler within this method would cause our event handler not to be informed about every new solution found after the first restart. Therefore, the right place to drop that event handler is the callback SCIP_DECL_EVENTEXIT. Below you find the source code.

static
SCIP_DECL_EVENTEXIT(eventExitBestsol)
{
assert(scip != NULL);
assert(eventhdlr != NULL);
assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
return SCIP_OKAY;
}

The method SCIPdropEvent() tells SCIP that we want to drop the event type SCIP_EVENTTYPE_BESTSOLFOUND of belonging to the event handler.

React on events

In the callback SCIP_DECL_EVENTEXEC, which is the execution method of the event handler, you can specify how the event handler reacts on an event it catches. In this case, we just want to output a line to the console every time a new best solution is found.

static
SCIP_DECL_EVENTEXEC(eventExecBestsol)
{
SCIP_SOL* bestsol;
SCIP_Real solvalue;
assert(eventhdlr != NULL);
assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
assert(event != NULL);
assert(scip != NULL);
SCIPdebugMessage("exec method of event handler for best solution found\n");
bestsol = SCIPgetBestSol(scip);
assert(bestsol != NULL);
solvalue = SCIPgetSolOrigObj(scip, bestsol);
SCIPinfoMessage(scip, NULL, "found new best solution with solution value <%g>\n", solvalue);
return SCIP_OKAY;
}

Including the event handler plugin

SCIP is plugin-based. This means that all plugins which should be used have be included into the SCIP environment. In the case of the event handler, we are doing this after the SCIP environment was created (see cmain.c).

static
int argc,
char** argv,
const char* defaultsetname
)
{
SCIP* scip = NULL;
SCIP_CALL( SCIPcreate(&scip) );
SCIP_CALL( SCIPprocessShellArguments(scip, argc, argv, defaultsetname) );
SCIP_CALL( SCIPfree(&scip) );
return SCIP_OKAY;
}