SCIP Frequently Asked Questions

Sections

General Questions about SCIP

What is SCIP?

SCIP is a constraint integer program solver and contain all necessary plugin to be a standalone MIP-Solver as well as a branch-cut-and-price-framework.

  • You can use the precompiled binaries with which you can solve MIPs in *.mps, *.lp, or others file format
  • You can use SCIP as a subroutine for solving MIPs from your own source code.
  • You can use SCIP as a framework in which you implement your own plugins.
  • You can use SCIP in any combination of the three purposes above.
This FAQ consists of four separate sections treating these usages of SCIP.

When should I use SCIP?

If you are either looking for a fast non-commercial MIP-Solver or for a branch-cut-and-price-framework in which you can directly implement your own methods — which can even be for more general purposes than MIP (see here).

I heard something about licenses. Do I have to pay for using SCIP?

As long as you use it for academic, non-commercial purposes: No. This will not change. For the other cases, check the explanation of the ZIB academic license and always feel free to ask us.

Do I need any extra software?

Except if you want to use SCIP as a pure CP-Solver (see here), you need an underlying LP-Solver which has first to be installed and linked to the libraries (see the INSTALL file in the SCIP root directory). LP-solvers currently supported by SCIP are:

We also provide some precompiled binaries. Besides that, you might need a modeling language like ZIMPL to generate *.mps or *.lp files. ZIMPL files can also directly be read by SCIP.

How do I get started?

An easy way is to use the SCIP-binaries and call SCIP from a shell. For that, you just have to download one of the precompiled binaries from the download section, or the zipped source code and compile it with your favorite settings. This is described in detail in the INSTALL file in the SCIP main directory.

Another way is to use SCIP as a solver integrated into your own program source code. See the directory "examples/MIPsolver/" for a simple example and this point.

A third way is to implement your own plugins into SCIP. This is explained in the HowTos for all plugin types, which you can find in the doxygen documentation. See also How to start a new project.

I would like to check whether some functionality is implemented into SCIP. How does the naming of the methods work? Where do I find the most common methods?

For an explanation of the naming see the coding style guidelines.
The methods being of interest for you, should normally be found either in scip.h or in pub_*.h, see also here. In the doxygen documentation of scip.h, the methods are ordered by topics.

The methods SCIPgetVarSol() and SCIPvarGetSol() seem to have the same functionality. Which one should I use?

In fact, there is a slight difference: SCIPvarGetSol() is also able to return pseudo solution values. If you do not have an idea, what pseudo solutions are, SCIPgetVarSol() should be just fine.
This should be the only case of 'duplicate methods'. If you find, however, another one, please contact us.

I have installation problems. What can I do?

Read the INSTALL file in the SCIP root directory. It contains hints of how to get around problems. You can also try the binaries available on the SCIP page.

If you want to use SoPlex as the underlying LP-solver, you can try the following: First, download the ZIB Optimization Suite. Then, extract the file, change into the ziboptsuite directory, and enter 'make'. As long as you have all the necessary libraries installed in your system, it should generate a SCIP binary linked to ZIMPL and Soplex. The necessary system libraries are:

  1. ZLIB (libz.a)
  2. GMP (libgmp.a)
  3. Readline (libreadline.a)

If you do not have all of these libraries, read the INSTALL file in the ZIB Optimization Suite directory.
As a summary, the call of make ZIMPL=false ZLIB=false READLINE=false should work on most systems.

If you have any problems while using an LP-solver different from SoPlex, please read the SCIP INSTALL file first.

I changed to a new version of SCIP and now compiling breaks with some error messages which I don't understand. Do you have a general hint on that?

Maybe the parameters of a function in SCIP changed. Relevant changes between version are listed below.

Can I use SCIP as a pure CP-Solver?

Yes. There is a setting-file "settings/emphasis/cpsolver.set". Furthermore, you can compile SCIP without any LP-Solver by make LPS=none.

How can I use the SCIP makefiles?

See Makefiles.

What is this business with .a and .so libraries in the directory lib/?

When SCIP builds the binary it needs to link with the corresponding libraries of the LP-solver. There are usually two ways to distribute a library. In the first (.a) the library is linked statically to SCIP; this means that all of its information is packed into the binary. In the second way (.so) the library is a shared library. In this case, the code of the library is not inserted into the binary itself, but is loaded at runtime. This has the advantage that the binaries are smaller, but it comes at the cost that you have to make sure that the library is found at runtime (for most systems it suffices to put the path of the library into the LD_LIBRARY_PATH variable).

Note: Depending on the system shared or static libraries are standard. If both links are present in the lib directory, the linker chooses which version to take (on newer Linux systems this is usually the shared version). If you do not want this to happen you have to delete the link that is not intended.

Can I compile SCIP as a shared library?

If you are using Linux and a GNU compiler you can use the OPT=opt-shared option when making SCIP. This will generate the libraries of SCIP in shared format. The binary then also uses this form. Note that the path to the lib directory of SCIP is used to locate the libraries. If you want to move the libraries, you might to set the LD_LIBRARY_PATH environment variable to include the new path. If you have a different system or compiler (which supports shared libraries) you might try to copy the file make.linux.x86.gnu.opt-shared and modify it according to your needs (see also Makefiles). The "magic" changes are the -FPIC compiler/liner option and the -Wl,-rpath option.

Using SCIP as a standalone MIP-Solver

The output is too wide for my terminal window. What can I do?

In the interactive shell you can set the width of the output with the following command "set display width" followed by an appropriate number. See also the next question.

What do the cryptic abbreviations for the columns mean which are displayed during the solving process of SCIP?

Type "display display" in the interactive shell to get an explanation of them.
By the way: If a letter appears in front of a display row, it indicates, which heuristic found the new primal bound, a star representing an integral LP-relaxation.
Typing "display statistics" after finishing or interrupting the solving process gives you plenty of extra information about the solving process.
(Typing "display heuristics" gives you a list of the heuristics including their letters.)

How do I change the behavior of SCIP?

You can find a variety of different general settings for SCIP in the directory "settings". They can be loaded via "set load settings/*/*.set" in the interactive shell. You can combine the general settings for cuts, presolving, and heuristics arbitrarily.
"display parameters" shows you which settings currently differ from their default, "set default" resets them all. Furthermore, there are complete settings in settings/emphasis/, analogously to ILOG CPLEX.

I recognized that one special plugin works very bad / very well for my problem and I want to disable it / weaken its influence / intensify its influence. How do I do this?

  • For using a non-default branching rule or node selection strategy as standard, you just have to give it the highest priority, using
    • SCIP> set branching <name of a branching rule> priority 9999999
    • SCIP> set nodeselectors <name of a node selector> priority 9999999
    With the commands
    • SCIP> display branching
    • SCIP> display nodeselectors
    you get a list of all branching rules and node selectors, respectively. These lists give information about the different priorities.
  • If you want to completely disable a heuristic or a separator you have to set its frequency to -1 and the sepafreq to -1 for separation by constraint handlers, respectively. The commands looks like this:
    • SCIP> set heuristics <name of a heuristic> freq -1
    • SCIP> set separators <name of a separator> freq -1
    • SCIP> set constraints <name of a constraint handler> sepafreq -1
  • For disabling a presolver, you have to set its maxrounds parameter to 0.
    • SCIP> set presolvers <name of a presolver> maxrounds 0
  • If you want to intensify the usage of a heuristic, you can reduce its frequency to some smaller, positive value, and/or raise the quotient and offset values (maxlpiterquot for diving heuristics, nodes for LNS heuristics).
    • SCIP> set heuristics <name of a heuristic> freq <some value>
    • SCIP> set heuristic <name of a diving heuristic> maxlpiterquot <some value>
    • SCIP> set heuristic <name of a LNS heuristic> nodesquot <some value>
  • For intensifying the usage of a separator, you can raise its maxroundsroot and maxsepacutsroot values.
    • SCIP> set separators <name of a separator> maxroundsroot <some value>
    • SCIP> set separators <name of a separator> maxrounds <some value>
    If you also want to use this separator locally, you have to set its frequency to a positive value and possibly raise maxrounds and maxsepacuts.
    • SCIP> set separators <name of a separator> freq <some value>
    • SCIP> set separators <name of a separator> maxsepacuts <some value>
    Compare the parameters of the heuristic/separator in the appropriate aggressive setting (see previous question).
  • For weakening, you should just do the opposite operation, i.e., reducing the values you would raise for intensification and vice versa.

Using SCIP included in another source code

How do I construct a problem instance in SCIP?

First you have to create a SCIP object via SCIPcreate(), then you start to build the problem via SCIPcreateProb(). Then you create variables via SCIPcreateVar() and add them to the problem via SCIPaddVar().
The same has to be done for the constraints. For example, if you want to fill in the rows of a general MIP, you have to call SCIPcreateConsLinear(), SCIPaddConsLinear() and additionally SCIPreleaseCons() after finishing. If all variables and constraints are present, you can initiate the solution process via SCIPsolve().
Make sure to also call SCIPreleaseVar() if you do not need the variable pointer anymore. For an explanation of creating and releasing objects, please see the doxygen documentation..

I already know a solution in advance, which I want to pass to SCIP. How do I do this?

First you have to build your problem, then you have to transform your problem (SCIP only accepts solutions if it is at least in the transformed stage, see here) via calling SCIPtransformProb(). Next, you create a new SCIP primal solution by calling SCIPcreateSol() and set all nonzero values by calling SCIPsetSolVal().
After that, you add this solution by calling SCIPtrySol() (the variable success should be true afterwards, if your solution was correct) and then release it by calling SCIPsolFree().

What operational stages of SCIP are there and are they important for me?

There are ten different stages during a run of SCIP. There are some methods which cannot be called in all stages, consider for example SCIPtrySol() (see previous question).

What is this thing with the original and the transformed problem about?

Before the solving process starts, the original problem is copied to a different memory area. This copy is called "transformed problem", and all modifications during the presolving and solving process are only applied to the transformed problem.
This has two main advantages: first, the user can also modify the problem after partially solving it. All modifications done by SCIP (presolving, cuts, variable fixings) during the partial solving process will be deleted together with the transformed problem, the user can modify the original problem and restart solving.
Second, the feasibility of solutions is always tested on the original problem!

Why do the names, e.g. in debug messages often differ from the ones I defined?

This can have several reasons. Especially names of binary variables can get different prefixes and suffixes. Each transformed variable and constraint (see here) gets a "t_" as prefix. Apart from that, the meaning of original and transformed variables and constraints is identical.
General integers with bounds that differ just by 1 will be aggregated to binary variables which get the same name with the suffix "_bin" . E.g. an integer variable t_x with lower bound 4 and upper bound 5 will be aggregated to a binary variable t_x_bin = t_x - 4.
Variables can have negated counterparts, e.g. for a binary t_x its (also binary) negated would be t_x_neg = 1 - t_x.
The knapsack constraint handler is able to disaggregate its constraints to cliques, which are set packing constraints and create names that consist of the knapsack's name and a suffix "_clq_<int>". E.g., a knapsack constraint knap: x_1 + x2 +2 x_3 ≤ 2 could be disaggregated to the set packing constraints knap_clq_1: x_1 + x_3 ≤ 1 and knap_clq_2: x_2 + x_3 ≤ 1.

What is SCIP_CALL()? Do I need this?

Yes, you do. SCIP_CALL() is a global define, which handles the return codes of all methods which return a SCIP_RETCODE and should therefore parenthesize each such method. SCIP_OKAY is the code which is returned if everything worked well; there are 18 different error codes, see type_retcode.h. Each method that calls methods which return a SCIP_RETCODE should itself return a SCIP_RETCODE. If this is not possible, use SCIP_CALL_ABORT() to catch the return codes of the methods. If you do not want to use this either, you have to do the exception handling (i.e. the case that the return code is not SCIP_OKAY) on your own.

Using SCIP as a Branch-Cut-And-Price-Framework

How do I start a project?

See How to start a new project.

What types of plugins can I add and how do I do this?

See the doxygen documentation for a list of plugin types. There is a HowTo for each of them.

When should I implement a constraint handler, when should I implement a separator?

This depends on whether you want to add constraints or only cutting planes. The main difference is that constraints can be "model constraints", while cutting planes are only additional LP rows that strengthen the LP relaxation. A model constraint is a constraint that is important for the feasibility of the integral solutions. If you delete a model constraint, some infeasible integral vectors would suddenly become feasible in the reduced model. A cutting plane is redundant w.r.t. integral solutions. The set of feasible integral vectors does not change if the cutting plane is removed. You can, however, relax this condition slightly and add cutting planes that do cut off feasible solutions, as long as at least one of the optimal solutions remains feasible.

You want to use a constraint handler in the following cases:

  1. Some of your feasibility conditions can not be expressed by existing constraint types (e.g., linear constraints), or you would need too many of them. For example, the "nosubtour" constraint in the TSP is equivalent to exponentially many linear constraints. Therefore, it is better to implement a "nosubtour" constraint handler that can inspect solutions for subtours and generate subtour elimination cuts and others (e.g., comb inequalities) to strengthen the LP relaxation.
  2. Although you can express your feasibility condition by a reasonable number of existing constraint types, you can represent and process the condition in a more efficient way. For example, it may be that you can, due to your structural knowledge, implement a stronger or faster domain propagation or find tighter cutting planes than what one could do with the sum of the individual "simple" constraints that model the feasibility condition.

You want to use a cutting plane separator in the following cases:

  1. You have a general purpose cutting plane procedure that can be applied to any MIP. It does not use problem specific knowledge. It only looks at the LP, the integrality conditions, and other deduced information like the implication graph.
  2. You can describe your feasibility condition by a set C of constraints of existing type (e.g., linear constraints). The cuts you want to separate are model specific, but apart from these cuts, there is nothing you can gain by substituting the set C of constraints with a special purpose constraint. For example, the preprocessing and the domain propagation methods for the special purpose constraint would do basically the same as what the existing constraint handler does with the set C of constraints. In this case, you don't need to implement the more complex constraint handler. You add constraints of existing type to your problem instance in order to produce a valid model, and you enrich the model by your problem specific cutting plane separator to make the solving process faster. You can easily evaluate the performance impact of your cutting planes by enabling and disabling the separator.

Note that a constraint handler is defined by the type of constraints that it manages. For constraint handlers, always think in terms of constraint programming. For example, the "nosubtour" constraint handler in the TSP (see "ConshdlrSubtour.cpp" in the directory "scip/examples/TSP/src/") manages "nosubtour" constraints, which demand that in a given graph no feasible solution can contain a tour that does not contain all cities. In the usual TSP problem, there is only one "nosubtour" constraint, because there is only one graph for which subtours have to be ruled out. The "nosubtour" constraint handler has various ways of enforcing the "nosubtour" property of the solutions. A simple way is to just check each integral solution candidate (in the CONSCHECK, CONSENFOLP, and CONSENFOPS callback methods) for subtours. If there is a subtour, the solution is rejected. A more elaborate way includes the generation of "subtour elimination cuts" in the CONSSEPALP callback method of the constraint handler. Additionally, the constraint handler may want to separate other types of cutting planes like comb inequalities in its CONSSEPALP callback.

Can I remove unnecessary display columns or—even better—add my own ones? Can I change the statistics displayed at the end of solving?

Setting the status of a display column to 0 turns it off. E.g., type "set display memused status 0" in the interactive shell to disable the memory information column, or include the line SCIPsetIntParam(scip, "display/memused/status", 0) into your source code. Adding an own display column can be realized via the SCIPincludeDisp() method, see the doxygen documentation.
The statistic display, which is shown by "display statistics" and SCIPprintStatistics(), respectively, cannot be changed.

How do LP-rows look like in SCIP?

Each row is of the form lhs ≤ Σ(val[jcol[j]) + constrhs. For now, val[jcol[j] can be interpreted as aij·xj (for the difference between columns and variables see here). The constant is essentially needed for collecting the influence of presolving reductions like variable fixings and aggregations.
The lhs and rhs may take infinite values: a less-than inequality would have lhs = -∞, and a greater-than inequality would have rhs = +∞. For equations lhs is equal to rhs. An infinite left hand side can be recognized by SCIPisInfinity(scip, -lhs), an infinite right hand side can be recognized by SCIPisInfinity(scip, rhs).

How do I get the data of the current LP-relaxation?

You can get all rows in the current LP-relaxation by calling SCIPgetLPRowsData(). The methods SCIProwGetConstant(), SCIProwGetLhs(), SCIProwGetRhs(), SCIProwGetVals(), SCIProwGetNNonz(), SCIProwGetCols() then give you information about each row, see previous question.
You get a columnwise representation by calling SCIPgetLPColsData(). The methods SCIPcolGetLb() and SCIPcolGetUb() give you the locally valid bounds of a column in the LP relaxation of the current branch-and-bound-node.
If you are interested in global information, you have to call SCIPcolGetVar() to get the variable associated to a column (see next question), which you can ask for global bounds via SCIPvarGetLbGlobal() and SCIPvarGetUbGlobal() as well as the type of the variable (binary, general integer, implicit integer, or continuous) by calling SCIPvarGetType(). For more information, also see this question.

What is the difference between columns and variables, rows and constraints?

The terms columns and rows always refer to the representation in the current LP-relaxation, variables and constraints to your global Constraint Integer Program.
Each column has an associated variable, which it represents, but not every variable must be part of the current LP-relaxation. E.g., it could be already fixed, aggregated to another variable, or be priced out if a column generation approach was implemented.
Each row has either been added to the LP by a constraint handler or by a cutting plane separator. A constraint handler is able to, but does not need to, add one or more rows to the LP as a linear relaxation of each of its constraints. E.g., in the usual case (i.e. without using dynamic rows) the linear constraint handler adds one row to the LP for each linear constraint.

Are the variables and rows sorted in any particular order?

The variable array which you get by SCIPgetVars() is internally sorted by variable types. The ordering is binary, integer, implicit integer and continuous variables, i.e., the binary variables are stored at position [0,...,nbinvars-1], the general integers at [nbinvars,...,nbinvars+nintvars-1], and so on. It holds that nvars = nbinvars + ninitvars + nimplvars + ncontvars. There is no further sorting within these sections, as well as there is no sorting for the rows. But each column and each row has a unique index, which can be obtained by SCIPcolGetIndex() and SCIProwGetIndex(), respectively.

When should I use which of the numerical comparison functions?

There are various numerical comparison functions available, each of them using a different epsilon in its comparisons. Let's take the equality comparison as an example. There are the following methods available: SCIPisEQ(), SCIPisSumEQ(), SCIPisFeasEQ(), SCIPisRelEQ(), SCIPisSumRelEQ().

  • SCIPisEQ() should be used to compare two single values that are either results of a simple calculation or are input data. The comparison is done w.r.t. the "numerics/epsilon" parameter, which is 1e-9 in the default settings.
  • SCIPisSumEQ() should be used to compare the results of two scalar products or other "long" sums of values. In these sums, numerical inaccuracy can occur due to cancellation of digits in the addition of values with opposite sign. Therefore, SCIPisSumEQ() uses a relaxed equality tolerance of "numerics/sumepsilon", which is 1e-6 in the default settings.
  • SCIPisFeasEQ() should be used to check the feasibility of some result, for example after you have calculated the activity of a constraint and compare it with the left and right hand sides. The feasibility is checked w.r.t. the "numerics/feastol" parameter, and equality is defined in a relative fashion in contrast to absolute differences. That means, two values are considered to be equal if their difference divided by the larger of their absolute values is smaller than "numerics/feastol". This parameter is 1e-6 in the default settings.
  • SCIPisRelEQ() can be used to check the relative difference between two values, just like what SCIPisFeasEQ() is doing. In contrast to SCIPisFeasEQ() it uses "numerics/epsilon" as tolerance.
  • SCIPisSumRelEQ() is the same as SCIPisRelEQ() but uses "numerics/sumepsilon" as tolerance. It should be used to compare two results of scalar products or other "long" sums.

Specific questions about Column Generation and Branch-And-Price with SCIP

Why are not all variables in the LP?

With SCIPgetLPColsData() you can obtain the columns of the current LP relaxation. It is correct that not all variables are necessarily part of the current LP relaxation. In particular, in branch-and-price the variables generated at one node in the tree are not necessarily included in the LP relaxation of a different node (e.g., if the other node is not a descendant of the first node). But even if you are still at the same node or at a descendant node, SCIP can remove columns from the LP, if they are 0 in the LP relaxation. This dynamic column deletion can be avoided by setting the "removable" flag to FALSE in the SCIPcreateVar() call.

I only implemented one pricer, why is there a second one, called variable pricer?

As described in the previous question, it may happen, that some variables are not in the current LP relaxation. Nevertheless, these variables still exist, and SCIP can calculate their reduced costs and add them to the LP again, if necessary. This is the job of the variable pricer. It is called before all other pricers.

How can I delete variables?

Currently, it is not possible to delete variables during solving. A variable can be removed from the problem by SCIPdelVar(), but it remains in the corresponding constraints. Instead of that, you should either fix the variable to zero by SCIPfixVar(), which fixes the variable globally or use SCIPchgVarUbNode() and SCIPchgVarLBNode(), which change the bounds only for the current subtree.

We are working on this problem and expect to provide functionalities for the deletion of variables in the next release.

How can I store branching decisions?

This is a very common problem in Branch-And-Price, which you can deal nicely with using SCIP. There are basically three different options.

The first one is to add binary variables to the problem that encode branching decisions. Then constraints should be added that enforce the corresponding branching decisions in the subtrees.

If you have complex pricer data like a graph and need to update it after each branching decision, you should introduce "marker constraints" that are added to the branching nodes and store all the information needed (see the next question).

The third way is the usage of an event handler like described in How can an event handler help me with my branching?.

I want to store some information at the nodes and update my pricer's data structures when entering a new node. How can I do that?

This can be done by creating a new constraint handler with constraint data that can store the information and do/undo changes in the pricer's data structures.

In general, all methods of the constraint handler (check, enforcing, separation, ...) should be empty (which means to always return the status SCIP_FEASIBLE for the fundamental callbacks), just as if all constraints of this type are always feasible. The important callbacks are the CONSACTIVE and CONSDEACTIVE methods.

The CONSACTIVE method is always called when a node is entered on which the constraint has been added. Here, you need to apply the changes to your pricing data structures. The CONSDEACTIVE method will be called if the node is left again. Since the CONSACTIVE and CONSDEACTIVE methods of different constraints are always called in a stack-like fashion, this should be exactly what you need.

If you have such a constraint handler, just create constraints of this type and add them to the child nodes of your branching by SCIPaddConsNode(). Make sure to set the "stickingatnode" flag to TRUE in order to prevent SCIP from moving the constraint around in the tree.

If you need to fix variables for enforcing your branching decision, this can be done in the propagation callback of the constraint handler. Since in general each node is only propagated once, in this case you will have to check in your CONSACTIVE method whether new variables were added after your last propagation of this node. If this is the case, you will have to mark this node for repropagation by SCIPrepropagateNode().

You can look into the constraint handler of the coloring problem (examples/Coloring/src/cons_storeGraph.c) to get an example of a constraint handler that does all these things.

How can an event handler help me with my branching?

An event handler can watch for events like local bound changes on variables. So, if your pricer wants to be informed whenever a local bound of a certain variable changes, add an event handler, catch the corresponding events of the variable, and in the event handler's execution method adjust the data structures of your pricer accordingly.

My pricer generates the same column twice. How can I solve this problem?

First check whether your pricing is correct. Are there upper bounds on variables that you have forgotten to take into account? If your pricer cannot cope with other variable bounds than 0 and infinity, you have to mark all constraints containing priced variables as modifiable, and you may have to disable reduced cost strengthening by setting propagating/rootredcost/freq to -1.

If your pricer works correctly and makes sure that the same column is added at most once in one pricing round, this behavior is probably caused by the PRICER_DELAY property of your pricer.

If it is set to FALSE, the following may have happened: The variable pricer (see this question) found a variable with negative dual feasibility that was not part of the current LP relaxation and added it to the LP. In the same pricing round, your own pricer found the same column and created a new variable for it. This might happen, since your pricer uses the same dual values as the variable pricer. To avoid this behavior, set PRICER_DELAY to TRUE, so that the LP is reoptimized after the variable pricer added variables to the LP. You can find some more information about the PRICER_DELAY property at How to add variable pricers .

Which default plugins should be deactivated in order to get a working branch-and price code?

In most cases, you should deactivate separators, since cutting planes that are added to your master problem may destroy your pricing problem. Additionally, it may be necessary to deactivate some presolvers, mainly the dual fixing presolver. This can be done by not including these plugins into SCIP, namely by not calling SCIPincludeSepaXxx() and SCIPincludePresolXxx() in your own plugins-including files. Alternatively, you can set the parameters maxrounds and maxroundsroot to zero for all separators and maxrounds to zero for the presolvers.

...to be continued...
Valid HTML 4.01
© 2003-2009 by Zuse Institute Berlin (ZIB), Imprint Last Update $Date: 2008/09/30 18:48:05 $