Обновление RHS и LHS конкретных ограничений в Gurobi и Python - PullRequest
0 голосов
/ 22 октября 2019

Используя gurobi и python, я пытаюсь решить водный баланс (аналогично классической транспортной задаче) задачи линейного программирования в виде:

свернуть c'x с учетом:

Ax = b

lb <= x <= ub </p>

A, L - это разреженные матрицы crs scipy, c, b, lb, ub - векторы.

Моя проблема должнабыть обновлен для ряда шагов, и некоторые элементы обновлены с новыми значениями. В частности, A является фиксированным, и все остальные элементы получают новые значения на каждом шаге. Следующий фрагмент отлично работает и является основой, которую я использовал до сих пор (игнорируйте «self», поскольку модель встроена в класс решателя, а «water_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) почему это происходит? замена getConstrs()[i] на getConstrByName('A'+str(i)) также завершается с той же ошибкой. Как обновить RHS / LHS конкретного ограничения?

2) Есть ли способ более эффективно обновить RHS для ограничений, содержащихся в списке self.EqualityConstraintA, а затем LHS для других ограничений, содержащихся всписок self.EqualityConstraintL?

Большое спасибо заранее!

Di

1 Ответ

1 голос
/ 22 октября 2019

Функция setAttr на объекте модели предназначена для

  • глобальных настроек атрибутов на модели
  • атрибутов для списка переменных
  • атрибутов настроекдля списка ограничений

Отдельные объекты ограничений и переменных имеют свои собственные функции setAttr для установки атрибутов для отдельных переменных и ограничений. В вашем случае,

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

, который можно заменить на более питонический (и, вероятно, более эффективный)

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