1. 用法简述
不同的编程语言写入表格文件的方式均不相同,下面将展示MindOpt APL建模语言的方式。
# 覆盖式样写csv文件 print "{}, {}, {}" % "日期", "班次", "员工编号" : "file.csv"; close "file.csv"; # append追加式样写csv文件 print "{}, {}, {}" % d,s,e >> "Schedule_Results.csv"; close "Schedule_Results.csv";
2. 说明
2.1. 建模语言介绍
- MindOpt建模语言(MindOpt APL, 简称为MAPL)是MindOpt团队研发的一种代数建模语言。用MAPL描述数学规划模型与用数学公式进行描述非常类似。
2.2. 语法
2.2.1. 读数据
MAPL目前read as
读数据的方式支持两种数据格式n
和s
,即数值和字符串。数字
表示要读入字段的索引,而类型
则表示按照何种类型来读入该字段。skip n
表示跳过表格的第n
行内容。
2.2.2. 写数据
任意MAPL支持的print语句+写入模式+文件名称即可将决策变量的取值打印成csv格式
- 合法的 print/format print 语句
- 任意MAPL支持的print语句,如
print A[1,2,3]
- filename
- 文本文件名,如
"result.txt"
、"result.csv"
等文本方式写
- 两种写模式
:
表示第一次打开后是覆盖(overwrite)方式写,打开后在后续是拼接(append)方式写,如果不存在则新建文件。>>
表示打开后都是拼接(append)方式写,如果不存在则新建文件。
更多使用方法可以参考MAPL文档:https://www.yuque.com/mindopt/apl/dw9pmekz73dxfxgd
3. 应用
在优化问题中,人员排班就是个比较好的例子,排班表非常的适合以表格的方式展示结果。
代码:
clear model; set Schedule = {read "班次.csv" as "<1s>" skip 1}; # 读取班次的名称 set Day = {read "需求人数.csv" as "<1n>" skip 1}; #读取排班的日期 param maxDay = max(Day); print "待排",maxDay,"天的班"; param NumDemand = read "需求人数-长列表.csv" as "<1n,2s> 3n" skip 1; #读取每天各个班次的需求人数,原横纵表拉成长列表为了读取数据方便 param totalSlots = sum {<d,s> in Day*Schedule} NumDemand[d,s]; print "总共有",totalSlots,"个班次待排"; #预估上班人数 param maxEmployee = ceil(totalSlots/5) + 1; #如果班次需求特殊导致不可解的时候,可以增加员工 print "设置参与排班人数:",maxEmployee; set Employee = {1..maxEmployee}; #声明变量 var x[Day*Schedule*Employee] binary; #约束 subto constraint_0 : forall {<d,s> in Day*Schedule} sum {e in Employee} x[d,s,e] >= NumDemand[d,s]; #满足用工需求 subto constraint_1 : forall {<d,e> in Day*Employee} sum {s in Schedule} x[d,s,e] <= 1; #每人每天只排一个班次 set DayPre = Day without {<maxDay>}; #去掉最后一天 subto constraint_2 : forall {e in Employee} forall {d in DayPre} x[d,"夜班0-8点",e] + x[d+1,"早班8-16点",e] <= 1; #前一天晚班的,第二天不排早班 subto constraint_3 : forall {e in Employee} sum {<d,s> in Day*Schedule} x[d,s,e] <= 5; #待排的7天里只上5天班 minimize minOnduty: sum {<d,s,e> in Day*Schedule*Employee} x[d,s,e]; #求解 option solver mindopt; # (可选)指定求解用的求解器,默认是MindOpt option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印 solve; # 求解 # 结果打印和检查结果 print "-----------------Display---------------"; #display; #打印太多,注释了 # 将结果打印为数据表格 print "{}, {}, {}" % "日期", "班次", "员工编号" : "Schedule_Results.csv"; close "Schedule_Results.csv"; forall {<d,s,e> in Day*Schedule*Employee with x[d,s,e] >0} print "{}, {}, {}" % d, s,e >> "Schedule_Results.csv"; close "Schedule_Results.csv";
结果:
待排7天的班 总共有99个班次待排 设置参与排班人数:21 Running mindoptampl wantsol=1 print=0 MindOpt Version 1.0.0 (Build date: 20231013) Copyright (c) 2020-2023 Alibaba Cloud. Start license validation (current time : 17-NOV-2023 16:52:20). License validation terminated. Time : 0.004s OPTIMAL; objective 99.00 Completed.
输出的Schedule_Results.csv
表格部分结果:
4. 更多应用示例
案例代码均可点击链接查看
- 物流运输 将每条通道分别运输多少商品写成表格
将结果输出为表格:
print "{},{},{} "% "起点","途径点","商品数量" : "Results.csv"; close "Results.csv"; forall {<i, j> in LINKS} print "{},{},{}" % i,j,Ship[i,j] >> "Results.csv"; close "Results.csv";
结果如下:
- 排产排程 将每月每种油脂的处理方式、生产计划写成表格
将结果输出为表格:
print "{}, {}, {}, {}" % "油脂", "月份", "处理方案","数量" : "每月油脂处理方式.csv"; close "每月油脂处理方式.csv"; forall {<j,m,n> in O*M*N} print "{}, {}, {}, {}" % j, m, n, x[j,m,n] >> "每月油脂的处理方式.csv"; close "每月油脂处理方式.csv"; print "{}, {}" % "月份", "生产计划" : "Results_.csv"; close "Results_.csv"; forall {<m> in M} print "{}, {}" % m,y[m] >> "Results_.csv"; close "Results_.csv";
结果如下: