Frozen Solve#

In rare cases, the GAMS model generation time dominates the solver solution time and GAMS itself becomes the bottleneck in an optimization application. For a model instance which is a single mathematical model generated by a GAMS solve statement, frozen solve provides a controlled way of modifying a model instance and solving the resulting problem in the most efficient way, by communicating only the changes of the model to the solver and doing a hot start (in case of a continuous model like LP) without the use of disk IO.

The freeze call will enable the frozen solve mode and query the symbol information of the modifiable symbols. The solve method uses this data to update the model instance. After the model instance has been updated, the model is passed to the selected solver. After the completion of the solve method, the container will contain the primal and dual solution of the model just solved. Moreover, the parameters that are modifiable are also accessible in database with the name of the GamsParameter plus “_var”. The Marginal of this GamsVariable can provide sensitivity information about the parameter setting. The status of the solve is accessible through the model_status and solver_status properties.

m = Container()

# Prepare data
distances = [
    ["seattle", "new-york", 2.5],
    ["seattle", "chicago", 1.7],
    ["seattle", "topeka", 1.8],
    ["san-diego", "new-york", 2.5],
    ["san-diego", "chicago", 1.8],
    ["san-diego", "topeka", 1.4],
]

capacities = [["seattle", 350], ["san-diego", 600]]
demands = [["new-york", 325], ["chicago", 300], ["topeka", 275]]

# Set
i = Set(m, name="i", records=["seattle", "san-diego"])
j = Set(m, name="j", records=["new-york", "chicago", "topeka"])

# Data
a = Parameter(m, name="a", domain=[i], records=capacities)
b = Parameter(m, name="b", domain=[j], records=demands)
d = Parameter(m, name="d", domain=[i, j], records=distances)
c = Parameter(m, name="c", domain=[i, j])
bmult = Parameter(m, name="bmult", records=1)
c[i, j] = 90 * d[i, j] / 1000

# Variable
x = Variable(m, name="x", domain=[i, j], type="Positive")
z = Variable(m, name="z")

# Equation
cost = Equation(m, name="cost")
supply = Equation(m, name="supply", domain=[i])
demand = Equation(m, name="demand", domain=[j])

cost[...] = z == Sum((i, j), c[i, j] * x[i, j])
supply[i] = Sum(j, x[i, j]) <= a[i]
demand[j] = Sum(i, x[i, j]) >= bmult * b[j]

transport = Model(
    m,
    name="transport",
    equations=m.getEquations(),
    problem="LP",
    sense=Sense.MIN,
    objective=z,
)

bmult_list = [0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3]

transport.freeze(modifiables=[bmult])

for b_value in bmult_list:
    bmult.setRecords(b_value)
    transport.solve(model_instance_options={"solver": "conopt"})
    print(z.records.level)

transport.unfreeze()