% Chat-80 : A small subset of English for database querying.

:-public hi/0, hi/1, quote/1.

:- mode control(+),
    doing(+,+),
    uses(+,?),
        process(+),
        simplify(+,?),
        simplify(+,?,?),
    simplify_not(+,?),
        revand(+,+,?),
        report(?,+,+,+),
        report_item(+,?).

:-fastcode.

/* Control loop */

hi :-
   hi(user).

hi(File) :-
   repeat,
      ask(File,P),
      control(P), !,
      end(File).

ask(user,P) :- !,
   write('Question: '),
   ttyflush,
   read_in(P).
ask(File,P) :-
   seeing(Old),
   see(File),
   read_in(P),
   nl,
   doing(P,0),
   nl,
   see(Old).

doing([],_) :- !.
doing([X|L],N0) :-
   out(X),
   advance(X,N0,N),
   doing(L,N).

out(nb(X)) :- !,
   write(X).
out(A) :-
   write(A).

advance(X,N0,N) :-
   uses(X,K),
   M is N0+K,
 ( M>72, !,
      nl,
      N is 0;
   N is M+1,
      write(' ')).

uses(nb(X),N) :- !,
   chars(X,N).
uses(X,N) :-
   chars(X,N).

chars(X,N) :- atomic(X), !,
   name(X,L),
   length(L,N).
chars(_,2).

end(user) :- !.
end(F) :-
   close(F).

control([bye,'.']) :- !,
   display('Cheerio.'),
   nl.
control([trace,'.']) :- !,
   assert(tracing),
   display('Tracing from now on.'), nl, fail.
control([do,not,trace,'.']) :-
   retract(tracing), !,
   display('No longer tracing.'), nl, fail.
control(['help', '.']) :-
    !,
write(
'--- Some special commands --------------------------------\
trace.            (gives some information on the workings)\
do not trace.     (switches it off again)\
bye.              (when you\'ve finished)\
help.             (prints this message)\
\
--- Some questions to try --------------------------------\
What rivers are there?\
Does Afghanistan border China?\
Which countries bordering Spain border France?\
What is the capital of Upper_Volta?\
Where is the largest country?\
which countries are european?\
what country is paris the capital of?\
\n'), fail.

control(U) :-
   process(U),
   fail.

process(U) :-
   statistics(runtime,_),
   sentence(E,U,[],[],[]),
   statistics(runtime,[_,Et0]),
   report(E,'Parse',Et0,tree),
   statistics(runtime,_),
   i_sentence(E,QT),
   report(QT,'Quant tree',0,quant),
   clausify(QT,UE),
   simplify(UE,S),
   statistics(runtime,[_,Et1]),
   report(S,'Semantics',Et1,expr),
   statistics(runtime,_),
   qplan(S,S1), !,
   statistics(runtime,[_,Et2]),
   report(S1,'Planning',Et2,expr),
   statistics(runtime,_),
   answer(S1), !, nl,
   statistics(runtime,[_,Et3]),
   report(_,'Reply',Et3,none).
process(_) :-
   failure.

failure :-
   write('I don\'t understand.'), nl.	;;; display changed to write

report(Item,Label,Time,Mode) :-
   tracing, !,
   nl, write(Label), write(': '), write(Time), write('msec.'), nl,
   report_item(Mode,Item).
report(_,_,_,_).

report_item(none,_).
report_item(expr,Item) :-
   write_tree(Item), nl.
report_item(tree,Item) :-
   print_tree(Item), nl.
report_item(quant,Item) :-
   pp_quant(Item,2), nl.

quote(A&R) :-
   atom(A), !,
   quote_amp(R).
quote(_-_).
quote(_--_).
quote(_+_).
quote(verb(_,_,_,_,_)).
quote(wh(_)).
quote(name(_)).
quote(prep(_)).
quote(det(_)).
quote(quant(_,_)).
quote(int_det(_)).

quote_amp('$VAR'(_)) :- !.
quote_amp(R) :-
   quote(R).


simplify(C,(P:-R)) :- !,
   unequalise(C,(P:-Q)),
   simplify(Q,R,true).

simplify(setof(X,P0,S),R,R0) :- !,
   simplify(P0,P,true),
   revand(R0,setof(X,P,S),R).
simplify((P,Q),R,R0) :-
   simplify(Q,R1,R0),
   simplify(P,R,R1).
simplify(true,R,R) :- !.
simplify(X^P0,R,R0) :- !,
   simplify(P0,P,true),
   revand(R0,X^P,R).
simplify(numberof(X,P0,Y),R,R0) :- !,
   simplify(P0,P,true),
   revand(R0,numberof(X,P,Y),R).
simplify(not P0,R,R0) :- !,
   simplify(P0,P1,true),
   simplify_not(P1,P),
   revand(R0,P,R).
simplify(P,R,R0) :-
   revand(R0,P,R).

simplify_not(not P,P) :- !.
simplify_not(P,not P).

revand(true,P,P) :- !.
revand(P,true,P) :- !.
revand(P,Q,(Q,P)).

unequalise(C0,C) :-
   numbervars(C0,1,N),
   functor(V,v,N),
   functor(M,v,N),
   inv_map(C0,V,M,C).

inv_map('$VAR'(I),V,_,X) :- !,
   arg(I,V,X).
inv_map(A=B,V,M,T) :- !,
   drop_eq(A,B,V,M,T).
inv_map(X^P0,V,M,P) :- !,
   inv_map(P0,V,M,P1),
   exquant(X,V,M,P1,P).
inv_map(A,_,_,A) :- atomic(A), !.
inv_map(T,V,M,R) :-
   functor(T,F,K),
   functor(R,F,K),
   inv_map_list(K,T,V,M,R).

inv_map_list(0,_,_,_,_) :- !.
inv_map_list(K0,T,V,M,R) :-
   arg(K0,T,A),
   arg(K0,R,B),
   inv_map(A,V,M,B),
   K is K0 - 1,
   inv_map_list(K,T,V,M,R).

drop_eq('$VAR'(I),'$VAR'(J),V,M,true) :- !,
 ( I=\=J, !,
      irev(I,J,K,L), 
      arg(K,M,L),
      arg(K,V,X),
      arg(L,V,X);
   true).
drop_eq('$VAR'(I),T,V,M,true) :- !,
   arg(I,V,T),
   arg(I,M,0).
drop_eq(T,'$VAR'(I),V,M,true) :- !,
   arg(I,V,T),
   arg(I,M,0).
drop_eq(X,Y,_,_,X=Y).

exquant('$VAR'(I),V,M,P0,P) :-
   arg(I,M,U),
 ( var(U), !,
      arg(I,V,X),
       P=(X^P0);
   P=P0).

irev(I,J,I,J) :- I>J, !.
irev(I,J,J,I).

/* Version of top level for benchmarks */

bench_hi(File) :-
   retractall(tracing),
   repeat,
   ask(File,P),
   statistics(runtime,_),
   control1(P), !,
   end(File).

control1([bye,'.']) :- !,
   display('Cheerio.'),
   nl.
control1([trace,'.']) :- !,
   assert(tracing),
   display('Tracing from now on!'), nl, fail.
control1([do,not,trace,'.']) :-
   retract(tracing), !,
   display('No longer tracing.'), nl, fail.
control1(U) :-
   sentence(E,U,[],[],[]),
   i_sentence(E,QT),
   clausify(QT,UE),
   simplify(UE,S),
   qplan(S,S1), !,
   answer(S1), !,
   statistics(runtime,[_,Diff]), nl,
   write(Diff), write(' msec'), nl, nl, fail.
