[英]How to use Pyomo decorator within a class
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
.下面是一个使用装饰器语法的简单 Pyomo 脚本——我想了解如何在类中使用这种语法——在本例中是在
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?__init__
方法中的函数吗? 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())
Trying to answer your direct question, here's something that seems to work for me.试图回答您的直接问题,这似乎对我有用。 My interpretation is that since your model is called
self.model
, the decorators should also match that.我的解释是,由于您的模型称为
self.model
,因此装饰器也应该与之匹配。
Note that I used s
as the first argument in the constraint method definitions just to see if it worked, but it could also be model
or whatever you want to call it.请注意,我将
s
用作约束方法定义中的第一个参数只是为了查看它是否有效,但它也可以是model
或任何您想调用的参数。
class Model:
def __init__(self):
self.model = pyo.AbstractModel()
self.model.N = pyo.Param(initialize=5, within=pyo.PositiveIntegers)
self.model.P = pyo.Param(initialize=3, within=pyo.RangeSet(1, self.model.N))
self.model.M = pyo.Param(initialize=3, within=pyo.PositiveIntegers)
self.model.Locations = pyo.RangeSet(1, self.model.N)
self.model.Customers = pyo.RangeSet(1, self.model.M)
self.model.d = pyo.Param(
self.model.Locations,
self.model.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
within=pyo.Reals,
)
self.model.x = pyo.Var(
self.model.Locations, self.model.Customers, bounds=(0.0, 1.0)
)
self.model.y = pyo.Var(self.model.Locations, within=pyo.Binary)
@self.model.Objective()
def obj(s):
return sum(
s.d[n, m] * s.x[n, m]
for n in s.Locations
for m in s.Customers
)
@self.model.Constraint(self.model.Customers)
def single_x(s, m):
return (sum(s.x[n, m] for n in s.Locations), 1.0)
@self.model.Constraint(self.model.Locations, self.model.Customers)
def bound_y(s, n, m):
return s.x[n, m] - s.y[n] <= 0.0
@self.model.Constraint()
def num_facilities(s):
return sum(s.y[n] for n in s.Locations) == s.P
You would then be able to instantiate the model with model = Model()
, though annoyingly (at least to me), all your Pyomo model components will be within the attribute model.model
(eg, model.model.P
).然后你就可以用
model = Model()
实例化模型,尽管很烦人(至少对我来说),你所有的 Pyomo 模型组件都将在属性model.model
(例如, model.model.P
)。
What I've done before to make the naming cleaner is to inherit from AbstractModel (though the other answer suggests that may not be good practice):为了使命名更清晰,我之前所做的是从 AbstractModel 继承(尽管另一个答案表明这可能不是好的做法):
from pyomo.core.base.PyomoModel import AbstractModel
class Model(AbstractModel):
def __init__(self):
AbstractModel.__init__(self)
self.N = pyo.Param(initialize=5, within=pyo.PositiveIntegers)
self.P = pyo.Param(initialize=3, within=pyo.RangeSet(1, self.N))
self.M = pyo.Param(initialize=3, within=pyo.PositiveIntegers)
self.Locations = pyo.RangeSet(1, self.N)
self.Customers = pyo.RangeSet(1, self.M)
self.d = pyo.Param(
self.Locations,
self.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
within=pyo.Reals,
)
self.x = pyo.Var(
self.Locations, self.Customers, bounds=(0.0, 1.0)
)
self.y = pyo.Var(self.Locations, within=pyo.Binary)
@self.Objective()
def obj(s):
return sum(
s.d[n, m] * s.x[n, m]
for n in s.Locations
for m in s.Customers
)
@self.Constraint(self.Customers)
def single_x(s, m):
return (sum(s.x[n, m] for n in s.Locations), 1.0)
@self.Constraint(self.Locations, self.Customers)
def bound_y(s, n, m):
return s.x[n, m] - s.y[n] <= 0.0
@self.Constraint()
def num_facilities(s):
return sum(s.y[n] for n in s.Locations) == s.P
In this case, you still instantiate as model = Model()
but your Pyomo model components can be accessed as model.P
.在这种情况下,您仍然实例化为
model = Model()
但您的 Pyomo 模型组件可以作为model.P
访问。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.