У меня есть приложение для разработки в школе, которое состоит в создании рабочих групп по предмету.Ограничения, которые я должен выполнить, следующие:
- Учащиеся, имеющие сходные 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]