Skip to main content

Setting up Branching Priority for GUROBI in Pyomo (Attention: Richard from OR Stackexchange)

Answered

Comments

11 comments

  • Eli Towle
    Gurobi Staff Gurobi Staff

    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
  • Che Han Lim
    Gurobi-versary
    Conversationalist
    First Question

    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
  • Eli Towle
    Gurobi Staff Gurobi Staff

    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)
    continue

    Then, 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
  • Che Han Lim
    Gurobi-versary
    Conversationalist
    First Question

    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)
              continue
    1
  • Eli Towle
    Gurobi Staff Gurobi Staff

    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 mypyomo

    Next, 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
  • Che Han Lim
    Gurobi-versary
    Conversationalist
    First Question

    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 - ignored

    The contents of the ord file are reproduced as follows:

    gamma 2
    selection 1

    Thank you.

    0
  • Che Han Lim
    Gurobi-versary
    Conversationalist
    First Question

    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
  • Eli Towle
    Gurobi Staff Gurobi Staff

    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
  • Javal Vyas
    First Comment

    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
  • Eli Towle
    Gurobi Staff Gurobi Staff

    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
  • Javal Vyas
    First Comment

    Thank you Eli for the help. This works really well. 

    0

Please sign in to leave a comment.