pyomo似乎非常慢地编写模型

时间:2018-07-10 15:40:13

标签: pyomo

我有一个很大的模型(大约500万个变量和约束)。

构建时间为几分钟,求解时间也为几分钟(使用古罗比)

但是编写模型需要很长时间(大约2个小时)

这是我使用model.write('model.lp', io_options={'symbolic_solver_labels': True})进行录制的时间

如果我直接使用pyomo中的模型SolverFactorysolve,大约是同一时间

这里有一个小样本,我知道这个模型对于gurobi来说是微不足道的,所以我不在这里将求解时间与构建时间进行比较,但是我不明白为什么它这么长,尽管有这个问题可能是因为磁盘的写入速度所致,但似乎磁盘从未过载并且几乎没有被使用

import pyomo.environ as pyo
import time

size = 500000

model = pyo.ConcreteModel()
model.set = pyo.RangeSet(0, size)
model.x = pyo.Var(model.set, within=pyo.Reals)
model.constrList = pyo.ConstraintList()
for i in range(size):
    model.constrList.add(expr = model.x[i] >= 1)
model.obj = pyo.Objective(expr=sum(model.x[i] for i in range(size)), sense=pyo.minimize)

opt = pyo.SolverFactory('gurobi')

_time = time.time()
res = opt.solve(model)
print(">>> total time () in {:.2f}s".format(time.time() - _time))

print(res)

结果是整个求解函数的时间为27 s,而古罗比的求解时间仅为4 s。

3 个答案:

答案 0 :(得分:1)

我认为您的隐性问题是“我怎样才能使其更快?”

如果写入时间有问题,您可以研究与Gurobi SolverFactory('gurobi', io_format='python')的直接python接口。将symbolic_solver_labels标志设置为True几乎总是会增加模型的写入时间,因为查找组件名称可能会很昂贵。

答案 1 :(得分:1)

从加快pyomo模型生成的速度出发,您需要首先确定该过程的哪一部分正在减慢它的速度。 (这实际上是性能调整的一般建议)

所以我将您的代码放入一个函数中

def main():
    size = 500000

    model = pyo.ConcreteModel()
    model.set = pyo.RangeSet(0, size)
    model.x = pyo.Var(model.set, within=pyo.Reals)
    model.constrList = pyo.ConstraintList()
    for i in range(size):
        model.constrList.add(expr = model.x[i] >= 1)
    model.obj = pyo.Objective(expr=sum(model.x[i] for i in range(size)), sense=pyo.minimize)
    return model

所以我可以在ipython中通过行探查器运行

In [1]: %load_ext line_profiler                                                                                                                                                                         

In [2]: import test_pyo                                                                                                                                                                                 

In [3]: %lprun -f test_pyo.main test_pyo.main()

这表明大部分时间都花在 model.constrList.add(expr = model.x [i]> = 1)中。

通过将其移至基于规则的约束中并没有看到太大的改进,因此我决定尝试像PyPSA code中一样手动构造表达式。

import pyomo.environ as pyo
import time
from pyomo.core.expr.numeric_expr import LinearExpression
from pyomo.core.base.constraint import _GeneralConstraintData
from pyomo.core.base.numvalue import NumericConstant

def main():
    size = 500000

    model = pyo.ConcreteModel()
    model.set = pyo.RangeSet(0, size)
    model.x = pyo.Var(model.set, within=pyo.Reals)
    setattr(model, "constraint", pyo.Constraint(model.set, noruleinit=True))
    v = getattr(model, "constraint")
    for i in v._index:
        v._data[i] = _GeneralConstraintData(None, v)
        expr = LinearExpression()
        expr.linear_vars = [model.x[i]]
        expr.linear_coefs = [1]
        expr.constant = 0
        v._data[i]._body = expr
        v._data[i]._equality = False
        v._data[i]._lower = NumericConstant(1)
        v._data[i]._upper = None

    model.obj = pyo.Objective(expr=pyo.quicksum(model.x[i] for i in range(size)), sense=pyo.minimize)
    return model

似乎可以提高约50%的性能。线剖析器显示,现在花费大量时间来创建集合,空的LinearExpression对象以及创建目标。摆弄目标也许可以使事情有所改善。

答案 2 :(得分:0)

也值得检查您是否安装了最新版本的pyomo。我最近从5.5.0版更新到5.6.8版,看到构建+解决时间从5s减少到1s(这个问题显然比您的要小得多!)。