Пролог Ограничения Ошибка минимизации.маркировка / 2 аргумента 1 ошибка - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть приложение для разработки в школе, которое состоит в создании рабочих групп по предмету.Ограничения, которые я должен выполнить, следующие:

  • Учащиеся, имеющие сходные GPA, должны быть в одной группе.
  • Учащиеся, которые ранее работали вместе, должны быть в разных группах.
  • Размер группы должен иметь минимальный и максимально возможный размер.

Мой предикат в настоящее время выглядит следующим образом:

groups(Students, GPAs, PreviouslyWorkedTogether, [MinSize,MaxSize],Groups).

Студенты - это список идентификаторов студентов (например,:. [1,2,3,4]).

GPA - это список GPA (например: [4.0,3.5,2.0,3.7]).

Приведенные выше списки относятсядруг с другом, так что учащийся с ID = 1 имеет средний балл 4,0, ID = 2 имеет средний балл 3,5 и т. д.

PreviouslyWorkedTogether - это список пар, где каждый элемент имеет идентификаторы двух студентов, которыеработал вместе раньше.(бывший [[1,3], [2,4]] - студент 1 работал со студентом 3, а студент 2 работал со студентом 4).

Группы - желаемый результат.Он имеет такой же размер списка студентов.Для каждого ученика он должен заполнить переменную идентификатором группы, к которой принадлежит ученик.(например: [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.

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]

1 Ответ

0 голосов
/ 19 декабря 2018

Вы получаете ошибку экземпляра, потому что ваша переменная SumDiffs функционально не зависит от LabelVars.Некоторые комментарии:

Основная проблема - это целевая функция.Спецификация немного двусмысленна:

Учащиеся, имеющие схожие GPA, должны быть в одной группе.

Очевидно, вы интерпретировали это как:

Найти решение, которое минимизирует сумму (g в 1..n) (max (i в группе g) (GPA [i]) - min (i в группе g) (GPA [i]))

Полагаю, это источник вашей проблемы в constrain_GPA/5.Я предполагаю, что вы пытаетесь вычислить количество DiffsH на группу и минимизировать их сумму.Вычислить это количество немного неудобно.Вы не можете использовать findall/3 таким образом, потому что element/3 является ограничением и никогда не сможет вернуть больше значений при возврате.Я бы прочитал спецификацию немного по-другому:

Найти решение, которое минимизирует сумму (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, ноимейте в виду, что вы должны учитывать пустые группы.

Надеюсь, это поможет вам выполнить задание.

...