Пролог: foreach или forall для решения ограничений?
Я пытаюсь планировать проект с помощью пролога SWI и CLP. Мне удалось поддерживать последовательные зависимости, но я стараюсь избегать двойного бронирования людей.
У меня есть список с именем Schedule, содержащий такие элементы, как [taskname, starttime], где starttime - это свободная переменная для решателя ограничений. Они уже ограничены последовательными зависимостями.
Я пытаюсь написать такой цикл, чтобы исключить двойное бронирование:
forall /* or maybe foreach*/ (isa(P,person), (
% Filter scheduled tasks on that person...
include(\[T,S]^(assigned(T,P)), Schedule, HisSchedule),
% Present what serialized expects..
maplist(\[T,S]^S^true, HisSchedule, Sts),
% duration is just user-defined data...
maplist(\[T,S]^D^(duration(T,D)), HisSchedule, Dus),
% Hit it...
serialized(Sts, Dus)
)),
С foreach он всегда терпит неудачу, а с другой - всегда успешно, ничего не ограничивая.
Расписание является глобальным, поскольку этот цикл касается, и цель состоит в том, чтобы ограничить его элементы времени начала, используя сериализованный. OTOH, HisSchedule, Sts и Dus зависят от конкретного человека. Поэтому я думаю, что мне нужен foreach, чтобы сделать расписание счастливым, но, в общем, сделать его счастливым. Это проблема? И если так, как я могу это исправить?
2 ответа
forall/2
встроенная функция предлагается некоторыми системами Prolog, она в значительной степени опирается на немонотонные конструкции и никогда не была разработана для совместной работы с ограничениями. То же самое верно для foreach/2
который пытается быть немного умнее.
Ответы, решения, ограничения
Итак, в чем здесь большая, фундаментальная проблема? Многие Пролог получили свою нынешнюю форму, когда ограничения не были широко известны. Таким образом, многие конструкции принимают успех цели как "да" как абсолютную истину. Но с ограничениями все немного по-другому. Успешная цель дает ответ, который теперь может вообще не содержать решения! По этой причине успех уже не тот, что раньше. Вот пример использования SICStus:
| ?- asserta(clpfd:full_answer).
yes
| ?- X mod 2 #= 1.
clpfd:(X mod 2#=1),
X in inf..sup ?
yes
| ?- X mod 2 #= 1, X mod 2 #= 0.
clpfd:(X mod 2#=0),
clpfd:(X mod 2#=1),
X in inf..sup ? ;
no
| ?- X mod 2 #= 1, X mod 2 #= 0, X in 0..9.
no
Ответы теперь могут вообще не содержать решения, другими словами, они могут быть ложными.
В вашем примере include/3
очень проблематично, так как forall/2
, Ах, а также setof/3
сходит с ума от ограничений:
| ?- setof(t, (I in 1..3 ; I in 3..5 ), _). % SICStus
yes
?- setof(t, (I in 1..3 ; I in 3..5 ),_). % SWI
I = 3.
Если вообще, правильный ответ будет I in 1..5
,
Чтобы решить эту проблему, сначала преобразуйте реляционные данные в списки:
...,
setof(P, isa(P, person), Ps),
maplist(perperson(P,Global),Ps),
...
Я сам исправил это так:
findall(Per, isa(Per,person), People),
maplist(nodoublebookings(Schedule),People),
nodoublebookings(Schedule, Per):-
include(\[T,S]^(assigned(T,Per)), Schedule, HisSchedule),
maplist(\[T,S]^S^true, HisSchedule, Sts),
maplist(\[T,S]^D^(duration(T,D)), HisSchedule, Dus),
serialized(Sts, Dus).
Почему-то я не мог писать nodoublebookings как лямбду.