Pyomo中基于初始化集合定义二维参数及索引错误解决
问题描述
我有一个二维列表s:
s = [ [0,0,9,6,8,1,6,2,3,9], [0,0,0,3,1,1,2,5,7,8], [3,10,0,2,6,4,0,4,8,3], [7,10,10,0,9,0,2,3,10,7], [1,10,8,9,0,9,6,6,8,8], [1,1,9,8,5,0,5,7,10,0], [3,2,2,6,7,1,0,6,0,6], [7,1,0,5,5,7,5,0,9,6], [10,5,7,3,0,10,1,4,0,7], [10,4,6,0,9,1,3,10,6,0] ]
需要将其转换为Pyomo参数,用于以下约束方程:
start[i] + p[i] + s[i,j] >= start[j] for all i,j in J: i < j
尝试用以下代码定义参数时触发错误:
m.PAIRS_1 = Set(initialize = m.J * m.J, dimen=2, filter=lambda m, j, k : j < k) m.setup = Param(initialize = m.PAIRS_1, default = s)
错误信息:
KeyError: "Cannot treat the scalar component 'setup' as an indexed component"
我的模型主函数结构如下:
def schedule_machines(A, B): # create model m = ConcreteModel() # index set to simplify notation m.J = Set(initialize=JOBS.keys()) m.PAIRS_1 = Set(initialize = m.J * m.J, dimen=2, filter=lambda m, j, k : j < k) def s_initializer(m, i, j): return s[i][j] m.setup = Param(m.J, m.J, initialize=s_initializer) # decision variables .... # for binary assignment ... # optimization model ... # SolverFactory() ... return SCHEDULE SCHEDULE = schedule_machines(A,B)
所有数据定义在主函数外部,求解决方法。
错误原因与解决方法
错误根源
你定义Param的写法存在两个核心问题:
- 未指定索引集就直接用
initialize=m.PAIRS_1,导致setup被识别为标量参数,但你实际需要的是可通过(i,j)索引的二维参数。 - 用
default=s完全错误,default是给未初始化的索引对设置默认值,不能直接传入二维列表。
正确实现方式
根据需求,有两种可行方案:
方案1:定义全二维参数(覆盖所有i,j组合)
如果需要保留所有(i,j)的参数值(即使i>=j),可直接基于m.J×m.J定义二维参数,初始化函数映射列表索引即可:
def schedule_machines(A, B): m = ConcreteModel() # 确保JOBS的keys和s的列表索引匹配(比如都是0-9的整数) m.J = Set(initialize=JOBS.keys()) # 定义覆盖所有i,j∈J的二维参数 def s_init(m, i, j): return s[i][j] m.setup = Param(m.J, m.J, initialize=s_init) # 定义i<j的索引集合用于约束 m.PAIRS_1 = Set(initialize=m.J*m.J, dimen=2, filter=lambda m, i, j: i<j) # 编写约束规则 def seq_rule(m, i, j): return m.start[i] + m.p[i] + m.setup[i,j] >= m.start[j] m.sequence_constraint = Constraint(m.PAIRS_1, rule=seq_rule) # 其余变量定义、求解器调用代码... return SCHEDULE
方案2:仅定义i<j的参数(更高效)
如果只需要i<j的参数值,可直接基于PAIRS_1集合定义参数:
def schedule_machines(A, B): m = ConcreteModel() m.J = Set(initialize=JOBS.keys()) # 先定义i<j的索引集合 m.PAIRS_1 = Set(initialize=m.J*m.J, dimen=2, filter=lambda m, i, j: i<j) # 针对PAIRS_1集合初始化参数 def s_init(m, i, j): return s[i][j] m.setup = Param(m.PAIRS_1, initialize=s_init) # 直接用PAIRS_1集合定义约束 def seq_rule(m, i, j): return m.start[i] + m.p[i] + m.setup[i,j] >= m.start[j] m.sequence_constraint = Constraint(m.PAIRS_1, rule=seq_rule) # 其余变量定义、求解器调用代码... return SCHEDULE
关键注意事项
- 必须保证
JOBS.keys()返回的索引值和二维列表s的索引完全匹配(比如都是0到9的整数),否则会出现索引不匹配错误。 - 如果
JOBS的key不是整数(比如字符串),需要先建立key到列表索引的映射字典:
然后在初始化函数中用job_idx = {job: idx for idx, job in enumerate(JOBS.keys())}job_idx[i]和job_idx[j]去取s中的对应值。
内容的提问来源于stack exchange,提问作者A.Omidi
相关产品推荐
相关产品推荐

