Setting up Branching Priority for GUROBI in Pyomo (Attention: Richard from OR Stackexchange)
AnsweredWith reference to our prior conversation (https://support.gurobi.com/hc/en-us/community/posts/4402982080785-Setting-up-Branching-Priority-for-GUROBI-in-Pyomo-Attention-RIchard-from-OR-Stackexchange-), I have attempted to paste the code given by you into pyomo_direct.py as below.
From comments located on top of the code, it seems that there is no mention of support for the 'InputFile' Option. I am hazarding a guess that this might be the cause of 'No parameters matching 'InputFile' found' statement by Pyomo.
May I ask if you have any other suggestions?
Thank you.
Yours sincerely,
Mike
# Options accepted by gurobi (case insensitive):
# ['Cutoff', 'IterationLimit', 'NodeLimit', 'SolutionLimit', 'TimeLimit',
# 'FeasibilityTol', 'IntFeasTol', 'MarkowitzTol', 'MIPGap', 'MIPGapAbs',
# 'OptimalityTol', 'PSDTol', 'Method', 'PerturbValue', 'ObjScale', 'ScaleFlag',
# 'SimplexPricing', 'Quad', 'NormAdjust', 'BarIterLimit', 'BarConvTol',
# 'BarCorrectors', 'BarOrder', 'Crossover', 'CrossoverBasis', 'BranchDir',
# 'Heuristics', 'MinRelNodes', 'MIPFocus', 'NodefileStart', 'NodefileDir',
# 'NodeMethod', 'PumpPasses', 'RINS', 'SolutionNumber', 'SubMIPNodes', 'Symmetry',
# 'VarBranch', 'Cuts', 'CutPasses', 'CliqueCuts', 'CoverCuts', 'CutAggPasses',
# 'FlowCoverCuts', 'FlowPathCuts', 'GomoryPasses', 'GUBCoverCuts', 'ImpliedCuts',
# 'MIPSepCuts', 'MIRCuts', 'NetworkCuts', 'SubMIPCuts', 'ZeroHalfCuts', 'ModKCuts',
# 'Aggregate', 'AggFill', 'PreDual', 'DisplayInterval', 'IISMethod', 'InfUnbdInfo',
# 'LogFile', 'PreCrush', 'PreDepRow', 'PreMIQPMethod', 'PrePasses', 'Presolve',
# 'ResultFile', 'ImproveStartTime', 'ImproveStartGap', 'Threads', 'Dummy', 'OutputFlag']
for key, option in self.options.items():
# When options come from the pyomo command, all
# values are string types, so we try to cast
# them to a numeric value in the event that
# setting the parameter fails.
try:
self._solver_model.setParam(key, option)
except TypeError:
# we place the exception handling for
# checking the cast of option to a float in
# another function so that we can simply
# call raise here instead of except
# TypeError as e / raise e, because the
# latter does not preserve the Gurobi stack
# trace
if not _is_numeric(option):
raise
self._solver_model.setParam(key, float(option))
except TypeError:
if key == "InputFile":
self._solver_model.read(option)
continue
-
Official comment
This post is more than three years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum. Or why not try our AI Gurobot?. -
Try moving the special handling of the InputFile parameter before Pyomo calls Model.setParam() in the \( \texttt{try} \) clause of GurobiDirect._apply_solver(). We also want to call Model.update() so the model's variable names are up-to-date:
for key, option in self.options.items():
# When options come from the pyomo command, all
# values are string types, so we try to cast
# them to a numeric value in the event that
# setting the parameter fails.
if key.lower() == 'inputfile':
self._solver_model.update()
self._solver_model.read(option)
continue
try:
self._solver_model.setParam(key, option)
except TypeError:
# we place the exception handling for
# checking the cast of option to a float in
# another function so that we can simply
# call raise here instead of except
# TypeError as e / raise e, because the
# latter does not preserve the Gurobi stack
# trace
if not _is_numeric(option):
raise
self._solver_model.setParam(key, float(option))With these changes, I could successfully direct Pyomo to read an ORD file with the code \( \texttt{solver.options['InputFile'] = 'test.ord'} \):
Read branching order from file test.ord
1 -
Dear Eli, thank you for your help. Unfortunately, it does not seem to be working as pyomo still returns the prior error messages regarding the missing parameters.
0 -
How did you install Pyomo? The approach I described should work if you install a local version of Pyomo in editable mode:
git clone https://github.com/Pyomo/pyomo.git
cd pyomo
python -m pip install -e .After installing Pyomo this way, modify \( \texttt{pyomo/pyomo/solvers/plugins/solvers/gurobi_direct.py} \) to include the four lines I mentioned:
if key.lower() == 'inputfile':
self._solver_model.update()
self._solver_model.read(option)
continueThen, try to use the InputFile parameter through Pyomo.
If this doesn't resolve the issue, try adding some \( \texttt{print()} \) function calls to \( \texttt{gurobi_direct.py} \) to make sure your changes to the Pyomo codebase are reflected in your Python environment. If this also doesn't help, please post a log from your terminal or command prompt that shows you downloading Pyomo, installing Pyomo into your Python environment in editable mode, then running a script that sets the InputFile parameter from Pyomo.
0 -
I installed it via the standard anaconda prompt window.
I have also used the print() function to print out the option, but nothing came out except for the error message. Thank you.
if key.lower() == 'inputfile':
print(option)
self._solver_model.update()
self._solver_model.read(option)
continue1 -
Since you are using conda, I recommend the following approach to install a local version of Pyomo in editable mode. When you do this, changes you make to the Pyomo codebase on your local filesystem will be immediately reflected in the version of Pyomo installed in your conda environment.
First, create a new conda environment that includes Gurobi and \( \texttt{pip} \), then activate the new environment:
conda create -n mypyomo python=3.8.10 gurobi pip
conda activate mypyomoNext, clone the Pyomo GitHub repository:
git clone https://github.com/Pyomo/pyomo
Finally, install this local version of Pyomo into your conda environment:
cd pyomo
python -m pip install -e .Now, you should be able to modify \( \texttt{pyomo/pyomo/solvers/plugins/solvers/gurobi_direct.py} \) like we discussed and use the InputFile parameter from Pyomo to read an ORD file. Note that you should be using Pyomo's direct Gurobi interface:
# Important: use direct Gurobi interface
opt = SolverFactory('gurobi', solver_io='python')
opt.options['InputFile'] = 'test.ord'
# Pass intelligible variable/constraint names to Gurobi
results = opt.solve(model, tee=True, symbolic_solver_labels=False)If this doesn't work, please post (i) a log from your Anaconda Prompt that shows you sequentially running all of the above commands, and (ii) a simplified version of your Python script.
0 -
Dear Eli,
It worked after I switched the opt object to invoke 'gurobi_direct.py'.
opt = SolverFactory('gurobi_direct')
I guess it was pointing to the wrong file previously when I merely used
opt = SolverFactory('gurobi')
I am now however facing a new problem as Gurobi is complaining that it is unable to locate the decision variables within the ord file
Unknown variable 'gamma' in priority file - ignored
Unknown variable 'selection' in priority file - ignoredThe contents of the ord file are reproduced as follows:
gamma 2
selection 1Thank you.
0 -
Dear Eli,
As gamma and selection are variables with 3-tuple indices, may I confirm if that is the reason why both are not being read?
If so, I would ask if there is any way to ensure that the entire set of gamma and selection decision variables are being read using an abbreviated command?
Or do I need to explicitly list them out individually within the said ORD file? If so, may I ask how do I list them out in accordance with Gurobi's convention?
Thank you.
0 -
Or do I need to explicitly list them out individually within the said ORD file?
Yes, you will have to provide the branching priority values for each individual variable. There is unfortunately no way to set the branching priorities for multiple variables in a single line using an ORD file.
If so, may I ask how do I list them out in accordance with Gurobi's convention?
Pyomo is choosing the names for the variables and passing them to Gurobi. As far as I can tell, a variable \( \texttt{x} \) indexed by the tuple \( \texttt{(1,2,3)} \) would be named \( \texttt{x(1_2_3)} \) by Pyomo. You can check how Pyomo names your variables by writing out an LP model file using Pyomo's built-in LP file writer:
model.write('model.lp', io_options={'symbolic_solver_labels': True})
Setting branching priorities is complex in Pyomo because it is not directly supported. This is much easier to do with Gurobi's native Python interface. You can directly set the BranchPriority attribute on the Var objects you create without worrying about name mappings. Here is one way to set branching priorities in Gurobi's supported Python interface:
import gurobipy as gp
from gurobipy import GRB
m = gp.Model()
x = m.addVars(3, 4, 5, vtype=GRB.BINARY, name='x')
m.setAttr('BranchPriority', x, 1)0 -
Hi Eli,
This thread has been of great help for me while implementing the same process, however, I am running into an issue where I get the following in the output, "Unknown variable 'foo[i,j]' in priority file - ignored". I make the .ord file using a for loop in python which appends "foo[i,j] k" to the .ord file (where k is the priority). Can you help me with this error. Thank you.
0 -
An easier way to set branching priorities through Pyomo is to use Pyomo's GurobiPersistent interface and directly set the BranchPriority attributes for the underlying \(\texttt{gurobipy}\) Var objects. For example:
import pyomo.environ as pyo
model = pyo.ConcreteModel()
model.x = pyo.Var([1, 2, 3], domain=pyo.Binary)
# Important: use persistent Gurobi interface
opt = pyo.SolverFactory("gurobi_persistent", model=model)
for i in model.x:
# Get gurobipy Var object
v = opt._pyomo_var_to_solver_var_map[model.x[i]]
# Set BranchPriority attribute
v.BranchPriority = i
opt.solve()0 -
Thank you Eli for the help. This works really well.
0
Post is closed for comments.
Comments
12 comments