连续变量乘积线性化及CPLEX OPL实现咨询:小数价格变量处理
连续变量乘积约束的线性化及CPLEX OPL实现方案
一、处理带4-5位小数的price离散化
因为price最多有5位小数,直接缩放成整数是最实用的办法:
- 设缩放因子
SCALE = 100000(对应5位小数,4位就用10000),把离散化后的price定义为整数变量price_int,连续变量price和它的关系是:price = price_int / SCALE - 原约束
price * time >= Ub转化为price_int * time >= Ub * SCALE,但这是整数×连续变量的乘积,还得用大M法线性化。
整数×连续乘积的线性化步骤
- 先确定
price_int的取值范围:根据price的最小/最大值,算出x_low = floor(price_min * SCALE),x_high = ceil(price_max * SCALE) - 引入二进制变量
b[k](k从x_low到x_high),保证只有一个b[k]取1,对应选中的price_int值 - 添加约束把price_int和b[k]绑定,再把乘积约束拆分成多个线性约束
CPLEX OPL代码示例
// 参数定义 float Ub = ...; // 给定的阈值 float price_min = ...; // price的下限 float price_max = ...; // price的上限 int SCALE = 100000; // 5位小数缩放因子 int x_low = floor(price_min * SCALE); int x_high = ceil(price_max * SCALE); float M = ...; // time的上限值(取足够大的合理值) // 变量定义 dvar int price_int in x_low..x_high; dvar float time >= 0; // 假设time非负,按需调整范围 dvar boolean b[x_low..x_high]; // 约束集合 subject to { // 二进制变量只能选一个 sum(k in x_low..x_high) b[k] == 1; // 绑定整数变量与二进制变量 price_int == sum(k in x_low..x_high) k * b[k]; // 线性化乘积约束:当b[k]=1时,k*time >= Ub*SCALE forall(k in x_low..x_high) { // 跳过k=0的情况(如果price不能为0可直接删) if (k != 0) { time >= (Ub * SCALE) / k - M * (1 - b[k]); } else { // 若Ub>0,k=0时约束不可能满足,直接禁止选这个值 (Ub <= 0) || (b[k] == 0); } } // 如需输出连续price,直接计算:float price = price_int / SCALE; }
二、正确实现price的floor值
你之前用sum(2^n-1)*p的方式逻辑不对,换缩放+整数变量的方法更直接:
dvar int price_floor_int; dvar float price; subject to { // 约束price*SCALE落在[price_floor_int, price_floor_int+SCALE-1]区间 price_floor_int <= price * SCALE <= price_floor_int + SCALE - 1; // 得到floor值:float price_floor = price_floor_int / SCALE; }
这样price_floor就是保留对应小数位数的price向下取整结果。
三、无需离散化price的线性化备选方案
如果不想把price转离散,也可以直接线性化连续×连续的乘积,引入辅助变量z=price*time,用大M法约束:
dvar float price >= price_min, <= price_max; dvar float time >= time_min, <= time_max; dvar float z; subject to { z >= Ub; // 大M法约束z = price*time的线性近似 z >= price_min * time + time_min * price - price_min * time_min; z >= price_max * time + time_max * price - price_max * time_max; z <= price_max * time + time_min * price - price_min * time_min; z <= price_min * time + time_max * price - price_max * time_max; }
这种方法的精度取决于price和time的上下界,界越紧,线性化效果越好。
内容的提问来源于stack exchange,提问作者Aida Bitaraf
相关产品推荐
相关产品推荐

