有没有一个程序可以绘制Prolog查询的搜索树?

发布于 2025-01-08 20:40:19 字数 40 浏览 1 评论 0原文

我想知道是否有一个工具可以绘制Prolog程序的逐步搜索树?谢谢。

I was wondering if there exists a tool that can draw a step-by-step search tree of a Prolog program? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

奢望 2025-01-15 20:40:19

如果您的 Prolog 系统具有可定制的调试器,您可以轻松地
编写您自己的运行时图形收集代码。假设你的
Prolog 系统有一个回调钩子 goal_tracing/2 就像 Jekejeke 中一样
序言。然后我们可以继续检查当前帧和
父框架以在图表中创建链接。这是代码:

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 可以理解的链接。
让我们尝试一下皮亚诺阶乘程序。程序代码看起来
如下所示:

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 的末尾。结果如下:

Call Graph

致以诚挚的问候

If your Prolog system has a customizable debugger you can easily
write your own runtime graph gathering code. Assume your
Prolog system has a call back hook goal_tracing/2 as in Jekejeke
Prolog. Then we can go on and inspect the current frame and the
parent frame to create a link in the graph. Here is the code:

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)).

As can be seen we only inspect the call port and we only look at the
predicate indicator. But other approaches are also possible that collect
more data. Now we need some utility to display the result. There is only
a reset to be called before the collection, and a show to be called after
the collection:

reset :-
    retract(link(_, _)), fail.
reset.

show :-
    write('http://yuml.me/diagram/scruffy/class/'),
    link(A, B),
    write(([B] -> [A])),
    write(', '),
    fail.
show.

We produce a link that is understood by yuml.me.
Lets give it a try with the peano factorial program. The program code looks
as follows:

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).

We can run the collector as follows:

?- 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

One can then paste the URL into a browser and will see the diagram. Remove the ", Yes"
at the end of the URL. Here is the result:

Call Graph

Best Regards

做个少女永远怀春 2025-01-15 20:40:19

Prolog 搜索树通常太大而无法逐步检查,但绘制一棵搜索树可能相当简单,也很有趣。也许我会尝试使用 html_write 库编写一个。在这种情况下,我将报告结果。

同时,SWI-Prolog 在其调试器中具有相当特殊的表示形式。关于 Prolog 程序树有一些有趣的细节。它并不那么容易使用,我必须承认我还没有阅读文档。不过我经常使用调试器。您可以导航树和各个节点上的实例化变量。这强大

可视化 Prolog 搜索空间是一项有趣的任务,但并不简单!

编辑 我忘了提及 XPCE 具有显示大树的能力。如果您已经拥有证明树,那么显示它应该非常容易。只需打开查看器即可。 XPCE手册帮助中应该有一些例子。您可以以此为基础进行显示。

Prolog search trees are often simply too big to be examined step by step, but drawing one could be rather simple, and interesting too. Maybe I'll try to write one using the html_write library. In that case, I will report the outcome.

In the meantime SWI-Prolog has a rather peculiar representation in its debugger. There are interesting details about the Prolog program tree. It's not that easy to use and I must confess I've still not read the docs. However I have used the debugger frequently. You can navigate the tree and the instantiated variables on the various nodes. That's powerful.

Visualizing the Prolog search space is an interesting task that is not simple!

edit I forgot to mention that XPCE has the ability to display large trees. If you already have the proof tree, displaying it should be very easy. Just open the viewer. There should be some examples in the XPCE manual help. You could base the display on that.

你的往事 2025-01-15 20:40:19

看看 swi-prolog 的 sldnfdraw 它就像一个魅力,我发现的唯一问题是术语不能包含下划线,但我已经向其作者发送了一封电子邮件报告该问题。

它创建一个具有树表示形式的 tex 文件,然后使用一些 bash 命令将其转换为 png 以进行可视化。

latex file.tex
dvipdf file.dvi
pdfcrop file.pdf
pdftoppm file-crop.pdf|pnmtopng > file.png

我还建议添加 \usepackage[landscape]{geometry} 为树提供额外的空间。

Take a look at sldnfdraw for swi-prolog it works like a charm, the only issue I found with it is that the terms cannot contain underscores, but I've already sent an email to its author reporting it.

It creates a tex file with a tree representation, then with some bash commands transform it to png for visualization.

latex file.tex
dvipdf file.dvi
pdfcrop file.pdf
pdftoppm file-crop.pdf|pnmtopng > file.png

I also recommend adding \usepackage[landscape]{geometry} give extra space to the tree.

心安伴我暖 2025-01-15 20:40:19

我用另一种方式解决了...
看看:
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)

这是结果:

要查看结果,请将文本树粘贴到记事本++并缩小:)
输入图片此处描述

I solved it in a different way...
take a look at:
https://github.com/reahaas/prolog-trace-to-tree

I run the program in prolog with trace, that give me an output of the trace as text. Each step in a different line.
Save this trace output to a file. it should look like this:

?- 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

Then use this python code to print the calls trace tree:
Its build the tree relying on the first word of the trace: {Call, Fail, Exit, Redo}.

notice: change the file path/name in the code (with 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)

This is the results:

To see the results, paste the text tree to notepad++ and zoom out :)
enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文