Python中CPLEX原生库无piecewise属性,如何实现分段函数?
CPLEX原生Python库实现分段函数的方法
CPLEX原生Python库并没有提供像docplex那样直接调用的piecewise()方法,要实现分段函数,得手动把分段线性关系转化为线性约束来处理。下面是具体的实现思路和示例:
核心思路
分段线性函数可以通过引入辅助变量和二进制变量(标记变量所在的分段区间),再用线性约束来表达每个区间内的函数关系。以一个简单的分段函数为例:
- 当
x < 0时,y = 0 - 当
0 ≤ x ≤ 5时,y = 2x - 当
x > 5时,y = x + 5
代码实现示例
import cplex # 创建CPLEX模型 mdl = cplex.Cplex() # 添加决策变量 x = mdl.variables.add(names=["x"], lb=[-cplex.infinity]) # x无下界 y = mdl.variables.add(names=["y"], lb=[0]) # y的下界为0 # 引入二进制变量,标记x所在的区间 # b0: x < 0; b1: 0 ≤ x ≤5; b2: x >5 b = mdl.variables.add(names=["b0", "b1", "b2"], types=["B"]*3) # 添加约束:三个二进制变量中只能有一个为1(x只能处于一个区间) mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["b0", "b1", "b2"], val=[1, 1, 1])], senses=["E"], rhs=[1] ) # 区间1:x < 0 时,y=0 epsilon = 1e-6 # 极小值,用于处理严格小于的边界 mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["x", "b0"], val=[1, epsilon])], senses=["L"], rhs=[0] ) mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["y"], val=[1])], senses=["E"], rhs=[0] ) # 区间2:0 ≤x ≤5 时,y=2x M = 1e5 # 足够大的数,用于大M法约束区间生效条件 mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["x", "b1"], val=[1, M])], senses=["G"], rhs=[0] ) mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["x", "b1"], val=[1, -M])], senses=["L"], rhs=[5] ) mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["y", "x"], val=[1, -2])], senses=["E"], rhs=[0] ) # 区间3:x>5 时,y=x+5 mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["x", "b2"], val=[1, -epsilon])], senses=["G"], rhs=[5] ) mdl.linear_constraints.add( lin_expr=[cplex.SparsePair(ind=["y", "x"], val=[1, -1])], senses=["E"], rhs=[5] ) # 设置目标函数(示例为最小化y) mdl.objective.set_sense(mdl.objective.sense.minimize) mdl.objective.set_linear([("y", 1)]) # 求解模型 mdl.solve() # 输出结果 print(f"x的值: {mdl.solution.get_values('x')[0]}") print(f"y的值: {mdl.solution.get_values('y')[0]}")
关键说明
- 用二进制变量标记变量所处的区间,确保变量只属于一个分段区间;
- 用大M法(M取足够大的正数)处理不同区间的边界约束,保证只有当对应二进制变量为1时,区间约束才生效;
- 每个分段的函数关系通过线性等式约束来表达。
内容的提问来源于stack exchange,提问作者Jimmy Jimmy
相关产品推荐
相关产品推荐

