- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 MiniZinc 来解决调度问题。这是主要设置:
当然学生不能同时参加两个主题,每个主题也有最小/最大人数(但同一主题可能有不同的类(class),或者另一个主题没有类(class))。这是最重要的约束条件,我们可以将其视为可满足性问题,尽管尝试最大限度地提高学生的快乐度是一个很好的奖励。
我尝试了以下方法,翻译了我所有的约束:
int: n; % number of students
int: m; % number of topics
int: c; % number of courses each student will take
int: maxseats; % number of seats available per course max
int: minseats; % number of seats minimum per course
int: timeslots; % possible time slots for the courses
set of int: STUDENTS=1..n; % students
set of int: PREFERENCE=1..m; % possible preference rankings
set of int: TOPICS=1..m; % different topics
set of int: TIMESLOTS=1..timeslots;
array[STUDENTS,TOPICS] of PREFERENCE: preference; % ranking of topics by each student
array[STUDENTS,1..c] of var TOPICS: course; % topics assigned to each student
array[TOPICS] of var TIMESLOTS: schedule; % time slot assigned to topics
include "alldifferent.mzn";
constraint % students have different topics
forall(student in STUDENTS)(alldifferent([course[student,i] | i in 1..c]));
constraint % no student has two topics at the same time
forall(student in STUDENTS)(forall(i,j in 1..c where i<j)(schedule[course[student,i]] != schedule[course[student,j]]));
constraint % less students per topic than available seats (NOTE : groups can be duplicated)
forall(topic in TOPICS)(sum(student in STUDENTS where exists(i in 1..c)(course[student,i] = topic))(1) <= maxseats);
constraint % more students per topic than the minimum
forall(topic in TOPICS)(sum(student in STUDENTS where exists(i in 1..c)(course[student,i] = topic))(1) >= minseats);
var int: satisfaction = sum(student in STUDENTS)(sum(i in 1..c)(preference[student, course[student,i]]));
solve minimize satisfaction;
问题是这只适用于少数学生,但对于我的学生名单(我有大约 100 个,虽然我没有那么多,但即使是 20 个也没有得出任何结论),这还远远不够十分钟后)。
这是我的部分数据文件(为简单起见,删掉了一些学生,但已经太长了:
n = 10;
m = 7;
c = 3;
maxseats=18;
minseats=1;
timeslots=4;
preference =[|
1,2,5,3,7,4,6|
6,4,7,5,1,2,3|
1,2,6,4,5,7,3|
5,3,1,2,6,4,7|
5,2,1,6,3,7,4|
7,5,1,6,3,2,4|
1,7,6,4,5,3,2|
1,4,2,6,3,5,7|
4,6,1,5,2,3,7|
1,6,4,3,5,7,2|
|];
我可以添加任何相关约束或结构来帮助求解器完成工作吗?
*** 编辑。这是进一步的尝试。我注意到另一个问题:基本上,组不能太大(小于 maxseats),因此每个主题会有不同的组(同一个老师)。因此,学生不仅不能同时上课,而且同一主题的不同群体也应该区分,不能同时上课。这看起来像是一个更大的组合问题!也许有一个聪明的方法来打包它,但现在我基本上选择了复制主题。
这是模型:
int: n; % number of students
int: m; % number of topics
int: c; % number of courses each student will take
int: g=5; % number of instances of each course
int: maxseats; % number of seats available per course max
int: minseats; % number of seats minimum per course
int: timeslots; % possible time slots for the courses
set of int: STUDENTS=1..n; % students
set of int: PREFERENCE=1..m; % possible preference rankings
set of int: TOPICS=1..g*m; % different topics
set of int: TIMESLOTS=0..timeslots;
array[STUDENTS,1..m] of PREFERENCE: preference; % ranking of topics by each student
array[STUDENTS, PREFERENCE] of TOPICS: prefRank = array2d(STUDENTS, PREFERENCE, [rank
| student in STUDENTS, p in 1..m, rank in 1..m where preference[student, rank] == p]);
array[STUDENTS,1..c] of var TOPICS: course; % topics assigned to each student
array[TOPICS] of var TIMESLOTS: schedule; % time slot assigned to topics
function int: topicToGroupFix(var int: t) =
fix(((t-1) mod g) + 1);
function var int: topicToTopic(var int: t) =
((t-1) div g) + 1;
function int: topicToTopicFix(var int: t) =
fix(((t-1) div g) + 1);
function int: topicGroupToTopic(int: t, int: gg) =
((t-1) * g) + gg;
array[TOPICS] of var 0..maxseats: number; % number of people taking each course
constraint
forall (topic in TOPICS)(number[topic] = sum(student in STUDENTS, i in 1..c)(course[student,i] == topic));
include "globals.mzn";
constraint % before using another topic group make sure the previous one has students in it
forall(t in 1..m, gg in 1..g-1)( number[topicGroupToTopic(t,gg+1)] > 0 -> number[topicGroupToTopic(t,gg)] >= minseats );
constraint % if students are assigned to a topic group it must have enough
forall(t in TOPICS)( number[t] > 0 -> number[t] >= minseats );
constraint % make sure topics are slotted at different times
forall(t in 1..m)( alldifferent_except_0([schedule[x] | x in topicGroupToTopic(t,1)..topicGroupToTopic(t,g)]));
array[STUDENTS,1..c] of var PREFERENCE: courseRank;
constraint % channeling constraint to obtain topic ranking
forall(student in STUDENTS, i in 1..c)(courseRank[student, i] = prefRank[student, topicToTopic(course[student, i])]);
constraint % no student has two topics at the same time
forall(student in STUDENTS)(alldifferent([schedule[course[student,i]] | i in 1..c]));
constraint % students have different topics (and break symmetries)
forall(student in STUDENTS)(strictly_increasing([courseRank[student, i] | i in 1..c]));
constraint % students have different topics
forall(student in STUDENTS)(alldifferent([topicToTopic(course[student, i]) | i in 1..c]));
constraint % fairness - don't want any one student to get a bad schedule relative to others
forall(student in STUDENTS)(sum([courseRank[student,i] | i in 1..c]) <=
min([sum([courseRank[s,i] | i in 1..c]) | s in STUDENTS where s != student])+1);
%constraint % fairness - don't want any one student to get a bad schedule relative to others
% forall(student in STUDENTS)(sum([courseRank[student,i] | i in 1..c]) <=
% min([sum([courseRank[s,i] | i in 1..c]) | s in STUDENTS])+1);
constraint % fairness - don't a student get a much worse choice than others
forall(student in STUDENTS)(courseRank[student,c] <= min([courseRank[s,c] | s in STUDENTS where s != student])+1);
%constraint % fairness - don't a student get a much worse choice than others
% forall(student in STUDENTS)(courseRank[student,c] <= min([courseRank[s,c] | s in STUDENTS])+1);
% break symmetries on the schedule
constraint forall(t in TOPICS)(if number[t] == 0 then schedule[t] == 0 else schedule[t] >= 1 /\ schedule[t] <= t endif);
%constraint forall(t in 1..m)(schedule[t] <= t);
constraint forall(t in 1..m*g-1)(schedule[t+1] <= (max(x in TOPICS)(schedule[x])+1));
var int: satisfaction = sum(student in STUDENTS, i in 1..c)(courseRank[student,i]);
solve :: int_search(courseRank, smallest, indomain_min)
minimize satisfaction;
%solve minimize satisfaction;
output(["satisfaction Level: \(satisfaction)\n"]);
output(["student", "\t", "topic", "\t\t", "group", "\t\t", "courseRank", "\n"]);
output([show(student) ++ "\t" ++ show([topicToTopicFix(course[student,i]) | i in 1..c]) ++ "\t" ++
show([topicToGroupFix(course[student,i]) | i in 1..c]) ++ "\t" ++
show([courseRank[student,i] | i in 1..c]) ++ "\n" | student in STUDENTS]);
output(["studentsPerTopic: \(number)\n"]);
output(["schedule: \([schedule[x] | x in TOPICS])\n"]);
可以使用相同的数据文件,但是有 100 个学生,即使 c=1(即只分配一节课,这应该是微不足道的!)也不会在数小时内完成...
有什么我可以做的,或者这个问题对于 MiniZinc 来说真的太大了吗?
最佳答案
我试着调整你的模型:
include "globals.mzn";
int: n; % number of students
int: m; % number of topics
int: c; % number of courses each student will take
int: maxseats; % number of seats available per course max
int: minseats; % number of seats minimum per course
int: timeslots; % possible time slots for the courses
set of int: STUDENTS=1..n; % students
set of int: PREFERENCE=1..m; % possible preference rankings
set of int: TOPICS=1..m; % different topics
set of int: TIMESLOTS=1..timeslots;
set of int: COURSES=1..c;
array[STUDENTS,TOPICS] of PREFERENCE: preference; % ranking of topics by each student
array[STUDENTS,COURSES] of var TOPICS: course; % topics assigned to each student
array[TOPICS] of var TIMESLOTS: schedule; % time slot assigned to topics
constraint % students have different topics; we thus enforce topics per student to be sorted
forall(student in STUDENTS, i in 1..c-1)(course[student,i] < course[student,i+1]);
constraint % no student has two topics at the same time
forall(student in STUDENTS)(alldifferent([schedule[course[student,i]] | i in COURSES]));
constraint % students per topic within allowed bounds (NOTE : groups can be duplicated)
forall(topic in TOPICS)(sum([(course[student,i] == topic)| student in STUDENTS, i in COURSES]) in minseats .. maxseats);
var n..n*m: dissatisfaction = sum(student in STUDENTS)(sum(i in COURSES)(preference[student, course[student,i]]));
constraint dissatisfaction < n * 5;
遗憾的是,对于给定的数据集,求解时间仍然超出我的耐心。
更新:
我第二次尝试使用 bool 决策变量来表示每个主题是否存在学生。
include "globals.mzn";
int: n; % number of students
int: m; % number of topics
int: c; % number of courses each student will take
int: maxseats; % number of seats available per course max
int: minseats; % number of seats minimum per course
int: timeslots; % possible time slots for the courses
set of int: STUDENTS=1..n; % students
set of int: PREFERENCE=1..m; % possible preference rankings
set of int: TOPICS=1..m; % different topics
set of int: TIMESLOTS=1..timeslots;
set of int: COURSES=1..c;
array[STUDENTS,TOPICS] of PREFERENCE: preference; % ranking of topics by each student
array[TOPICS, STUDENTS] of var bool: course; % students assigned to topics
array[TOPICS] of var TIMESLOTS: schedule; % time slot assigned to topics
constraint % enforce the number of courses per student
forall(student in STUDENTS)(c = sum([course[t, student] | t in TOPICS]));
constraint % no student has two topics at the same time
forall(student in STUDENTS)(alldifferent([schedule[t] | t in TOPICS where course[t, student]]));
constraint % students per topic within allowed bounds (NOTE : groups can be duplicated)
forall(topic in TOPICS)(sum([course[topic, student] | student in STUDENTS]) in minseats .. maxseats);
constraint % limit the dissatisfaction of students
max([preference[student, t] | student in STUDENTS, t in TOPICS where course[t, student]]) < 4;
使用求解器后端 Chuffed、Google OR 工具或 COIN-BC,这个问题在 10 秒内解决了。
如果最差偏好值的上限低于 3,则没有找到解决方案。选择两个主题并不奇怪。
关于optimization - 针对调度问题优化 MiniZinc 约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73479796/
我想在 MiniZinc 中用相同的项目创建两个数组,不一定按相同的顺序。在这里,A0 中的每一项也应该在 A1 : array[1..3] of var int:A0; array[1..3] of
假设我想计算 {1,2,..100} 的 80 个元素子集的数量,使它们的总和为 3690。 我有以下模型: array[1..100] of var 0..1: b; constraint (sum
我看到 MiniZinc Handbook 中的各个地方都使用了 $ (主要在 Reference Manual 部分),但我一直找不到定义。有人可以向我解释一下吗?谢谢。 最佳答案 MiniZinc
在斑马谜题 ( http://rosettacode.org/wiki/Zebra_puzzle#MiniZinc ) 的解决方案中,有一个约束条件,规定其中一只宠物必须是斑马: var 1..5:
在斑马谜题 ( http://rosettacode.org/wiki/Zebra_puzzle#MiniZinc ) 的解决方案中,有一个约束条件,规定其中一只宠物必须是斑马: var 1..5:
我正在尝试解决 MiniZinc 中的一个练习,其中部分排序关系由二维数组给出: enum NODE = { A, B, C, D, E }; int : SOURCE = 1; int : TARG
我正在熟悉 MiniZinc 的基础知识。因此,借助 MiniZinc IDE,我编写了如下代码片段 solve satisfy; string: s1 = "hello"; string: s2 =
锌规范是这样说的: If no output item is present, the implementation should print all the global variables and
MiniZinc 中的 channel 是什么?你能提供一个简单的例子来解释 channel 吗?最后,什么是逆? 最佳答案 两者都用于建立两个数组之间的双向关系。 设 f 是一个数组,index_s
FlatZinc 文档说 只有非标谓词必须在 FlatZinc 模型的顶部声明: Predicates used in the model that are not standard FlatZinc
我有一个二维网格,其中某些单元格值会产生不同的分数,我想通过为单元格分配值来最大化分数。是否可以跟踪求解器在求解过程中尝试的每个网格?下面是模型的一个片段,只是为了演示这个想法。 int: i_cou
picat求解器 (v. 2.6#2) 指出示例模型 knights.mzn包含在 minizinc 存储库中,特此复制粘贴: % RUNS ON mzn20_fd % RUNS ON mzn-fzn
尝试学习 minizinc,但在完成示例之后,我是否可以确认,如果我想获得多个输出,或者有一种更“自然的 minizinc”方式来获得它,我实际上必须编写一些程序语言。 例如,假设我想让所有不同的数字
练习是: n个人想要拍一张合影。每个人都可以给出他或她旁边的偏好想要放置在照片上。要解决的问题是找到满足最大数量的放置位置偏好。 到目前为止我编写的代码: include "globals.mzn";
我正在尝试编写一个带有嵌套循环的输出语句,以及在外部级别的重要输出。如果 Minizinc 有一个顶级 for 命令,我会做类似的事情 for (f in Foo) ( output(["Foo:
我想检查 1 到 5 之间的哪个数字没有出现在数组组中,并将这个(或多个)数字放在另一个数组中。 g=2; set of int: GROUPS = 1..g; groups = [{1, 3}, {
问题 给定一个 MiniZinc 字符串数组: int: numStats; set of int: Stats = 1..numStats; array[Stats] of string: stat
我有一个变量,它应该只在特定条件下有一个值,所以我想它需要是一个可选变量。如果满足该条件,则可选变量应限制为集合的元素。 问题是,MiniZinc 似乎不喜欢可选变量和集合。 如何重写,使 MiniZ
我如何使用嵌套 for 循环(就像下面 java 所做的那样)在 Minizinc 中生成/填充数组? int[][] input1 = {{1,1,1}, {3,3,3}, {5,5,5} }; i
我正在使用 minizinc 和 gecode 以分布式方式解决最小化问题。我有多个分布式服务器,它们使用相同的输入来解决相同的模型,并且我希望所有服务器都能获得相同的解决方案。 问题是模型有多个解决
我是一名优秀的程序员,十分优秀!