MiniZinc中简化含大量零的LB参数数组的方法问询
时间表模型中简化LB参数定义的实现方法
问题背景
开发时间表模型时,需定义4行66列的参数数组LB,但绝大多数元素为0,手动输入效率极低。改用硬编码的等效约束虽能实现需求,但数据与模型耦合,不利于泛化和复用。希望采用如下简洁形式定义LB,询问可行性及调整方法:
subjclass = [{ITA, ING}, {CHI, SCI, DIS, DIR}, {ITA, ING, MAT}, {ITA, ING, LELE}]; LB = [ {2, 1}, {0, 0, 1, 0}, {2, 1, 2}, {2, 1, 1}];
可行性说明
完全可以实现这种简洁定义方式,核心思路是利用subjclass中科目集合的顺序与LB数值列表的顺序一一对应,通过关联映射生成完整的LB数组,同时保留原约束逻辑的通用性。
具体调整步骤
1. 替换LB的定义形式
将原二维数组改为与subjclass结构匹配的列表集合(用列表而非集合,保证顺序对应):
array[class] of list of int: LB_simple = [ [2, 1], % 对应subjclass[1]的{ITA, ING} [0, 0, 1, 0], % 对应subjclass[2]的{CHI, SCI, DIS, DIR} [2, 1, 2], % 对应subjclass[3]的{ITA, ING, MAT} [2, 1, 1] % 对应subjclass[4]的{ITA, ING, LELE} ];
2. 生成完整LB数组
通过循环遍历,根据subjclass和LB_simple的映射关系自动填充LB,非目标科目默认设为0:
array[class, allsubjects] of 0..3: LB = array2d(class, allsubjects, [ let { set of allsubjects: subjs = subjclass[i], list of int: lbs = LB_simple[i], array[subjs] of int: subj_to_lb = array1d(subjs, lbs) } in if k in subjs then subj_to_lb[k] else 0 endif | i in class, k in allsubjects ]);
3. 保留原约束逻辑
原约束无需修改,生成的LB数组与手动定义的结构完全一致:
constraint forall (i in class, k in subjclass[i]) ( sum([tbl[i,j] | j in weektime where subjects[i,j] == k]) >= LB[i,k] );
4. 处理特殊等式约束
如果需要像原替代约束中第4类LELE的等式约束(=1而非>=1),可单独补充:
constraint sum([tbl[4,j] | j in weektime where subjects[4,j] == LELE]) == 1;
若需更通用的约束类型区分,可扩展定义结构:
array[class] of list of tuple(allsubjects, int, string): LB_constraints = [ [(ITA, 2, ">="), (ING, 1, ">=")], [(DIS, 1, ">=")], [(ITA, 2, ">="), (ING, 1, ">="), (MAT, 2, ">=")], [(ITA, 2, ">="), (ING, 1, ">="), (LELE, 1, "==")] ]; constraint forall (i in class, c in LB_constraints[i]) ( let { allsubjects: k = c.1, int: val = c.2, string: op = c.3 } in if op == ">=" then sum([tbl[i,j] | j in weektime where subjects[i,j] == k]) >= val elseif op == "==" then sum([tbl[i,j] | j in weektime where subjects[i,j] == k]) == val endif );
这种方式彻底解耦数据与模型,无需维护大数组LB。
完整调整后代码示例
include "globals.mzn"; enum weektime = {M1,M2,M3,M4,M5,M6,T1,T2,T3,T4,T5,T6,W1,W2,W3,W4,W5,W6,TH1,TH2,TH3,TH4,TH5,TH6,F1,F2,F3,F4,F5,F6,S1,S2,S3,S4}; enum allsubjects = {BIO, CHA, CHI, CHO, CMAT, DES, DIR, DIS, EFI, ELE, EMM, FIS, GCA, GEE, GEO, GEP, IGI, INF, ING, IPM, ITA, LBIO, LCHA, LCHI, LCHO, LDES, LDIS, LELE, LFIS, LGCA, LGEE, LGEP, LIGI, LINF, LIPM, LLTE, LPCI, LSA, LSIS, LSTA, LTCH, LTE, LTEL, LTLC, LTMA, LTMM, LTOP, LTPS, LTTI, MAT, PCI, REL, ROB, SCI, SIS, STA, STO, TCH, TEL, TLC, TMA, TMM, TOP, TPS, TTI, n}; int: nc = 4; set of int: class = 1..nc; array[class, weektime] of allsubjects: subjects; subjects = [| EFI, EFI, LIGI, LBIO, LBIO, n, MAT, MAT, BIO, ITA, IGI, n, ING, REL, ITA, LCHO, LCHO, IGI, LCHA, LCHA, CHO, IGI, MAT, ING, ING, BIO, ITA, ITA, CHA, MAT, ITA, ITA, LIGI, LIGI | DIS, DIS, LCHI, MAT, SCI, ITA, MAT, ITA, ITA, SCI, DIR, n, ITA, LDIS, MAT, CHI, LSTA, LSTA, CHI, ING, DIR, LFIS, EFI, EFI, STA, ITA, ING, FIS, MAT, n, REL, ING, ITA, FIS | REL, MAT, SIS, ITA, TPS, ING, ITA, ITA, INF, MAT, ING, n, ROB, ROB, ING, MAT, ITA, n, ITA, INF, LTPS, LTPS, MAT, TEL, LSIS, LSIS, ITA, LINF, LINF, LINF, LTEL, LTEL, EFI, EFI | TMA, LTE, REL, MAT, LTTI, LTTI, MAT, TTI, TTI, ITA, LELE, n, ITA, MAT, LTTI, ING, LELE, LELE, ITA, EFI, EFI, LTMA, TTI, n, LTMA, LTMA, ITA, ITA, LLTE, LLTE, ITA, ING, LTE, LTE |]; array[class] of set of allsubjects: subjclass = [ {ITA, ING}, {CHI, SCI, DIS, DIR}, {ITA, ING, MAT}, {ITA, ING, LELE} ]; % 简化的LB定义:与subjclass科目顺序一一对应 array[class] of list of int: LB_simple = [ [2, 1], [0, 0, 1, 0], [2, 1, 2], [2, 1, 1] ]; array[class, allsubjects] of 0..3: LB = array2d(class, allsubjects, [ let { set of allsubjects: subjs = subjclass[i], list of int: lbs = LB_simple[i], array[subjs] of int: subj_to_lb = array1d(subjs, lbs) } in if k in subjs then subj_to_lb[k] else 0 endif | i in class, k in allsubjects ]); array[class, weektime] of var 0..1: tbl; % 原约束逻辑不变 constraint forall (i in class, k in subjclass[i]) ( sum([tbl[i,j] | j in weektime where subjects[i,j] == k]) >= LB[i,k] ); % 补充第4类LELE的等式约束 constraint sum([tbl[4,j] | j in weektime where subjects[4,j] == LELE]) == 1;
内容的提问来源于stack exchange,提问作者cnzo
相关产品推荐
相关产品推荐

