Получение приказа в разрешении предикатов

Посмотрите на следующие цели (я использую swi-prolog с clpfd от Маркуса Триски):

result(Input,Result) :-
    Input #> 10,
    Result=decline.
result(Input,Result) :-
    Input in 0..20,
    Result=offer.

Возможный запрос выглядит так:

?- result(15,B).
B = decline ;
B = offer.

Я хочу добавить заказ или какой-то приоритет решения. Если "отклонение" является допустимым ответом для Input=15, то вторую цель больше не следует рассматривать, так что только B=decline является решением, но не B=offer.

Я знаю, что могу добавить !/0, но тогда обратное не сработает. Дайте мне все возможные ответы на этот предикат.

Рассматривая этот пример, Result=offer должно быть истинным только для Input 0..10, потому что в противном случае должна сработать более высокая цель предыдущего снижения.

Думаю ли я слишком императивно, когда пытаюсь рассмотреть порядок внутри предикатов?


person ri5b6    schedule 22.11.2012    source источник
comment
Я также знаю, что могу, конечно, изменить ограничения для входной переменной, но это не должно быть решением.   -  person ri5b6    schedule 22.11.2012
comment
Существует порядок внутри предложений предиката. Я думаю, что решение здесь - изменение ограничений для входной переменной.   -  person gusbro    schedule 22.11.2012
comment
Да, вы мыслите процедурно, но это проблема сама по себе. Почему вы используете CLP / FD? То, как вы его настроили, не похоже на программу ограничения и генерации, а просто обычную программу генерации и тестирования.   -  person Fred Foo    schedule 22.11.2012
comment
Кроме того, ваши требования кажутся противоречивыми: если отклонение является допустимым ответом на Input=15, то вторая цель больше не должна рассматриваться, что означает, что все возможные ответы должны быть просто [decline], верно?   -  person Fred Foo    schedule 22.11.2012
comment
Не совсем так, должно быть так: Result=decline, если Input in 11..sup и Result=offer, если Input in 0..10   -  person ri5b6    schedule 22.11.2012


Ответы (4)


Здесь есть несколько проблем, давайте начнем с самого очевидного:

Проблемы моделирования

У вас есть отношение (result/2, возможно, не лучшее название), и предполагается, что это отношение моделируется, когда decline и когда offer должны быть истинными. Прежде чем читать вашу программу, я предпочитаю спросить Пролог:

?- result(X, decline), result(X, offer).
X in 11..20 ;
false.

Таким образом, для значений от 11 до 20 ваше отношение неоднозначно. Если вы хотите принять решение, сначала исправьте это отношение. Собственно, я бы начал с

  • лучшее название для отношения, которое проясняет, что это отношение
  • без повелительного словоблудия (например, Input или императивы)
  • более компактная формулировка, вам не нужно столько (=)/2 целей в вашей программе. Вместо этого вы можете написать это так:
heigth_decision(I, decline) :-
   I #< 10.

Ответы и успех против решений в CLP

И есть еще одна проблема, более фундаментальная. На самом деле это гораздо серьезнее, поскольку все приведенные до сих пор SO-ответы полностью игнорируют этот аспект. Это понятие ответов и успеха и, с другой стороны, понятие решений.

Когда вы задаете запрос на Прологе, вы получаете ответ. Такой ответ может содержать решения, например ответ L = [_,_], который содержит бесконечно много решений. Или ответ может содержать ровно одно решение, например Decision = decline. Но если вы используете ограничения вроде library(clpfd), между ними гораздо больше.

Теперь вы можете получить конечное количество решений:

?- abs(X) #< 3.
X in -2..2.

Или бесконечно много:

?- X #> Y.
Y#=<X+ -1.

Но вы также можете получить ровно одно решение, которое не похоже на одно:

?- 2^X #= 1.
2^X#=1.

Итак, просто повторим это: у нас есть ровно одно решение в целых числах, но для Пролога это слишком сложно. Мы получили ответ, который гласил: Да, это все правда, при условии, что весь этот мелкий шрифт верен.

Хуже того, иногда мы получаем ответы, в которых нет решения.

?- X^X#=0.
X^X#=0.

Если бы Пролог был достаточно умным, он бы ответил false. Но он не всегда может быть таким умным просто потому, что вы можете легко формулировать неразрешимые проблемы. Такой ответ иногда называют несоответствием. Немецкое понятие Scheinlösung (~ поддельное решение, но с менее негативным подтекстом) передает идею немного лучше.

Таким образом, ответ может содержать решения, но некоторые ответы вообще не содержат решений. По этой причине успех цели не может считаться существованием решения! То есть все SO-ответы, предлагающие какую-то фиксацию как (;) / 2 if-then-else, once / 1 или! / 0, неверны, если они принимают успех как решение. Чтобы убедиться в этом, попробуйте их:

?- X^X#=0, result(X,decline).
X in 11..sup,
X^X#=0 ;
false.

?- X^X#=0, result(X,offer).
X in 0..20,
X^X#=0.

Так как же теперь можно быть в чем-то уверенным?

  • Вы можете рассчитывать на провал гола.

  • Вы можете попробовать labeling/2, но это работает только на конечных доменах.

  • Вы можете использовать call_residue_vars/2 и copy_term/3, чтобы определить, есть ли ограничения, "торчащие"

  • К сожалению, вы не можете полностью полагаться на верхний уровень SWI, который скрывает ограничения, не связанные с переменными в ответе. Только SICStus отображает их правильно.

person false    schedule 23.11.2012
comment
Вау, еще раз спасибо за то, что предоставили мне так много справочной информации. Я очень ценю это, и вы полностью поняли мою проблему здесь. Действительно, успех здесь не всегда является выходом. - person ri5b6; 25.11.2012

Меня озадачивает, когда вы говорите, что «наоборот не сработает». Почему вы хотите пойти другим путем?

Это явный случай детерминированного поиска, и способ сделать это в Prolog - сократить. Если первое правило выполнено, не оставляйте другие ветки открытыми. В качестве альтернативы вы можете сделать проверяемые диапазоны взаимоисключающими.

Если вы не просто бездельничаете и пытаетесь реализовать что-то серьезное, я рекомендую прочитать правила с правилами с приоритетом и телеореактивными правилами. Вы должны найти фреймворки, построенные на основе Prolog, которые можно использовать для решения вашей проблемы, не изобретая велосипед.

person NotAUser    schedule 22.11.2012
comment
Что ж, я думаю, мне понадобится предикат, который принимает входные данные и дает правильный ответ. Вот где начинается сокращение, и это работает для этого. Но я бы хотел иметь возможность запрашивать: ?-result(Input,Ouput), и он должен возвращать мне следующее: Result=decline, Input in 11..sup и Result=offer,Input in 0..10 - person ri5b6; 22.11.2012
comment
Хорошо, вот как бы я это сделал. Я бы переосмыслил вашу проблему. Вы хотите назначить результат на основе самого сурового условия. Поэтому сначала определите заказ, например, отклоните предложение ››. Затем используйте также конечные ограничения на результат, скажем, что Результат - это переменная с доменом {отклонение, предложение}. Обработайте результат через ограничения и получите в итоге самый строгий. - person NotAUser; 22.11.2012
comment
Сейчас я делаю следующее: Input #> 10, decline; #\ Input #>10, Input in 0..20, Result=offer. Затем я получаю ожидаемый результат: снижение на 11..sup, предложение на 0..10. Я надеялся, что есть более элегантный способ сделать это, чем отрицать каждое условие в каждой цели. - person ri5b6; 23.11.2012
comment
Ваш совет по использованию сокращений неверен. Независимо от того, выполняется ли первое правило успешно (как вы обеспечиваете его выполнение?), Не обязательно имеет какое-либо отношение к тому, что описано. - person false; 23.11.2012
comment
@false вы правы. Мой немедленный ответ был основан на результатах примера запроса (15, B). В этом случае ограничения становятся бесполезными. В более общем случае порез там плохой. - person NotAUser; 23.11.2012
comment
Даже в случае result(15,B) ваш вывод может быть неверным. Вам нужно будет проверить источник или проверить затронутые переменные. Представьте, что у правила есть цель X^X#=0 с X новой переменной. - person false; 23.11.2012
comment
Я уверен, что вы можете найти много случаев, когда это решение не работает. Но это нормально для этих двух правил и такого типа запросов. - person NotAUser; 26.11.2012

Порядок предикатов - это важная часть программ на Прологе. Это связано с тем, что поиск проверки выполняется в строго определенном порядке с применением разрешения SLD.

Ваш предикат дает разумные результаты:

?- result(X,Y).
Y = decline,
X in 11..sup ;
Y = offer,
X in 0..20.

Вместо сокращения результата / 2 вы можете использовать при его вызове once / 1, сохранив правильное определение для общего использования.

?- once(result(X,Y)).
Y = decline,
X in 11..sup.
person CapelliC    schedule 22.11.2012
comment
Но ?- once(result(X, offer)) дает другой ответ. Ваш код можно понять только процедурно. - person false; 23.11.2012

Здесь могут помочь некоторые идеи конструктивного отрицания.

Теория

Есть простой способ логично сократить. Особенно для ограничений, поскольку ограничения обычно являются полным отрицанием. Итак, если у вас есть ограничение C, вы обычно можете найти ограничение C 'со следующим свойством:

C' <=> ~C

Предоставить предпочтение двум статьям следующего содержания:

p :- C, q.
p :- r

Просто сделайте следующее:

p :- C, q.
p :- C', r.

Если ваш решатель ограничений предоставляет овеществленное отрицание, например (#\)/1, вы даже можете определить для этого оператор:

:- op(1050,xfy,#?).
:- op(1100,xfy,#:).
(A #? B #: C) :- (A, B); (#\ A, C).

А затем напишите следующее:

p :- C #? q #: r.

Давайте применим эту стратегию к вашему примеру:

Пример

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

result(Input, Result) :-
    Input #> 10,
    Result = decline.
result(Input, Result) :-
    Input in 0..20,
    Result = offer.

Затем сделайте следующее:

result(Input, Result) :-
    Input #> 10,
    Result = decline.
result(Input, Result) :-
    Input #=< 10, Input in 0..20,
    Result = offer.

Вот пример запуска:

?- result(15, X).
X = decline ;
false.

?- result(8, X).
X = offer.

А теперь используется (#?)/2, что, например, возможно в SWI-Prolog, поскольку библиотека CLP (FD) там поддерживает реификацию. Предполагая, что мы проконсультировались с библиотекой CLP (FD), а затем определили (#:)/2, как указано выше:

 result(Input, Result) :-
    Input #> 10 
    #? 
       Result = decline 
    #: 
       Input in 0..20,
       Result = offer.

Вот пример запуска:

?- result(15, X).
X = decline ;
false.

?- result(8, X).
X = offer.

Заявление об ограничении ответственности

Более поздний синтаксис (#?)/2 и (#:)/2 основан на операторах Java if-then-else (?)/2 и (:)/2. Синтаксис, более вдохновленный Прологом, невозможен, поскольку мы не можем переопределить или расширить определение (;)/2.

Для получения дополнительной информации о реификации см., Например, здесь раздел A.8.4 Рефикация. Чего мы не сделали, так это повторения конъюнкции и дизъюнкции в нашем определении CLP (FD) if-then-else, поскольку часть then then и else может содержать другие цели, а не ограничения CLP (FD).

до свидания

person Mostowski Collapse    schedule 28.02.2016