Prologプログラムの段階的な検索ツリーを描くことができるツールがあるかどうか疑問に思いましたか?ありがとう。
4 に答える
Prologシステムにカスタマイズ可能なデバッガーがある場合は、独自のランタイムグラフ収集コードを簡単に作成できます。Jekejeke Prologのように、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階乗プログラムで試してみましょう。プログラムコードは次のようになります。
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の末尾にある「、はい」を削除します。結果は次のとおりです。
よろしくお願いします
多くの場合、プロローグ検索ツリーは大きすぎて段階的に調べることができませんが、ツリーを描画するのはかなり単純で興味深いものになる可能性があります。たぶん、html_writeライブラリを使用して作成しようとします。その場合は、結果を報告します。
その間、SWI-Prologはそのデバッガーにかなり独特な表現を持っています。Prologプログラムツリーについて興味深い詳細があります。使い方はそれほど簡単ではなく、まだドキュメントを読んでいないことを告白しなければなりません。しかし、私はデバッガーを頻繁に使用しました。さまざまなノードでツリーとインスタンス化された変数をナビゲートできます。それは強力です。
Prolog検索スペースの視覚化は、単純ではない興味深いタスクです!
編集XPCEには大きな木を表示する機能があることを忘れました。すでにプルーフツリーがある場合、それを表示するのは非常に簡単です。ビューアを開くだけです。XPCEマニュアルヘルプにいくつかの例があるはずです。それに基づいて表示することができます。
魅力のように機能する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}
また、ツリーにスペースを追加することをお勧めします。
私は別の方法でそれを解決しました...見てください: 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)
結果は次のとおりです。