1/*
    2
    3 _________________________________________________________________________
    4|	Copyright (C) 1982						  |
    5|									  |
    6|	David Warren,							  |
    7|		SRI International, 333 Ravenswood Ave., Menlo Park,	  |
    8|		California 94025, USA;					  |
    9|									  |
   10|	Fernando Pereira,						  |
   11|		Dept. of Archi80tecture, University of Edinburgh,		  |
   12|		20 Chambers St., Edinburgh EH1 1JZ, Scotland		  |
   13|									  |
   14|	Thi80s program may be used, copied, altered or included in other	  |
   15|	programs only for academic purposes and provided that the	  |
   16|	authorshi80p of the initial program is aknowledged.		  |
   17|	Use for commercial purposes without the previous written 	  |
   18|	agreement of the authors is forbidden.				  |
   19|_________________________________________________________________________|
   20
   21*/
   22
   23
   24
   25% Chat-80 : A small subset of English for database querying.
   26
   27/* Control loop */
   28
   29:-share_mp(hi80/0).   30hi80 :-
   31   hi80(user).
   32
   33:-share_mp(hi80/1).   34hi80(File):- hi80(report,File).
   35
   36:-share_mp(hi80/2).   37hi80(Callback,File):-
   38    absolute_file_name(File,FOpen),
   39    setup_call_cleanup((
   40     open(FOpen,read, Fd, [alias(FOpen)]),
   41      see(Fd)),
   42      (( repeat,
   43         ask80(Fd,P),
   44         control80(Callback,P), !)),
   45   end(FOpen)).
   46
   47ask80(user,P) :- 
   48  setup_call_cleanup(see(user),
   49   (prompt(_,'Question: '),
   50   readin80:read_sent(P)),seen).
   51
   52ask80(_F,P) :- readin80:read_sent(P), doing80(P,0),!.
   53
   54doing80([],_) :- !,nl.
   55doing80([X|L],N0) :-
   56   out80(X),  
   57   advance80(X,N0,N),
   58   doing80(L,N),!.
   59
   60out80(nquant(X)) :- !,
   61   reply(X).
   62out80(A) :-
   63   reply(A).
   64
   65advance80(X,N0,N) :-
   66   uses80(X,K),
   67   M is N0+K,
   68 ( M>72, !,
   69      nl,
   70      N is 0;
   71   N is M+1,
   72      put(" ")).
   73
   74uses80(nquant(X),N) :- !,
   75   chars80(X,N).
   76uses80(X,N) :-
   77   chars80(X,N).
   78
   79chars80(X,N) :- atomic(X), !,
   80   name(X,L),
   81   length(L,N).
   82chars80(_,2).
   83
   84end(user) :- !.
   85end(F) :- 
   86   told,seen,
   87   catch(close(F),_,seen),!.
   88
   89
   90:-share_mp(control80/1).   91% t_l:tracing80 ?
   92control80(U):-locally([],control80(report,U)).
   93
   94:-share_mp(control80/2).   95
   96control80(_,O):- O==[],!.
   97control80(Callback,NotList):-  
   98 ( \+ is_list(NotList); \+ maplist(atom,NotList) ) ->
   99   to_word_list(NotList,List),
  100   maplist(string_to_atom,List,ListIn),
  101   dmsg(NotList \=@= ListIn),!,   
  102   control80(Callback,ListIn).
  103control80(Callback,ListIn):- 
  104   append(Left,[Last],ListIn), 
  105 ( \+ atom_length(Last,1),
  106   char_type(P,period), % covers Q, ! , etc
  107   atom_concat(Word,P,Last)),
  108   append(Left,[Word,P],ListMid),!,
  109   control80(Callback,ListMid).
  110control80(Callback,ListIn):- 
  111   append(Left,[P],ListIn), 
  112 (\+ atom_length(P,1); \+ char_type(P,period)),!,
  113   append(ListIn,[('.')],ListMid),!,
  114   control80(Callback,ListMid).
  115control80(Callback,[W,'.']):- 
  116   downcase_atom(W,D),W\==D,!,
  117   control80(Callback,[D,'.']).
  118
  119control80(Callback,[bye,'.']) :- !,
  120   call(Callback,"Goodbye",'control80',!,call),
  121   reply('Cheerio.'),!,nl.
  122
  123control80(Callback,[trace,'.']) :- !,
  124   assert(t_l:tracing80),
  125   call(Callback,assert(t_l:tracing80),'t_l:tracing80',true,boolean),
  126   reply('Tracing from now on!'), nl, fail.
  127
  128control80(Callback,[do,not,trace,'.']) :-
  129   retract(t_l:tracing80), !,
  130   call(Callback,retract(t_l:tracing80),'t_l:tracing80',false,boolean),
  131   reply('No longer tracing.'), nl, fail.
  132
  133control80(Callback,U) :- 
  134  locally(t_l:tracing80, 
  135     call_in_banner(U,(ignore(process_run(Callback,U,_List,_Time))))),fail.
  136   
  137:- share_mp(chat80/1).  138chat80(U):-
  139 locally(t_l:tracing80,
  140           locally(t_l:chat80_interactive,
  141            locally_hide(t_l:useOnlyExternalDBs,
  142             locally_hide(thglobal:use_cyc_database,
  143              ignore(control80(U)))))).
  144
  145:- share_mp(parser_chat80:test_chat80/1).  146parser_chat80:test_chat80(U):-
  147 locally(t_l:tracing80,
  148           locally(t_l:chat80_interactive,
  149            locally_hide(t_l:useOnlyExternalDBs,
  150             locally_hide(thglobal:use_cyc_database,
  151              ignore(control80(U)))))).
  152   
  153
  154
  155get_prev_run_results(U,List,Time):-must_test_801(U,List,Time),!.
  156get_prev_run_results(U,List,Time):-must_test_80(U,List,Time),!.
  157get_prev_run_results(_,[],[]).
  158
  159
  160reportDif(_U,List,BList,_Time,_BTime):-forall(member(N=V,List),ignore((member(N=BV,BList), \+ (BV = V), dfmt('~n1) ~q = ~q ~~n2) ~q = ~q ~n',[N,V,N,BV])))).
  161
  162:-share_mp(process_run_diff/4).  163process_run_diff(Callback,U,BList,BTime):-
  164 call_in_banner(U,( process_run(Callback,U,List,Time),
  165   ignore((reportDif(U,List,BList,Time,BTime))))),!.
  166   
  167
  168:-share_mp(process_run/4).   
  169process_run(Callback,U,List,Time):-
  170  runtime(StartParse),   
  171  process_run(Callback,StartParse,U,List,Time),!.
  172
  173:- share_mp(call_in_banner/2).  174call_in_banner(U,Call):- nl, 
  175 Result = call(p2('red',end:"Error":U)),
  176 setup_call_cleanup(
  177   p2('white',begin:U), 
  178     (Call->setarg(1,Result,(p3('green',"Success"),p1));setarg(1,Result,p2('yellow',end:"Failed":U))),
  179     Result),
  180   format('~N',[]).
  181
  182process_run(Callback,StartParse,U,List,Time):-    
  183    show_failure(process_run_real(Callback,StartParse,U,List,Time)) *-> true; process_run_unreal(Callback,StartParse,U,List,Time).
  184    
  185   
  186process_run_unreal(Callback,Start,U,[sent=(U),parse=(E),sem=(error),qplan=(error),answers=(failed)],[time(WholeTime)]):-   
  187         runtime(Stop),WholeTime is Stop-Start,
  188         reply(Callback - 'Failed after '-WholeTime-' to understand: '+ [sent=(U),parse=(E),sem=(error),qplan=(error),answers=(failed)] ), nl.
  189
  190if_try(Cond,DoAll):-Cond,!,DoAll.
  191if_try(_,_):-sleep(1),!.
  192
  193p3(Color,BE):-ansi_format([fg(Color)],'~N% ============================================~w=============================================================',[BE]).
  194p2(Color,begin:Term):-!, p3(Color,'Starting'),p4(Term),p1,format('~N~n',[]).
  195p2(Color,end:Term):-!, p1, p4(Term),p3(Color,'Finished'),format('~N~n',[]).
  196p2(Color,Term):- p3(Color,''), p4(Term), p3(Color,'').
  197p1:- format('~N% ---------------------------------------------------------------------------------------------------',[]),!.
  198     
  199p4(Term):-format('~N%                       ~q',[Term]).
  200
  201words_to_w2(U,W2):-var(U),must(W2=U).
  202words_to_w2([],W2):-must(W2=[]).
  203words_to_w2(U,W2):- \+ is_list(U),convert_to_atoms_list(U,List),U \=@= List,!,words_to_w2(List,W2).
  204words_to_w2(U,W2):- \+ compound(U),must(W2=U).
  205words_to_w2([W|WL],[W2|W2L]):-w_to_w2(W,W2),words_to_w2(WL,W2L).
  206
  207
  208:-thread_local t_l:old_text/0.  209
  210t_l:old_text.
  211% TODO dont use open marker use []
  212use_open_marker.
  213
  214w_to_w2(W,W):-t_l:old_text,!.
  215
  216w_to_w2(Var,Var):-var(Var),!.
  217w_to_w2(w(Txt,Props),w(Txt,Props)):-!.
  218% w_to_w2([Prop,Txt],w(Txt,[Prop])):-!.
  219w_to_w2(w(X),w(X,[])):-!.
  220w_to_w2(S,w(A,open)):-use_open_marker,atomic(S),atom_string(A,S),!.
  221w_to_w2(S,w(S,open)):-use_open_marker,!.
  222w_to_w2(S,w(A,[])):-atomic(S),atom_string(A,S),!.
  223w_to_w2(U,w(U,[])):-compound(U),!.
  224w_to_w2(X,w(X,[])):-!.
  225
  226w2_to_w(w(Txt,_),Txt):-!.
  227w2_to_w(Txt,Txt).
  228
  229%theTextC(W1,CYCPOS,Y=W1)  ---> {t_l:old_text,!},[W1],{W1=Y}.
  230theTextC(A,_,F=A,B,C,D,E) :-t_l:old_text, !,terminal(A, B, C, D, E),A=F,is_sane_nv(A).
  231theTextC(A,_,F=A,B,C,D,E) :- !,terminal(w(A, _), B, C, D, E),A=F,is_sane_nv(A).
  232%theTextC(W1,CYCPOS,Y=W1)  ---> {!},[w(W1,_)],{W1=Y}.
  233%theTextC(W1,CYCPOS,WHY) ---> [W2],{memoize_pos_to_db(WHY,CYCPOS,W2,W1)}.
  234theTextC(H,F,E,A,B,C,D) :- fail, is_sane(C), terminal(G, A, B, C, D),memoize_pos_to_db(E, F, G, H),is_sane_nv(H).
  235
  236/*
  237theTextC(W1,_CYCPOS,Y=W1) ---> {t_l:old_text,!},[W1],{W1=Y}.
  238%theTextC(W1,_CYCPOS,Y=W1) ---> {!},[w(W1,_)],{W1=Y}.
  239theTextC(A,_,F=A,B,C,D,E) :- !,terminal(w(A, _), B, C, D, E),A=F,is_sane_nv(A).
  240theTextC(W1,_CYCPOS,WHY) ---> {t_l:old_text,!},[W1],WHY.
  241% theTextC(W1,CYCPOS,WHY) ---> {trace_or_throw(memoize_pos_to_db(WHY,CYCPOS,W2,W1))},[W2],{memoize_pos_to_db(WHY,CYCPOS,W2,W1)}.
  242*/
  243
  244term_depth(C,TD):-notrace(term_depth0(C,TD)).
  245term_depth0(C,1):-var(C),!.
  246term_depth0(C,0):-not(compound(C)),!.
  247term_depth0(C,TDO):-is_list(C),!,findall(D,(member(T,C),term_depth0(T,D)),DL), max_list([0|DL],TD),TDO is TD+1,!.
  248term_depth0(C,TDO):-C=..[_|LIST],findall(D,(member(T,LIST),term_depth0(T,D)),DL), max_list([0|DL],TD),TDO is TD+1,!.
  249
  250
  251is_sane(C):- must((term_depth(C,D),D<100)).
  252is_sane_nv(C):-must((nonvar(C),term_depth(C,D),D<100)).
  253
  254sent_to_parsed(U,E):- deepen_pos(parser_chat80:sentence80(E,U,[],[],[])).
  255
  256:- share_mp(deepen_pos/1).  257:-meta_predicate(deepen_pos(0)).  258deepen_pos(Call):- deepen_pos_0(Call) *->  true ; locally(t_l:useAltPOS,deepen_pos_0(Call)).
  259:- share_mp(deepen_pos_0/1).  260:-meta_predicate(deepen_pos_0(0)).  261deepen_pos_0(Call):-one_must(Call,locally(t_l:usePlTalk,Call)).
  262
  263
  264% any_to_string("How many countries are there?",X),splt_words(X,Y,Z),vars_to_ucase(Y,Z),maplist(call,Z)
  265
  266:- share_mp(process_run_real/5).  267process_run_real(Callback,StartParse,UIn,[sent=(U),parse=(E),sem=(S),qplan=(QP),answers=(Results)],[time(WholeTime)]) :-
  268   flag(sentenceTrial,_,0),
  269   ignore((var(Callback),Callback=report)),
  270   words_to_w2(UIn,U),!,
  271   call(Callback,U,'Sentence'(Callback),0,expr),
  272   ignore((var(StartParse),runtime(StartParse))),!,
  273   (if_try(nonvar(U),sent_to_parsed(U,E)) *-> ignore((U\==UIn,call(Callback,U,'POS Sentence'(Callback),0,expr))); (call(Callback,U,'Rewire Sentence'(Callback),0,expr),!,fail)),
  274   (flag(sentenceTrial,TZ,TZ), TZ>5 -> (!) ; true),
  275   once((
  276      runtime(StopParse),
  277      ParseTime is StopParse - StartParse,
  278      call(Callback,E,'Parse',ParseTime,portray),  
  279      (flag(sentenceTrial,TZ2,TZ2+1), TZ2>5 -> (!,fail) ; true),
  280      runtime(StartSem))),
  281   once((if_try(nonvar(E),deepen_pos(sent_to_prelogic(E,S))))),
  282   runtime(StopSem),
  283   SemTime is StopSem - StartSem,
  284   call(Callback,S,'Semantics',SemTime,expr),
  285   runtime(StartPlan),
  286   once(if_try(nonvar(S),deepen_pos(qplan(S,S1)))),
  287   copy_term80(S1,QP),
  288   runtime(StopPlan),
  289   TimePlan is StopPlan - StartPlan,
  290   if_try(S\=S1,call(Callback,S1,'Planning',TimePlan,expr)),
  291   runtime(StartAns),
  292   nonvar(S1),findall(Res,deepen_pos((answer802(S1,Res),Res\=[])),Results), Results\=[],!,
  293   runtime(StopAns),
  294   TimeAns is StopAns - StartAns,
  295   call(Callback,Results,'Reply',TimeAns,expr),
  296   WholeTime is ParseTime + SemTime + TimePlan + TimeAns,
  297   p1.
  298
  299
  300:-share_mp(test_quiet/4).  301test_quiet(_,_,_,_).
  302
  303:-share_mp(report/4).  304report(Item,Label, Time, Mode) :- (\+ t_l:tracing80 ; Time==0), !,
  305   nop((nl, write(Label), write(':(report) '),ignore(safely_call_ro(report_item(Mode,Item))))),!.
  306report(Item,Label,Time,Mode) :- 
  307   nl, write(Label), write(':(report4) '), write(Time), write(' sec(s).'), nl,
  308   ignore(safely_call_ro(report_item(Mode,Item))),!.
  309report(_,_,_,_).
  310
  311
  312call_with_limits(Call):- call_with_limited_reason(Call,FailedWhy),(FailedWhy=success(_)-> true; throw(failed(FailedWhy,Call))).
  313call_with_limited_reason(Call,Result):-  
  314 catch(
  315  call_with_time_limit(7,
  316   ((Call,(deterministic(yes)->Result=success(det);Result=success(nondet)))
  317     *->true;Result=failed)),Result,true).
  318
  319% call_with_limits0(Copy):-call_with_time_limit(10,call_with_depth_limit(call_with_inference_limit(Copy,10000,_),500,_)).
  320
  321safely_call_ro(Call):-copy_term(Call,Copy),catchv(call_with_limits(Copy),E,(dmsg(error_safely_call(E,in,Copy)),!,fail)).
  322safely_call(Call):-copy_term(Call,Copy),catchv((Copy,Call=Copy),E,(dmsg(error_safely_call(E,in,Copy)),!,fail)).
  323
  324report_item(none,_).
  325report_item(T,Var):-var(Var),!,write('FAILED: '+T),nl.
  326report_item(portray,Item) :-
  327   portray_clause((Item:-Item)), nl.
  328report_item(expr,Item) :-
  329   write_tree(Item), nl.
  330report_item(tree,Item) :-
  331   print_tree(Item), nl.
  332
  333runtime(TimeSecs) :- statistics(runtime,[MSec,_]), TimeSecs is MSec/1000,!.
  334
  335
  336quote(A&R) :-
  337   atom(A), !,
  338   quote_amp(R).
  339quote(_-_).
  340quote('--'(_,_)).
  341quote(_+_).
  342quote(verb(_,_,_,_,_,_Kind)).
  343quote(wh(_)).
  344quote(nameOf(_)).
  345quote(prep(_)).
  346quote(det(_)).
  347quote(quant(_,_)).
  348quote(int_det(_)).
  349
  350quote_amp(F):- compound(F), functor(F,'$VAR',1),!.
  351quote_amp(R) :-
  352   quote(R).
  353
  354sent_to_prelogic(S0,S) :-
  355   i_sentence(S0,S1),
  356   clausify80(S1,S2),
  357   once(simplify(S2,S)),!.
  358
  359sent_to_prelogic(S0,S) :- 
  360  t_l:chat80_interactive,plt,
  361   must((i_sentence(S0,S1),
  362   clausify80(S1,S2),
  363   simplify(S2,S))),!.
  364
  365simplify(C,C0):-var(C),dmsg(var_simplify(C,C0)),!,fail.
  366simplify(C,(P:-R)) :- !,
  367   unequalise(C,(P:-Q)),
  368   simplify(Q,R,true).
  369
  370simplify(C,C0,C1):-var(C),dmsg(var_simplify(C,C0,C1)),fail.
  371simplify(C,C,R):-var(C),!,R=C.
  372simplify(setof(X,P0,S),R,R0) :- !,
  373   simplify(P0,P,true),
  374   revand(R0,setof(X,P,S),R).
  375simplify((P,Q),R,R0) :-
  376   simplify(Q,R1,R0),
  377   simplify(P,R,R1).
  378simplify(true,R,R) :- !.
  379simplify(X^P0,R,R0) :- !,
  380   simplify(P0,P,true),
  381   revand(R0,X^P,R).
  382simplify(numberof(X,P0,Y),R,R0) :- !,
  383   simplify(P0,P,true),
  384   revand(R0,numberof(X,P,Y),R).
  385simplify(\+P0,R,R0) :- !,
  386   simplify(P0,P1,true),
  387   simplify_not(P1,P),
  388   revand(R0,P,R).
  389simplify(P,R,R0) :-
  390   revand(R0,P,R).
  391
  392simplify_not(\+P,P) :- !.
  393simplify_not(P,\+P).
  394
  395revand(true,P,P) :- !.
  396revand(P,true,P) :- !.
  397revand(P,Q,(Q,P)).
  398
  399unequalise(C0,C) :-
  400   numbervars80(C0,1,N),
  401   functor(V,v,N),
  402   functor(M,v,N),
  403   inv_map_enter(C0,V,M,C).
  404
  405inv_map_enter(C0,V,M,C):- catch(inv_map(C0,V,M,C),too_deep(Why),(dmsg(Why),dtrace(inv_map(C0,V,M,C)))).
  406
  407inv_map(Var,V,M,T) :- stack_depth(X), X> 400, throw(too_deep(inv_map(Var,V,M,T))).
  408inv_map(Var,V,M,T) :- stack_check(500), var(Var),dmsg(var_inv_map(Var,V,M,T)),!,Var==T.
  409inv_map('$VAR'(I),V,_,X) :- !,
  410   arg(I,V,X).
  411inv_map(A=B,V,M,T) :- !,
  412   drop_eq(A,B,V,M,T).
  413inv_map(X^P0,V,M,P) :- !,
  414   inv_map(P0,V,M,P1),
  415   exquant(X,V,M,P1,P).
  416inv_map(A,_,_,A) :- atomic(A), !.
  417inv_map(T,V,M,R) :-
  418   functor(T,F,K),
  419   functor(R,F,K),
  420   inv_map_list(K,T,V,M,R).
  421
  422inv_map_list(0,_,_,_,_) :- !.
  423inv_map_list(K0,T,V,M,R) :-
  424   arg(K0,T,A),
  425   arg(K0,R,B),
  426   inv_map(A,V,M,B),
  427   K is K0-1,
  428   inv_map_list(K,T,V,M,R).
  429
  430drop_eq('$VAR'(I),'$VAR'(J),V,M,true) :- !,
  431 ( I=\=J, !,
  432      irev(I,J,K,L), 
  433      arg(K,M,L),
  434      arg(K,V,X),
  435      arg(L,V,X);
  436   true).
  437drop_eq('$VAR'(I),T,V,M,true) :- !,
  438   arg(I,V,T),
  439   arg(I,M,0).
  440drop_eq(T,'$VAR'(I),V,M,true) :- !,
  441   arg(I,V,T),
  442   arg(I,M,0).
  443drop_eq(X,Y,_,_,X=Y).
  444
  445exquant('$VAR'(I),V,M,P0,P) :-
  446   arg(I,M,U),
  447 ( var(U), !,
  448      arg(I,V,X),
  449       P=(X^P0);
  450   P=P0).
  451
  452irev(I,J,I,J) :- I>J, !.
  453irev(I,J,J,I)