在Gurobi和Python中更新特定约束的RHS和LHS

2024-06-25 06:13:07 发布

您现在位置:Python中文网/ 问答频道 /正文

使用gurobi和python,我试图解决水平衡(类似于经典的运输问题)线性规划问题,形式如下:

将c'x最小化,前提是:

轴=b

lb<;=x<;=ub

A,L是稀疏crs-scipy矩阵,c,b,lb,ub是向量。你知道吗

我的问题应该更新一些步骤,一些元素会用新值更新。具体来说,A是固定的,所有其他元素在每一步都会得到新的值。下面的代码片段工作得很好,是我迄今为止使用的基础(忽略“self”,因为模型嵌入在解算器类中,而“water\u network是保存每个步骤的值和属性的图形对象):

### Snippet 1: Formulating/initializing the problem
# unitC is the c vector
# Bounds holds both lb and ub values for each x

self.model = gurobipy.Model()
rows, cols = len(self.water_network.node_list), len(self.water_network.edge_name_list)
self.x1 = []
for j in range(cols):
    self.x1.append(self.model.addVar(lb=self.water_network.Bounds[j,0], ub=self.water_network.Bounds[j,1],obj=self.water_network.unitC[j]))
self.model.update()

self.EqualityConstraintA=[]
for i in range(rows):
    start = self.water_network.A_sparse.indptr[i]
    end = self.water_network.A_sparse.indptr[i+1]
    variables = [self.x1[j] for j in self.water_network.A_sparse.indices[start:end]]
    coeff = self.water_network.A_sparse.data[start:end]
    expr = gurobipy.LinExpr(coeff, variables)
    self.EqualityConstraintA.append(self.model.addConstr(lhs=expr, sense=gurobipy.GRB.EQUAL, rhs=self.water_network.b [i],name='A'+str(i)))

self.model.update()
self.model.ModelSense = 1
self.model.optimize()

下面的简单代码段用于在每个步骤更新问题。注意:我使用getConstrs函数:

#### Snippet 2: Updating the constraints, working ok for every step. 

self.model.setAttr("LB",self.model.getVars(), self.water_network.Bounds[:,0])
self.model.setAttr("UB", self.model.getVars(), self.water_network.Bounds[:,1])
self.model.setAttr("OBJ", self.model.getVars(), self.water_network.unitC)
self.model.setAttr("RHS", self.model.getConstrs(),self.water_network.b)

当一组新的约束应以以下形式添加到问题中时,会出现问题:

Lx=0,其中L是每一步更新的稀疏矩阵!现在在公式中,我在片段1之后添加了以下内容:

self.EqualityConstraintL=[]
leakrows= len(self.water_network.ZeroVector)
for i in range(leakrows):
    start = self.water_network.L_sparse.indptr[i]
    end=self.water_network.L_sparse.indptr[i+1]
    variables=[self.x1[j] for j in self.water_network.L_sparse.indices[start:end]]
    coeff=self.water_network.L_sparse.data[start:end]
    expr = gurobipy.LinExpr(coeff, variables)
    self.EqualityConstraintL.append(self.model.addConstr(lhs=expr, sense=gurobipy.GRB.EQUAL, rhs=self.water_network.ZeroVector[i],name='L'+str(i)))

但是,我不能再使用getConstrs一次更新所有约束,因为有些约束只需要更改RHS,而有些约束只需要更改LHS。因此,我为更新做了以下操作(代码段3):

self.model.setAttr("LB",self.model.getVars(), self.water_network.Bounds[:,0])
self.model.setAttr("UB", self.model.getVars(), self.water_network.Bounds[:,1])
self.model.setAttr("OBJ", self.model.getVars(), self.water_network.unitC)
# Update A rhs...
for i in range(len(self.water_network.edge_name_list)):
    self.model.setAttr("RHS", self.model.getConstrs()[i],self.water_network.b[i])

# Update L expr...
x1=self.model.getVars()
n=len(self.water_network.node_list) # because there are n rows in the A constrains, and L constraints are added after

# Now i rebuild the LHS expressions
for i in range(len(self.water_network.ZeroVector)):
    start = self.water_network.L_sparse.indptr[i]
    end=self.water_network.L_sparse.indptr[i+1]
    variables=[x1[j] for j in self.water_network.L_sparse.indices[start:end]]
    coeff=self.water_network.L_sparse.data[start:end]
    expr = gurobipy.LinExpr(coeff, variables)
    self.model.setAttr("LHS",self.model.getConstrs()[n+i],expr)

self.model.update()
self.model.optimize()

当我运行该问题时,它会很好地初始化,但在第二步,它会返回以下错误:

File "model.pxi", line 1709, in gurobipy.Model.setAttr

TypeError: object of type 'Constr' has no len()

冒犯的是:

self.model.setAttr("RHS", self.model.getConstrs()[i],self.water_network.b[i])

两个问题:1)为什么会这样?用getConstrByName('A'+str(i))替换getConstrs()[i]也会失败,并出现完全相同的错误。如何更新特定约束的右/左?你知道吗

2)有没有办法更有效地更新RHS中包含的约束自平衡约束然后列出包含在自平衡约束列表?你知道吗

非常感谢!你知道吗

Di公司


Tags: inselfformodellennetworkstartend
1条回答
网友
1楼 · 发布于 2024-06-25 06:13:07

model对象上的setAttr函数用于

  • 在模型上全局设置属性
  • 设置变量列表的属性
  • 为约束列表设置属性

单个约束和变量对象有自己的setAttr函数来设置单个变量和约束的属性。就你而言

for i in range(len(self.water_network.edge_name_list)):
    self.model.getConstrs()[i].setAttr('RHS', self.water_network.b[i])

可以用更pythonic(可能更有效)的

m = self.model
constrs = m.getConstrs()[:len(self.water_network.edge_name_list)]
m.setAttr('RHS', constrs, self.water_network.b)

相关问题 更多 >