我有一个在学校开发的应用程序,其中包括为某个主题生成工作组。 我必须满足的限制如下:
我的谓词当前如下:
groups(Students, GPAs, PreviouslyWorkedTogether, [MinSize,MaxSize],Groups).
学生是学生ID的列表(例如:。[1,2,3,4])。
GPA是GPA的列表(例如:。[4.0,3.5,2.0,3.7])。
上面的列表相互关联,因此ID = 1的学生的GPA为4.0,ID = 2的GPA = 3.5,依此类推。
PreviouslyWorkedTogether是对的列表,其中每个元素具有两个以前一起工作的学生的ID。 (例如[[1,3],[2,4]]-学生1与学生3合作,学生2与学生4合作)。
分组是期望的结果。它具有与学生列表相同的大小。对于每个学生,应使用该学生所属的组ID填充变量。 (例如:。[1,2,1,2]->这意味着学生1和3在第1组中,学生2和4在第2组中。)
我已经成功实现了(我认为)组大小边界。 但是,我在GPA和WorkedTogether部分遇到了麻烦。
由于它们看起来彼此非常相似,所以我只会接近其中之一。
下一个代码段是我当前解决GPA问题的方法。
getGPAs(_, [], []).
getGPAs(GPAs, [H|T], [GroupGPAsH | GroupGPAsT]):-
element(H, GPAs, GPA),
GroupGPAsH #= GPA,
getGPAs(GPAs, T, GroupGPAsT).
constrain_GPA(_, _, MaxGroupID, GroupID, []):- GroupID #> MaxGroupID, !.
constrain_GPA(GPAs, Groups, MaxGroupID, GroupID, [DiffsH | DiffsT]):-
findall(Index, element(Index,Groups,GroupID),GroupElems),
getGPAs(GPAs, GroupElems, GroupGPAs),
minimum(MinGPA, GroupGPAs),
maximum(MaxGPA, GroupGPAs),
NextID is GroupID + 1,
DiffsH #= MaxGPA - MinGPA,
constrain_GPA(GPAs, Groups, MaxGroupID, NextID, DiffsT).
首先,我找到属于GroupID的元素的所有索引,并将其存储在列表(GroupElems)中。
之后,我使用这些索引来获取组中每个成员的GPA。
然后,我只需要获取组中GPA的最大值和最小值并计算差异,将其存储在包含每个组GPA差异的列表中即可。
在那之后,我要做的就是最小化数组值的总和,这样我们得到的结果将包含具有相似GPA的组的最佳结果。
constrain_GPA(GPAs, Groups, MaxGroupID, 1, Diffs),
sum(Diffs, #=, SumDiffs),
labeling([minimize(SumDiffs)], Groups),
但是,它继续使我对标签谓词产生错误。我相信问题是findall谓词。我不知道我是否可以使用它。
逻辑似乎正确,但是编码是问题所在。
这是完整的代码(最后是测试查询)
:- use_module(library(clpfd)).
:- use_module(library(lists)).
groups(Students, GPAs, PreviousUCsInfo, [MinSize, MaxSize], Groups):-
%create an array representing the groups of each student
length(Students, NumStudents),
length(Groups, NumStudents),
MaxNumGroups is NumStudents div MinSize,
MinNumGroupsMod is NumStudents mod MaxSize,
if_then_else(
(MinNumGroupsMod = 0),
(MinNumGroups is NumStudents div MaxSize),
(MinNumGroups is (NumStudents div MaxSize) + 1)
),
domain([MaxGroupID], MinNumGroups, MaxNumGroups),
domain(Groups, 1, MaxNumGroups),
%constrain group size
nvalue(MaxGroupID, Groups),
constrain_count(Groups, [MinSize, MaxSize], MaxGroupID, 1),
%contrain GPA
constrain_GPA(GPAs, Groups, MaxGroupID, 1, Diffs),
sum(Diffs, #=, SumDiffs),
append(Groups, [MaxGroupID], LabelVars),
labeling([minimize(SumDiffs)], LabelVars).
constrain_count(_, _, MaxGroupID, GroupID):- GroupID #> MaxGroupID.
constrain_count(Groups, [MinSize, MaxSize], MaxGroupID, GroupID):-
count(GroupID, Groups, #=, Times),
Times #>= MinSize #/\ Times #=< MaxSize,
NextID is GroupID + 1,
constrain_count(Groups, [MinSize, MaxSize], MaxGroupID, NextID).
getGPAs(_, [], []).
getGPAs(GPAs, [H|T], [GroupGPAsH | GroupGPAsT]):-
element(H, GPAs, GPA),
GroupGPAsH #= GPA,
getGPAs(GPAs, T, GroupGPAsT).
constrain_GPA(_, _, MaxGroupID, GroupID, []):- GroupID #> MaxGroupID, !.
constrain_GPA(GPAs, Groups, MaxGroupID, GroupID, [DiffsH | DiffsT]):-
findall(Index, element(Index,Groups,GroupID),GroupElems),
getGPAs(GPAs, GroupElems, GroupGPAs),
minimum(MinGPA, GroupGPAs),
maximum(MaxGPA, GroupGPAs),
NextID is GroupID + 1,
DiffsH #= MaxGPA - MinGPA,
constrain_GPA(GPAs, Groups, MaxGroupID, NextID, DiffsT).
if_then_else(C, I, _):- C, !, I.
if_then_else(_, _, E):- E.
%Query to test: groups([1,2,3],[4,2,3],_,[1,2],Var).
% The results expected are:
%for groups of 1 student every combination of groups.
%For groups of 2 students the following:
%[1,2,1]
%[1,2,2]
%[2,1,1]
%[2,1,2]
答案 0 :(得分:1)
您收到实例化错误,因为变量SumDiffs
在功能上不依赖于LabelVars
。一些评论:
主要问题是目标函数。规范有点模棱两可:
GPA相似的学生应该在同一组中。
显然,您将其解释为:
找到一个最小化sum(g。1.n)(max(i in group g)(GPA [i])-min(g组中的i)(GPA [i]))
我想这是您在constrain_GPA/5
中遇到麻烦的根源。我猜您正在尝试计算每个组的数量DiffsH
,并将其总和最小化。计算该数量有点尴尬。您不能以这种方式使用findall/3
,因为element/3
是一个约束,并且永远不能在回溯时返回更多值。我会稍微不同地阅读规范:
找到一个使sum(i,j在同一组中)最小的解决方案(| GPA [i]- GPA [j] |)
这更容易实现:计算(n-1)*(n-2)个数量,每个有序对(i,j)取一个,然后求和。
或者您可以通过另一种方式阅读规范:
找到一个解决方案,使得如果GPA [i] = GPA [j],则i和j应为 在同一组中。
将整个问题变成可满足性的问题。我想请教授对规范进行澄清。
小点:
代替nvalue(MaxGroupID,Groups)
,maximum(MaxGroupID,Groups)
对我来说可能更有效率。
使用内置的if_then_else(A,B,C)
代替(A -> B ; C)
。
constrain_count/4
可以替换为global_cardinality/2
,但请记住,您必须允许使用空组。
我希望这可以帮助您完成任务。