Search code examples
pythonmathematical-optimizationglpkpyomo

instantiate a concrete model from an abstract pyomo model


I'm trying to create an abstract model in Pyomo 5.1.1 and then populate it with values within python (i.e. not using the AMPL files). I'm basically following the Pyomo documentation example, but am getting "Constant objective detected".

import pyomo.environ as oe
model = oe.AbstractModel()
model.I = oe.Set()
model.J = oe.Set()
model.a = oe.Param(model.I,model.J)
model.b = oe.Param(model.I)
model.c = oe.Param(model.J)
model.x = oe.Var(model.J,domain=oe.NonNegativeReals)
def obj_expression(model):
    return oe.summation(model.c,model.x)

model.OBJ = oe.Objective(rule=obj_expression)
def ax_constraint_rule(model,i):
    return sum(model.a[i,j]*model.x[j] for j in model.J) >= model.b[i]

model.AxbConstraint = oe.Constraint(model.I,rule=ax_constraint_rule)

And then, I try to initialise this model with actual values

aa = np.array([[1,2,1,4],[5,2,2,4]])
bb = np.array([2,4])
cc = np.array([1,2,4,2])

cmodel = model.create_instance()
cmodel.a.values = aa
cmodel.b.values = bb
cmodel.c.values = cc

opt = oe.SolverFactory("glpk")
results = opt.solve(cmodel)

I get the following error:

WARNING:pyomo.core:Constant objective detected, replacing with a placeholder to prevent solver failure. WARNING:pyomo.core:Empty constraint block written in LP format - solver may error WARNING: Constant objective detected, replacing with a placeholder to prevent solver failure. WARNING: Empty constraint block written in LP format - solver may error

Evidently there's something wrong in the way I am initialising cmodel but I cannot find any documentation describing initialisation within python.


Solution

  • If you don't need to load your data from AMPL .dat files, I would recommend starting from a ConcreteModel. In that case, there is no need to store data into Param objects unless you need them to be mutable. Creation of Set objects for indexing components is still advised; otherwise, Set objects will be implicitly created with names that might clash with components you add to the model.

    By placing your ConcreteModel definition inside of a function that takes in data as input, you are essentially duplicating the functionality provided by AbstractModel and its create_instance method. E.g.,

    import pyomo.environ as oe
    
    def build_model(a, b, c):
        m = len(b)
        n = len(c)
        model = oe.ConcreteModel()
        model.I = oe.Set(initialize=range(m))
        model.J = oe.Set(initialize=range(n))
        model.x = oe.Var(model.J,domain=oe.NonNegativeReals)
    
        model.OBJ = oe.Objective(expr= oe.summation(c,model.x))
        def ax_constraint_rule(model,i):
            arow = a[i]
            return sum(arow[j]*model.x[j] for j in model.J) >= b[i]
        model.AxbConstraint = oe.Constraint(model.I,rule=ax_constraint_rule)
        return model
    
    # Note that there is no need to call create_instance on a ConcreteModel
    m = build_model(...)
    opt = oe.SolverFactory("glpk")
    results = opt.solve(m)
    

    Also, it is advisable to first convert all Numpy arrays to Python lists using the array.tolist() method before using them to build Pyomo expressions. Pyomo does not yet have the concept of array operations built into its expression system, and the use of Numpy arrays the way you are using them can be much slower than just using Python lists.