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):
141class DefaultScipSolver(ScipSolver):
142    """
143    Default scip solver.
144    Solve the instances based on the given scip parameters.
145    """
146    def __init__(self, branching_strategy, *args, **kwargs):
147        """
148        Parameters
149        ----------
150        branching_strategy : str
151            Branching strategy to use. Must be a default SCIP strategy, or a strategy included in the Model using
152            the configure callback
153        args :
154            Arguments to build the parent class ScipSolver
155        kwargs :
156            Arguments to build the parent class ScipSolver
157        """
158        super().__init__(*args, **kwargs)
159        self.branching_strategy = branching_strategy
160        self.state = (
161            [branching_strategy, *args],
162            kwargs
163        )
164
165    def build_model(self):
166        super().build_model()
167        self.model.setParam(f"branching/{self.branching_strategy}/priority", 9999999)
168
169
170    def solve(self, instance: str):
171        self.build_model()
172        self.model.readProblem(instance)
173        self.model.optimize()
174
175    def __getstate__(self):
176        return self.state
177
178    def __setstate__(self, state):
179        self.__init__(*state[0], **state[1])
180
181    def __str__(self):
182        return self.branching_strategy

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

DefaultScipSolver(branching_strategy, *args, **kwargs)
146    def __init__(self, branching_strategy, *args, **kwargs):
147        """
148        Parameters
149        ----------
150        branching_strategy : str
151            Branching strategy to use. Must be a default SCIP strategy, or a strategy included in the Model using
152            the configure callback
153        args :
154            Arguments to build the parent class ScipSolver
155        kwargs :
156            Arguments to build the parent class ScipSolver
157        """
158        super().__init__(*args, **kwargs)
159        self.branching_strategy = branching_strategy
160        self.state = (
161            [branching_strategy, *args],
162            kwargs
163        )
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):
165    def build_model(self):
166        super().build_model()
167        self.model.setParam(f"branching/{self.branching_strategy}/priority", 9999999)
def solve(self, instance: str):
170    def solve(self, instance: str):
171        self.build_model()
172        self.model.readProblem(instance)
173        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
13    def __init__(self):
14        self.seed = 0
15
16
17    def seed(self, seed):
18        """
19        Seed used by the underground solver.
20        Parameters
21        ----------
22        seed : int
23            The new seed
24        """
25        self.seed = seed
26
27    @abstractmethod
28    def solve(self, instance: str):
29        """
30        Solves a instancse that is a file
31        Parameters
32        ----------
33        instance : str
34            Path to the instance
35        """
36        raise NotImplementedError("Subclasses must implement this method.")
37
38    def solve_model(self, model: Model):
39        """
40        Solve directly a pyscipopt model.
41        Can work even if the underlying solver is not SCIP, as it only write the corresponding problem to a file in
42        order to use the method solve
43        Parameters
44        ----------
45        model : Model
46            model to solve.
47        """
48        model.setParam("display/verblevel", 0)
49        prob_file = tempfile.NamedTemporaryFile(suffix=".lp")
50        model.writeProblem(prob_file.name, verbose=False)
51
52        self.solve(prob_file.name)
53        prob_file.close()
54
55    @abstractmethod
56    def __getitem__(self, item: str) -> float:
57        """
58        Get an attribute from the solver after a solving process.
59
60        Parameters
61        ----------
62        item : str
63            Name of the attribute to get. Depends on the subtype of the solver.
64
65        Returns
66        -------
67        Value of the attribute.
68        """
69        raise NotImplementedError("Subclasses must implement this method.")

An abstract base class for solvers.

def seed(self, seed):
17    def seed(self, seed):
18        """
19        Seed used by the underground solver.
20        Parameters
21        ----------
22        seed : int
23            The new seed
24        """
25        self.seed = seed

Seed used by the underground solver.

Parameters
  • seed (int): The new seed
@abstractmethod
def solve(self, instance: str):
27    @abstractmethod
28    def solve(self, instance: str):
29        """
30        Solves a instancse that is a file
31        Parameters
32        ----------
33        instance : str
34            Path to the instance
35        """
36        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):
38    def solve_model(self, model: Model):
39        """
40        Solve directly a pyscipopt model.
41        Can work even if the underlying solver is not SCIP, as it only write the corresponding problem to a file in
42        order to use the method solve
43        Parameters
44        ----------
45        model : Model
46            model to solve.
47        """
48        model.setParam("display/verblevel", 0)
49        prob_file = tempfile.NamedTemporaryFile(suffix=".lp")
50        model.writeProblem(prob_file.name, verbose=False)
51
52        self.solve(prob_file.name)
53        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):
 71class ScipSolver(Solver):
 72    def __init__(self, scip_params: dict = None, configure: Callable[[Model], None] = None):
 73        """
 74        Parameters
 75        ----------
 76        scip_params : dict, optional
 77            Dictionary of parameters to pass to the scip solver.
 78        configure :  Callable[[Model], None], optional
 79            Callback function to configure the solver (e.g. add branching strategies, ...)
 80        """
 81        super().__init__()
 82        self.scip_params = scip_params or {}
 83        self.configure = configure
 84        self.model = None
 85
 86    def build_model(self):
 87        self.model = Model()
 88        self.set_params(self.scip_params)
 89        if self.configure is not None:
 90            self.configure(self.model)
 91        self.model.setParam("display/verblevel", 0)
 92        self.model.setParam("randomization/randomseedshift", self.seed)
 93
 94    def set_params(self, params):
 95        self.scip_params = params
 96
 97    def __getitem__(self, item: str) -> float:
 98        """
 99        Get an attribute from the solver after a solving process.
100
101        Parameters
102        ----------
103        item : str
104            Name of the attribute to get. Either:
105                time: time in seconds used by the solver
106                nnodes: number of nodes used by the solver
107                obj: Final objective value
108                sol: Best solution found
109                estimate_nnodes: Estimated number of nodes used by the solver to go to optimality
110
111        Returns
112        -------
113        Value of the attribute.
114        """
115        match item:
116            case "time":
117                return self.model.getSolvingTime()
118            case "nnodes":
119                # return self.model.getNNodes()
120                return self.model.getNTotalNodes()
121            case "obj":
122                return self.model.getObjVal()
123            case "gap":
124                return self.model.getGap()
125            case "sol":
126                return self.model.getBestSol()
127            case "estimate_nnodes":
128                if self.model.getGap() == 0:
129                    return self["nnodes"]
130                else:
131                    return self.model.getTreesizeEstimation()
132            case _:
133                raise KeyError
134
135    def __getstate__(self):
136        return self.scip_params, self.configure
137
138    def __setstate__(self, state):
139        self.__init__(*state)

An abstract base class for solvers.

ScipSolver( scip_params: dict = None, configure: Callable[[pyscipopt.scip.Model], NoneType] = None)
72    def __init__(self, scip_params: dict = None, configure: Callable[[Model], None] = None):
73        """
74        Parameters
75        ----------
76        scip_params : dict, optional
77            Dictionary of parameters to pass to the scip solver.
78        configure :  Callable[[Model], None], optional
79            Callback function to configure the solver (e.g. add branching strategies, ...)
80        """
81        super().__init__()
82        self.scip_params = scip_params or {}
83        self.configure = configure
84        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):
86    def build_model(self):
87        self.model = Model()
88        self.set_params(self.scip_params)
89        if self.configure is not None:
90            self.configure(self.model)
91        self.model.setParam("display/verblevel", 0)
92        self.model.setParam("randomization/randomseedshift", self.seed)
def set_params(self, params):
94    def set_params(self, params):
95        self.scip_params = params