Search code examples
pyomo

efficient update of objective function in pyomo (for re-solving)


I have a model that I need to solve many times, with different objective function coefficients. Naturally, I want to spend as little time as possible on updating the model. My current setup is as follows (simplified):

Abstract model:

def obj_rule(m):
    return sum(Dist[m, n] * m.flow[m,n] for (m,n) in m.From * m.To)
m.obj = Objective(rule=obj_rule, sense=minimize)

After solve, I update the concrete model instance mi this way, we new values in Dist:

mi.obj = sum(Dist[m, n] * mi.flow[m,n] for (m,n) in mi.From * mi.To)

However, I see that the update line takes a lot of time - ca. 1/4 of the overall solution time, several seconds for bigger cases. Is there some faster way of updating the objective function? (After all, in the usual way of saving an LP model, the objective function coefficients are in a separate vector, so changing them should not affect anything else.)


Solution

  • Do you have a reason to define an Abstract model before creating your Concrete model? If you define your concrete model with the rule you show above, you should be able to just update your data and re-solve the model without a lot of overhead since you do don't redefine the objective object. Here's a simple example where I change the values of the cost parameter and re-solve.

    import pyomo.environ as pyo
    a = list(range(2)) # set the variables define over
    
    #%% Begin basic model
    model = pyo.ConcreteModel()
    model.c = pyo.Param(a,initialize={0:5,1:3},mutable=True)
    
    model.x = pyo.Var(a,domain = pyo.Binary)
    model.con = pyo.Constraint(expr=model.x[0] + model.x[1] <= 1)
    
    def obj_rule(model):
        return(sum(model.x[ind] * model.c[ind] for ind in a))
    
    model.obj = pyo.Objective(rule=obj_rule,sense=pyo.maximize)
    
    #%% Solve the first time
    solver = pyo.SolverFactory('glpk')
    
    res=solver.solve(model)
    print('x[0]: {} \nx[1]: {}'.format(pyo.value(model.x[0]),
                                       pyo.value(model.x[1])))
    # x[0]: 1
    # x[1]: 0
          
    
    #%% Update data and re-solve
    model.c.reconstruct({0:0,1:5})
    
    res=solver.solve(model)
    print('x[0]: {} \nx[1]: {}'.format(pyo.value(model.x[0]),
                                       pyo.value(model.x[1])))
    # x[0]: 0
    # x[1]: 1