CPLEX决策变量显示“No Value”问题及模型修正请求
急诊室资源优化随机MIP模型修正(CPLEX OPL)
首次使用CPLEX Studio IDE v22.1.0开展大学项目,通过随机混合整数规划(Stochastic Mixed Integer Program)优化5类医院资源(医生、护士、实验室人员、影像设备、床位)以缓解急诊室拥挤问题。已完成模型编写,但运行后决策变量显示“No Value”,请求修正后的模型。
原模型代码
{string} resources = {"Doctors", "Nurses", "Lab Scientists", "Imaging", "Beds"}; int capacity[resources] = [2, 3, 4, 2, 10]; // 定义时间段与队列索引 //===================================================== int t = ...; int q = ...; range timeperiods = 1..3; range queues = 1..5; // 定义场景 //======================= range scenarios = 1..3; // 定义患者到达率与资源服务能力 //============================================================ int arrivalrate[scenarios][timeperiods][queues] = ...; int servicecapacity[scenarios][timeperiods][queues] = ...; // 定义决策变量 //=============================== dvar int R[timeperiods][resources]; dvar int W[scenarios][timeperiods][queues]; dvar int S[scenarios][timeperiods][queues]; // 目标函数 //========= // 表达式 dexpr int WP = sum (s in scenarios, t in timeperiods, q in queues) W[s][t][q]; dexpr int SP = sum (s in scenarios, t in timeperiods, q in queues) S[s][t][q]; dexpr int NWP = WP - SP; // 目标函数 //=================== minimize NWP; // 约束条件 //=========== subject to { // 初始化各场景下每个队列的等待患者数 //===================================================== forall (s in scenarios, t1 in timeperiods, q1, q2, q3, q4, q5, q in queues) { W[s][t1][q1] == arrivalrate[s][1][q]; W[s][t1][q2] == 0; W[s][t1][q3] == 0; W[s][t1][q4] == 0; W[s][t1][q5] == 0; S[s][t1][q1] == 0; S[s][t1][q2] == 0; S[s][t1][q3] == 0; S[s][t1][q4] == 0; S[s][t1][q5] == 0; } // 更新各时间段每个队列的患者数 //============================================================== forall (s in scenarios, t2, t3 in timeperiods, q1 in queues) { W[s][t][q1] == W[s][t-1][q1] + arrivalrate[s][t][1] - S[s][t-1][q1]; } forall (s in scenarios, t2, t3 in timeperiods, q1, q2 in queues) { W[s][t][q2] == W[s][t-1][q2] + S[s][t-1][q1] - S[s][t-1][q2]; } forall (s in scenarios, t2, t3 in timeperiods, q1, q3 in queues) { W[s][t][q3] == W[s][t-1][q3] + S[s][t-1][q1] - S[s][t-1][q3]; } forall (s in scenarios, t2, t3 in timeperiods, q2, q3, q4 in queues) { W[s][t][q4] == W[s][t-1][q4] + S[s][t-1][q2] + S[s][t-1][q3] - S[s][t-1][q4]; } forall (s in scenarios, t2, t3 in timeperiods, q2, q3, q5 in queues) { W[s][t][q5] == W[s][t-1][q5] + S[s][t-1][q2] + S[s][t-1][q3] - S[s][t-1][q5]; } // 单时间段服务患者数上限 //================================================= forall (s in scenarios, t in timeperiods, q in queues) { S[s][t][q] <= W[s][t][q]; } // 各时间段每个队列的服务患者数限制 //============================================================= forall (s in scenarios, t in timeperiods, q1 in queues) { S[s][t][q1] <= sum (s in scenarios, t in timeperiods, q in queues) servicecapacity[s][t][1] * 1; } forall (s in scenarios, t in timeperiods, q2 in queues) { S[s][t][q2] <= sum (s in scenarios, t in timeperiods, q in queues) servicecapacity[s][t][2] * 1; } forall (s in scenarios, t in timeperiods, q3 in queues) { S[s][t][q3] <= sum (s in scenarios, t in timeperiods, q in queues) servicecapacity[s][t][3] * 1; } forall (s in scenarios, t in timeperiods, q4 in queues) { S[s][t][q4] <= sum (s in scenarios, t in timeperiods, q in queues) servicecapacity[s][t][4] * 1; } forall (s in scenarios, t in timeperiods, q5 in queues, r5 in resources) { S[s][t][q5] <= R[t][r5]; } // 人力资源可用工时限制(每人8小时) //============================================================== forall (r1 in resources) { sum (t in timeperiods) R[t][r1] <= 8; } forall (r2 in resources) { sum (t in timeperiods) R[t][r2] <= 8; } forall (r3 in resources) { sum (t in timeperiods) R[t][r3] <= 8; } // 各时间段每种资源至少配置1个 //============================================================ forall (t in timeperiods, r1 in resources) { R[t][r1] >= 1; } forall (t in timeperiods, r2 in resources) { R[t][r2] >= 1; } forall (t in timeperiods, r3 in resources) { R[t][r3] >= 1; } forall (t in timeperiods, r4 in resources) { R[t][r4] >= 1; } forall (t in timeperiods, r5 in resources) { R[t][r5] >= 1; } }
原测试数据
t = 3; q = 5; arrivalrate = [ [[14,10,95,34,23], [90,80,60,34,23], [50,30,20,34,23]], [[14,13,11,34,23], [50,30,20,34,23], [12,31,27,34,23]], [[14,10,95,34,23], [90,80,60,34,23], [50,30,20,34,23]], ]; servicecapacity = [ [[14,10,95,34,23], [90,80,60,34,23], [50,30,20,34,23]], [[14,13,11,34,23], [50,30,20,34,23], [12,31,27,34,23]], [[14,10,95,34,23], [90,80,60,34,23], [50,30,20,34,23]], ];
错误核心问题
- 初始化约束矛盾:遍历所有时间段初始化等待人数,且用多队列变量重复赋值,导致同一决策变量被强制赋予多个冲突值,模型直接不可行。
- 队列更新逻辑混乱:未限定更新仅针对
t>=2的时间段,且硬编码队列索引,未匹配对应队列的到达/流转逻辑。 - 服务能力约束逻辑错误:将所有场景、时间段的服务能力求和作为单时间段单队列的上限,完全不符合业务逻辑。
- 资源匹配约束错误:让队列5的服务人数小于等于所有资源配置,未对应到实际关联的床位资源。
- 冗余重复约束:多次重复相同的资源总量、下限约束,无意义且增加模型复杂度。
修正后的模型代码
{string} resources = {"Doctors", "Nurses", "Lab Scientists", "Imaging", "Beds"}; int capacity[resources] = [2, 3, 4, 2, 10]; // 定义时间段与队列索引 range timeperiods = 1..3; range queues = 1..5; // 定义场景 range scenarios = 1..3; // 定义患者到达率与资源服务能力 int arrivalrate[scenarios][timeperiods][queues] = ...; int servicecapacity[scenarios][timeperiods][queues] = ...; // 定义决策变量(添加非负约束,符合实际意义) dvar int R[timeperiods][resources]; // 各时间段各资源配置数量 dvar int W[scenarios][timeperiods][queues] >= 0; // 各场景各时间段各队列等待患者数 dvar int S[scenarios][timeperiods][queues] >= 0; // 各场景各时间段各队列服务患者数 // 目标函数:最小化所有场景下的总等待患者数(贴合急诊拥挤优化核心需求) minimize sum (s in scenarios, t in timeperiods, q in queues) W[s][t][q]; // 约束条件 subject to { // 初始化:仅第一个时间段,等待人数等于对应场景到达率,服务人数为0 forall (s in scenarios, q in queues) { W[s][1][q] == arrivalrate[s][1][q]; S[s][1][q] == 0; } // 队列流转更新:仅针对t>=2的时间段 forall (s in scenarios, t in timeperiods: t > 1) { // 队列1:新到达患者 + 上周期等待 - 上周期服务 W[s][t][1] == W[s][t-1][1] + arrivalrate[s][t][1] - S[s][t-1][1]; // 队列2:来自队列1的完成患者 + 上周期等待 - 上周期服务 W[s][t][2] == W[s][t-1][2] + S[s][t-1][1] - S[s][t-1][2]; // 队列3:来自队列1的完成患者 + 上周期等待 - 上周期服务 W[s][t][3] == W[s][t-1][3] + S[s][t-1][1] - S[s][t-1][3]; // 队列4:来自队列2、3的完成患者 + 上周期等待 - 上周期服务 W[s][t][4] == W[s][t-1][4] + S[s][t-1][2] + S[s][t-1][3] - S[s][t-1][4]; // 队列5:来自队列2、3的完成患者 + 上周期等待 - 上周期服务 W[s][t][5] == W[s][t-1][5] + S[s][t-1][2] + S[s][t-1][3] - S[s][t-1][5]; } // 服务人数不超过当前队列等待人数 forall (s in scenarios, t in timeperiods, q in queues) { S[s][t][q] <= W[s][t][q]; } // 各队列服务能力上限:当前场景当前时间段的对应队列服务能力 forall (s in scenarios, t in timeperiods, q in queues) { S[s][t][q] <= servicecapacity[s][t][q]; } // 资源-队列匹配约束(按业务逻辑关联) forall (s in scenarios, t in timeperiods) { S[s][t][1] <= R[t]["Doctors"]; // 队列1(接诊)关联医生 S[s][t][2] <= R[t]["Nurses"]; // 队列2(护理)关联护士 S[s][t][3] <= R[t]["Lab Scientists"];// 队列3(检验)关联实验室人员 S[s][t][4] <= R[t]["Imaging"]; // 队列4(影像)关联影像设备 S[s][t][5] <= R[t]["Beds"]; // 队列5(住院)关联床位 } // 人力资源总工时限制(每人每天8小时,非人力资源无需此约束) forall (r in resources: r != "Beds") { sum(t in timeperiods) R[t][r] <= 8; } // 资源配置上下限:至少1个,不超过最大容量 forall (t in timeperiods, r in resources) { R[t][r] >= 1; R[t][r] <= capacity[r]; } }
修正说明
- 明确队列流转逻辑,消除约束矛盾,确保模型可行;
- 调整目标函数为最小化总等待人数,贴合急诊拥挤优化的核心目标;
- 补充资源-队列的实际关联约束,符合业务逻辑;
- 添加决策变量非负约束,匹配实际场景;
- 简化冗余约束,提升模型可读性与求解效率。
内容的提问来源于stack exchange,提问作者Yusuf Bello Hammanyero
相关产品推荐
相关产品推荐

