Edit on GitHub

boundml.solvers

1from .solvers import DefaultScipSolver, Solver, ScipSolver
2from .modular_solver import ModularSolver
3
4__all__ = ["DefaultScipSolver", "ModularSolver", "Solver", "ScipSolver"]
class DefaultScipSolver(boundml.solvers.ScipSolver):
125class DefaultScipSolver(ScipSolver):
126    """
127    Default scip solver.
128    Solve the instances based on the given scip parameters.
129    """
130    def __init__(self, branching_strategy, *args, **kwargs):
131        """
132        Parameters
133        ----------
134        branching_strategy : str
135            Branching strategy to use. Must be a default SCIP strategy, or a strategy included in the Model using
136            the configure callback
137        args :
138            Arguments to build the parent class ScipSolver
139        kwargs :
140            Arguments to build the parent class ScipSolver
141        """
142        super().__init__(*args, **kwargs)
143        self.branching_strategy = branching_strategy
144        self.state = (
145            [branching_strategy, *args],
146            kwargs
147        )
148
149    def build_model(self):
150        super().build_model()
151        self.model.setParam(f"branching/{self.branching_strategy}/priority", 9999999)
152
153
154    def solve(self, instance: str):
155        self.build_model()
156        self.model.readProblem(instance)
157        self.model.optimize()
158
159    def __getstate__(self):
160        return self.state
161
162    def __setstate__(self, state):
163        self.__init__(*state[0], **state[1])
164
165    def __str__(self):
166        return self.branching_strategy

Default scip solver. Solve the instances based on the given scip parameters.

DefaultScipSolver(branching_strategy, *args, **kwargs)
130    def __init__(self, branching_strategy, *args, **kwargs):
131        """
132        Parameters
133        ----------
134        branching_strategy : str
135            Branching strategy to use. Must be a default SCIP strategy, or a strategy included in the Model using
136            the configure callback
137        args :
138            Arguments to build the parent class ScipSolver
139        kwargs :
140            Arguments to build the parent class ScipSolver
141        """
142        super().__init__(*args, **kwargs)
143        self.branching_strategy = branching_strategy
144        self.state = (
145            [branching_strategy, *args],
146            kwargs
147        )
Parameters
  • branching_strategy (str): Branching strategy to use. Must be a default SCIP strategy, or a strategy included in the Model using the configure callback
  • args :: Arguments to build the parent class ScipSolver
  • kwargs :: Arguments to build the parent class ScipSolver
branching_strategy
state
def build_model(self):
149    def build_model(self):
150        super().build_model()
151        self.model.setParam(f"branching/{self.branching_strategy}/priority", 9999999)
def solve(self, instance: str):
154    def solve(self, instance: str):
155        self.build_model()
156        self.model.readProblem(instance)
157        self.model.optimize()

Solves a instancse that is a file

Parameters
  • instance (str): Path to the instance
class ModularSolver(boundml.solvers.ScipSolver):
12class ModularSolver(ScipSolver):
13    """
14    A ModularSolver is  ScipSolver that is parametrized with a list of Component
15    """
16
17    def __init__(self, *components: Component, scip_params = None, configure: Callable[[Model], None] = None):
18        """
19        Parameters
20        ----------
21        components : [Component]
22             List of components that parametrized the solver. During a solving process, they are called depending on
23             their subtypes (e.g. BranchingComponent are called before making a branching strategy). If several
24             components have the same subtypes, they are called in the order they are given. Only the first component
25             of each subtype is allowed to perform an action (with passive=False). The other must remain passive.
26        scip_params : dict, optional
27            Dictionary of parameters to pass to the scip solver.
28        configure :  Callable[[Model], None], optional
29            Callback function to configure the solver (e.g. add branching strategies, ...)
30        """
31        super().__init__(scip_params, configure)
32
33        self.components = ComponentList(list(components))
34        self.branching_components = []
35
36        for component in components:
37            if isinstance(component, BranchingComponent):
38                self.branching_components.append(component)
39
40
41
42    def build_model(self):
43        super().build_model()
44        branchrule = BoundmlBranchrule(self.model, self.branching_components)
45        self.model.includeBranchrule(
46            branchrule,
47            "boundml",
48            "Custom branching rule for ModularSolver",
49            priority=10000000,
50            maxdepth=-1,
51            maxbounddist=1
52        )
53
54    def solve(self, instance: str):
55        self.build_model()
56
57        self.model.readProblem(instance)
58
59        self.components.reset(self.model)
60
61        self.model.optimize()
62
63        self.components.done(self.model)
64
65    def __getstate__(self):
66        return (self.components, self.scip_params, self.configure)
67
68    def __setstate__(self, state):
69        self.__init__(*state[0], scip_params=state[1], configure=state[2])
70
71    def __str__(self):
72        return "+".join([str(c) for c in self.components])

A ModularSolver is ScipSolver that is parametrized with a list of Component

ModularSolver( *components: boundml.components.Component, scip_params=None, configure: Callable[[pyscipopt.scip.Model], NoneType] = None)
17    def __init__(self, *components: Component, scip_params = None, configure: Callable[[Model], None] = None):
18        """
19        Parameters
20        ----------
21        components : [Component]
22             List of components that parametrized the solver. During a solving process, they are called depending on
23             their subtypes (e.g. BranchingComponent are called before making a branching strategy). If several
24             components have the same subtypes, they are called in the order they are given. Only the first component
25             of each subtype is allowed to perform an action (with passive=False). The other must remain passive.
26        scip_params : dict, optional
27            Dictionary of parameters to pass to the scip solver.
28        configure :  Callable[[Model], None], optional
29            Callback function to configure the solver (e.g. add branching strategies, ...)
30        """
31        super().__init__(scip_params, configure)
32
33        self.components = ComponentList(list(components))
34        self.branching_components = []
35
36        for component in components:
37            if isinstance(component, BranchingComponent):
38                self.branching_components.append(component)
Parameters
  • components ([Component]): List of components that parametrized the solver. During a solving process, they are called depending on their subtypes (e.g. BranchingComponent are called before making a branching strategy). If several components have the same subtypes, they are called in the order they are given. Only the first component of each subtype is allowed to perform an action (with passive=False). The other must remain passive.
  • scip_params (dict, optional): Dictionary of parameters to pass to the scip solver.
  • configure (Callable[[Model], None], optional): Callback function to configure the solver (e.g. add branching strategies, ...)
components
branching_components
def build_model(self):
42    def build_model(self):
43        super().build_model()
44        branchrule = BoundmlBranchrule(self.model, self.branching_components)
45        self.model.includeBranchrule(
46            branchrule,
47            "boundml",
48            "Custom branching rule for ModularSolver",
49            priority=10000000,
50            maxdepth=-1,
51            maxbounddist=1
52        )
def solve(self, instance: str):
54    def solve(self, instance: str):
55        self.build_model()
56
57        self.model.readProblem(instance)
58
59        self.components.reset(self.model)
60
61        self.model.optimize()
62
63        self.components.done(self.model)

Solves a instancse that is a file

Parameters
  • instance (str): Path to the instance
class Solver(abc.ABC):
 8class Solver(ABC):
 9    """
10    An abstract base class for solvers.
11    """
12    @abstractmethod
13    def solve(self, instance: str):
14        """
15        Solves a instancse that is a file
16        Parameters
17        ----------
18        instance : str
19            Path to the instance
20        """
21        raise NotImplementedError("Subclasses must implement this method.")
22
23    def solve_model(self, model: Model):
24        """
25        Solve directly a pyscipopt model.
26        Can work even if the underlying solver is not SCIP, as it only write the corresponding problem to a file in
27        order to use the method solve
28        Parameters
29        ----------
30        model : Model
31            model to solve.
32        """
33        model.setParam("display/verblevel", 0)
34        prob_file = tempfile.NamedTemporaryFile(suffix=".lp")
35        model.writeProblem(prob_file.name, verbose=False)
36
37        self.solve(prob_file.name)
38        prob_file.close()
39
40    @abstractmethod
41    def __getitem__(self, item: str) -> float:
42        """
43        Get an attribute from the solver after a solving process.
44
45        Parameters
46        ----------
47        item : str
48            Name of the attribute to get. Depends on the subtype of the solver.
49
50        Returns
51        -------
52        Value of the attribute.
53        """
54        raise NotImplementedError("Subclasses must implement this method.")

An abstract base class for solvers.

@abstractmethod
def solve(self, instance: str):
12    @abstractmethod
13    def solve(self, instance: str):
14        """
15        Solves a instancse that is a file
16        Parameters
17        ----------
18        instance : str
19            Path to the instance
20        """
21        raise NotImplementedError("Subclasses must implement this method.")

Solves a instancse that is a file

Parameters
  • instance (str): Path to the instance
def solve_model(self, model: pyscipopt.scip.Model):
23    def solve_model(self, model: Model):
24        """
25        Solve directly a pyscipopt model.
26        Can work even if the underlying solver is not SCIP, as it only write the corresponding problem to a file in
27        order to use the method solve
28        Parameters
29        ----------
30        model : Model
31            model to solve.
32        """
33        model.setParam("display/verblevel", 0)
34        prob_file = tempfile.NamedTemporaryFile(suffix=".lp")
35        model.writeProblem(prob_file.name, verbose=False)
36
37        self.solve(prob_file.name)
38        prob_file.close()

Solve directly a pyscipopt model. Can work even if the underlying solver is not SCIP, as it only write the corresponding problem to a file in order to use the method solve

Parameters
  • model (Model): model to solve.
class ScipSolver(boundml.solvers.Solver):
 56class ScipSolver(Solver):
 57    def __init__(self, scip_params: dict = None, configure: Callable[[Model], None] = None):
 58        """
 59        Parameters
 60        ----------
 61        scip_params : dict, optional
 62            Dictionary of parameters to pass to the scip solver.
 63        configure :  Callable[[Model], None], optional
 64            Callback function to configure the solver (e.g. add branching strategies, ...)
 65        """
 66        self.scip_params = scip_params or {}
 67        self.configure = configure
 68        self.model = None
 69
 70    def build_model(self):
 71        self.model = Model()
 72        self.set_params(self.scip_params)
 73        if self.configure is not None:
 74            self.configure(self.model)
 75        self.model.setParam("display/verblevel", 0)
 76
 77    def set_params(self, params):
 78        self.scip_params = params
 79        self.model.setParams(self.scip_params)
 80
 81    def __getitem__(self, item: str) -> float:
 82        """
 83        Get an attribute from the solver after a solving process.
 84
 85        Parameters
 86        ----------
 87        item : str
 88            Name of the attribute to get. Either:
 89                time: time in seconds used by the solver
 90                nnodes: number of nodes used by the solver
 91                obj: Final objective value
 92                sol: Best solution found
 93                estimate_nnodes: Estimated number of nodes used by the solver to go to optimality
 94
 95        Returns
 96        -------
 97        Value of the attribute.
 98        """
 99        match item:
100            case "time":
101                return self.model.getSolvingTime()
102            case "nnodes":
103                # return self.model.getNNodes()
104                return self.model.getNTotalNodes()
105            case "obj":
106                return self.model.getObjVal()
107            case "gap":
108                return self.model.getGap()
109            case "sol":
110                return self.model.getBestSol()
111            case "estimate_nnodes":
112                if self.model.getGap() == 0:
113                    return self["nnodes"]
114                else:
115                    return self.model.getTreesizeEstimation()
116            case _:
117                raise KeyError
118
119    def __getstate__(self):
120        return self.scip_params, self.configure
121
122    def __setstate__(self, state):
123        self.__init__(*state)

An abstract base class for solvers.

ScipSolver( scip_params: dict = None, configure: Callable[[pyscipopt.scip.Model], NoneType] = None)
57    def __init__(self, scip_params: dict = None, configure: Callable[[Model], None] = None):
58        """
59        Parameters
60        ----------
61        scip_params : dict, optional
62            Dictionary of parameters to pass to the scip solver.
63        configure :  Callable[[Model], None], optional
64            Callback function to configure the solver (e.g. add branching strategies, ...)
65        """
66        self.scip_params = scip_params or {}
67        self.configure = configure
68        self.model = None
Parameters
  • scip_params (dict, optional): Dictionary of parameters to pass to the scip solver.
  • configure (Callable[[Model], None], optional): Callback function to configure the solver (e.g. add branching strategies, ...)
scip_params
configure
model
def build_model(self):
70    def build_model(self):
71        self.model = Model()
72        self.set_params(self.scip_params)
73        if self.configure is not None:
74            self.configure(self.model)
75        self.model.setParam("display/verblevel", 0)
def set_params(self, params):
77    def set_params(self, params):
78        self.scip_params = params
79        self.model.setParams(self.scip_params)