Domanda

Mi chiedevo se esistesse uno strumento che può disegnare un albero di ricerca passo-passo di un programma Prolog? Grazie.

È stato utile?

Soluzione

Se il tuo sistema Prolog ha un debugger personalizzabile, puoi facilmente scrivere il tuo codice di raccolta dei grafici di runtime. Supponiamo che il tuo sistema prolog abbia un call back hook goal_tracing/2 come in Jekejeke Prolog. Quindi possiamo andare avanti e ispezionare il frame corrente e il frame genitore per creare un collegamento nel grafico. Ecco il codice:

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

Come si può vedere, ispezioniamo solo la porta di chiamata e guardiamo solo l'indicatore predicato. Ma sono anche possibili altri approcci che raccolgono più dati. Ora abbiamo bisogno di un po 'di utilità per visualizzare il risultato. C'è solo un ripristino da chiamare prima della raccolta e uno spettacolo da chiamare dopo la raccolta:

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

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

Produciamo un collegamento che è compreso da yuml.me. Diamo un'occhiata al programma fattoriale di Peano. Il codice del programma sembra segue:

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

Possiamo eseguire il collezionista come segue:

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

Si può quindi incollare l'URL in un browser e vedrà il diagramma. Rimuovere il ", sì" alla fine dell'URL. Ecco il risultato:

Call Graph

Distinti saluti

Altri suggerimenti

Gli alberi di ricerca prolog sono spesso semplicemente troppo grandi per essere esaminati passo dopo passo, ma disegnare uno potrebbe essere piuttosto semplice e anche interessante. Forse proverò a scriverne uno usando la libreria HTML_WRITE. In tal caso, segnalerò il risultato.

Nel frattempo SWI-PROLOG ha una rappresentazione piuttosto peculiare nella sua debugger. Ci sono dettagli interessanti sull'albero del programma Prolog. Non è così facile da usare e devo confessare di non aver ancora letto i documenti. Tuttavia ho usato frequentemente il debugger. È possibile navigare nell'albero e le variabili istanziate sui vari nodi. Quello è potente.

Visualizzare lo spazio di ricerca prolog è un compito interessante che non è semplice!

modificare Ho dimenticato di menzionare che XPCE ha la capacità di mostrare alberi di grandi dimensioni. Se già avere L'albero di prova, visualizzandolo dovrebbe essere molto facile. Apri lo spettatore. Dovrebbero esserci alcuni esempi nell'aiuto manuale XPCE. Potresti basare il display su questo.

Date un'occhiata al sldnfdraw Per SWI-PROLOG funziona come un incantesimo, l'unico problema che ho riscontrato è che i termini non possono contenere sottoti, ma ho già inviato un'e-mail al suo autore che lo segnala.

Crea un file tex con una rappresentazione di albero, quindi con alcuni comandi bash lo trasformano in PNG per la visualizzazione.

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

Ti consiglio anche di aggiungere \usepackage[landscape]{geometry} Dai spazio extra all'albero.

L'ho risolto in un modo diverso ... dai un'occhiata:https://github.com/reahaas/prolog-trace-to-tree

Eseguo il programma in Prolog con Trace, che mi dà un output della traccia come testo. Ogni passo in una linea diversa. Salva questo output di traccia su un file. Dovrebbe sembrare come questo:

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

Quindi usa questo codice Python per stampare la tracce di chiamate: costruisce l'albero basandosi sulla prima parola della traccia: {chiama, fallimento, uscita, ripeti}.

Avviso: modificare il percorso/nome del file nel codice (con aperto (...)).

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)

Questo è i risultati:

Per vedere i risultati, incolla l'albero di testo in blocco note ++ e zoom :)enter image description here

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top