如何解析 Clingo Python 中的程序部分?

How to parse program parts in Clingo Python?

我正在尝试 运行 python 中的以下 Blockworld 规划程序:

#include <incmode>.

#program base.
% Define
location(table).
location(X) :- block(X).
holds(F,0) :- init(F).

#program step(t).
% Generate
{ move(X,Y,t) : block(X), location(Y), X != Y } = 1.
% Test
:- move(X,Y,t), holds(on(A,X),t-1).
:- move(X,Y,t), holds(on(B,Y),t-1), B != X, Y != table.
% Define
moved(X,t) :- move(X,Y,t).
holds(on(X,Y),t) :- move(X,Y,t).
holds(on(X,Z),t) :- holds(on(X,Z),t-1), not moved(X,t).

#program check(t).
% Test
:- query(t), goal(F), not holds(F,t).

% Display
#show move/3.

#program base.
% Sussman Anomaly
%
block(b0).
block(b1).
block(b2).
%
% initial state:
%
%  2
%  0 1
% -------
%
init(on(b1,table)).
init(on(b2,b0)).
init(on(b0,table)).
%
% goal state:
%
%  2
%  1
%  0
% -------
%
goal(on(b1,b0)).
goal(on(b2,b1)).
goal(on(b0,table)).

我通过使用以下简单函数来做到这一点

def print_answer_sets(program):
    control = clingo.Control()
    control.add("base", [], program)
    control.ground([("base", [])])
    control.configuration.solve.models = 0
    for model in control.solve(yield_=True):
        sorted_model = [str(atom) for atom in model.symbols(shown=True)]
        sorted_model.sort()
        print("Answer set: {{{}}}".format(", ".join(sorted_model)))

我将上面程序的一个长三引号字符串传递给它。即

print_answer_sets("""
#include <incmode>.

#program base.
% Define
location(table).
location(X) :- bl

...etc.
""")

这通常适用于其他 clingo 程序。

但是,我似乎无法生成答案集,并且出现错误

no atoms over signature occur in program:
  move/3

请注意,运行在终端或他们的 web interface 上使用 clingo 直接运行同一个程序可以正常工作。

我认为这是因为此字符串使用了多个“#program”语句和一个“#include”语句,我可能无法在 print_answer_sets 中正确(或根本)解析这些语句。有没有办法正确处理 python 中的程序部分?我试过查看文档和用户手册,但它有点密集。

谢谢!

我的教授帮助我找到了解决方案。我为自己和其他人添加了一些评论并在下面发布:

import clingo

asp_code_base = """
    #include <incmode>.
    % Define
    location(table).
    location(X) :- block(X).
    holds(F,0) :- init(F).

    block(b0).
    block(b1).
    block(b2).

    init(on(b1,table)).
    init(on(b2,b0)).
    init(on(b0,table)).

    goal(on(b1,b0)).
    goal(on(b2,b1)).
    goal(on(b0,table)).

    #show move/3.
"""
asp_code_step = """
    % Generate
    { move(X,Y,t) : block(X), location(Y), X != Y } = 1.

    % Test
    :- move(X,Y,t), holds(on(A,X),t-1).
    :- move(X,Y,t), holds(on(B,Y),t-1), B != X, Y != table.
    % Define
    moved(X,t) :- move(X,Y,t).
    holds(on(X,Y),t) :- move(X,Y,t).
    holds(on(X,Z),t) :- holds(on(X,Z),t-1), not moved(X,t).
"""
asp_code_check = """
    #external query(t).

    % Test
    :- query(t), goal(F), not holds(F,t).
"""


def on_model(model):
    print("Found solution:", model)


# this is an arbitrary upper limit set to ensure process terminates
max_step = 5

control = clingo.Control()
control.configuration.solve.models = 1  # find one answer only

# add each #program
control.add("base", [], asp_code_base)
control.add("step", ["t"], asp_code_step)
control.add("check", ["t"], asp_code_check)

# for grounding, we make use of a parts array
parts = []
parts.append(("base", []))
control.ground(parts)
ret, step = None, 1
# try solving until max number of steps or until solved
while step <= max_step and (step == 1 or not ret.satisfiable):
    parts = []
    # handle #external call
    control.release_external(clingo.Function("query", [clingo.Number(step - 1)]))
    parts.append(("step", [clingo.Number(step)]))
    parts.append(("check", [clingo.Number(step)]))
    control.cleanup()  # cleanup previous grounding call, so we can ground again
    control.ground(parts)
    # finish handling #external call
    control.assign_external(clingo.Function("query", [clingo.Number(step)]), True)
    print(f"Solving step: t={step}")
    ret = control.solve(on_model=on_model)
    print(f"Returned: {ret}")
    step += 1

如预期的那样输出(省略警告)

Solving step: t=1
Returned: UNSAT
Solving step: t=2
Returned: UNSAT
Solving step: t=3
Found solution: move(b2,table,1) move(b1,b0,2) move(b2,b1,3)
Returned: SAT