具有多个索引变量的分段线性函数 Pyomo

问题描述 投票:0回答:1

我目前正在使用 Pyomo 模块的优化来对设施位置分配进行建模。对于我的模型,我想使用分段线性函数,约束变量有两个索引。我已经尝试了下面可以看到的三种方法,但它们似乎都不能正常工作(或有错误)

有人对如何解决这个问题有任何想法吗?

piece_wise = {'ab': {0:1,1:1,2:2}, 'cd': {0:1,1:1,2:3}, 'ef': {0:1,1:2,2:4}}
piece_wise_ab = {0:1,1:1,2:2}
piece_wise_cd = {0:1,1:1,2:3}
piece_wise_ef = {0:1,1:2,2:4}




################# Option 1 - not working 
model.y_ab = Var(model.Nodes, model.Vehicles,  within = NonNegativeIntegers, bounds = (0, max_chargers))
model.arriv_ab = Var(model.Nodes, model.Vehicles,  within = NonNegativeIntegers, bounds = (0, max_chargers))

model.y_cd = Var(model.Nodes, model.Vehicles,  within = NonNegativeIntegers, bounds = (0, max_chargers))
model.arriv_cd = Var(model.Nodes, model.Vehicles,  within = NonNegativeIntegers, bounds = (0, max_chargers))

model.y_ef = Var(model.Nodes, model.Vehicles,  within = NonNegativeIntegers, bounds = (0, max_chargers))
model.arriv_ef = Var(model.Nodes, model.Vehicles,  within = NonNegativeIntegers, bounds = (0, max_chargers))

model.piece_wise_ab = Piecewise(model.Nodes, model.Vehicles, model.arriv_ab, model.y_ab, 
                                pw_pts = list(piece_wise_ab.values()), f_rule = list(piece_wise_ab.keys()), pw_repn = 'SOS2', pw_constr_type='EQ',unbounded_domain_var=True)
        
model.piece_wise_cd = Piecewise(model.Nodes, model.Vehicles, model.arriv_cd, model.y_cd, 
                                pw_pts = list(piece_wise_cd.values()), f_rule = list(piece_wise_cd.keys()), pw_repn = 'SOS2', pw_constr_type='EQ',unbounded_domain_var=True)
        
model.piece_wise_ef = Piecewise(model.Nodes, model.Vehicles, model.arriv_cd, model.y_cd, 
                                pw_pts = list(piece_wise_ef.values()), f_rule = list(piece_wise_ef.keys()), pw_repn = 'SOS2', pw_constr_type='EQ',unbounded_domain_var=True)


def service_rule (model,i,veh):
    try:
        if 'ab' in veh:
            return sum(model.arrival [o,d,veh] * model.lam[i,o,d,veh]  for o,d in model.sp) <= model.y_ab[i]
        elif 'cd' in veh:
            return sum(model.arrival [o,d,veh] * model.lam[i,o,d,veh]  for o,d in model.sp) <= model.y_cd[i]
        elif 'ef' in veh:
            return sum(model.arrival [o,d,veh] * model.lam[i,o,d,veh]  for o,d in model.sp) <= model.y_ef[i]
    except:
        return Constraint.Skip

model.service = Constraint(model.Nodes, model.Vehicles, rule = service_rule)



#################################### Option 2 - not working
                                
model.piecewise_constraint = ConstraintList()

all_breakpoints = set(breakpoint for breakpoints in piece_wise.values() for breakpoint in breakpoints)

model.y_pc = Var(model.Nodes, model.Vehicles, within = NonNegativeIntegers, bounds = (0, max_chargers) )
model.arriv_pc = Var(model.Nodes, model.Vehicles, all_breakpoints,  within = Binary)

for veh in model.Vehicles:
    for node in model.Nodes:
        breakpoints = list(piece_wise[veh].keys())
        values_at_breakpoints = list(piece_wise[veh].values())

        print(breakpoints, all_breakpoints)

        model.piecewise_constraint.add(model.y_pc[node, veh] == sum(values_at_breakpoints[k] * model.arriv_pc[node, veh, k] for k in breakpoints))

 

############################## Option 3 - Not working
for node in model.Nodes:
    for veh in model.Vehicles:
        if "ab" in veh:

            model.piecewise_constraint.add (model.y_pc [node, veh] == Piecewise (expr = [(model.arriv_pc [node, veh], model.y_pc [node, veh])],
                                                                                pw_pts = list(piece_wise_ab.values()), f_rule = list(piece_wise_ab.keys()), pw_repn = 'SOS2',
                                                                                pw_constr_type='EQ',unbounded_domain_var=True))
        elif "cd" in veh:
            model.piecewise_constraint.add (model.y_pc [node, veh] == Piecewise (expr = model.arriv_pc [node, veh],
                                                                    pw_pts = list(piece_wise_cd.values()), f_rule = list(piece_wise_cd.keys()), pw_repn = 'SOS2',
                                                                    pw_constr_type='EQ',unbounded_domain_var=True))
        elif "ef" in veh:
            model.piecewise_constraint.add (model.y_pc [node, veh] == Piecewise (expr = model.arriv_pc [node, veh],
                                                        pw_pts = list(piece_wise_ef.values()), f_rule = list(piece_wise_ef.keys()), pw_repn = 'SOS2',
                                                        pw_constr_type='EQ',unbounded_domain_var=True))

提前谢谢您!

python runtime-error pyomo piecewise
1个回答
0
投票

这是一个在变量

x
y
之间建立分段线性约束的示例,这两个变量都是双索引变量。

您没有遵循位于here的 dox 来构造分段约束。具体请参阅 f_rule 的指导。

代码

from pyomo.environ import Objective, NonNegativeIntegers, ConcreteModel, Constraint, Var, Set, SolverFactory, \
    sum_product, maximize, Piecewise

m = ConcreteModel('piecewise_example')

piecewise_elements = {0: 1, 5: 2, 10: 20}

m.Nodes = Set(initialize=[1, 2, 3])
m.Vehicles = Set(initialize=['a81', 'b22', 'c43'])

m.x = Var(m.Nodes, m.Vehicles, domain=NonNegativeIntegers, bounds=(0, 10))
m.y = Var(m.Nodes, m.Vehicles, domain=NonNegativeIntegers)

# max the sum of m.y...
m.obj = Objective(expr=sum_product(m.y), sense=maximize)

# subset the "c" cars...
m.c_vehicles = Set(initialize=[v for v in m.Vehicles if 'c' in v])


# limit the x vals based on node
@m.Constraint(m.Nodes, m.Vehicles)
def x_limit(m, node, vehicle):
    if node == 1:
        return m.x[node, vehicle] <= 4
    return m.x[node, vehicle] <= 9


def limit_vals(model, node, vehicle, x_val):
    # per the dox, the limit function needs to catch the model and all indices, but does
    # not need to use them...
    return piecewise_elements[x_val]


m.pw_limit = Piecewise(
    m.Nodes,
    m.Vehicles,
    m.y,
    m.x,
    pw_pts=list(piecewise_elements.keys()),
    f_rule=limit_vals,
    pw_constr_type='UB')

m.pprint()

solver = SolverFactory('cbc')
res = solver.solve(m)

print(res)

for idx in m.x.index_set():
    print(idx, m.x[idx].value, m.y[idx].value)

部分输出:

(1, 'a81') 4.0 1.0
(1, 'b22') 4.0 1.0
(1, 'c43') 4.0 1.0
(2, 'a81') 9.0 16.0
(2, 'b22') 9.0 16.0
(2, 'c43') 9.0 16.0
(3, 'a81') 9.0 16.0
(3, 'b22') 9.0 16.0
(3, 'c43') 9.0 16.0
© www.soinside.com 2019 - 2024. All rights reserved.