我想知道是否存在可以绘制Prolog程序的逐步搜索树的工具?感谢。
答案 0 :(得分:13)
如果您的Prolog系统具有可自定义的调试器,您可以轻松完成 编写自己的运行时图形收集代码。假设你的 Prolog系统在Jekejeke Prolog中有一个回调钩子goal_tracing / 2。然后我们可以继续检查当前帧和 父框架在图形中创建链接。这是代码:
goal_tracing(call, F) :-
frame_property(F, sys_call_indicator(N, A)),
frame_property(F, sys_parent_frame(G)),
frame_property(G, sys_call_indicator(M, B)),
!,
update_link(N / A, M / B).
goal_tracing(_, _).
:- dynamic link/2.
update_link(A, B) :-
link(A, B),
!.
update_link(A, B) :-
assertz(link(A, B)).
可以看出,我们只检查呼叫端口,我们只看一下 谓词指标。但也可以收集其他方法 更多数据。现在我们需要一些实用程序来显示结果。只有 要在集合之前调用的重置,以及要在之后调用的节目 集合:
reset :-
retract(link(_, _)), fail.
reset.
show :-
write('http://yuml.me/diagram/scruffy/class/'),
link(A, B),
write(([B] -> [A])),
write(', '),
fail.
show.
我们生成yuml.me理解的链接。 让我们尝试一下peano factorial程序。程序代码看起来 如下:
add(n, X, X).
add(s(X), Y, Z) :-
add(X, s(Y), Z).
mul(n, _, n).
mul(s(X), Y, Z) :-
mul(X, Y, H),
add(Y, H, Z).
fac(n, s(n)).
fac(s(X), Y) :-
fac(X, H),
mul(s(X), H, Y).
我们可以按如下方式运行收集器:
?- reset.
?- trace.
?- fac(s(s(n)),X).
X = s(s(n))
?- nodebug.
?- show.
http://yuml.me/diagram/scruffy/class/[fac / 2] -> [fac / 2], [fac / 2] -> [mul / 3], [mul / 3] -> [mul / 3], [mul / 3] -> [add / 3], [add / 3] -> [add / 3], Yes
然后可以将URL粘贴到浏览器中并查看图表。删除“,是” 在URL的末尾。结果如下:
最好的问候
答案 1 :(得分:2)
Prolog搜索树通常太大而无法逐步检查,但绘制一个可能相当简单,也很有趣。也许我会尝试使用html_write库编写一个。在那种情况下,我将报告结果。
与此同时,SWI-Prolog在其调试器中有一个相当特殊的表示。有关Prolog程序树的有趣细节。它不是那么容易使用,我必须承认我还没有阅读过这些文档。但是我经常使用调试器。您可以在各个节点上导航树和实例化变量。那是强大的。
可视化Prolog搜索空间是一项有趣的任务,并不简单!
编辑我忘了提到XPCE能够显示大树。如果您已经拥有证明树,那么显示它应该非常简单。只需打开查看器即可。 XPCE手册帮助中应该有一些示例。您可以将显示基于此。
答案 2 :(得分:0)
看看sldnfdraw的swi-prolog,它像一个咒语一样工作,我发现的唯一问题是这些术语不能包含下划线,但是我已经向其作者发送了一封电子邮件,报告该问题。
它将创建一个具有树表示形式的tex文件,然后使用一些bash命令将其转换为png以进行可视化。
latex file.tex
dvipdf file.dvi
pdfcrop file.pdf
pdftoppm file-crop.pdf|pnmtopng > file.png
我还建议添加\usepackage[landscape]{geometry}
为树提供更多空间。
答案 3 :(得分:0)
我用另一种方式解决了... 看一眼: https://github.com/reahaas/prolog-trace-to-tree
我在带有跟踪的序言中运行该程序,该跟踪程序以文本形式输出跟踪。每个步骤都在不同的行中。 将此跟踪输出保存到文件。它应该看起来像这样:
?- trace,there_is_way(telaviv,heifa).
Call: (9) there_is_way(telaviv, heifa) ? creep
Call: (10) there_is_way(telaviv, heifa, nil) ? creep
Call: (11) road_from(telaviv, heifa) ? creep
Call: (12) road(telaviv, heifa) ? creep
Fail: (12) road(telaviv, heifa) ? creep
Fail: (11) road_from(telaviv, heifa) ? creep
Redo: (10) there_is_way(telaviv, heifa, nil) ? creep
Call: (11) road_from(telaviv, _4236) ? creep
Call: (12) road(telaviv, _4236) ? creep
然后使用此python代码打印呼叫跟踪树: 它根据跟踪的第一个单词来构建树:{Call,Fail,Exit,Redo}。
注意:更改代码中的文件路径/名称(使用open(...))。
from pptree import *
import os
def get_first_word(line):
if line is "":
return
words = line.split()
if len(words) > 0:
first_word = words[0]
return first_word
def add_node(current, line):
if current is None:
return Node("head" + line, None)
else:
return Node(line, current)
with open("/home/vagrant/openu/prolog/trace_monkey.txt", 'r') as trace_file:
current = None
while True:
line = trace_file.readline()
if line.strip() == "": # run till it face an empty string.
break
first_word = get_first_word(line)
if current is None:
call_tree = add_node(current, line)
current = call_tree
elif first_word == "Call:":
current = add_node(current, line)
elif first_word == "Exit:":
add_node(current, line) # get_assignment(line))
current = current.parent
elif first_word == "Fail:":
add_node(current, line)
current = current.parent
elif first_word == "Redo:":
current = add_node(current, line)
print_tree(call_tree)
这是结果: