Setting solver parameters and hyperparameter search
Calling a solver by name
You can see the list of available solvers (and subsolvers) as follows:
from cpmpy import *
print(SolverLookup.solvernames())
On my system, with pysat and minizinc installed, this gives `[‘ortools’, ‘minizinc’, ‘minizinc:chuffed’, ‘minizinc:coin-bc’, …, ‘pysat:minicard’, ‘pysat:minisat22’, ‘pysat:minisat-gh’]
You can use any of these solvers by passing its name to the Model.solve()
parameter ‘solver’ as such:
a,b = boolvar(2)
Model(a|b).solve(solver='minizinc:chuffed')
Setting solver parameters
OR-tools has many solver parameters, documented here.
CPMpy’s interface to ortools accepts keyword arguments to solve()
, and will set the corresponding or-tools parameters if the name matches. We documented some of the frequent once in our CPM_ortools API.
For example, with model
a CPMpy Model(), you can do the following to make or-tools use 8 parallel cores and print search progress:
from cpmpy import *
from cpmpy.solvers import CPM_ortools
s = CPM_ortools(model)
s.solve(num_search_workers=8, log_search_progress=True)
Hyperparameter search across different parameters
Because CPMpy offers programmatic access to the solver API, hyperparameter search can be straightforwardly done with little overhead between the calls.
The tools directory contains a utility to efficiently search through the hyperparameter space defined by the solvers tunable_params
.
This utlity is based on the SMBO framework and speeds up the search by implementing adaptive capping.
The parameter tuner is based on the following publication:
Ignace Bleukx, Senne Berden, Lize Coenen, Nicholas Decleyre, Tias Guns (2022). Model-Based Algorithm Configuration with Adaptive Capping and Prior Distributions. In: Schaus, P. (eds) Integration of Constraint Programming, Artificial Intelligence, and Operations Research. CPAIOR 2022. Lecture Notes in Computer Science, vol 13292. Springer, Cham. https://doi.org/10.1007/978-3-031-08011-1_6
In the following example, we tune the OR-tools solver.
from cpmpy import *
from cpmpy.tools import ParameterTuner
model = Model(...)
tuner = ParameterTuner("ortools", model)
best_params = tuner.tune(max_tries=100)
print(f"Tuner reduced runtime from {tuner.base_runtime}s to {tuner.best_runtime}s")
# now solve (a slightly different?) model using the best parameters
solver = SolverLookup.get("ortools", model)
solver.solve(**best_params)
However, solverinterfaces are not required to present a list of tunable parameters and the tool allows you to define the set of tunable parameters (and values) yourself.
from cpmpy import *
from cpmpy.tools import ParameterTuner
model = Model(...)
tunables ={
"MIPFocus": [0,1,2,3],
"Method" : [-1, 0, 1,2,3,4,5],
"FlowCoverCuts" :[-1,0,1,2]
}
defaults = {
"MIPFocus": 0,
"Method": -1,
"FlowCoverCuts": -1
}
tuner = ParameterTuner("gurobi", model, tunables, defaults)
print(f"Tuner reduced runtime from {tuner.base_runtime}s to {tuner.best_runtime}s")
best_params = tuner.tune(time_limit=10)
solver = SolverLookup.get("gurobi", model)
solver.solve(**best_params)