SCIP comes with a command line shell which allows the user to read in problem instances, modify the solver's parameters, initiate the optimization and display certain statistics and solution information. This shell consists of dialogs, which are organized as a tree in SCIP. A node of this tree which is not a leaf represents a menu in the shell and the children of this node correspond to the entries of this menu (which can again be menus). All different dialogs are managed by a dialog handler, which, in particular, is responsible for executing the dialog corresponding to the user's command in the shell. The concept of a dialog handler is different to that of a constraint handler, which is used to manage objects of the same structure, see How to add constraint handlers. In particular, SCIP features only one dialog handler (dialog_default.h), whereas there may exist different constraint handlers.
A complete list of all dialogs contained in this release can be found here.
We now explain how users can extend the interactive shell by adding their own dialog. We give the explanation for creating your own source file for each additional dialog. Of course, you can collect different dialogs in one source file. Take src/scip/dialog_default.c, where all default dialog plugins are collected, as an example. As all other default plugins, the default dialog plugin and the template dialog are written in C. C++ users can easily adapt the code by using the scip::ObjDialog wrapper base class and implement the scip_...() virtual methods instead of the SCIP_DECL_DIALOG... callback methods.
Additional documentation for the callback methods of a dialog can be found in the file type_dialog.h.
Here is what you have to do to add a dialog (assuming your dialog is named "mydialog"):
- Copy the template files src/scip/dialog_xyz.c and src/scip/dialog_xyz.h into files named "dialog_mydialog.c" and "dialog_mydialog.h".
Make sure to adjust your Makefile such that these files are compiled and linked to your project.
- Use SCIPincludeDialogMydialog() in order to include the dialog handler into your SCIP instance, e.g., in the main file of your project (see, e.g., src/cmain.c in the Binpacking example).
- Open the new files with a text editor and replace all occurrences of "xyz" by "mydialog".
- Adjust the properties of the dialog.
- Define the dialog data. This is optional.
- Implement the interface methods.
- Implement the fundamental callback methods.
- Implement the additional callback methods. This is optional.
At the top of the new file "dialog_mydialog.c" you can find the dialog properties. These are given as compiler defines. In the C++ wrapper class, you have to provide the dialog properties by calling the constructor of the abstract base class scip::ObjDialog from within your constructor. The properties you have to set have the following meaning:
- DIALOG_NAME: the name of the dialog.
- In the interactive shell, this name appears as the command name of the dialog in the parent dialog. Additionally, if you are searching an entry in a menu with SCIPdialogFindEntry(), this name is looked up. Names within one menu have to be unique: no two dialogs in the same menu may have the same name.
- DIALOG_DESC: the description of the dialog.
- This string is printed as a description of the dialog in the interactive shell if the additional callback method DIALOGDESC is not implemented.
- DIALOG_ISSUBMENU: whether the dialog is a (sub)menu.
- This parameter states whether the dialog is a menu in the interactive shell, i.e., is the parent of further dialogs.
Below the header "Data structures" you can find a struct which is called "struct SCIP_DialogData". In this data structure, you can store the data of your dialog. If you are using C++, you can add dialog data as usual as object variables to your class.
Defining dialog data is optional. You can leave the struct empty.
At the bottom of "dialog_mydialog.c" you can find the interface method SCIPincludeDialogMydialog(), which also appears in "dialog_mydialog.h".
This method only has to be adjusted slightly. It is responsible for notifying SCIP of the presence of the dialog, which can be done by the following lines of code:
Here "parentdialog" has to be an existing dialog which is defined to be a menu (see DIALOG_ISSUBMENU), e.g., the default root dialog. The method SCIPgetRootDialog() returns the root dialog.
The interface method is called by the user, if (s)he wants to include the dialog, i.e., if (s)he wants to use the dialog in his/her application. Note that in order to be able to link the new dialog to an existing default dialog (except the root dialog) it has to be included after the default dialogs plugin, i.e., the SCIPincludeDialogMydialog() call has to occur after the SCIPincludeDialogDefault() call. The SCIPincludeDialogDefault() method is called from within the SCIPincludeDefaultPlugins() method. Therefore, it suffices to include your dialog plugins after you have called SCIPincludeDefaultPlugins(). In case you want to add a dialog to the root dialog, you just use the following lines of code to get/create the root dialog.
If you are using dialog data, you have to allocate the memory for the data at this point. You can do this by calling:
You also have to initialize the fields in struct SCIP_DialogData afterwards.
Consider the following example. The user wants to add a "drawgraph" command to the root menu of SCIP. (S)he copies the "dialog_xyz.c" and "dialog_xyz.h" files into files "dialog_drawgraph.c" and "dialog_drawgraph.h", respectively. Then, (s)he puts the following code into the SCIPincludeDialogDrawgraph() method, compare SCIPincludeDialogDefault() in src/scip/dialog_default.c:
Using this code, it is even possible to call SCIPincludeDialogDrawgraph() before including the default dialog plugins, and you can also call it multiple times without causing inconsistencies in the dialog structure.
Dialogs have only one fundamental callback method, namely the DIALOGEXEC method. This method has to be implemented for every dialog; the other callback methods are optional. In the C++ wrapper class scip::ObjDialog, the scip_exec() method (which corresponds to the DIALOGEXEC callback) is a virtual abstract member function. You have to implement it in order to be able to construct an object of your dialog class.
Additional documentation for the callback methods can be found in type_dialog.h.
The DIALOGEXEC method is invoked, if the user selected the dialog's command name in the parent's menu. It should execute what is stated in DIALOG_DESC, e.g., the display constraint handlers dialog should display information about the constraint handlers included in SCIP, see src/scip/dialog_default.c.
For typical methods called by the execution method, have a look at src/scip/dialog_default.c.
The callback has to return which dialog should be processed next. This can be, for example, the root dialog (SCIPdialoghdlrGetRoot()), the parent dialog (SCIPdialogGetParent()) or NULL, which stands for closing the interactive shell.
The additional callback methods do not need to be implemented in every case. They can be used, for example, to free private data.
If you are using dialog data, you have to implement this method in order to free the dialog data. This can be done by the following procedure:
If you have allocated memory for fields in your dialog data, remember to free this memory before freeing the dialog data itself. If you are using the C++ wrapper class, this method is not available. Instead, just use the destructor of your class to free the member variables of your class.
This method is called when the help menu of the parent is displayed. It should output (usually a single line of) information describing the meaning of the dialog.
If this callback is not implemented, the description string of the dialog (DIALOG_DESC) is displayed instead.
The DIALOGCOPY callback is executed when a SCIP instance is copied, e.g. to solve a sub-SCIP. By defining this callback as
NULL the user disables the execution of this dialog for all copied SCIP instances. In general there is no need to copy any dialog since it is most unlikely to start the interactive shell of the copied instances.