Skip to main content

How to save a complete solution of an already executed and solved model which allows to load next time without executing again?

Answered

Comments

7 comments

  • Matthias Miltenberger
    Gurobi Staff Gurobi Staff

    Hi Runqui,

    The simplest way is to store the solution in the SOL format. Then, you can get whatever solution value you need without running Gurobi again. Saving the computed solution to a SOL file is considered best practice even if you don't right away need all solution values.

    You can generate a SOL file on the command line using

    gurobi_cl ResultFile=model.sol model.lp

    or you call any of the API methods that write a SOL file, e.g., Model.write().

    Cheers,
    Matthias

    0
  • Runqiu Hu
    Conversationalist
    Curious
    Gurobi-versary

    Thanks Matthias.

    Actually, I've tried using the SOL file with codes in another post.

    gv = m.getVars()
    names = m.getAttr('VarName', gv)
    for i in range(m.SolCount):
    m.params.SolutionNumber = i
    xn = m.getAttr('Xn', gv)
    lines = ["{} {}".format(v1, v2) for v1, v2 in zip(names, xn)]
    with open('{}_{}.sol'.format(m.ModelName, i), 'w') as f:
    f.write("# Solution for model {}\n".format(m.modelName))
    f.write("# Objective value = {}\n".format(m.PoolObjVal))
    f.write("\n".join(lines))

    And I indeed got the variables and the values in a structured format.

     

    # Solution for model brp_demo
    # Objective value = 0.0
    visit_truck[0,0,0,0] 1.0
    visit_truck[0,0,1,0] 1.0
    visit_truck[0,0,2,0] -0.0
    visit_truck[0,0,3,0] -0.0
    visit_truck[0,0,4,0] -0.0
    visit_truck[0,0,5,0] -0.0
    visit_truck[0,0,6,0] -0.0
    visit_truck[0,0,7,0] -0.0
    ... ...

    However,

    Then I called model.read(xx.sol) in a new program, and tried to get the variable values via model.getAttr('Xn', var), it is reported No variable names available to index.

    import gurobipy as gp
    
    model = gp.Model()
    model.read("../brp_demo_0.sol")
    x = model.getVars()
    model.getAttr('Xn', x)

    So the question is how do I load the solution for further analysis? Does gurobipy have a built-in parser for SOL files so that I can normally call APIs of the class Model just like I solve it at the beginning? Or do I have to manually write a parser to get what I want?

    0
  • Matthias Miltenberger
    Gurobi Staff Gurobi Staff

    You seem to be making this more complicated than it is. You can store all solutions in the solution pool like this:

    for i in range(model.SolCount):
    model.Params.SolutionNumber = i
    model.write(f"{i}.sol")

    Then, to read in a solution, you just do

    model.read("model.sol")

    You don't have to handle every single value manually.

    Please note that you should only read in the best solution found before.

    Best regards,
    Matthias

    0
  • Runqiu Hu
    Conversationalist
    Curious
    Gurobi-versary

    I'll summarize the steps below of my method on saving the model and read solutions directly without taking long time to run again.

    1. create a model m

    2. add variables, set objectives and constraints for m using m.addVars(), m.setObjective() and m.addConstrs(), respectively.

    3. solve model m with m.optimize()

    4. save the results with m.write(<filename.sol>)

    5. create a new model m1

    6. add same variables as m for m1, using m1.addVars(), and then update with m1.update()
    [ps: actually m1.optimize() should contain m1.update(). However, by testing, without m1.update() here would cause error]

    7. read the solution from <filename.sol> by calling m1.read(<filename.sol>)

    8. execute model m1 by calling m1.optimize(), this could take nearly no time to solve as all values are given.

    9. get the values with m1.getVars()

    An example can be found below in the reply to the post of Ashutosh Shukla or this link.

    0
  • Ashutosh Shukla
    Gurobi-versary
    First Question
    First Comment

    Hi 

    I am stuck in the same problem. Below is the toy example I am trying to run and getting an error message : "

    AttributeError: Unable to retrieve attribute 'X'

    my code:

    #!/usr/bin/env python3.7

    # Copyright 2022, Gurobi Optimization, LLC

    # This example formulates and solves the following simple MIP model:
    #  maximize
    #        x +   y + 2 z
    #  subject to
    #        x + 2 y + 3 z <= 4
    #        x +   y       >= 1
    #        x, y, z binary

    import gurobipy as gp
    from gurobipy import GRB

    # Create a new model
    m = gp.Model("mip1")

    # Create variables
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")
    z = m.addVar(vtype=GRB.BINARY, name="z")

    # Set objective
    m.setObjective(x + y + 2 * z, GRB.MAXIMIZE)

    # Add constraint: x + 2 y + 3 z <= 4
    m.addConstr(x + 2 * y + 3 * z <= 4, "c0")

    # Add constraint: x + y >= 1
    m.addConstr(x + y >= 1, "c1")

    # Optimize model
    m.optimize()

    for v in m.getVars():
        print('%s %g' % (v.VarName, v.X))

    print('Obj: %g' % m.ObjVal)

    m.write("test.sol")

    # Create a new model
    m = gp.Model("mip1")

    # Create variables
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")
    z = m.addVar(vtype=GRB.BINARY, name="z")

    m.update()
    m.read("test.sol")

    for v in m.getVars():
        print('%s %g' % (v.VarName, v.X))

    0
  • Runqiu Hu
    Conversationalist
    Curious
    Gurobi-versary

    Hello, Shukla,

    Actually, you just have to call m.optimize() after m.read(). I tested your code, and can obtain the result now.

    Sorry for my misleading in the previous post on "removing the model.optimize()". Actually, the idea is solving another model with constraints that forces all the values of variables being equal to the ones given in the sol file. Therefore, you still need to call optimize() to solve the model, and retrieve the value by "getVars()".

    The complete code:

    The results:

    Hope that helps.

    Thank you!

    Runqiu

    0
  • Ashutosh Shukla
    Gurobi-versary
    First Question
    First Comment

    Hi Runqui

    Thank you for your response. In the meantime, with the help of my colleague, I also discovered something interesting. When you read the solution from a .sol file, they are used to start the optimization process. So if you do not wish to solve the optimization problem again and extract those values, you can use Start attribute as well. Below is a sample code to do so.

    Thank you again :)

    import gurobipy as gp
    from gurobipy import GRB

    # Create a new model
    m = gp.Model("mip1")

    # Create variables
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")
    z = m.addVar(vtype=GRB.BINARY, name="z")

    # Set objective
    m.setObjective(x + y + 2 * z, GRB.MAXIMIZE)

    # Add constraint: x + 2 y + 3 z <= 4
    m.addConstr(x + 2 * y + 3 * z <= 4, "c0")

    # Add constraint: x + y >= 1
    m.addConstr(x + y >= 1, "c1")

    # Optimize model
    m.optimize()

    for v in m.getVars():
        print('%s %g' % (v.VarName, v.X))

    print('Obj: %g' % m.ObjVal)

    print("\n\n\n\n")

    m.write("test.sol")

    # Create a new model
    m = gp.Model("mip1")

    # Create variables
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")
    z = m.addVar(vtype=GRB.BINARY, name="z")

    m.update()
    m.read("test.sol")
    for v in m.getVars():
        print('%s %g' % (v.VarName, v.Start))
    2

Please sign in to leave a comment.