【问题标题】:Prolog Restrictions Minimize Error. labeling/2 argument 1 errorProlog 限制最小化错误。 labeling/2 参数 1 错误
【发布时间】: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


    【解决方案1】:

    您遇到了一个实例化错误,因为您的变量 SumDiffs 在功能上不依赖于 LabelVars。一些cmets:

    主要问题是目标函数。规范有点模棱两可:

    具有相似 GPA 的学生应该在同一组。

    显然,您已将其解释为:

    找到一个最小化 sum(g in 1..n)(max(i in group g)(GPA[i]) - min(g 组中的 i)(GPA[i]))

    我猜这就是你在constrain_GPA/5 的麻烦的根源。我猜您正在尝试计算每个组的数量 DiffsH 并最小化它们的总和。计算这个数量有点尴尬。您不能那样使用findall/3,因为element/3 是一个约束,并且在回溯时永远不能返回更多值。我会稍微不同地阅读规范:

    求和最小化的解(i,j在同一组中)(|GPA[i] - 平均绩点[j]|)

    这更容易实现:计算 (n-1)*(n-2) 个数量,每个有序对 (i,j) 一个,然后取它们的总和。

    或者您可以通过另一种方式阅读规范:

    找到一个解,如果 GPA[i] = GPA[j],那么 i 和 j 应该是 同组。

    把整个事情变成一个可满足性问题。我想请我的教授澄清一下规范。

    小点:

    • 代替nvalue(MaxGroupID,Groups)maximum(MaxGroupID,Groups) 对我来说可能更有效率。

    • 使用内置的(A -&gt; B ; C),而不是if_then_else(A,B,C)

    • constrain_count/4 可以替换为 global_cardinality/2,但请记住,您必须允许空组。

    我希望这可以帮助你完成你的任务。

    【讨论】:

    • 该项目是关于优化的。限制:“具有相似 GPA 的学生应该在同一组。”是关于获得可能的最佳解决方案(关闭组成员的 GPA)。这就是我使用最小化的原因。
    • 即,“找到一个使总和(i,j 在同一组中)(|GPA[i] - GPA[j]|) 最小化的解决方案。”
    • 感谢您的反馈。我相信如果我解决了 findall 问题,这段代码就可以工作。由于 findall 不能在这里使用,我现在的问题如下:给定一个列表,我怎样才能得到一个值出现的位置。 (即:给定列表 [1,2,3,1,2,1] 和值 1,它应该返回 [1,4,6],因为它们是值 1 的位置)。我相信我必须使用元素,但是如果我有多个值,它不会以我想要的格式给出答案,即索引列表
    • 问题是,你需要一个约束,比如说,occurrences(Values,N,Positions),它将 Positions 约束为 Values 的位置列表/位置集,其中N 出现。您不能对非固定长度的列表进行约束。如果 SICStus 包含的变量的域不是整数,而是整数集,那么您可以使用它。但 SICStus 不支持这一点。出于这个原因,我建议对规范进行二读。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 2012-02-07
    相关资源
    最近更新 更多