OR-Tools中如何通过AddElement约束按行列决策变量提取矩阵元素
问题解决
你遇到的报错本质是Python原生列表无法使用OR-Tools的IntVar类型作为下标索引,AddElement约束要求第二个入参必须是Python常量列表,因此二维收益表的取值需要做对应调整,这里提供两种基于AddElement的实现方案:
方案1:扁平化收益表+单层AddElement(推荐)
把二维收益表拉平为一维列表,用「A类动作索引 * B类动作总数 + B类动作索引」作为一维表的访问下标,即可直接调用AddElement实现取值:
from ortools.sat.python import cp_model model = cp_model.CpModel() # 不同A型动作(行)与B型动作(列)组合对应的收益值 value = [ [ -1, 5, 3, 2, 2], [ 2, 4, 2, -1, 1], [ 4, 4, 0, -1, 2], [ 5, 1, -1, 2, 2], [ 0, 0, 0, 0, 0], [ 2, 1, 1, 2, 0] ] num_moves_A = len(value) num_moves_B = len(value[0]) num_positions = 8 # 拉平二维收益表为一维 flat_value = [] for row in value: flat_value.extend(row) type_move_A_position = [model.NewIntVar(0, num_moves_A - 1, f"move_A[{i}]") for i in range(num_positions)] type_move_B_position = [model.NewIntVar(0, num_moves_B - 1, f"move_B[{i}]") for i in range(num_positions)] # 注意收益存在-1,变量下界要调整为-1避免约束冲突 value_position = [model.NewIntVar(-1, 10, f"value_position[{i}]") for i in range(num_positions)] objective_terms = [] for i in range(num_positions): # 计算一维表的访问索引 idx = model.NewIntVar(0, num_moves_A * num_moves_B - 1, f"idx_{i}") model.Add(idx == type_move_A_position[i] * num_moves_B + type_move_B_position[i]) # 调用AddElement取值 model.AddElement(idx, flat_value, value_position[i]) objective_terms.append(value_position[i]) # 补充最大化目标 model.Maximize(sum(objective_terms))
方案2:两层AddElement嵌套实现
如果你需要严格通过两层AddElement对应二维表的两次索引,可结合布尔可选约束实现:
# 前面变量定义和方案1一致,仅修改循环部分 objective_terms = [] for i in range(num_positions): # 为每个A类动作定义行选择布尔变量 row_select = [model.NewBoolVar(f"row_select_{i}_{a}") for a in range(num_moves_A)] for a in range(num_moves_A): model.Add(type_move_A_position[i] == a).OnlyEnforceIf(row_select[a]) model.Add(type_move_A_position[i] != a).OnlyEnforceIf(row_select[a].Not()) # 当选中第a行时,用B类索引取对应行的收益 model.AddElement(type_move_B_position[i], value[a], value_position[i]).OnlyEnforceIf(row_select[a]) objective_terms.append(value_position[i])
方案1的执行效率远高于方案2,是OR-Tools处理二维表索引的官方推荐写法。
内容的提问来源于stack exchange,提问作者Bhartendu Awasthi
相关产品推荐
相关产品推荐

