:- include('synonyms.pl'). %%%% FLAGS % :- dynamic translating_query/0. % avoids passing the parameter over and over :- dynamic debug/0. % controls debugging output sentence_filename('test1'). query_filename('query1'). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % do_it(F) % % Reads an LFT from file F, and outputs its A-Prolog encoding. % do_it(F) :- read_LFT(F,List), debug_write('LFT: '), debug_write(List), debug_nl, collect_verbs(List,V), debug_write('Verbs: '), debug_write(V), debug_nl, debug_nl, debug_nl, output_events(V,List), output_event_sequence(V), nl, output_NE_info(List). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % translate % % [ENTRY POINT] % % Translates into A-Prolog an LFT, whose ``affirmative'' part is % in the file specified by sentence_filename, and whose ``query'' % part is in the file specified by query_filename. % % (Includes a debugging version.) % translate :- do_it, query_it. translate_debug :- assert(debug), translate, retract(debug). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % do_it % % Reads an ``affirmative'' LFT from the file specified by % sentence_filename, and outputs its A-Prolog encoding. % do_it :- sentence_filename(F), do_it(F). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % query_it % % Reads a ``query'' LFT from the file specified by % query_filename, and outputs its A-Prolog encoding. % query_it:- query_filename(F), assert(translating_query), do_it(F), retract(translating_query). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_events(VerbList,LFTList) % % Outputs the A-Prolog encoding of the events corresponding % to the verbs in VerbList. LFTList is used to collect the % relevant data on the events. % output_events([],_). output_events([Event1|Tail],List) :- output_event(Event1,List), nl, output_events(Tail,List). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_event(Verb,LFTList) % % Outputs the A-Prolog encoding of the event corresponding % to the verb in Verb. LFTList is used to collect the % relevant data on the events. % output_event([Verb,Pos,Sense,[Event,Actor,Object|OtherArgs]],List) :- ( Verb \= be ; Sense \= 3 ), % be#3 is corresponds to a statement, rather than event write('event('), get_event_name(Event,EventName), write(EventName), write(','), write(Verb), write(','), write(Sense), write(').'), nl, output_event_type(Event), output_parameter(Event,'event_actor',Actor,List), output_parameter(Event,'object',Object,List), output_prepositional(Event,('in','IN'),List), output_prepositional(Event,('from','IN'),List), output_prepositional(Event,('to','TO'),List). output_event([be,Pos,3,[Statement,Actor,_|_]],List) :- get_event_name(Statement,StatementName), find_object_name(Actor,List,ActorName), find_preposition((Preposition,_),Statement,List,ObjectName), get_synonym(Preposition, Relation), Fluent =.. [ Relation, ActorName, ObjectName ], output_statement(StatementName,Fluent). output_statement(StatementName,Fluent) :- translating_query, write(answer_true(StatementName) :- h(Fluent,n)), write('.'), nl, write(answer_false(StatementName) :- -h(Fluent,n)), write('.'), nl, write(type_query(StatementName,boolean)), write('.'), nl. output_statement(StatementName,Fluent) :- write(h_at(Fluent,StatementName)), write('.'), nl. output_event_type(Event) :- not(translating_query), get_event_name(Event,EventName), write(happened(EventName)), write('.'), nl. output_event_type(Event) :- translating_query, get_event_name(Event,EventName), write(queried(EventName)), write('.'), nl. % % Old code -- may be reused later % %output_relation(Statement,List) :- % get_event_name(Statement,StatementName), % find_preposition((Preposition,_),Statement,List,ObjectName), % !, % only one should be present in the query % write(relation(StatementName,Preposition)), write('.'), nl, % write(parameter(StatementName,ObjectName)), write('.'), nl. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_parameter(Event,ParamName,Object,List) % % Given an LFT constant (specified in Object), finds the noun % (NN position) associated with the constant in the LFT encoded % by List, and outputs the noun as an element of the relation % specified in ParamName. % % Example: % % If Event=e1, Object=x1, ParamName=actor, and List contains % John_NN(x1), % then the A-Prolog fact will be % % actor(e1,john). % % output_parameter(Event,ParamName,Object,List) :- find_object_name(Object,List,ObjectName) -> write(ParamName), write('('), get_event_name(Event,EventName), write(EventName), write(','), write(ObjectName), write(').'), nl ; true. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_prepositional(Event,(Preposition,Position),ParamName,List) % % Similar to output_parameter/4. Given an Event, a Preposition % (e.g. "in", "from") and a position corresponding to a % prepositional phrase (e.g. IN, TO), it looks for the LFT % constant associated with the prepositional phrase. It % outputs the pair consisting of Preposition and of the noun % linked to the LFT constant, as an element of relation ParamName. % % Example: % % If Event=e1, Preposition=from, Position=IN, ParamName=location, % and List contains from_IN(e1,x3) & Baghdad_NN(x3), % then the A-Prolog fact will be % % location(e1,from,baghdad). % output_prepositional(Event,(Preposition,Position),ParamName,List) :- find_preposition((Preposition,Position),Event,List,ObjectName) -> write(ParamName), write('('), get_event_name(Event,EventName), write(EventName), write(','), write(Preposition), write(','), write(ObjectName), write(').'), nl ; true. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_prepositional(Event,(Preposition,Position),List) % % Like output_prepositional/4, except that the ParamName % is fixed to 'parameter'. % output_prepositional(Event,(Preposition,Position),List) :- output_prepositional(Event,(Preposition,Position),'parameter',List). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_NE_info(List) % % Outputs all the xxx_NE(X) atoms that occur in the LFT. % These atoms describe superclasses to which the argument % belongs, and they are extracted from the WordNet database. % % Example: % % If List contains town_NE(x1) & Baghdad(x1), % then the A-Prolog fact will be % % town(baghdad). % output_NE_info(List) :- member([LFTType,'NE',_,[LFTConstant]],List), get_synonym(LFTType,Type), find_object_name(LFTConstant,List,ObjectName), write(Type), write('('), write(ObjectName), write(').'), nl, fail. output_NE_info(_). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % find_preposition((Preposition,Position),Event,List,ObjectName) % % Given Event, finds the LFT constant associated with the % prepositional phrase "Preposition_Position" and returns % the corresponding noun in ObjectName. % find_preposition((Preposition,Position),Event,List,ObjectName) :- member([Preposition,Position,_,[Event,LFTConstant]],List), find_object_name(LFTConstant,List,ObjectName). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_event_sequence(Verbs) % % Outputs the sequence of events from the LFT, % encoded by relation next/2. % output_event_sequence(Verbs) :- compute_event_sequence(Verbs,Seq), output_next_relation(Seq), output_suggested_step(Seq,0). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_suggested_step(Sequence,Step) % % Outputs the suggested step for the events in Sequence, starting % from step Step. The suggested step is simply based on the % order of verbs in the sentence. % % Example: % % output_suggested_step([e1,e2],0) outputs: % % suggested_step(e1,0). % suggested_step(e2,1). % output_suggested_step([],_) :- not(translating_query). output_suggested_step([Event|Tail],Step) :- not(translating_query), get_event_name(Event,EventName), write(suggested_step(EventName,Step)), write('.'), nl, output_suggested_step(Tail,Step+1). output_suggested_step(_,_) :- translating_query. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % compute_event_sequence(VerbList,Sequence) % % Extracts from VerbList the sequence of events, i.e. [e1,e2,...]. % compute_event_sequence([],[]). compute_event_sequence([[_,_,_,[Event|_]]|Tail],[Event|OtherEvents]) :- compute_event_sequence(Tail,OtherEvents). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % output_next_relation(Sequence) % % Extracts the pairs of events from Sequence and outputs them % with facts "next(e1,e2).". % output_next_relation([]). output_next_relation([_]). output_next_relation([E1,E2|Tail]) :- get_event_name(E1,EN1), get_event_name(E2,EN2), write(next(EN1,EN2)), write('.'), nl, output_next_relation([E2|Tail]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % get_event_name(Event,EventName) % % Returns the name of event Event. If an affirmative statement % is being translated, EventName=Event. If a query is being % translated, EventName=q(Event). This step is necessary % because apparently the constants used to denote events that % occur in queries may be used to denote different events % in the affirmative statement. % get_event_name(Event,Event) :- not(translating_query). get_event_name(Event,q(Event)) :- translating_query. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % find_object_name(LFTConstant,List,ObjectName) % % finds the name associated, in the LFT encoded by List, with % LFTConstant, and returns it in ObjectName. % % IT ASSUMES THAT THERE IS ONLY *ONE* SUCH NAME. % find_object_name(LFTConstant,List,ObjectName) :- member([ObjectName,'NN',_,[LFTConstant]],List). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % collect_verbs(WordInfos,VerbList) % % Extracts from the list of Word Infos, those corresponding to % verbs and collects them in VerbList. % collect_verbs([],[]). collect_verbs([WordInfo|Tail],[WordInfo|OtherVerbs]) :- nth1(2,WordInfo,'VB'), collect_verbs(Tail,OtherVerbs). collect_verbs([WordInfo|Tail],OtherVerbs) :- nth1(2,WordInfo,Pos), Pos \= 'VB', collect_verbs(Tail,OtherVerbs). %================================================================= %================================================================= % % Functions to read the LFT from a file and convert it into % word info lists. % %================================================================= %================================================================= %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % read_LFTs(File,List) % % Reads the LFT contained in file File and returns in List % the word info list (see extract_word_info/2) of each % atom of the LFT. % read_LFT(File,List) :- read_file_to_codes(File,Codes,[]), atom_codes('&',[AmperCode]), % the code of '&' split_list(Codes,AmperCode,ComponentList), create_wordinfo_list(ComponentList,List). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % create_wordinfo_list(ComponentList,WordInfoList) % % Input: ComponentList -- a list of lists; each element of % ComponentList is a list of characters % corresponding to an atom in the LFT. % % For each element of ComponentList, create_wordinfo_list/2 % computes its word info list (see extract_word_info/2), % and collects the results in WordInfoList. % % WordInfoList PRESERVES the order in which the atoms appear % in the LFT. % create_wordinfo_list([],[]). create_wordinfo_list([AtomChars | Tail],[WordInfo | TailWordInfo]) :- get_atom(AtomChars,Atom), extract_word_info(Atom,WordInfo), create_wordinfo_list(Tail,TailWordInfo). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % get_atom(Codes,Atom) % % Converts a list of character codes into the corresponding % Prolog atom in Atom (making sure the first character is % legal for Prolog atoms, and that no '-' occurs in the atom). % get_atom(Codes,Atom) :- atom_codes(L1,Codes), atom_chars(L1,C1), normalize_chars(C1,C2), delete(C2,'-',C3), term_to_atom(Atom,C3). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % normalize_chars(CharListIn,CharListOut) % % CharListOut is a modification of CharListIn, such that % the first character of CharListOut is a lowercase letter. % % First of all, leading spaces are removed. Next, if the first % character of CharListIn is: % % * uppercase letter, it is converted to lowercase. % * number, "num" is prepended to CharListIn. % * a punctuation character, the character is removed. % normalize_chars([C|T1],T2) :- char_type(C,space), normalize_chars(T1,T2). normalize_chars([C1|T],[C2|T]) :- char_type(C1,alpha), downcase_atom(C1,C2). normalize_chars([C1|T],C4) :- char_type(C1,digit), atom_chars('num',C2), append(C2,[C1],C3), append(C3,T,C4). normalize_chars([C1|T],T) :- char_type(C1,punct). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % extract_word_info(Atom,WordInfoList) % % Splits Atom (taken from an LFT) into its various parts: % word, position (NN, VB, ...), sense (1 if not specified), % and list of arguments. % extract_word_info(Atom,[Word,Position,Sense,Args]) :- Atom =.. [Pred|Args], concat_atom([Word,Position,SenseAtom],'_',Pred), atom_number(SenseAtom,Sense). extract_word_info(Atom,[Word,Position,1,Args]) :- Atom =.. [Pred|Args], concat_atom([Word,Position],'_',Pred). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % split_list2(List,Separator,ListA,ListB) % % Splits List at the first occurrence of Separator, % so that ListA is the part of List that precedes it, % and ListB is the part that follows it. % split_list2([],_,[],[]). split_list2([Separator | Tail],Separator,[],Tail). split_list2([Head | Tail],Separator,[Head | ListA],ListB) :- Head \= Separator, split_list2(Tail,Separator,ListA,ListB). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % split_list(List,Separator,ComponentList) % % Splits List in the sublists determined by Separator. % split_list(List,Separator,[ListA]) :- split_list2(List,Separator,ListA,[]). split_list(List,Separator,[ListA|ComponentList]) :- split_list2(List,Separator,ListA,ListB), ListB \= [], split_list(ListB,Separator,ComponentList). %================================================================= %================================================================= % % Debugging predicates % %================================================================= %================================================================= debug_write(A) :- debug -> write(A) ; true. debug_nl :- debug -> nl ; true.