Выражение числовых ограничений с использованием Prolog без CLP (FD)

#prolog

#prolog

Вопрос:

 ordering(A, B, C) :-
    integer(A),
    integer(B),
    integer(C),
    A > B,
    B > C,
    A > 0,
    10 > C.
 

удовлетворяется ordering(3,2,1). . Но когда я оставляю одну или несколько переменных в качестве переменных ordering(3,X,1). , она вычисляется false .

Чего мне не хватает?

Обновление: спасибо за все подробные ответы. Я кое-чему научился у всех из них.

Ответ №1:

integer/1 сбой, если аргумент не является целым числом, например, если вы передаете несвязанную переменную. Я считаю, что вы должны использовать CLP (FD) для таких задач. В противном случае вы можете вручную привязать / протестировать переменные в некотором целочисленном диапазоне, используя between/3 для установки этого диапазона.

Например.:

 ordering(A, B, C) :-
   between(0, 100, A),  % A is an integer in the range [0,100]
   between(0, 100, B),  % same for B
   between(0, 100, C),  % and C
   A > B,
   B > C,
   A > 0,
   10 > C.
 

Пример запуска:

 ?- ordering(3,X,1).
X = 2 ;
false.
 

Ответ №2:

Это неудивительно.

Очевидно integer(X) , что с X unbound немедленно произойдет сбой. В этом отношении это очень «важно».

Кроме того, предикат завершится ошибкой с C unbound из-за 10 > C .

В лучшем случае вы могли бы написать предикат can_be/2 так, чтобы can_be(integer,X) он выполнялся успешно, когда несвязанная переменная X «все еще может стать целым числом», а в противном случае не выполняется.

По расширению было бы a can_be_ordered(A, B, C) , который терпит неудачу, если он уверен, что [A,B,C] никогда не может быть упорядочен из-за значений, которые они уже обозначают, или завершается успешно, если [A,B,C] все еще может быть упорядочен в зависимости от того, какие значения любые несвязанные переменные в нем принимают в будущем.

Было бы еще лучше уточнить значение истинности:

ordering(List,Result)

где Result

  • true : Да, упорядочено и останется упорядоченным.
  • false : Определенно не упорядочено, и это не изменится.
  • unknown/maybe : Нет четких доказательств того, что он неупорядоченный или упорядоченный.

Затем вы также можете присоединяться ordering(List,Result) к несвязанным переменным, которые повторно проверяют порядок всякий раз, когда одна из переменных становится связанной, используя freeze/2 . Это в основном выполняет работу CLP (FD).

Ответ №3:

Вы можете отложить сравнение до инициализации переменных:

 ordering(A, B, C) :-
    greater(A, B),
    greater(B, C).

greater(X, Y) :-
    when((nonvar(X), nonvar(Y)), X > Y).
 

Тесты:

 ?- greater(3, 2).
true.

?- ordering(3, 2, 1).
true.

?- ordering(3, 2, 2).
false.

?- ordering(3, X, 1).
when(nonvar(X), 3>X),
when(nonvar(X), X>1).
 

Комментарии:

1. Почему бы не добавить условие для greater(A, C). тоже? «Сбой раньше», не так ли?

2. @DavidTonhofer достаточно умный CLP должен разобраться с этим самостоятельно.

3. Возможно, но здесь мы действуем прямо, используя when/2 triggered by nonvar/1 . Я не буду делать ставку на то, что компилятор будет таким умным. 😁