You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pyomo 5.7.3及以上版本AbstractModel依赖组件实例化失败问题

Pyomo 5.7.3+中用Param定义RangeSet报错的解决办法

问题重现

以下代码在Pyomo 5.7.0可正常运行,但升级到5.7.3及以上版本时,构造time_steps集合会抛出ValueError: Error retrieving immutable Param value (battery.n_time_steps):

import pyomo.environ as pyo

def test_param_pyomo5_7():
    def create_battery():
        block = pyo.Block()
        block.n_time_steps = pyo.Param(within=pyo.NonNegativeIntegers, doc='Number of time steps')
        block.time_steps = pyo.RangeSet(1, block.n_time_steps, doc='Time steps')
        return block

    def create_model() -> pyo.AbstractModel:
        model = pyo.AbstractModel()
        model.battery = create_battery()
        return model

    data = {
        None: {
            'battery': {
                'n_time_steps': {None: 24},
            },
        }
    }
    
    model = create_model()
    instance = model.create_instance(data=data)

完整报错回溯:

..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:697: in create_instance
    instance.load( data,
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:734: in load
    self._load_model_data(dp,
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:787: in _load_model_data
    self._initialize_component(modeldata, namespaces, component_name, profile_memory)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:825: in _initialize_component
    declaration.construct(data)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\block.py:2207: in construct
    obj.construct(data.get(name, None))
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\disable_methods.py:116: in construct
    return base.construct(self, data)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\set.py:2792: in construct
    args = tuple(value(arg) for arg in args)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\set.py:2792: in <genexpr>
    args = tuple(value(arg) for arg in args)
pyomo\core\expr\numvalue.pyx:153: in pyomo.core.expr.numvalue.value
    ???
pyomo\core\expr\numvalue.pyx:138: in pyomo.core.expr.numvalue.value
    ???
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\param.py:853: in __call__
    return self[None]
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\indexed_component.py:577: in __getitem__
    return self._getitem_when_not_present(index)

问题原因

Pyomo 5.7.3版本调整了组件构造的执行顺序:创建实例时,RangeSet会提前触发构造逻辑,尝试立即解析传入的上限参数block.n_time_steps,但此时这个Param还未从数据字典中加载具体值,导致访问未初始化的不可变Param报错。而5.7.0版本中RangeSet的构造会延迟到Param加载完成后执行,因此不会触发错误。

解决方案

方案1:用Lambda表达式延迟Param值的获取

修改RangeSet的定义,用lambda表达式延迟对Param值的读取,确保构造时Param已经完成数据加载:

def create_battery():
    block = pyo.Block()
    block.n_time_steps = pyo.Param(within=pyo.NonNegativeIntegers, doc='Number of time steps')
    # 使用lambda延迟获取Param的值,直到构造阶段Param已初始化
    block.time_steps = pyo.RangeSet(1, lambda m: m.n_time_steps, doc='Time steps')
    return block

方案2:重写Block的construct方法,手动控制构造顺序

通过自定义Block的construct方法,在Param加载完成后再创建time_steps集合:

def create_battery():
    block = pyo.Block()
    block.n_time_steps = pyo.Param(within=pyo.NonNegativeIntegers, doc='Number of time steps')
    
    # 自定义构造逻辑,确保先加载Param再创建集合
    def _construct_block(block_data):
        # 此时n_time_steps已经从数据中获取到值
        block_data.time_steps = pyo.RangeSet(1, block_data.n_time_steps, doc='Time steps')
    
    block.construct = _construct_block
    return block

两种方案都能确保time_steps集合在n_time_steps Param完成数据初始化后再构造,避免访问未初始化的Param导致的报错。

内容的提问来源于stack exchange,提问作者phaebz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:35:18