Есть ли программа, которая может нарисовать дерево поиска запросов Prolog?

Мне было интересно, существует ли инструмент, который может нарисовать пошаговое дерево поиска программы Prolog? Благодарю.

2 ответа

Решение

Если ваша система Prolog имеет настраиваемый отладчик, вы можете легко написать свой собственный код для сбора графиков времени выполнения. Предположим, что ваша система Prolog имеет функцию перехвата call_tracing/2, как в Jekejeke Prolog. Затем мы можем перейти к проверке текущего кадра и родительского кадра, чтобы создать ссылку на графике. Вот код:

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.

Мы создаем ссылку, понятную http://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. Вы можете основать дисплей на этом.

Взгляните на sldnfdraw для swi -prolog, он работает как шарм, единственная проблема, с которой я столкнулся, заключается в том, что термины не могут содержать подчеркивания, но я уже отправил электронное письмо его автору, сообщив об этом.

Он создает текстовый файл с древовидным представлением, а затем с помощью некоторых команд 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)

Вот результаты:

Чтобы увидеть результаты, вставьте текстовое дерево в блокнот ++ и уменьшите масштаб:)

Другие вопросы по тегам