pyomo seems very slow to write models

人走茶凉 提交于 2019-12-08 08:40:31

From my trails with speeding up pyomo model generation you need to benchmark first what part of the process is slowing it down. (Which is really a general advice for perfomance tuning)

so I put you code into a function:

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

so I can run in through the line profiler in ipython:

In [1]: %load_ext line_profiler                                                                                                                                                                         

In [2]: import test_pyo                                                                                                                                                                                 

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

which shows that most of the time is spent in model.constrList.add(expr = model.x[i] >= 1).

I did not see much improvement by moving this into a rule based constraint so I decided to try to construct the expression by hand, like in the 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

which seems to yield about 50% performance improvement. The line profiler shows that a lot of time is now spend in creating the set, the empty LinearExpression object, and also in creating the objective. It might be that fiddling with the objective might improve things a little more.

I think that your implicit question is "How can I make this faster?"

If write time is a problem, you might look into the direct python interface to Gurobi SolverFactory('gurobi', io_format='python'). Setting the symbolic_solver_labels flag to True will almost always increase the write time of the model, because component name lookups can be expensive.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!