How to save a complete solution of an already executed and solved model which allows to load next time without executing again?
AnsweredHello,
I am using gurobipy to solve a model. I would like to know if it is possible to save the executed result of a model as a whole, which can be loaded next time for result processing or for some modifications in the result display without having to solve the model again.
The current structure of the code is as follows:
model = gp.Model("name")
# add variables using
# varXXX = model.addVars(...)
# add constraints using
# model.addConstrs(...)
# add objective function using
# model.setObjective(...)
# conduct optimization
model.optimize()
# view the result
for v in model.getVars():
print(v.varName, v.x)
# or if we want to see some specific variables, we do
for v in model.getVars():
if ("xxx" in v.VarName):
print(v.varName, v.x)
For example, sometimes I would like to only view the values of the variables `a` and sometimes only `b`. In this case, the code for result output must be modified (e.g., from ```if ("a" in v.VarName)``` to `if ("b" in v.VarName)`).
Currently, after this modification for the output part in the code, I will have to execute the model again after modification to the output, which means the model is solved again from the beginning.
Is there any provided API in `gurobipy` like `model.save_solution_to_fille('xx')` to allow me to save the result of the optimization into a file named "xx", and next time, without executing the model again, I can directly call something like `sol = gp.load_solution_from_file('xx')` to load this solution into an object `sol` and manipulate on `sol` to view the results or conduct further analysis? (e.g., if I want to view `sol.varA`, I just `print(sol.varA)`, and next time I want to view `sol.varB`, I just do `print(sol.varB)`)
Thanks.
-
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,
Matthias0 -
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 viamodel.getAttr('Xn', var)
, it is reportedNo 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 -
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,
Matthias0 -
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 -
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 binaryimport 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 -
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 -
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.
Comments
7 comments