mcovingt@athena.cs.uga.edu (Michael A. Covington) (02/16/91)
Has anyone written a routine to display a Prolog structure in tree form, so that for example s(np(d(the),n(dog)),vp(v(barked))) prints as something like this: --? s | ---------- np vp | | ------ | | | | d n v the dog barked This is obviously useful for displaying the output of a parser, but it also has other uses.
peter@doe.utoronto.ca (Peter Mielke) (02/17/91)
In <1991Feb16.035944.3055@athena.cs.uga.edu>, Michael A. Covington writes: > Has anyone written a routine to display a Prolog structure in > tree form, so that for example > > s(np(d(the),n(dog)),vp(v(barked))) > > prints as something like this: --? > > s > | > ---------- > np vp > | | > ------ | > | | | > d n v > > the dog barked Are you writing some sort of NL parser? :-) Here is some code that i used to print out tree diagrams for my project. (It is written in the C-Prolog variant). It's not quite the way you want but it may help... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % USER INTERFACE % % $Header: /usr/u/jrrandall/prolog/RCS/io,v 3.3 91/01/29 09:35:32 jrrandall Exp $ % % $Log: io,v $ % Revision 3.3 91/01/29 09:35:32 jrrandall % added the move frame, and cleaned stuff up so it would work under quintus log. % % Revision 3.2 91/01/26 12:59:19 psmielke % made changes to the print struct routine and the way annotation is % done. % % Revision 3.1 91/01/22 19:06:49 psmielke % removed misc routines that are no longer needed % % print_output([Word]) :- !, write(Word), nl. % % do not follow punctuation with a space % print_output([Word,','|Words]) :- write(Word), print_output([','|Words]), !. print_output([Word,'?'|Words]) :- write(Word), print_output(['?'|Words]), !. print_output([Word|Words]) :- write(Word), write(' '), print_output(Words), !. print_output([]). read_sent(Words) :- get0(Char), read_sent(Char,Words). read_sent(C,[]) :- newline(C),!. read_sent(C,Words) :- skipchar(C), !, get0(Char), read_sent(Char,Words). read_sent(Char,[Word|Words]) :- read_word(Char,Chars,Next), name(Word,Chars), read_sent(Next,Words). skipchar(32). % skip spaces skipchar(33). % skip exclamation mark skipchar(44). % skip comma skipchar(46). % skip period skipchar(58). % skip colon skipchar(59). % skip semi-colon skipchar(63). % skip question mark newline(10). read_word(C,[],C) :- skipchar(C),!. read_word(C,[],C) :- newline(C),!. read_word(Char,[Char|Chars],New) :- get0(Next), read_word(Next,Chars,New). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % print a structure tree % % (now also prints lists) % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % print_struct(Tree) % print_struct(Tree,Tab) % % eg. print_struct(a(b,c,d(e,f))) gives: % % a( % b, % c, % d( % e, % f % ) % ) % print_struct(Tree, Tab) :- !, Tree =.. [Node|List], p_struct(0, Tab, Node, List), nl. print_struct(Tree) :- !, Tree =.. [Node|List], p_struct(0, 4, Node, List), nl. % % list of printable nodes (all others are rejected; used for % information hiding) % allowable_nodes( [ adjectives, aux_verb, copula, determiner, ind_object, infinitive_clause, noun, noun_phrase, prep_phrase, preposition, pronoun, proper_noun, quantifier, rel_phrase, sentence, verb, verb_phrase, comp, mods, qualifier ] ). % % print the node name of the current node and then list all the % (check to see if node is in current list of printable nodes) % % subnodes (if only one subnode print it on the same line) % p_struct(Offset, Tab, frame, [Head|[SList]] ) :- !, tab(Offset), write( frame ), nl, Offset2 is Offset + Tab, tab(Offset2), write( Head ), nl, p_slots( Offset2, SList ). p_slots( _, [] ). p_slots( Offset, [Slot|Rest] ) :- p_slot( Offset, Slot ), nl, p_slots( Offset, Rest ). p_slot( Offset, [Slotname|Filler] ) :- tab(Offset), write( Slotname ), put(32), put(58), put(32), % double colon p_slot2( Filler ). p_slot2( [] ). % % exception for uninstatiated values % p_slot2( [Head|Tail] ) :- var( Head ), !, write( '_' ), p_comma( Tail ), p_slot2( Tail ). p_slot2( [Head|Tail] ) :- write( Head ), p_comma( Tail ), p_slot2( Tail ). % % print a comma only if we are NOT at the end of the list % p_comma([]). p_comma(_) :- put(44), put(32). p_struct(Offset, _, Node, [Head|Tail]) :- allowable_nodes( NList ), member( Node, NList ), atom(Head), Tail = [], !, nl, tab(Offset), write(Node), put(40), % left bracket put(32), write(Head), put(32), put(41). % finishing right bracket % % normal processing % p_struct(Offset, Tab, Node, List) :- allowable_nodes( NList ), member( Node, NList ), !, nl, tab(Offset), write( Node ), put(40), % left bracket Offset2 is Offset + Tab, p_list(Offset2, Tab, List), nl, tab(Offset), put(41). % finishing right bracket % % the fall through if the node is not to be printed % p_struct(_, _, _, _). % % p_struct(_, _, Node, _) :- % write( '**'), write( Node ), write('**'). % % prints out the list of subnodes for a given node, % % % (if the element is a list print it out all on one line) % p_list(_, _,[]). p_list(Offset, Tab, [Head|List]) :- atom(Head), !, nl, tab(Offset), write( Head ), p_comma(List), p_list(Offset, Tab, List). % % exception for uninstatiated values % p_list(Offset, Tab, [Head|List]) :- var(Head), !, nl, tab(Offset), write( '_' ), p_comma(List), p_list(Offset, Tab, List). % % the element is a list % p_list(Offset, Tab, [Head|List]) :- Head =.. [Node|_], Node = '.', !, tab(Offset), put( 91), put( 32 ), p_list2( Head ), p_comma(List), p_list(Offset, Tab, List). p_list(Offset, Tab, [Head|List]) :- Head =.. [Node|Sublist], p_struct(Offset, Tab, Node, Sublist), p_comma(List), p_list(Offset, Tab, List). % % print out a list structure % p_list2( [] ) :- put( 32 ), put( 93 ). % % exception for uninstatiated values % p_list2( [Head|Tail] ) :- var( Head ), !, write( '_' ), p_comma( Tail ), p_list2( Tail ). p_list2( [Head|Tail] ) :- write( Head ), p_comma( Tail ), p_list2( Tail ). % % print a comma only if we are NOT at the end of the list % p_comma([]). p_comma(_) :- put(44), put(32). -- Peter Mielke peter@doe.utoronto.ca Dictionary of Old English Project utgpu!utzoo!utdoe!peter University of Toronto
neumann@dec4.wu-wien.ac.at (Gustaf Neumann) (02/17/91)
In article <1991Feb16.035944.3055@athena.cs.uga.edu>, mcovingt@athena.cs.uga.edu (Michael A. Covington) writes: |> Has anyone written a routine to display a Prolog structure in |> tree form, so that for example |> |> s(np(d(the),n(dog)),vp(v(barked))) |> |> prints as something like this: --? |> |> s |> | |> ---------- |> np vp |> | | |> ------ | |> | | | |> d n v |> Here comes such a program that i have written some time ago. It is not well documented and might entail some criticism on the prolog style, but it does the requested job. Have fun. in addition i could offer a version for graphical devices with much more features (such as different box-styles, multiple colors, various arc drawing styles and several tree-layouts), which needs some work from my side, since it was written first on VM/Prolog (with gddm-output), then it was ported to X11 (Xlib-calls) and the current version produces tgif input files (tgif is a free graphic editor for X11-R4) where the trees can be easily edited or commented. If some is interested, please email to my id. /* ppt/1, printing Prolog terms in a tree layout for typewriter output. Written in Spring 1985 -- Gustaf Neumann (c)1985 Gustaf Neumann, Wirtschaftsuniversitaet Wien, Augasse 2-6, 1090 Vienna, Austria *222/31 336-4533. email: neumann@wu-wien.ac.at or neumann@awiwuw11.bitnet Permission is granted to use, copy and distribute this program as long (1) this note remains intact, (2) no fees are charged and (3) no further restrictions are imposed. The following predicates are not defined within this program: - length(List,Length), - tab(Exp), - append(A,B,AB). Do not try to print infinite trees :-) To show, what this program does, issue the goal: examples. */ ?-op(100,xfy,:). examples:- example(X), ppt(X), nl, nl, write(X), nl, wait_for_input, fail. examples. example(sin(alpha)/cos(beta-phi)+cos(beta)*tan(360-alpha)). example(buch(titel(wirschaftsinformatik1),autor(hans_robert, hansen))). example((a:-b,c,d)). %example((ppt(X,Y):-Body)):- clause(ppt(X,Y),Body). example(sentence(np(proper(gustaf)),vp(v(likes),np(proper(prolog))))). example(sentence(np(det(that),n(man),rel(that,vp(iv(whistle)))), vp(tv(tunes),np(det(nil),n(pianos),rel(nil))))). example(wirtschaftsinformatik(leitung(hans_robert), sekretariat(virly,anita), assistenten(lore,rony,goeha,gu,margret,andy,stessi))). /************************************************************************ * top level predicate ppt/1 * ************************************************************************/ ppt(Term):- ppt(Term,arc). ppt(Term,Arc) :- number_vars(Term,0,_), /* ground all variables in Term */ {pos(Term,Pos,C,0-Right)}, /* compute hor. positions of nodes */ {inv([Pos],[]:_,H:T,s)}, /* invert structure for printing */ posdiff(-(72-Right)//2,0,Tab), /* compute hor. tab for centering */ {print_tree(H:T,[C],Tab,Arc)}. /* print tree in line printer mode */ /************************************************************************ * Compute Positions of Nodes * ************************************************************************/ pos(Head,t(Head,Rel,L,[],0)-[], Nc, N0-Nn):- /* leaf node */ atomic(Head), !, string_length(Head,L), Nn is N0+L, Rel is L//2, /* middle of the node */ Nc is (N0+Nn)//2. /* center over node */ pos(X,t(Head,Rel,L,Centers,Adj)-A, Nc, N0-N2):- /* non-leaf node */ X =.. [Head|Args], pos_list(Args,A,Centers,N0-N1), string_length(Head,L), posdiff(N1-N0,L,Error), Adj is (Error+((N1-N0) mod 2))//2, N2 is N1+Error, Rel is L//2, /* middle of the node */ Nc is (N0+N2)//2. pos_list([], [], [], N-N). pos_list([H], [A], [Center], N-N1) :- !, pos(H,A,Center,N-N1). pos_list([H|T],[A|Args],[C|Centers],N0-Nn):- pos( H, A, C, N0-N1), N2 is N1+2, pos_list(T,Args,Centers,N2-Nn). string_length(X,L):- atomic(X), name(X,S), length(S,L). posdiff(Expr,L,Adj):- Adj is L-Expr, Adj > 0, !. posdiff(_,_,0). /************************************************************************ * invert tree * ************************************************************************/ inv([Node-Sons|Brothers],List:Deep,[Node|List1]:Deep2,_):- inv(Brothers,List:Deep,List1:Deep1,b), inv(Sons,Deep1,Deep2,s). inv([],[]:[],[],s). inv([],[]:[],[]:_,b). inv([],E,E,_). /************************************************************************ * print tree * ************************************************************************/ print_tree(Node:Deep, Centers, Tab, Arc) :- tab(Tab), print_list(Node,0,Centers,Cd), nl, {( Arc == noarc ; Deep == [] ; tab(Tab), marks(Centers,Node,0), tab(Tab), horarc(Node,0,_), nl, tab(Tab), marks(Cd,0) )}, print_tree(Deep,Cd,Tab,Arc). print_tree([],[],_,_). print_list([t(H,Rel,L,Cd,Adj)|R], P0, [C|Centers], Ca) :- P is C-Rel, tab(P-P0), write(H), Pn is P+L, print_list(R,Pn,Centers,Cr), add_to(Cd,Adj,Cda), {append(Cda,Cr,Ca)}. print_list([],_,[],[]). /************************************************************************ * draw arcs * ************************************************************************/ marks([],[],_) :- nl. marks([H|T],[t(_,_,_,[],_)|R],E) :- !, tab(H-E), write(' '),marks(T,R,H+1). marks([H|T],[_|R], E) :- tab(H-E), write('|'),marks(T,R,H+1). marks([],_) :- nl. marks([H|T],E) :- tab(H-E), write('|'), marks(T,H+1). horarc([], A,A). horarc([t([],_,_,_,_ )|R],P,P2) :- !, horarc(R,P,P2). horarc([t(_,_,_,Cd,Adj)|R],P,P2) :- line(Cd,Adj,P,P1), horarc(R,P1,P2). line([], _,E,P) :- P is E. line([H], A,E,P) :- !, tab(H+A-E), write('.'), P is H+A+1. line([H|T],A,E,P) :- tab(H+A-E), write('.'), line_([H|T],A,H+A+1,P). line_([], _,E,P) :- P is E. line_([H], A,E,P) :- line_to(H+A-E), P is H+A+1. line_([_,T|Tt],A,E,P) :- line_to(T+A-E), write('.'), line_([T|Tt],A,T+A+1,P). line_to(Exp) :- L is Exp, line_to_(L,'-'). line_to_(L,_) :- L < 1. line_to_(L,C) :- L >= 1, write(C), L1 is L-1, line_to_(L1,C). add_to([],_,[]). add_to([H|T],A,[Ha|Ta]) :- Ha is H+A, add_to(T,A,Ta). /************************************************************************ * misc utility predicates * ************************************************************************/ {G} :- G,!. wait_for_input :- get0(_). %wait_for_input :- system([clrscrn,more]). number_vars(Term,N0,N1) :- var(Term), !, name(N0,Digits), name('V',[C]), name(Term,[C|Digits]), N1 is N0+1. number_vars(Term,N0,N0) :- atomic(Term), !. number_vars(Term,N0,N1) :- Term =.. [_|Args], number_list(Args,N0,N1). number_list([],N0,N0). number_list([H|T],N0,N2) :- number_vars(H,N0,N1), number_list(T,N1,N2).
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (02/19/91)
In article <1991Feb16.035944.3055@athena.cs.uga.edu>, mcovingt@athena.cs.uga.edu (Michael A. Covington) writes: > Has anyone written a routine to display a Prolog structure in > tree form, ... for example s(np(d(the),n(dog)),vp(v(barked))) The Quintus library provides several ways of displaying trees, but rotated by 90 degrees from what you want. The basic problem is that s(np(d(the),n(dog)),vp(v(barked))) is not a very good way of representing a parse tree, except for toy programs and tiny illustrations. (You really should allow for non-atomic category labels.) "Rotated" pictures s +-- np | +-- d the | +-- n dog +-- vp +-- v barked are quite easy to print, and rather easier to find your way around. -- Professional programming is paranoid programming