Только вычислить/решить конкретное правило в clingo
Предупреждение: новичок в ASP.
Предположим, у нас есть эта простая программа:
% crime scene
% Facts
present(harry). % was present on the crime scene
present(sally).
present(mary).
motive(harry). % has a motive
motive(sally).
guilty(harry).
% encoding / rules
innocent(Suspect) :- motive(Suspect), not guilty(Suspect).
witness(Suspect) :- present(Suspect), not motive(Suspect), not guilty(Suspect).
Вывод, как и ожидалось, таков:
present(harry) present(sally) present(mary)
motive(harry) motive(sally) guilty(harry)
innocent(sally) witness(mary)
Есть ли способ вычислить только конкретное правило из всех определенных? Я не говорю о том, чтобы спрятать атом за#show
заявление, но на самом деле говорит решателю только вычислитьwitness(Suspect)
правило например.
Я предполагаю, что написание двух разных программ - это ответ, но есть ли что-нибудь еще?
Для контекста я использую Clingo Python API для выполнения ASP-программы, содержащей десятки правил. Эти (независимые) правила соответствуют вопросам, на которые пользователь может захотеть получить ответ. На данный момент все они вычисляются при выполнении программы, и я фильтрую вывод, чтобы обрабатывать интересующие атомы только после того, как будет найден ответ.
1 ответ
Я нашел ответ в статье «Учебное пособие по решению гибридных наборов ответов с помощью clingo» Камински и др. (2017) [Архив здесь] .
Короткий ответ
Используйте директиву для разделения программы на подпрограммы (блоки правил). Затем используйте сценарии для выполнения только той подпрограммы, которую вы хотите.
Конкретно:
% crime scene
% Facts
#program base. % NEW
present(harry).
present(sally).
present(mary).
motive(harry).
motive(sally).
guilty(harry).
% encoding / rules
#program groundInnocent. % NEW
innocent(Suspect) :- motive(Suspect), not guilty(Suspect).
#program groundWitness. % NEW
witness(Suspect) :- present(Suspect), not motive(Suspect), not guilty(Suspect).
Затем вы можете либо включить скрипт в код ASP:
#script(python)
def main(prg):
prg.ground([("base", []), ("groundWitness", [])])
prg.solve()
#end
Или используйте Clingo Python API:
from clingo.control import Control
def on_model(model):
print ("result = ", model)
if __name__ == '__main__':
ctl = Control()
ctl.configuration.solve.models = 1
ctl.load("path_to_asp_file")
ctl.ground([("base", []), ("groundWitness", [])])
ctl.solve(on_model=on_model)
Важный:
- Обратите внимание, что факты помещаются в подпрограмму. И базовая программа явно вызывается перед любой другой подпрограммой, чтобы гарантировать, что факты, используемые в
witness
заземлены. - Это означает, что подпрограммы должны быть независимыми. Здесь оба наших правила независимы. Если бы у нас было
witness(Suspect) :- present(Suspect), not innocent(Suspect).
, правило не будет обоснованным, посколькуinnocent
выходит за рамкиgroundWitness
подпрограммы и не является частью ни той, ни другой.
См. длинный ответ ниже, чтобы понять, почему.
Длинный ответ
Прямая цитата из раздела 3.1 («Нежное введение») упомянутой выше статьи:
[...] программу можно разделить на несколько подпрограмм с помощью директивы ; он поставляется с именем и необязательным списком параметров. [...] В качестве примера две подпрограммы base и acid(k) могут быть указаны следующим образом:
a(1). #program acid(k). b(k). c(X,k) :- a(X). #program base. a(2).
Обратите внимание, что
base
является специальной подпрограммой (с пустым списком параметров): в дополнение к правилам в ее области действия она собирает все правила, которым не предшествует какой-либо#program
директива. Следовательно, в приведенном выше примере базовая подпрограмма включает фактыa(1)
иa(2)
, хотя только последний находится в фактической сфере действия директивы [...].Без дополнительных управляющих инструкций (см. ниже) clingo обосновывает и решает только базовую подпрограмму [...]. Обработка других подпрограмм, например, подлежит управлению сценариями.
Для индивидуального управления заземлением и решением может быть предоставлена основная процедура (принимающая объект управления, представляющий состояние clingo в качестве аргумента).
#script(python) def main(prg): prg.ground([("base",[])]) prg.solve() #end.
В то время как приведенная выше управляющая программа соответствует поведению clingo по умолчанию, приведенная ниже программа игнорирует все правила базовой программы, а вместо этого содержит наземную инструкцию для
acid(k)
[...], где параметрk
должен быть конкретизирован термином 42.#script(python) def main(prg): prg.ground([("acid",[42])]) prg.solve() #end.
Соответственно, схематический факт
b(k)
превращается в , из него не получается никакого основного правилаc(X,k) :- a(X)
из-за отсутствия экземпляровa(X)
, а команда решения [...] дает устойчивую модель, состоящую изb(42)
только.Обратите внимание, что основные инструкции применяются к подпрограммам, заданным в качестве аргументов, в то время как триггеры решения основаны на всех накопленных основных правилах.