Below is a simple Pyomo script using the decorator syntax - I would like to understand how to use this syntax within a class - in this case inside Model.
None-class version
from pyomo.environ import *
import random
random.seed(1000)
model = AbstractModel()
model.N = Param(within=PositiveIntegers)
model.P = Param(within=RangeSet(1, model.N))
model.M = Param(within=PositiveIntegers)
model.Locations = RangeSet(1, model.N)
model.Customers = RangeSet(1, model.M)
model.d = Param(
model.Locations,
model.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
within=Reals,
)
model.x = Var(model.Locations, model.Customers, bounds=(0.0, 1.0))
model.y = Var(model.Locations, within=Binary)
@model.Objective()
def obj(model):
return sum(
model.d[n, m] * model.x[n, m] for n in model.Locations for m in model.Customers
)
@model.Constraint(model.Customers)
def single_x(model, m):
return (sum(model.x[n, m] for n in model.Locations), 1.0)
@model.Constraint(model.Locations, model.Customers)
def bound_y(model, n, m):
return model.x[n, m] - model.y[n] <= 0.0
@model.Constraint()
def num_facilities(model):
return sum(model.y[n] for n in model.Locations) == model.P
Decorator version within a class that doesn't work:
from pyomo.environ import *
import random
random.seed(1000)
class Model:
def __init__(self):
self.model = AbstractModel()
self.model.N = Param(within=PositiveIntegers)
self.model.P = Param(within=RangeSet(1, self.model.N))
self.model.M = Param(within=PositiveIntegers)
self.model.Locations = RangeSet(1, self.model.N)
self.model.Customers = RangeSet(1, self.model.M)
self.model.d = Param(
self.model.Locations,
self.model.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
within=Reals,
)
self.model.x = Var(
self.model.Locations, self.model.Customers, bounds=(0.0, 1.0)
)
self.model.y = Var(self.model.Locations, within=Binary)
@model.Objective()
def obj(model):
return sum(
model.d[n, m] * model.x[n, m]
for n in model.Locations
for m in model.Customers
)
@model.Constraint(model.Customers)
def single_x(model, m):
return (sum(model.x[n, m] for n in model.Locations), 1.0)
@model.Constraint(model.Locations, model.Customers)
def bound_y(model, n, m):
return model.x[n, m] - model.y[n] <= 0.0
@model.Constraint()
def num_facilities(model):
return sum(model.y[n] for n in model.Locations) == model.P
I'm not able to help you on this, I just have a few qustions:
__init__ method?I guess what I'm missing is the benefit of using a class in the first place. If you are just trying to wrap the model construction somehow, then a better approach is using a function:
def create_model():
model = AbstractModel()
...
@model.Constraint()
def some_rule_function(model):
...
...
return model
EDIT: if you really want to wrap everything into a class:
class Model:
def __init__(self, model):
self.model = model
# alternative constructor:
# def __init__(self):
# self.model = create_model()
def construct(self, data):
# get concrete model
self.model = self.model.create_instance(data)
def run(self, solver, **kwargs):
with pe.SolverFactory(solver) as solver:
solver.solve(self.model, **kwargs)
def construct_and_run(self, data, solver, **kwargs):
self.construct(data)
self.data(solver, **kwargs)
# other behavior you want to add to the class
example usage:
model = Model(create_model())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With