如何在Or-tools中深度复制Solver对象及复制约束并添加变量?
在OR-Tools中复制Solver对象并给约束添加新变量的方法
问题背景
需要在OR-Tools中复制Solver对象的变量与约束,并给副本的每个约束新增一个松弛变量。原代码中直接复用原Solver的约束对象会报错,因为约束属于原Solver上下文,无法跨实例使用。
解决思路
- 复制变量并建立映射:遍历原Solver的变量,在新Solver中创建相同属性的变量,同时维护原变量到新变量的映射关系,方便后续约束系数的迁移。
- 重建约束并添加松弛变量:提取原约束的上下界、变量系数,在新Solver中重新构建约束,同时为每个约束添加对应的松弛变量。
- 设置目标函数:将所有松弛变量的和设为新Solver的最小化目标。
完整可运行代码
from ortools.linear_solver import pywraplp def create_constraints(model): x = model.NumVar(0, 1, 'x') y = model.NumVar(0, 1, 'y') constraint = model.Constraint(-pywraplp.Solver.infinity(), 1) constraint.SetCoefficient(x, 1) constraint.SetCoefficient(y, 1) return constraint # 创建第一个Solver并添加约束 solver1 = pywraplp.Solver.CreateSolver('SCIP') constraint1 = create_constraints(solver1) # 创建第二个Solver new_solver = pywraplp.Solver.CreateSolver('SCIP') # 复制变量并建立原变量到新变量的映射 var_map = {} for var in solver1.variables(): new_var = new_solver.NumVar(lb=var.Lb(), ub=var.Ub(), name=var.name()) var_map[var] = new_var # 复制约束并添加松弛变量 slacks = [] for i, cst in enumerate(solver1.constraints()): # 创建松弛变量 sl = new_solver.NumVar(0, 1e20, f'Slack{i}') slacks.append(sl) # 提取原约束的上下界 lb = cst.lb() ub = cst.ub() # 在新Solver中构建约束 new_cst = new_solver.Constraint(lb, ub) # 复制原约束的变量系数 for var in cst.variables(): new_cst.SetCoefficient(var_map[var], cst.GetCoefficient(var)) # 为约束添加松弛变量 new_cst.SetCoefficient(sl, 1) # 设置目标函数:最小化松弛变量的和 new_solver.Minimize(new_solver.Sum(slacks)) # 可选:求解并输出结果 status = new_solver.Solve() if status == pywraplp.Solver.OPTIMAL: print(f"最优目标值: {new_solver.Objective().Value()}") for var in new_solver.variables(): print(f"{var.name()}: {var.solution_value()}")
关键说明
- 变量映射的必要性:原Solver的变量与新Solver的变量属于不同实例,必须通过映射替换,才能正确迁移约束系数。
- 约束重建逻辑:无法直接复用原约束对象,必须手动提取上下界和系数信息,在新Solver中重新创建约束。
- 松弛变量的添加:通过
SetCoefficient方法给新约束添加松弛变量的系数,实现原约束加松弛变量的需求。
内容的提问来源于stack exchange,提问作者Santi Peñate-Vera
相关产品推荐
相关产品推荐

