【发布时间】:2018-12-19 23:41:23
【问题描述】:
我有一个要在学校开发的应用程序,其中包括为某个主题生成工作组。 我必须满足的限制如下:
- GPA 相似的学生应该在同一组。
- 以前一起工作过的学生应该分在不同的小组中。
- 组大小应有可能的最小和最大大小。
我的谓词目前看起来像这样:
groups(Students, GPAs, PreviouslyWorkedTogether, [MinSize,MaxSize],Groups).
Students 是学生 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,依此类推。
PreviousWorkedTogether 是一个 Pairs 列表,其中每个元素都有两个以前一起工作过的学生的 ID。 (例如 [ [1,3] , [2,4] ] - 学生 1 与学生 3 一起工作,学生 2 与学生 4 一起工作)。
组是期望的结果。它与学生列表的大小相同。对于每个学生,它应该用学生所属的组 ID 填充变量。 (例如:[1,2,1,2] -> 这意味着学生 1 和 3 在第 1 组,学生 2 和 4 在第 2 组)。
我已经成功实施(我认为)组大小边界。 但是我在 GPA 和 WorkedTogether 部分遇到了问题。
因为它们看起来非常相似,所以我只会接近其中一个。
下一个代码 sn-p 是我目前对 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]
【问题讨论】:
标签: prolog clpfd sicstus-prolog