Cut Selector#
For the following let us assume that a Model object is available, which is created as follows:
from pyscipopt import Model, SCIP_RESULT
from pyscipopt.scip import Cutsel
scip = Model()
What is a Cut Selector?#
A cutting plane (cut) selector is an algorithm that selects which cuts to add to the optimization problem. It is given a set of candidate cuts, and from the set must decide which subset to add.
Cut Selector Structure#
A cut selector in PySCIPOpt takes the following structure:
class DummyCutsel(Cutsel):
def cutselselect(self, cuts, forcedcuts, root, maxnselectedcuts):
"""
:param cuts: the cuts which we want to select from. Is a list of scip Rows
:param forcedcuts: the cuts which we must add. Is a list of scip Rows
:param root: boolean indicating whether we are at the root node
:param maxnselectedcuts: int which is the maximum amount of cuts that can be selected
:return: sorted cuts and forcedcuts
"""
return {'cuts': sorted_cuts, 'nselectedcuts': n,
'result': SCIP_RESULT.SUCCESS}
The class DummyCutsel inherits the necessary Cutsel class, and then programs
the necessary function cutselselect. The docstrings of the cutselselect explain
the input to the function. It is then up to the user to create some new ordering cuts,
which we have represented by sorted_cuts. The returned value of nselectedcuts results in the first
nselectedcuts of the sorted_cuts being added to the optimization problem. The
SCIP_RESULT is there to indicate whether the algorithm was successful. See the
appropriate documentation for more potential result codes.
To include a cut selector one would need to do something like the following code:
cutsel = DummyCutsel()
scip.includeCutsel(cutsel, 'name', 'description', 5000000)
The final argument of the includeCutsel function in the example above was the
priority. If the priority is higher than all other cut selectors then it will be called
first. In the case of some failure or non-success return code, then the second-highest
priority cut selector is called and so on.
Example Cut Selector#
In this example we will program a cut selector that selects the 10 most efficacious cuts. Efficacy is the standard measure for cut quality and can be calculated via SCIP directly.
class MaxEfficacyCutsel(Cutsel):
def cutselselect(self, cuts, forcedcuts, root, maxnselectedcuts):
"""
Selects the 10 cuts with largest efficacy.
"""
scip = self.model
scores = [0] * len(cuts)
for i in range(len(scores)):
scores[i] = scip.getCutEfficacy(cuts[i])
rankings = sorted(range(len(cuts)), key=lambda x: scores[x], reverse=True)
sorted_cuts = [cuts[rank] for rank in rankings]
assert len(sorted_cuts) == len(cuts)
return {'cuts': sorted_cuts, 'nselectedcuts': min(maxnselectedcuts, len(cuts), 10),
'result': SCIP_RESULT.SUCCESS}
Things to Keep in Mind#
Here are some things to keep in mind when programming your own custom cut selector.
Do not change any of the actual cut information!
Do not reorder the
forcedcuts. They are provided as reference points to inform the selection process. They should not be edited or reordered.Only reorder
cuts. Do not add any new cuts.