In Pyomo, Is it possible to write an objective function or a constraint based on several Expressions?

4.3k views Asked by At

I am quite new in Pyomo and I try to write the objective function and a constraint of my model by using several methods. Actually, I would like to construct the objective function/constraint based on several contributions of different object types implemented in different python scripts.

For doing this, I have used pyomo Expression objects. I don't know if this is the right object to use.

To illustrate my question, here is an example code implementing what I would like to do:

import pyomo.environ
model = pyomo.environ.ConcreteModel()

model.market = pyomo.environ.Set(initialize=['market'])

model.ask_price = pyomo.environ.Param(model.market, initialize={'market' : 12})
model.bid_price = pyomo.environ.Param(model.market, initialize={'market' : 10})
model.ask_liquidity = pyomo.environ.Param(model.market, initialize={'market' : 100})
model.bid_liquidity = pyomo.environ.Param(model.market, initialize={'market' : 100})

model.VOLUME_BUY = pyomo.environ.Var(model.market, within = pyomo.environ.NonNegativeReals)
model.VOLUME_SELL = pyomo.environ.Var(model.market, within = pyomo.environ.NonNegativeReals)

def max_buy(model, market):
    return model.VOLUME_BUY[market] <= model.ask_liquidity[market]

model.max_buy_equation = pyomo.environ.Constraint(model.market, rule=max_buy)

def max_sell(model, market):
    return model.VOLUME_SELL[market] <= model.bid_liquidity[market]

model.max_sell_equation = pyomo.environ.Constraint(model.market, rule=max_sell)

I then try to implement my objective function. If I try to implement it basically, everything works correctly:

def total_objective(model):
    return   sum(model.VOLUME_BUY[market] * model.ask_price[market] for market in model.market) \
           - sum(model.VOLUME_SELL[market] * model.bid_price[market] for market in model.market)

model.objective = pyomo.environ.Objective(rule=total_objective, sense=-1)

But if I try to use expression objects :

def objective_component1(model):
    return sum(model.VOLUME_BUY[market] * model.ask_price[market] for market in model.market)

model.obj_component1 = pyomo.environ.Expression(rule=objective_component1)

def objective_component2(model):
    return - sum(model.VOLUME_SELL[market] * model.bid_price[market] for market in model.market)

model.obj_component2 = pyomo.environ.Expression(rule=objective_component2)

model.objective = pyomo.environ.Objective(rule=model.obj_component1 + model.obj_component2, sense=-1)

I get an error :

ValueError: No value for uninitialized NumericValue object VOLUME_BUY[market]

I even try to write the expression as follows:

obj1 = sum(model.VOLUME_BUY[market] * model.ask_price[market] for market in model.market)
obj2 = - sum(model.VOLUME_SELL[market] * model.bid_price[market] for market in model.market)
model.objective = pyomo.environ.Objective(rule=obj1 + obj2, sense=-1)

But I get the same error.

I don't understand why I get a uninitialized error message for a variable object. Maybe the expression pyomo object is not the right object to use to construct my objective function ?

Note that I also want to construct the balance constraint of my model using different expressions and I don't manage to do it either.

I am using Python 2.7 and pyomo 4.4.1.

Thanks in advance for your help !

1

There are 1 answers

0
Gabe Hackebeil On BEST ANSWER

I believe the problem is that you are using the rule keyword to initialize the Objective object. You really only need to do this when starting from an AbstractModel (or when declaring an indexed component). Since Pyomo expressions are callable, it is not distinguishing what you are passing it from a standard function (so it calls it, expecting it to return an expression, but it actually just evaluates the expression).

Changing rule= to expr= should fix things.