如何在答案集编程中找到倒数第二个值(ASP Clingo)

How to find second last value in Answer Set Programming (ASP Clingo)

我正在使用答案集编程 (Clingo) 为大学课程表建模。要求是每节课必须分配到特定的周、日和开始/结束时间,直到达到总小时数。

一天最多8小时,每节课最少2小时。另外预定课程到第10周。

week(1..10). time(9,11;11,13;14,16;16,18).  

因此,首先我生成了每个分配的课程时段

TotalHours { assigned(Week,Day,Start,End,Course,Teacher) : day(Day), time(Start,End), week(Week) } TotalHours :-
lesson(Course,Teacher,TotalHours).

之后,对于其他要求和规则,我需要找到时间表中分配的最后一门课程。我不知道这是否是个好方法,但我找到了解决方案

MaxWeek =  #max {Week : assigned(Week,_,_,_,Course,_)},
MaxDay = #max {Day : assigned(MaxWeek,Day,_,_,Course,_)},
MaxStart= #max {Start : assigned(MaxWeek,MaxDay,Start,_,Course,_)},
assigned(_,_,_,_,Course,_).

我是 ASP 的新手,到目前为止我找不到找到时间表(周、日、开始、结束)中分配的课程的倒数第二节课的好方法其他时间表要求。

举个例子

assigned(1,Monday,9,11,History,John) , assigned(1,Tuesday,11,13,Math,Smith), assigned(4,Tuesday,16,18,History,John),assigned(5,Monday,11,13,History,John)

我想找到历史课的倒数第二课

assigned(4,Tuesday,16,18)

非常感谢任何提示或解决方案

考虑让第二个分配的谓词(具有不同的元数)变得更绝对,例如:

assigned((Week-1)*7*24+Day+Start,End,Course,Teacher) :- assigned(Week,Day,Start,End,Course,Teacher).

现在您只有一个字段对所有作业进行了完全排序,即自年初以来的总小时数。

要查找最后的课程,最后的聚合表现非常糟糕,可以使用链接约束进行优化:

auxLastCourse(C,T) :- assigned(T,_,C,_).
auxLastCourse(C,T-1) :- auxLastCourse(C,T), T > 0.
lastCourse(C,T) :- auxLastCourse(C,T), not auxLastCourse(C,T+1).

另请注意,在您的示例中,夜间没有任何课程,因此可以通过不那么细化和明确表示每个小时来进一步优化,但可能只是在可能的时间表中实际发生的时间。这意味着在几周、几天和几小时内用明确的下一个关系替换辅助代码中的 T-1。目前我只是懒得添加这样的东西。

对于倒数第二门课程,您可以做完全相同的事情:

auxSecondLastCourse(C,T) :- assigned(T,_,C,_), not lastCourse(C,T).
auxSecondLastCourse(C,T-1) :- auxSecondLastCourse(C,T), T > 0.
secondLastCourse(C,T) :- auxSecondLastCourse(C,T), not auxSecondLastCourse(C,T+1).

PS:请注意,我假设您的日期是数字 0..6,而不是您示例中的单词,我相信您会想出如何使用另一个来翻译它们谓词。

PPS: 我没有测试代码,因为你没有提供 MWE。