当前位置: 首页 > news >正文

学习日志38-cpelx求解器使用

cplex中在目标函数中使用分段线性函数

基于cplex的考虑质量系数的最大化收益代码

/********************************************** OPL 22.1.0.0 模型* 作者: 示例* 创建日期: 2025年5月15日* 功能: 拆卸线平衡优化模型* 目标: 最大化拆卸净收益 = 组件回收价值 - 拆卸成本*********************************************//*** 基本参数定义 ***/
int I = 15;       // 产品组件数的最大值(索引1-15)
int J = 13;       // 产品任务数的最大值(索引1-13)
int W = 3;        // 可用的工作站数量
int R = 3;        // 每个任务可选的拆卸方式数量/*** 实际产品参数 ***/
int I_p = 15;     // 当前产品实际组件数
int J_p = 13;     // 当前产品实际任务数/*** 组件参数 ***/
int v_mpi[1..I] = [0,115,125,111,104,96,115,100,106,114,107,100,111,89,1030]; // 组件i的市场价格(第0位占位)
float H_pi[1..I] = [0.99,0.98,0.95,0.94,0.93,0.98,0.95,0.96,0.89,0.9,0.91,0.93,0.79,0.99,0.9]; // 组件i的初始质量系数/*** 任务参数 ***/
int t_pj[1..R][1..J] = [  // 任务j采用方式r的拆卸时间[[9,7,9,5,8,8,8,8,7,8,7,8,9],[8,9,8,6,6,5,5,5,10,6,8,9,7],[7,8,6,8,9,8,8,8,7,9,10,6,5]];
int c_pj[1..R][1..J] = [  // 任务j采用方式r的单位时间成本[[9,7,9,5,8,8,8,8,7,8,7,8,9],[8,9,8,6,6,5,5,5,10,6,8,9,7],[7,8,6,8,9,8,8,8,7,9,10,6,5]];/*** 质量影响参数 ***/
float gamma_pjri[1..R][1..I][1..J] = [// 拆卸方式r对组件i在任务j执行后的质量保留系数[[1,1,1,...], ...],  // 具体数据已简略[[1,1,1,...], ...],[[1,1,1,...], ...]
];/*** 任务-组件关系矩阵 ***/
int q_pij[1..I][1..J] = [  // 任务j是否需要组件i存在 (1=需要)[0,0,0,...], [1,0,0,...], ... 
];
int d_pij[1..I][1..J] = [  // 任务j对组件i的影响:-1=拆卸,1=获得,0=无关[-1,0,0,...],[1,0,0,...],...
];/*** 任务间关系矩阵 ***/
int r_pjq[1..J][1..J] = [  // 任务冲突矩阵 (1=冲突任务不能分配到同一工作站)[0,0,0,...],[0,0,1,...],...
];
int s_pjq[1..J][1..J] = [  // 任务优先关系矩阵 (1=任务j是q的紧前任务)[0,1,1,...],[0,0,0,...],...
];/*** 收益分段函数参数 ***/
int n = 2;  // 分段点数量
float objectiveForXEqualsStart = 0;  // 起始点(0,0)
float breakpoint[1..n] = [0.5, 1];  // 分段点位置
float slope[1..n+1] = [0.5, 1.5, 0];  // 各段斜率/*** 决策变量声明 ***/
dvar boolean x_pjkw[1..J][1..W][1..R]; // 任务j分配到工作站w以方式r执行 (二进制)
dvar boolean u_w[1..W];                // 工作站w是否启用 (二进制)
dvar float H_pij[1..I][1..J];          // 执行任务j后组件i的质量 (0-1)
dvar float H_pe[1..I];                 // 组件i的最终质量 (取所有相关任务后的最小值)/*** 求解器配置 ***/
execute {cplex.tilim = 10800;       // 设置求解时间限制为3小时cplex.optimalitytarget = 3; // 追求全局最优解
}/*** 目标函数:最大化净收益 ***/
maximize 
// 第一部分:组件回收收益(考虑质量分段函数)
sum(i in 1..I, j in 1..J, r in 1..R, w in 1..W) (v_mpi[i] * x_pjkw[j][w][r] * d_pij[i][j] * piecewise(i in 1..n) {slope[i] -> breakpoint[i]; slope[n+1]} (0, objectiveForXEqualsStart) H_pe[i]
) 
// 第二部分:减去拆卸成本
- sum(j in 1..J, w in 1..W, r in 1..R) (c_pj[r][j] * t_pj[r][j] * x_pjkw[j][w][r]
);/*** 约束条件 ***/
subject to {// 约束1:工作站启用状态必须为二进制 (式4)forall(w in 1..W)u_w[w] <= 1;  // 二进制变量自然满足<=1,此处显式声明约束// 约束2:任务只能分配到已启用的工作站 (式7)forall(j in 1..J, w in 1..W, r in 1..R)x_pjkw[j][w][r] <= u_w[w];  // 如果工作站w未启用(u_w=0),则不能分配任务// 约束3:每个任务最多执行一次 (式9)forall(j in 1..J)sum(w in 1..W, r in 1..R) x_pjkw[j][w][r] <= 1;  // 所有工作站和方式的选择总和<=1// 约束4:优先关系约束——紧前任务必须执行 (式10)forall(j1 in 1..J, j2 in 1..J)if (s_pjq[j1][j2] == 1)  // 如果j1是j2的紧前任务sum(w in 1..W, r in 1..R) x_pjkw[j1][w][r] >= sum(w in 1..W, r in 1..R) x_pjkw[j2][w][r];// 约束5:优先关系约束——工作站顺序 (式11)forall(j in 1..J, q in 1..J)if (s_pjq[j][q] == 1)  // j是q的紧前任务sum(w in 1..W, r in 1..R) (w * (x_pjkw[j][w][r] - x_pjkw[q][w][r])) + W * (sum(w in 1..W, r in 1..R) (x_pjkw[q][w][r]) - 1) <= 0;  // 确保j分配到的工作站号<=q的工作站号// 约束6:冲突任务不能分配到同一工作站 (式12)forall(j in 1..J, q in 1..J)if (r_pjq[j][q] == 1)  // 任务j与q冲突sum(w in 1..W, r in 1..R) (x_pjkw[j][w][r] + x_pjkw[q][w][r]) <= 1;  // 两个任务不能同时被分配// 约束7:组件质量更新——初始质量传递 (式13)forall(j in 1..J, w in 1..W, i in 1..I, r in 1..R)H_pij[i][j] <= (1 - x_pjkw[j][w][r]) + H_pi[i] * gamma_pjri[r][i][j];  // 如果任务j未执行(x=0),质量保持原值;否则按gamma系数衰减// 约束8:组件质量更新——前驱任务质量传递 (式14)forall(j in 1..J, v in 1..J, i in 1..I, w in 1..W, r in 1..R)if (s_pjq[v][j] == 1 && q_pij[i][j] == 1)  // v是j的前驱任务且j需要组件iH_pij[i][j] <= (1 - x_pjkw[j][w][r]) + H_pij[i][v] * gamma_pjri[r][i][j];  // j的质量继承自前驱任务v的质量// 约束9:质量上限约束 (式15)forall(j in 1..J, i in 1..I)H_pij[i][j] <= H_pi[i];  // 质量不能超过初始质量// 约束10:最终质量取最小值 (式16)forall(j in 1..J, i in 1..I)H_pe[i] <= H_pij[i][j];  // 最终质量是所有相关任务后的最小质量// 非负约束forall(j in 1..J, i in 1..I) {H_pe[i] >= 0;H_pij[i][j] >= 0;}
}/*** 结果输出模块 ***/
execute DISPLAY {// 输出组件价值计算详情writeln("\n=== 组件价值贡献详情 ===");for (var i = 1; i <= I; i++) {var total = 0;for (var j = 1; j <= J; j++) {for (var w = 1; w <= W; w++) {for (var r = 1; r <= R; r++) {if (x_pjkw[j][w][r] == 1) {total += v_mpi[i] * H_pe[i] * d_pij[i][j];}}}}writeln("组件", i, "总贡献值: ", total);}// 输出被拆除组件信息writeln("\n=== 被拆除组件列表 ===");for (var i = 1; i <= I; i++) {var removedValue = 0;for (var j = 1; j <= J; j++) {if (d_pij[i][j] == -1) { // 仅处理拆卸操作for (var w = 1; w <= W; w++) {for (var r = 1; r <= R; r++) {if (x_pjkw[j][w][r] == 1) {removedValue += v_mpi[i] * H_pe[i] * (-d_pij[i][j]); }}}}}if (removedValue > 0) {writeln("组件", i, " 被拆除,价值: ", removedValue);}}// 输出工作站启用状态writeln("\n=== 工作站启用状态 ===");for (var w = 1; w <= W; w++) {writeln("工作站", w, ": ", u_w[w] == 1 ? "启用" : "未启用");}// 输出组件最终质量writeln("\n=== 组件最终质量 ===");for (var i = 1; i <= I; i++) {writeln("组件", i, ": ", H_pe[i]);}// 输出任务分配详情writeln("\n=== 任务分配详情 ===");for (var j = 1; j <= J; j++) {for (var w = 1; w <= W; w++) {for (var r = 1; r <= R; r++) {if (x_pjkw[j][w][r] == 1) {writeln("任务", j, " -> 工作站", w, " 方式", r);}}}}
}

主要注释说明:

  • 参数部分

     使用多维数组描述拆卸时间、成本、质量影响等复杂关系gamma_pjri三维数组体现不同拆卸方式对质量的差异化影响
    
  • 变量部分

     x_pjkw三维二进制变量精确描述"任务-工作站-方式"的三重分配H_pe最终质量变量通过最小值约束确保质量评估的保守性
    
  • 目标函数

     使用piecewise函数实现分段线性收益计算第一部分计算组件回收价值,第二部分计算拆卸成本
    
  • 约束体系

     约束4-5处理任务优先级,既保证执行顺序又控制工作站分配约束7-8构建质量传递网络,体现任务执行对组件状态的累积影响
    
  • 输出模块

     分模块展示组件价值贡献、工作站状态、质量变化等关键信息使用条件判断精准识别被拆卸组件及其价值
    

分段函数cpelx代码实现

int n=2;
float objectiveForXEqualsStart=0; // 起始点为(0,0)
float breakpoint[1..n]=[0.5,1];   // 分段点为0.5和1
float slope[1..n+1]=[0.5,1.5,0];  // 每段的斜率,第一段斜率为0.5,第二段斜率为1.5,第三段斜率为0
dvar int x;// 分段函数:在x<0.5时,斜率为0.5;0.5≤x<1时,斜率为1.5;x≥1时,斜率为0
maximize 
piecewise(i in 1..n) 
{slope[i] -> breakpoint[i]; slope[n+1]}(0,objectiveForXEqualsStart) x;

在这里插入图片描述

以下面代码为例

piecewise{1 -> 100; 2->200;-3}(0,300) x; 

其中, 1, 2, -3 分别是3个线段的斜率, 100, 200 是3个线段的分割点(3个线段有两个分割点), 而 (0, 300) 表示分段线性函数其中一点, x 是自变量。

http://www.xdnf.cn/news/477631.html

相关文章:

  • 前端脚手架开发指南:提高开发效率的核心操作
  • React学习———React Router
  • Jenkins 执行器(Executor)如何调整限制?
  • vue3中预览Excel文件
  • 技术文章:解决汇川MD500系列变频器干扰问题——GRJ9000S EMC滤波器的应用
  • 影楼精修-肤色统一算法解析
  • 7-15 计算圆周率
  • C++ Kafka客户端(cppkafka)安装与问题解决指南
  • Oracle — 总结
  • 智能接处警系统:以秒级联动响应重塑应急处置效能
  • 使用exceljs将excel文件转化为html预览最佳实践(完整源码)
  • 掌握HTML文件上传:从基础到高级技巧
  • 【HTML 全栈进阶】从语义化到现代 Web 开发实战
  • 数字化工厂升级引擎:Modbus TCP转Profinet网关助力打造柔性生产系统
  • SPL做量化---MTM(动量指数)
  • 在 Ubuntu 20.04 中使用 init.d 或者systemd实现开机自动执行脚本
  • 炼丹学习笔记3---ubuntu2004部署运行openpcdet记录
  • OrangePi Zero 3学习笔记(Android篇)11 - IR遥控器
  • 现在环保方面有什么新的技术动态
  • Qt/C++编写音视频实时通话程序/画中画/设备热插拔/支持本地摄像头和桌面
  • MySQL 8.0 OCP 1Z0-908 121-130题
  • 蓝牙协议架构与调试工具详解(含 BLE、HCI 命令、调试命令)
  • Prometheus实战教程:k8s平台-Mysql监控案例
  • 记一次缓存填坑省市区级联获取的操作
  • 自学嵌入式 day19-数据结构 链表
  • 【前端】构建关系图谱的前端组件推荐
  • SqlHelper 实现类,支持多数据库,提供异步操作、自动重试、事务、存储过程、分页、缓存等功能。
  • 使用哈希表封装myunordered_set和myunordered_map
  • 【Python CGI编程】
  • go-中间件的使用