initial commit
authorMart Lubbers <mart@martlubbers.net>
Thu, 11 Dec 2014 09:18:12 +0000 (10:18 +0100)
committerMart Lubbers <mart@martlubbers.net>
Thu, 11 Dec 2014 09:18:12 +0000 (10:18 +0100)
docs/ailog_man.pdf [new file with mode: 0644]
docs/ker-assignment2.pdf [new file with mode: 0644]
pl-ail-files/ailog2.pl [new file with mode: 0644]
pl-ail-files/exercise0.pl [new file with mode: 0644]
pl-ail-files/exercise10.ail [new file with mode: 0644]
pl-ail-files/exmbr.ail [new file with mode: 0644]
pl-ail-files/heart.ail [new file with mode: 0644]
report/report.tex [new file with mode: 0644]

diff --git a/docs/ailog_man.pdf b/docs/ailog_man.pdf
new file mode 100644 (file)
index 0000000..e1f640a
Binary files /dev/null and b/docs/ailog_man.pdf differ
diff --git a/docs/ker-assignment2.pdf b/docs/ker-assignment2.pdf
new file mode 100644 (file)
index 0000000..46752c0
Binary files /dev/null and b/docs/ker-assignment2.pdf differ
diff --git a/pl-ail-files/ailog2.pl b/pl-ail-files/ailog2.pl
new file mode 100644 (file)
index 0000000..22693f7
--- /dev/null
@@ -0,0 +1,2185 @@
+% -*- Mode: Prolog -*-\r
+% ailog2.pl  logic engine for Artificial Intelligence http://artint.info\r
+% Copyright (C) 1997-2012, David Poole.\r
+% This is subject to the GNU Public License (GPL). See user manual for details.\r
+% Designed for standard Prolog, but only tested on SWI Prolog.\r
+% It is written in one file to make it easy to use:\r
+%      Get swi-prolog, double click on this file and it should start!\r
+\r
+ailog_version('2.3.6.2',2013).\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%          SYSTEM DEPENDENT CODE               %\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+%% the keys to stastics don't seem to be standard. This should cover the cases:\r
+%% get_runtime(T,Units) gets accumulated runtime from the system\r
+get_runtime(T,U) :-   catch((statistics(cputime,T),U=secs),_,\r
+                           (statistics(runtime,[T,_]),U=ms)). % Sicstus/Quintus Prolog\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%          OPERATOR DEFINITIONS                %\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% <- is the "if"\r
+:- op(1150, xfx, <- ).\r
+% <= is the base-level "if" (it is not used here, but can be used in\r
+% programs). \r
+:- op(1120, xfx, <= ).\r
+% "&" is the conjunction.\r
+:- op(950,xfy, &).\r
+% "~" is the negation\r
+:- op(900,fy,~).\r
+% "\=" is inequality\r
+:- op(700,xfx,\=).\r
+% "#=" is can't be equal\r
+:- op(700,xfx,#=).\r
+%  ":" is used for probability declarations.\r
+:- op(800,xfx,:).\r
+\r
+:- op(1170, fx, tell).\r
+:- op(1170, fx, ask).\r
+:- op(1170, fx, whynot).\r
+:- op(1170, fx, how).\r
+:- op(1170, fx, how).\r
+:- op(1170, fx, help).\r
+:- op(1170,fx,load).\r
+:- op(1170,fx,prload).\r
+:- op(1170,fx,cd).\r
+:- op(1170,fx,bound).\r
+:- op(1170,fx,stats).\r
+:- op(1170,fx,listing).\r
+:- op(1170,fx,clear).\r
+:- op(1170,fx,askable).\r
+:- op(1170,fx,assumable).\r
+:- op(1170,fx,prob).\r
+:- op(1170,fx,observe).\r
+:- op(1170,fx,unobserve).\r
+:- op(1170,fx,predict).\r
+:- op(1170,fx,deterministic).\r
+:- op(1170,fx,prob_threshold).\r
+:- op(1170,fx,arbitrary).\r
+:- op(1170,fx,allow).\r
+\r
+:- dynamic (<-)/2.\r
+:- dynamic failed/1.\r
+:- dynamic depth_bound/1.\r
+:- dynamic askabl/1.\r
+:- dynamic assumabl/1.\r
+:- dynamic choice/3.\r
+:- dynamic alt/1.\r
+:- dynamic asked/2.\r
+:- dynamic debugging_failure/0.\r
+:- dynamic answer_found/0.\r
+:- dynamic checking_runtime/0.\r
+:- dynamic lastruntime/1.\r
+:- dynamic deter/1.\r
+:- dynamic explanations/4.\r
+:- dynamic nogood/2.\r
+:- dynamic anogood/2.\r
+:- dynamic (prob_threshold)/1.\r
+:- dynamic pruned_prob/1.\r
+:- dynamic arbit/2.\r
+:- dynamic builtin/2.\r
+\r
+depth_bound(30).\r
+prob_threshold(0.000001).\r
+pruned_prob(0.0).\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            AILog Help\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+help_message(['\r
+AILog Version ',V,' Help','\r
+\r
+A clause is of the form','\r
+  Head <- Body','\r
+  Head','\r
+Head is an atom.','\r
+Body is an expression made up of','\r
+   Atom','\r
+   ~ B1           negation as finite failure','\r
+   B1 & B2        conjunction B1 and B2','\r
+where B1 and B2 are expressions.','\r
+\r
+***** Basic commands:','\r
+\r
+tell CLAUSE.           add the clause to the knowledge base','\r
+askable Atom.          makes Atom askable.','\r
+\r
+ask QUERY.             ask if expression QUERY is a consequence of the KB','\r
+whynot QUERY.          find out why an answer to QUERY was not returned.','\r
+\r
+allow G.               allow goal G to use the Prolog definition.','\r
+bound N.               set search depth-bound to N (default=30)','\r
+listing.               list all clauses in the knowledge base.','\r
+listing H.             list clauses in the knowledge base with head H.','\r
+askables.              list all askables.','\r
+clear.                 clear the knowledge base','\r
+clear asked.           clear all user responses','\r
+clear H.               clear clauses with head H from knowledge base','\r
+check.                 check the knowledge base for undefined predicates','\r
+help.                  print this help message','\r
+help prob.             prints help on probabilistic reasoning','\r
+help abduction.        prints help on abductive reasoning','\r
+stats runtime.         turn on runtime statistics','\r
+quit.                  quit ailog','\r
+prolog.                exit to Prolog. Type "start." to start ailog again.','\r
+\r
+***** Input/Output','\r
+\r
+load ''Filename''.      load the clauses in file Filename','\r
+prload ''Filename''.    load the clauses in Filename, using Prolog''s syntax.','\r
+cd ''directory''.       changes directory (folder) for loads']) :-\r
+   ailog_version(V,_).\r
+\r
+help_message(prob,[\r
+'AILog Version ',V,' Probabilistic Reasoning Help','\r
+\r
+This help is for probabilistic reasoning in Ailog. This is not useful\r
+if you are a beginner interested in deductive reasoning.','\r
+\r
+AILog implements a version of the independent choice logic that allows\r
+for probabilities on atoms. These atoms should not be the head of clauses.','\r
+\r
+prob a:p.              makes atom a probabilistic with probability p.','\r
+prob a1:p1,a2:p2,...,ak:pk.  makes atoms ai probabilistic with probability pi.','\r
+                       a''s are exclusive and covering; the p''s must sum to 1.','\r
+\r
+probs.                 list all prob assertions.','\r
+\r
+observe QUERY.         observe that QUERY is true','\r
+predict QUERY.         ask the posterior probability that QUERY is true','\r
+observations.          list all observations made','\r
+unobserve.             undo whylast observation','\r
+unobserve all.         undo all observations','\r
+explanations.          describe the explanations of the observations','\r
+worlds.                describe the worlds of the observations','\r
+\r
+prob_threshold V.      set the probability threshold to V in range [0,1]','\r
+prob_threshold.        get the current probability threshold']) :-\r
+   ailog_version(V,_).\r
+\r
+help_message(abduction,[\r
+'AILog Version ',V,' Abductive Reasoning Help','\r
+\r
+This help is for abductive reasoning in AILog. This is not useful if\r
+you are a beginner interested in deductive reasoning.','\r
+\r
+Abduction allows the system to make assumptions to prove a goal, as\r
+long as the assumptions are consistent.',' The atoms that can be\r
+assumed are called assumables.',' You use "false" at the head of a\r
+clause to make constraints.',' After adding assumables or more\r
+clauses, you need to create nogoods to make sure that inconsistent\r
+sets of assumables are found.',' Abduction in AILog does not work\r
+satisfactorily with negation as failure.','\r
+\r
+assumable Atoms.       makes (comma-separated) Atoms assumable.','\r
+assumables.            list all assumables.','\r
+\r
+create_nogoods         construct nogoods.','\r
+nogoods                list nogoods.'\r
+]) :-\r
+   ailog_version(V,_).\r
+\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            AILog Commands\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+interpret(C) :-\r
+   file_or_command(C,command),!.\r
+\r
+interpret(help) :- !,\r
+   help_message(Help),\r
+   write_all(Help).\r
+interpret(help What) :-\r
+   help_message(What,Help),!,\r
+   write_all(Help).\r
+interpret(help What) :- !,\r
+   write_all(['No help on "',What,'". Type "help." for more information.']).\r
+\r
+interpret((tell _ :- _)) :- !,\r
+   write_all(['Illegal rule: ":-" is not a legal implication. Use "<-".']).\r
+interpret((tell C)) :- !,\r
+   tell_clause(C).\r
+\r
+interpret((ask Q)) :- !,\r
+   retractall(debugging_failure),\r
+   retractall(answer_found),\r
+   depth_bound(DB),\r
+   askq(Q,DB).\r
+\r
+interpret((whynot Q)) :- !,\r
+   depth_bound(DB),\r
+   (explanations(_,ETs,_,_)\r
+   ->\r
+    member(et(E,_),ETs),\r
+    whynotb(Q,DB,_,E,_)\r
+    ;\r
+    whynotb(Q,DB,_,ass([],[],1),_)\r
+   ).\r
+\r
+interpret(clear) :- !,\r
+   retractall((_ <- _)),\r
+   retractall(assumabl(_)),\r
+   retractall(alt(_)),\r
+   retractall(choice(_,_,_)), \r
+   retractall(askabl(_)),\r
+   retractall(asked(_,_)),\r
+   retractall(nogood(_,_)),\r
+   retractall(anogood(_,_)),\r
+   retractall(explanations(_,_,_,_)),\r
+   retractall(pruned_prob(_)),\r
+   retractall(arbit(_,_)),\r
+   assert(pruned_prob(0.0)).\r
+\r
+interpret((clear asked)) :- !,\r
+   retractall(asked(_,_)),\r
+   write_all(['User responses cleared.']).\r
+\r
+interpret((clear H)) :- !,\r
+   retractall((H <- _)),\r
+   retractall(assumabl(H)),\r
+   ( alt(A) , member(H:_, A)\r
+      ->\r
+       retract(alt(A)),\r
+       forall(member(G:_, A), retract(choice(G,_,_)))\r
+   ; true),\r
+   retractall(askabl(H)),\r
+   retractall(asked(H,_)),\r
+   (H=(X,V) -> retractall(arbit(X,V));true).\r
+\r
+interpret((stats Cmd)) :- !,\r
+   stats_command(Cmd).\r
+\r
+interpret((prload File)) :- !,\r
+   prolog_load(File).\r
+\r
+interpret((load File)) :- !,\r
+   ci_load(File).\r
+\r
+interpret((cd Dir)) :- !,\r
+   working_directory(_,Dir).\r
+\r
+interpret((cd)) :- !,\r
+   working_directory(_,'~').\r
+\r
+interpret((bound)) :- !,\r
+   depth_bound(N),\r
+   write_all(['Current depth bound is ',N]).\r
+\r
+interpret((bound N)) :- !,\r
+   (integer(N) ->\r
+      retract(depth_bound(_)),\r
+      asserta(depth_bound(N))\r
+   ; write_all(['Depth bound must be an integer'])).\r
+\r
+interpret(quit) :-\r
+   throw(quit).\r
+\r
+interpret(check) :- !,\r
+   check.\r
+\r
+interpret((observe G)) :- !,\r
+   observe(G).\r
+\r
+interpret((predict G)) :- !,\r
+   predict(G).\r
+\r
+interpret(askables) :- \r
+   askabl(G),\r
+   write_all(['askable ',G,'.']),\r
+   fail.\r
+interpret(askables) :- !.\r
+\r
+interpret(assumables) :- \r
+   assumabl(G),\r
+   write_all(['assumable ',G,'.']),\r
+   fail.\r
+interpret(assumables) :- !.\r
+\r
+interpret(arbitraries) :- \r
+   arbit(X,V),\r
+   write_all(['arbitrary ',X=V,'.']),\r
+   fail.\r
+interpret(arbitraries) :- !.\r
+\r
+interpret(probs) :-\r
+   alt(L),\r
+   (L=[A:P1,~A:_]\r
+     ->\r
+      write_all(['prob ',A,':',P1,'.'])\r
+   ;\r
+     write('prob '),\r
+     writeAllDelim(L,', '),\r
+     write('.'),\r
+     nl\r
+   ),\r
+   fail.\r
+interpret(probs) :- !.\r
+\r
+interpret((listing)) :- !,\r
+   interpret((listing _)),\r
+   interpret(askables),\r
+   interpret(assumables),\r
+   interpret(probs),\r
+   interpret(arbitraries).\r
+\r
+interpret((listing H)) :-\r
+   (H <- B),\r
+   (B == true \r
+   -> write_all([H,'.'])\r
+   ; write_all([H,' <- ',B,'.'])\r
+   ),\r
+   fail.\r
+interpret((listing _)) :- !.\r
+\r
+interpret(unobserve all) :- !,\r
+   retractall(explanations(_,_,_,_)),\r
+   retractall(pruned_prob(_)),\r
+   assert(pruned_prob(0.0)).\r
+\r
+interpret(unobserve) :- !,\r
+   (retract(explanations(_,_,_,_))\r
+     ->\r
+      (\r
+       explanations(_,_,_,Err)\r
+      ->\r
+       retractall(pruned_prob(_)),\r
+       assert(pruned_prob(Err))\r
+      ;\r
+       retractall(pruned_prob(_)),\r
+       assert(pruned_prob(0.0))\r
+       \r
+       )\r
+    ;\r
+      write_all(['No observations to undo.'])\r
+   ).\r
+\r
+interpret(observations) :- !,\r
+   (explanations(Obs,_,_,_) ->\r
+      print_observations(Obs,_)\r
+   ;  write_all(['There are no observations.'])).\r
+\r
+interpret(explanations) :- !,\r
+   (explanations(_,ETs,_,_) ->\r
+      print_explanations(ETs,0)\r
+   ;  write_all(['There are no observations.'])).\r
+\r
+interpret(worlds) :- !,\r
+   (explanations(Obs,Expls,Pr,Err) ->\r
+       extract_expls(Expls,Sexpls),\r
+       make_disjoint(Sexpls,Worlds),\r
+       print_worlds(Worlds,0),\r
+        (Err=:=0.0\r
+        ->\r
+          write_all(['P(',Obs,') = ',Pr])\r
+       ;\r
+        Max is Pr+Err,\r
+        write_all(['P(',Obs,') = [',Pr,',',Max,']'])\r
+       )\r
+   ;  write_all(['There are no observations.'])).\r
+\r
+interpret(prob_threshold V) :-\r
+     (number(V), V>=0.0, V=<1.0)\r
+     ->\r
+       retract(prob_threshold(_)),\r
+       assert(prob_threshold(V))\r
+       ;\r
+       write_all(['Argument to prob_threshold must be in range [0,1].']).\r
+interpret(prob_threshold) :-\r
+       prob_threshold(V),\r
+       write_all(['Probability threshold is ',V]).\r
+\r
+\r
+interpret(nogoods) :- !,\r
+    list_nogoods.\r
+    \r
+interpret((A <- B)) :- !,\r
+   write_all(['Illegal command, ',(A <- B),'. You have to "tell" a clause.']).\r
+\r
+interpret(C) :-\r
+   write_all(['Unknown Command, ',C,'. Type "help." for help.']).\r
+\r
+% listifyProbs(St,L0,L1,S0,S1)\r
+%    St is a probability structure \r
+%    L1-L0 is thhe list corresponding to the structure\r
+%    S1-S0 is the sum of the probabilities\r
+listifyProbs((X,Y),L0,L2,S0,S2) :- !,\r
+    listifyProbs(X,L0,L1,S0,S1),\r
+    listifyProbs(Y,L1,L2,S1,S2).\r
+listifyProbs((A:P),L0,[A:P|L0],S0,S1) :-\r
+%    atomic(A),     % we want it to mean its a ailog atom\r
+%    number(P),\r
+    P >= 0,\r
+    S1 is S0+P.\r
+\r
+% file_or_command(C,W) C is a command that can be in a file or on the\r
+% command line, W is either command or file \r
+file_or_command((askable G),_) :- !,\r
+   assertz(askabl(G)).\r
+\r
+file_or_command((assumable G),_) :- !,\r
+   make_assumable(G).\r
+\r
+file_or_command((allow G),_) :- !,\r
+   assertz(builtin(G,true)).\r
+\r
+\r
+file_or_command((prob A:P),W) :- !,\r
+   (number(P), P>=0, P=<1 ->\r
+      P1 is 1-P,\r
+      assertz(alt([A:P,~A:P1])),\r
+      assertz(choice(A,P,[~A])),\r
+      assertz(choice(~A,P1,[A]))\r
+   ;\r
+       legal_arithmetic_expression(P) ->\r
+             assertz(alt([A:P,~A:(1-P)])),\r
+      assertz(choice(A,P,[~A])),\r
+      assertz(choice(~A,(1-P),[A]))\r
+\r
+   ;\r
+     (W=file \r
+      ->\r
+     write_all(['Error: ',(prob A:P)])\r
+     ; true),\r
+     write_all(['Probability must be a number or expression in range [0,1]'])\r
+   ).\r
+\r
+file_or_command((prob APs),W) :- !, \r
+   ( (listifyProbs(APs,[],L,0,Sum) )%, Sum > 0.9999999999999, Sum< 1.0000000000001)\r
+    ->\r
+      normalise(L,Sum*1.0,LN),\r
+      assertz(alt(LN)),\r
+      make_choices(LN)\r
+   ;\r
+     (W=file \r
+      ->\r
+     write_all(['Error: ',(prob APs)])\r
+     ; true),\r
+      write_all(['Error: command should be: prob a1:p1,a2:p2,...,ak:pk.']),\r
+      write_all(['       the pi''s must be nonnegative and sum to 1.0'])\r
+  ).\r
+\r
+file_or_command((arbitrary A),W) :- !,\r
+       A=(X=V)\r
+       ->\r
+               assertz(arbit(X,V))\r
+       ;\r
+       (W=file \r
+       ->\r
+        write_all(['Error: ',(arbitrary A)])\r
+       ; true),\r
+       write_all(['Error: command should be: arbitrary X=V.']).\r
+       \r
+       \r
+file_or_command((deterministic G),_) :- !,\r
+   assertz(deter(G)).\r
+\r
+file_or_command(create_nogoods,_) :- !,\r
+   depth_bound(DB),\r
+   construct_nogoods(DB).\r
+\r
+\r
+legal_arithmetic_expression(N) :- var(N),!.\r
+legal_arithmetic_expression(N) :- number(N),!.\r
+legal_arithmetic_expression(E1+E2) :- !,\r
+       legal_arithmetic_expression(E1),\r
+       legal_arithmetic_expression(E2).\r
+legal_arithmetic_expression(E1-E2) :- !,\r
+       legal_arithmetic_expression(E1),\r
+       legal_arithmetic_expression(E2).\r
+legal_arithmetic_expression(E1*E2) :- !,\r
+       legal_arithmetic_expression(E1),\r
+       legal_arithmetic_expression(E2).\r
+legal_arithmetic_expression(E1/E2) :- !,\r
+       legal_arithmetic_expression(E1),\r
+       legal_arithmetic_expression(E2).\r
+\r
+% make_assumable makes an atom or a comma-separated atoms assumable.\r
+make_assumable((A,B)) :- !,\r
+   make_assumable(A),\r
+   make_assumable(B).\r
+\r
+make_assumable(G) :-\r
+   assertz(assumabl(G)).\r
+\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            ASKING\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+askq(Q,_) :-\r
+   illegal_body(Q,Why),!,\r
+   write_all(['Illegal query: '|Why]).\r
+askq(Q,DB) :-\r
+   retractall(failed(_)),\r
+   assert(failed(naturally)),\r
+   reset_runtime,\r
+   solve(Q,DB,Res,[wrule(yes,true,Q,true)],ass([],[],1),Ass),\r
+   (answer_found -> true ; assert(answer_found)),\r
+   mynumbervars((Q,Res,Ass),0,_),\r
+   report(Q,Res,Ass).\r
+askq(Q,_) :- \r
+   failed(naturally),!,\r
+   (answer_found\r
+    ->  write_all(['No more answers.'])\r
+    ; write_all(['No. ',Q,' doesn''t follow from the knowledge base.'])),\r
+   report_runtime.\r
+askq(Q,DB) :- !,\r
+   ask_failing(Q,DB).\r
+\r
+ask_failing(Q,DB) :-\r
+   write_all(['Query failed due to depth-bound ',DB,'.']),\r
+   report_runtime,\r
+   writel(['     [New-depth-bound,where,ok,help]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_failing_question(Comm,Q,DB).\r
+\r
+% interpret_failing_question(Comm,Q,DB).\r
+interpret_failing_question(help,Q,DB) :- !,\r
+   write_all([\r
+    '     Give one of the following commands:',nl,\r
+    '        an integer > ',DB,'      to use this depth bound.',nl,\r
+    '           (use "bound N." to set it permanently).',nl,\r
+    '        where.  to explore the proof tree where the depth-bound was reached.',nl,\r
+    '        ok.     to return to the ailog prompt.',nl,\r
+    '        help.   to print this message.']),\r
+   ask_failing(Q,DB).\r
+interpret_failing_question(end_of_file,_,_) :- !.\r
+interpret_failing_question(ok,_,_) :- !.\r
+interpret_failing_question(where,Q,DB) :-\r
+   assert(debugging_failure),\r
+   askq(Q,DB).\r
+interpret_failing_question(Comm,Q,_) :-\r
+   integer(Comm),!,\r
+   askq(Q,Comm).\r
+interpret_failing_question(Comm,Q,DB) :-\r
+   write_all(['   Unknown command, ',Comm,' type "help." for help.']),\r
+   ask_failing(Q,DB).\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            TELLING\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+tell_clause((~ H <- B)) :- !,\r
+   write_all(['Illegal rule: ~',H,' <- ',B,'.',nl,\r
+      'You cannot have negation in the head of a clause.']).\r
+tell_clause((H1 & H2 <- B)) :- !,\r
+   write_all(['Illegal rule: ',H1 & H2,' <- ',B,'.',nl,\r
+      'You cannot have a conjunction in the head of a clause.']).\r
+tell_clause((H1 , H2 <- B)) :- !,\r
+   write_all(['Illegal rule: ',H1 ,',', H2,' <- ',B,'.',nl,\r
+      'You cannot have a "," in the head of a clause.']).\r
+tell_clause((H <- B)) :-\r
+   !,\r
+   ( builtin(H,_) ->\r
+     write_all([H,' is built-in. It cannot be redefined.'])\r
+   ; illegal_body(B,Why) ->\r
+     write_all(['Illegal rule: ',H,'<-',B,'. '|Why])\r
+   ; assertz((H <- B))).\r
+tell_clause((H :- B)) :-\r
+   !,\r
+   write_all(['Illegal rule: ',H,':-',B,'. ":-" is not a legal implication. Use "<-".']).\r
+tell_clause((A, B)) :-\r
+   !,\r
+   write_all(['Error: ',(A,B),' is not a valid clause.']).\r
+tell_clause((A & B)) :-\r
+   !,\r
+   write_all(['Error: ',(A&B),' is not a valid clause.']).\r
+tell_clause((~A)) :-\r
+   !,\r
+   write_all(['Error: ',~A,' is not a valid clause.']).\r
+tell_clause(H) :-\r
+   builtin(H,_),!,\r
+   write_all([H,' is built-in. It cannot be redefined.']).\r
+tell_clause(H) :-\r
+   !,\r
+   assertz((H <- true)).\r
+\r
+illegal_body(X,['Variables cannot be atoms. Use call(',X,').']) :- var(X).\r
+illegal_body((_,_),[' "," is not a legal conjunction. Use "&".']).\r
+illegal_body((\+ _),[' "\\+" is not a legal negation. Use "~".']).\r
+illegal_body(!,[' "!" is not supported.']).\r
+illegal_body([_|_],[' Lists cannot be atoms.']).\r
+\r
+illegal_body((A&_),Why) :-\r
+   illegal_body(A,Why).\r
+illegal_body((_&A),Why) :-\r
+   illegal_body(A,Why).\r
+illegal_body((A;_),Why) :-\r
+   illegal_body(A,Why).\r
+illegal_body((_;A),Why) :-\r
+   illegal_body(A,Why).\r
+illegal_body((~A),Why) :-\r
+   illegal_body(A,Why).\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            META-INTERPRETER\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% solve(Goal,DepthBnd,PfTree,WhyTree,Ass0,Ass1) \r
+%  Goal is the goal to be proved\r
+%  DepthBnd is the depth bound\r
+%  PfTree is the proof tree returned\r
+%  Whytree is a list of wrule(Head,LeftTree,Current,RightBody)\r
+%  Ass0 is the assumables coming in. \r
+%       This is structure of the form ass(As,PAs,P)\r
+%  Ass1 is the assumables coming out\r
+solve(true,_,true,_,Ass,Ass) :- !.\r
+solve((A&B),N,(AT&BT),[wrule(H,LT,_,RB)|WT],A0,A2) :- !,\r
+   solve(A,N,AT,[wrule(H,LT,A,(B&RB))|WT],A0,A1),\r
+   solve(B,N,BT,[wrule(H,(LT&AT),B,RB)|WT],A1,A2).\r
+\r
+%    The following is tempting, but doesn't work if A makes assumptions...\r
+% solve((A -> B ; C),N,(AT -> BT;CT),[wrule(H,LT,_,RB)|WT],A0,A2) :-\r
+%    solve(A,N,AT,[wrule(H,LT,A,(B&RB))|WT],A0,A1) % why rules is wrong\r
+%    ->\r
+%    solve(B,N,BT,[wrule(H,(LT&AT),B,RB)|WT],A1,A2)\r
+%    ;\r
+%    solve(C,N,CT,[wrule(H,LT,C,RB)|WT],A0,A2).\r
+   \r
+solve(A \= B,_,if(A \= B,builtin),_,A0,A0) :- !,\r
+   dif(A,B).\r
+solve(A #= B,_,if(A #= B,builtin),_,A0,A0) :- !,\r
+   \+(A=B).\r
+solve(call(G),_,_,WT,A0,A0) :- \r
+   var(G),!,\r
+   debug_error(['   Error: argument to call must be bound when evaluated.'],\r
+              WT).\r
+solve(call(G),N,T,WT,A0,A1) :- !,\r
+   solve(G,N,T,WT,A0,A1).\r
+solve((~ G),N,if(~G,T),WT,A0,A1) :- !,\r
+       (ground(G) ->\r
+         failtoprove(G,N,T,WT,A0,A1)\r
+       ;\r
+         debug_error(['   Error: ',~G,' needs to be ground when called.'],\r
+               WT)).\r
+\r
+\r
+solve(G,_,if(G,assumed),_,ass(A0,PAs,P),ass(A0,PAs,P)) :-\r
+   assumabl(G),\r
+%   (ground(G) -> true\r
+%   ; debug_error(['   Error: assumable ',G,' needs to be ground when called.'],\r
+%               WT)),\r
+   idmember(G,A0),!.\r
+solve(G,_,if(G,assumed),_,ass(A0,PAs,P),ass(A1,PAs,P)) :-\r
+   assumabl(G),\r
+%   (ground(G) -> true\r
+%   ; debug_error(['   Error: assumable ',G,' needs to be ground when called.'],\r
+%               WT)),\r
+%   \+ idmember(G,A0),\r
+   good(G,A0),\r
+   insert_into_sorted_list(G,A0,A1).\r
+solve(G,_,if(G,assumed),_,ass(A0,PAs0,P0),ass(A0,PAs1,P1)) :-\r
+   choice(G,P,A),\r
+%    (ground(G) -> true\r
+%    ; debug_error(['   Error: assumable ',G,' needs to be ground when called.'],\r
+%               WT)),\r
+   consistent(PAs0,A),\r
+   insertUpdateProbs(PAs0,P0,G,P,PAs1,P1),\r
+   prob_threshold(Bound),\r
+   ((P1 < Bound)\r
+   ->\r
+    retract(pruned_prob(PP)),\r
+    PP1 is PP+P1,\r
+    asserta(pruned_prob(PP1)),\r
+    fail\r
+   ;\r
+    true\r
+    ).\r
+\r
+solve(G=V,_,if(G=V,assumed),_,ass(A0,PAs,P),ass(A1,PAs,P)) :-\r
+   arbit(G,V),\r
+   (member((G=V1),A0)\r
+   ->\r
+    V=V1, A1=A0\r
+   ;\r
+    nonvar(V) ->  % this seems to be necessary to get it to work.\r
+                % The arbitrary choice has not been made, but this call\r
+                % isn't making the choice.\r
+    A1=[G=V|A0];\r
+    A1=[G=V|A0]\r
+%    fail\r
+%     gensym(ind,V),\r
+%     A1=[G=V|A0]\r
+   ).\r
+    \r
+solve(G,_,if(G,asked),WT,A0,A0) :-\r
+   askabl(G),\r
+   ask_user(G,WT,Ans),\r
+   Ans \== unknown,!,      % fail if Ans=unknown, otherwise don't try clauses\r
+   Ans=yes.\r
+solve(H,_,if(H,builtin),WT,A0,A0) :-\r
+   builtin(H,C),!,\r
+   (C ->  catch(H,_,debugging_builtin_error(H,WT))\r
+   ; write_all(['Error: "',H,'" can''t be called in this form, as ',C,' isn''t true.']), \r
+     debugging_builtin_error(H,WT)\r
+   ).\r
+solve(H,N0,if(H,BT),WT,A0,A1) :-\r
+   N0 > 0,\r
+   deter(H),\r
+   N1 is N0-1,\r
+   (H <- B),\r
+   solve(B,N1,BT,[wrule(H,true,B,true)|WT],A0,A1), !.\r
+solve(H,N0,if(H,BT),WT,A0,A1) :-\r
+   N0 > 0,\r
+   N1 is N0-1,\r
+   (H <- B),\r
+   solve(B,N1,BT,[wrule(H,true,B,true)|WT],A0,A1).\r
+solve(H,0,if(H,asked),WT,ass(A0,PAs0,P0),ass(A0,PAs0,P0)) :-\r
+   debugging_failure,!,\r
+   debugging_failure_goal(H,WT,P0).\r
+solve(_,0,_,_,ass(_,_,P),_) :-\r
+   retractall(failed(_)),\r
+   assert(failed(unnaturally)),\r
+   P>0,\r
+   retract(pruned_prob(PP)),\r
+   PP1 is PP+P,\r
+   asserta(pruned_prob(PP1)),\r
+   fail.\r
+\r
+% report(Query,Res,Ass) report an answer after an ask\r
+report(Q,Res,ass([],[],1)) :- !,\r
+   write_all(['Answer: ',Q,'.']),\r
+   report_runtime,\r
+   writel(['  [ok,more,how,help]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_report(Comm,Q,Res,ass([],[],1)).\r
+report(Q,Res,Ass) :-\r
+   write_all(['Answer: ',Q,'.']),\r
+   ( Ass=ass(A0,[],1) ->\r
+       write_all(['Assuming: ',A0,'.'])\r
+   ;   write_all(['Assuming: ',Ass,'.'])),\r
+   report_runtime,\r
+   writel(['  [more,ok,how,help]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_report(Comm,Q,Res,Ass).\r
+\r
+% interpret_report(Comm,Q,Res,Ass) interprets the answer given by the user\r
+%   to an answer given after and ask \r
+interpret_report(ok,_,_,_) :- !.\r
+interpret_report(more,_,_,_) :- !,\r
+   reset_runtime,fail.\r
+interpret_report(end_of_file,_,_,_) :- !,\r
+   write_all(['^D']).\r
+interpret_report(how,Q,Res,Ass) :- !,\r
+   traverse(Res,Rep),\r
+   ( (Rep = top; Rep=up)\r
+   -> report(Q,Res,Ass)\r
+   ; Rep= retry\r
+   -> reset_runtime,fail\r
+   ; Rep=prompt\r
+   -> true\r
+   ; write_all(['This shouldn''t occur. Traverse reported ',Rep])\r
+   ).\r
+interpret_report(help,Q,Res,Ass) :- !,\r
+   write_all([\r
+     '  The system has proven an instance of your query.',nl,\r
+     '  You can give the following commands:',nl,\r
+     '    more.    for more answers',nl,\r
+     '    ok.      for no more answers',nl,\r
+     '    how.     to enter a dialog to determine how the goal was proved.']),\r
+   report(Q,Res,Ass).\r
+interpret_report(Comm,Q,Res,Ass) :-\r
+   Comm \== more,\r
+   write_all(['Unknown command; ',Comm,'. Type "help." if you need help.']),\r
+   report(Q,Res,Ass).\r
+\r
+% Depth-bound reached\r
+% debugging_failure_goal(H,WT,P)\r
+%   H is the current goal\r
+%   WT is the why-tree\r
+%   P is the probability of this proof\r
+debugging_failure_goal(H,WT,P) :-\r
+   write_all(['  Depth-bound reached. Current subgoal: ',H,'.']),\r
+   writel(['     [fail,succeed,proceed,why,ok,help]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_debugging_failure_command(Comm,H,WT,P).\r
+\r
+\r
+% interpret_debugging_failure_command(Comm,H,WT,P)\r
+%   Comm is the command the user gave\r
+%   H is the current goal\r
+%   WT is the why-tree\r
+%   P is the probability of this proof\r
+\r
+interpret_debugging_failure_command(help,H,WT,P) :- !,\r
+   write_all([\r
+     '  The system has reached the depth bound.',nl,\r
+     '  You can give the following commands:',nl,\r
+     '    fail.       fail this subgoal.',nl,\r
+     '    succeed.    make this subgoal succeed.',nl,\r
+     '    proceed.    fail and don''t stop any more at failing subgoals.',nl,\r
+     '    why.        determine why this subgoal was called.',nl,\r
+     '    ok.         return to ailog prompt.',nl,\r
+     '    help.       print this message.']),\r
+   debugging_failure_goal(H,WT,P).\r
+interpret_debugging_failure_command(fail,_,_,P) :- !,\r
+   retractall(failed(_)),\r
+   assert(failed(unnaturally)),\r
+   P>0,\r
+   retract(pruned_prob(PP)),\r
+   PP1 is PP+P,\r
+   asserta(pruned_prob(PP1)),\r
+   fail.\r
+interpret_debugging_failure_command(succeed,_,_,_) :- !.\r
+interpret_debugging_failure_command(proceed,_,_,P) :- !,\r
+   retractall(debugging_failure),\r
+   retractall(failed(_)),\r
+   assert(failed(unnaturally)),\r
+   P>0,\r
+   retract(pruned_prob(PP)),\r
+   PP1 is PP+P,\r
+   asserta(pruned_prob(PP1)),\r
+   fail.\r
+interpret_debugging_failure_command(ok,_,_,_) :- !,\r
+   throw(prompt).\r
+interpret_debugging_failure_command(end_of_file,_,_,_) :- !,\r
+   throw(prompt).\r
+interpret_debugging_failure_command(why,H,WT,P) :- !,\r
+   \+ \+ (mynumbervars(WT,0,_),why_question(WT,_)),\r
+   debugging_failure_goal(H,WT,P).\r
+interpret_debugging_failure_command(Comm,H,WT,P) :- !,\r
+   write_all(['  Unknown command: ',Comm,'. Type "help." for help.']),\r
+   debugging_failure_goal(H,WT,P).\r
+\r
+\r
+% builtin(G,C) is true if goal G is defined in the system (as opposed to \r
+% being defined in clauses). C is the condition that must hold to make sure\r
+% there are no errors.\r
+builtin((A =< B), ground((A =< B))).\r
+builtin((A >= B), ground((A >= B))).\r
+builtin((A =\= B), ground((A =\= B))).\r
+builtin((A < B), ground((A<B))).\r
+builtin((A > B), ground((A>B))).\r
+builtin((_ is E),ground(E)).\r
+builtin(number(E),ground(E)).\r
+builtin(atomic(E),ground(E)).\r
+\r
+% Error in a built-in\r
+debugging_builtin_error(H,WT) :-\r
+   debug_error(['  Error in built-in predicate: ',H,'.'],WT).\r
+\r
+% RUNTIME ERROR HANDLING\r
+debug_error(Message,WT) :-\r
+   write_all(Message),\r
+   writel(['     [fail,succeed,why,ok,help]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_error_command(Comm,Message,WT).\r
+\r
+interpret_error_command(help,Message,WT) :- !,\r
+%   write_all(Message),\r
+   write_all([\r
+      '  You can give the following commands:',nl,\r
+     '    fail.       fail this subgoal.',nl,\r
+     '    succeed.    make this subgoal succeed.',nl,\r
+     '    why.        determine why this subgoal was called.',nl,\r
+     '    ok.         return to ailog prompt.',nl,\r
+     '    help.       print this message.']),\r
+   debug_error(Message,WT).\r
+interpret_error_command(fail,_,_) :- !,\r
+   fail.\r
+interpret_error_command(succeed,_,_) :- !.\r
+interpret_error_command(ok,_,_) :- !,\r
+   throw(prompt).\r
+interpret_error_command(end_of_file,_,_) :- !,\r
+   throw(prompt).\r
+interpret_error_command(why,H,WT) :- !,\r
+   \+ \+ (mynumbervars(WT,0,_),why_question(WT,_)),\r
+   debug_error(H,WT).\r
+interpret_error_command(Comm,H,WT) :- !,\r
+   write_all(['  Unknown command: ',Comm,'. Type "help." for help.']),\r
+   debug_error(H,WT).\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            ASK THE USER\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+%  ask_user(G,WT,Ans)\r
+%     G is the goal to ask\r
+%     WT is the why-tree\r
+%     Ans is the reply\r
+ask_user(G,_,Ans) :-\r
+   ground(G),\r
+   asked(G,Ans1),!,Ans=Ans1.\r
+ask_user(G=V,_,yes) :-\r
+   ground(G),\r
+   asked(G=V1,yes),!,V=V1.\r
+\r
+ask_user(T=V,WT,Ans) :-\r
+   ground(T),var(V),!,\r
+   writel(['What is the value of ',T,'? [value,unknown,why,help]: ']),\r
+   flush_and_read(Reply),\r
+   (member(Reply,[unknown,why,help])\r
+     -> interpret_ask_answer(Reply,T=V,WT,Ans)\r
+    ;  V=Reply,\r
+       interpret_ask_answer(yes,T=V,WT,Ans)\r
+   ).\r
+ask_user(G,WT,Ans) :-\r
+   ground(G),!,\r
+   writel(['Is ',G,' true? [yes,no,unknown,why,help]: ']),\r
+   flush_and_read(Rep),\r
+   interpret_ask_answer(Rep,G,WT,Ans).\r
+  \r
+ask_user(G,WT,fail) :-\r
+   write_all(['   Error: Askables with free variables not implemented.',nl,\r
+            '   The system wanted to ask ',G,'.',nl,\r
+            '   Entering why interation.']),\r
+   mynumbervars(WT,0,_),\r
+   why_question(WT,_),\r
+   write_all(['   Askable subgoal ',G,' failing due to free variables.']).\r
+\r
+\r
+% interpret_ask_answer(Rep,G,WT,Ans).\r
+interpret_ask_answer(help,G,WT,Rep) :- !,\r
+   write_all(['   The system is asking whether ',G,' is true or not. Give one of:',nl,\r
+     '      "yes." if ',G,' is known to be true.',nl,\r
+     '      "no." if ',G,' is known to be false.',nl,\r
+     '      "unknown." if ',G,' is unknown (so applicable clauses can be used).',nl,\r
+     '      "fail." to fail the subgoal (but not record an answer).',nl,\r
+     '      "why." to see why the system was asking this question.',nl,\r
+     '      "prompt." to return to the ailog prompt.',nl,\r
+     '      "help." to print this message.']),\r
+   ask_user(G,WT,Rep).\r
+interpret_ask_answer(yes,G,_,yes) :- !,\r
+   assertz(asked(G,yes)).\r
+interpret_ask_answer(no,G,_,no) :- !,\r
+   assertz(asked(G,no)).\r
+interpret_ask_answer(unknown,G,_,unknown) :- !,\r
+   assertz(asked(G,unknown)).\r
+interpret_ask_answer(fail,_,_,fail) :- !.\r
+interpret_ask_answer(prompt,_,_,_) :- !,\r
+   throw(prompt).\r
+interpret_ask_answer(end_of_file,_,_,_) :- !,\r
+   write_all(['^D']),\r
+   throw(prompt).\r
+\r
+interpret_ask_answer(why,G,WT,Rep) :- !,\r
+   \+ \+ ( mynumbervars(WT,0,_),why_question(WT,Rep),Rep \== prompt),\r
+   ask_user(G,WT,Rep).\r
+interpret_ask_answer(Ans,G,WT,Rep) :-\r
+   Ans \== fail,\r
+   write_all(['   Unknown response "',Ans,'". For help type "help.".']),\r
+   ask_user(G,WT,Rep).\r
+\r
+\r
+% why_question(WT,Rep)\r
+%  WT is a list of wrule(Head,LeftTree,Current,RightBody)\r
+%     Rep is the reply. It is one of:\r
+%        down       go back one step\r
+%        bottom     return to the ask-the-user query\r
+%        prompt     return to prompt\r
+why_question([wrule(H,LT,C,RB)|WT],Rep) :-\r
+   write_all(['   ',C,' is used in the rule ']),\r
+   write_all(['   ',H,' <-']),\r
+   print_tree_body(LT,1,Max),\r
+   write_all(['   ** ',Max,': ',C]),\r
+   M1 is Max+1,\r
+   print_body(RB,M1,_),\r
+   writel(['   [Number,why,help,ok]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_why_ans(Comm,Max,[wrule(H,LT,C,RB)|WT],Rep).\r
+why_question([],down) :-\r
+   write_all(['   This was the original query.']).\r
+\r
+% interpret_why_ans(Comm,[wrule(H,LT,C,RB)|WT],Rep).\r
+interpret_why_ans(help,Max,[wrule(H,LT,C,RB)|WT],Rep) :- !,\r
+   write_all([\r
+'   You can taverse the proof for a subgoal using following commands:',nl,\r
+'      how i.     show how element i (i<',Max,') of the body was proved.',nl,\r
+'      how ',Max,'.     show the rule being considered for ',C,'.',nl,\r
+'      why.       show why ',H,' is being proved.',nl,\r
+'      prompt.    return to the ailog prompt.',nl,\r
+'      help.      print this message.']),\r
+   why_question([wrule(H,LT,C,RB)|WT],Rep).\r
+interpret_why_ans(up,_,WT,Rep) :- !,\r
+   interpret_why_ans(why,_,WT,Rep).\r
+interpret_why_ans(why,_,[WR|WT],Rep) :- !,\r
+   why_question(WT,Rep1),\r
+   (Rep1 = down\r
+   -> why_question([WR|WT],Rep)\r
+   ; Rep=Rep1).\r
+interpret_why_ans((how N),Max,[wrule(H,LT,C,RB)|WT],Rep) :-\r
+   integer(N),!,\r
+   interpret_why_ans(N,Max,[wrule(H,LT,C,RB)|WT],Rep).\r
+interpret_why_ans(N,Max,[wrule(H,LT,C,RB)|WT],Rep) :-\r
+   integer(N),\r
+   N > 0,\r
+   N < Max, !,\r
+   nth(LT,1,_,N,E),\r
+   traverse(E,Rep1),\r
+   (Rep1=up -> why_question([wrule(H,LT,C,RB)|WT],Rep) ;\r
+    Rep1=top -> Rep=bottom ;\r
+    Rep1=retry\r
+     -> write_all(['   retry doesn''t make sense here.']),\r
+        why_question([wrule(H,LT,C,RB)|WT],Rep) ;\r
+    Rep=Rep1).\r
+interpret_why_ans(Max,Max,_,down) :- !.\r
+interpret_why_ans(N,Max,WT,Rep) :-\r
+   integer(N),\r
+   N > Max, !,\r
+   write_all(['You can''t trace this, as it hasn''t been proved.']),\r
+   why_question(WT,Rep).\r
+interpret_why_ans(end_of_file,_,_,_) :- !,\r
+   write_all(['^D']),\r
+   throw(prompt).\r
+interpret_why_ans(prompt,_,_,_) :- !,\r
+   throw(prompt).\r
+interpret_why_ans(ok,_,_,bottom) :- !.\r
+\r
+interpret_why_ans(Comm,_,WT,Rep) :- !,\r
+   write_all(['Unknown command: ',Comm,'. Type "help." for help.']),\r
+   why_question(WT,Rep).\r
+\r
+\r
+% print_body(B,N) is true if B is a body to be printed and N is the \r
+% count of atoms before B was called.\r
+print_body(true,N,N) :- !.\r
+print_body((A&B),N0,N2) :- !,\r
+   print_body(A,N0,N1),\r
+   print_body(B,N1,N2).\r
+print_body(H,N,N1) :-\r
+   write_all(['      ',N,': ',H]),\r
+   N1 is N+1.\r
+\r
+\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            NEGATION AS FAILURE\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% failtoprove(G,N,T,WT,A0,A1)  \r
+% G is a ground goal, \r
+% N is a depth-bound\r
+% T is the tree returned\r
+% WT is the why tree\r
+% A0 is the assumables before and A1 is the set after\r
+% The complication here is due to the interaction with the depth-bound\r
+% and assumables\r
+\r
+failtoprove(G,N,nafproof(PA1,ETs),WT,ass(A,PAs,Pr),ass(A,PA1,Pr1)) :-\r
+    failed(HowFailedInit),\r
+    retractall(failed(_)),\r
+    assert(failed(naturally)),\r
+    findall(et(Ass,T),solve(G,N,T,~WT,ass(A,PAs,Pr),Ass),ETs),\r
+    (failed(naturally) ->\r
+       extract_expls(ETs,EGs),\r
+       duals(EGs,PAs,[PAs],Ds),\r
+       member(PA1,Ds),\r
+       prob(PA1,1,Pr1)\r
+    ;\r
+    member(et(ass(A,PAs,Pr),_),ETs) ->  % found a proof with no assumptions \r
+       retractall(failed(_)),\r
+       assert(failed(HowFailedInit)),\r
+       fail                    % fail naturally\r
+    ;\r
+       fail  % fail unnaturally as depth-bound was hit\r
+    ).\r
+\r
+/* interaction with depth-bound\r
+    (failed(naturally) ->\r
+       (solve(G,N,_,WT,[],_) ->\r
+         retract(failed(unnaturally)), asserta(failed(naturally)),fail\r
+              % note this just fails if failed(naturally) still true\r
+       ; failed(naturally)\r
+       )\r
+    ;  retract(failed(_)),\r
+       assert(failed(naturally)),\r
+       (solve(G,N,_,WT,[],_) ->\r
+         retract(failed(naturally)), asserta(failed(unnaturally)),fail\r
+       ; retract(failed(naturally)), asserta(failed(unnaturally))\r
+              % note this just fails if failed(unnaturally) still true\r
+       )).\r
+*/\r
+\r
+\r
+% prob(AL,P0,P1) \r
+%  AL is a list of probabilistic assumables\r
+%  P1 = P0*P(AL)\r
+prob([],P,P).\r
+prob([H|T],P0,P2) :-\r
+   choice(H,P,_),\r
+   P1 is P0*P,\r
+   prob(T,P1,P2).\r
+\r
+\r
+% The following code gives the interaction between negation and probabilities\r
+\r
+% A composite choice is a consistent set of probabilistic assumables.\r
+\r
+% duals(Es,R0,D0,D1) is true if Es is a list of terms of the form\r
+% ass(A,PAs,Pr) where R0 is a subset of PAs, and \r
+% D1-D0 is a list of ass(A1,R1,P1) such that\r
+% R1-R0 is a hitting set of negations of Es.\r
+\r
+duals([],_,D,D).\r
+duals([S|L],R0,D0,D2) :- !,\r
+   setDiff(S,R0,NA),\r
+   hit_every_complement(NA,D0,[],D1),\r
+   duals(L,R0,D1,D2).\r
+\r
+% hit_every_complement(S,R0,D0,D,D1) is true if S is a composite choice (with\r
+% tail R0), and D2 is D together with the hitting set of negations of\r
+% D0.\r
+\r
+hit_every_complement([],_,D0,D0) :- !.\r
+hit_every_complement([A|R],Ds,D0,D2) :-\r
+   choice(A,_,NAs),\r
+   hit_every_element(NAs,Ds,D0,D1),\r
+   hit_every_complement(R,Ds,D1,D2).\r
+\r
+% hit_every_element(As,A,D0,D1) is true if S is a composite choice (with\r
+% tail R0), and D2 is D together with the hitting set of negations of\r
+% D0.\r
+\r
+hit_every_element([],_,D,D).\r
+hit_every_element([E|T],Es,D0,D2) :-\r
+   insert_into_each_exp(Es,E,D0,D1),\r
+   hit_every_element(T,Es,D1,D2).\r
+\r
+% insert_into_each_exp(L,A,L0,L1) is true if inserting atomic choice A\r
+% into each explanation in L, and adding these to L0 produces L1. L,\r
+% L0 and L1 are all lists of explanations. Subsumed and inconsistent\r
+% explanations are removed. \r
+\r
+insert_into_each_exp([],_,L,L) :-!.\r
+insert_into_each_exp([E1|R],A,L0,L1) :-\r
+   incompatible(A,E1),!,\r
+   insert_into_each_exp(R,A,L0,L1).\r
+insert_into_each_exp([E1|R],A,L0,L2) :-\r
+   insert_into_sorted_list(A,E1,E2),\r
+   insert_exp(E2,L0,L1),\r
+   insert_into_each_exp(R,A,L1,L2).\r
+\r
+% insert_exp(E,Es1,Es2) is true if inserting explanation E into list\r
+% Es1 of explanations produces list of explanations Es2.\r
+insert_exp(E,[],[E]) :- !.\r
+insert_exp(E0,[E|T],[E|T]) :- \r
+    subset_sorted(E,E0),!.  % includes the case where E0==E.\r
+insert_exp(E0,[E|T],R) :-\r
+    subset_sorted(E0,E),!,\r
+    insert_exp(E0,T,R).\r
+insert_exp(E,[H|T],[H|R]) :-\r
+    insert_exp(E,T,R).\r
+\r
+% mutually_incompatible(As1,As2) is true if A is inconsistent with all of As.\r
+mutually_incompatible(E1,E2) :-\r
+   member(A,E1),\r
+   incompatible(A,E2).\r
+\r
+% incompatible(A,As) is true if A is inconsistent with all of As.\r
+incompatible(A,E) :-\r
+   choice(A,_,NAs),\r
+   \+ consistent(E,NAs).\r
\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            Probabilities\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% normalize(L,Sum,LS)  Sum is assumed to be a float.\r
+normalise([],_,[]).\r
+normalise([(A:P)|R],S,[(A:PN)|RN]) :-\r
+       PN is P/S,\r
+       normalise(R,S,RN).\r
+         \r
+% make_choices(L)\r
+make_choices(L) :-\r
+    remove(A:P,L,L0),\r
+    setof(AA,P1^member(AA:P1,L0),Alts),\r
+    assertz(choice(A,P,Alts)),\r
+    fail.\r
+make_choices(_).\r
+\r
+% insertUpdateProbs(PAs0,P0,G,P,PAs1,P1)\r
+%   PAs0 is the initial probabilistic assumptions\r
+%   P0 is the probability of the probablistic assumptions\r
+%   G is the choice\r
+%   P is the probability of G\r
+%   PAs1 is the resulting probabilistic assumptions\r
+%   P1 is the resulting probability\r
+insertUpdateProbs([],P0,G,P,[G],P1) :-\r
+   P1 is P0*P.\r
+insertUpdateProbs([G|R],P0,G,_,[G|R],P0) :- !.\r
+insertUpdateProbs([G0|R0],P0,G,P,[G,G0|R0],P1) :-\r
+   G @< G0, !,\r
+   P1 is P0*P.\r
+insertUpdateProbs([G0|R0],P0,G,P,[G0|PAs1],P1) :-\r
+   insertUpdateProbs(R0,P0,G,P,PAs1,P1).\r
+\r
+% latest_explanations(Obervations,ETs,Prob,Err)\r
+%    ETs is a list of et(Explanation,ProofTree)\r
+latest_explanations(O,E,P,Err) :-\r
+   explanations(O,E,P,Err),!.\r
+latest_explanations([],[et(ass([],[],1),null)],1,0.0).\r
+\r
+% predict(G)\r
+%    Warning: this may not work properly with multiple answers + errors\r
+%    We should really reset the pruned_prob for each proof...\r
+predict(G) :-\r
+   latest_explanations(_,ETs,Pr0,Err0),\r
+   retractall(pruned_prob(_)),\r
+   assert(pruned_prob(Err0)),\r
+   depth_bound(DB),\r
+   retractall(failed(_)),\r
+   assert(failed(naturally)),\r
+   reset_runtime,\r
+   find_expls(G,ETs,DB,Expls),\r
+   extract_expls(Expls,Sexpls),\r
+   make_disjoint(Sexpls,DExpls),\r
+   acc_probs(DExpls,0,Pr),\r
+   pruned_prob(Err1),\r
+   report_expls(Expls,DExpls,G,Pr0,Pr,Err0,Err1).\r
+predict(_) :-\r
+    write_all(['No (more) answers.']).\r
+\r
+% observe(G)\r
+observe(G) :-\r
+   retractall(debugging_failure),\r
+   retractall(failed(_)),\r
+   assert(failed(naturally)),\r
+   latest_explanations(Obs,ETs,PrObs,Err0),\r
+   retractall(pruned_prob(_)),\r
+   assert(pruned_prob(Err0)),\r
+   depth_bound(DB),\r
+   reset_runtime,\r
+   find_expls(G,ETs,DB,Expls),\r
+   extract_expls(Expls,Sexpls),\r
+   make_disjoint(Sexpls,DExpls),\r
+   acc_probs(DExpls,0,Pnew),\r
+   pruned_prob(Err1),\r
+   asserta(explanations([G|Obs],Expls,Pnew,Err1)),\r
+   report_expls(Expls,DExpls,G,PrObs,Pnew,Err0,Err1).\r
+observe(_) :-\r
+    write_all(['No (more) answers.']).\r
+\r
+% find_expls(G,ETs,DB,Expls)\r
+%   +G is the goal to be solved\r
+%   +ETs is the list of explanations of previous observations\r
+%   +DB is the depth-bound\r
+%   -Expls is the list of explanations of G and the previous observations\r
+find_expls(G,ETs,DB,Expls) :-\r
+   bagof(et(Expl,Res),\r
+         E0^Tr^( member(et(E0,Tr),ETs),\r
+                 solve(G,DB,Res,[wrule(yes,true,G,true)],E0,Expl)), \r
+         Expls),\r
+   (ground(Expls) ->\r
+    true\r
+   ; write_all(['Warning Explanations not ground: ',Expls])).\r
+\r
+% report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1)\r
+%    +Ets is a list of et(Explanation,ProofTree)\r
+%    +DExpls is a set of possible worlds (disjoint explanations)\r
+%    +G is the goal\r
+%    +Pr0 is the probability of the previous observations\r
+%    +Pr1 is the probability of the current observations\r
+%    +Err0 is the error (pruned probability mass) before the query\r
+%    +Err1 is the error (pruned probability mass) after the query  Err1>Err0\r
+report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :-\r
+   (Err1=:=0.0\r
+   ->\r
+    Post is Pr1/Pr0\r
+   ;\r
+    Min is Pr1/(Pr0+Err0),\r
+    Max is (Pr1+Err1)/(Pr0+Err0),\r
+    Post=[Min,Max]\r
+   ),\r
+   write_all(['Answer: P(',G,'|Obs)=',Post,'.']),\r
+   report_runtime,\r
+   writel(['  [ok,more,explanations,worlds,help]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_prob_report(Comm,Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+\r
+% acc_probs(Expls,P0,P1) determines the probabilities of the assumables in Expls\r
+%    +Expls is a list of explanations\r
+%    +P0 is the previous probability\r
+%    -P1 is the new probability\r
+acc_probs([],P,P).\r
+acc_probs([A|R],P0,P2) :-\r
+    prob_expl(A,1,P),\r
+    P1 is P+P0,\r
+    acc_probs(R,P1,P2).\r
+\r
+% probs_expl(Expl,P0,P1) determines the probability of an expanation\r
+%   +Expl is an explanation\r
+%   +P0 is the previous probability\r
+%   -P1 is the resulting probability  (P1 = P0*prob(Expl))\r
+prob_expl([],P,P).\r
+prob_expl([A|R],P0,P2) :-\r
+    choice(A,P,_),\r
+    P1 is P*P0,\r
+    prob_expl(R,P1,P2).\r
+\r
+% interpret_prob_report(Comm,Expls,DExpls,G,Pr0,Pr1,Err0,Err1)\r
+%   +Comm is the command given by the user\r
+%   +Expls is the set of explanations\r
+%   +DExpls is the set of worlds (disjoint explanations)\r
+%   +G is the goal to be proved\r
+%   +Pr0 is the  probability of the previous observations\r
+%   +Pr1 is the probability of the current observations\r
+interpret_prob_report(ok,_,_,_,_,_,_,_) :- !.\r
+interpret_prob_report(more,_,_,_,_,_,_,_) :- !,\r
+   reset_runtime,fail.\r
+interpret_prob_report(end_of_file,_,_,_,_,_,_,_) :- !,\r
+   write_all(['^D']).\r
+interpret_prob_report(explanations,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :- !,\r
+   show_explanations(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+interpret_prob_report(worlds,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :- !,\r
+   print_worlds(DExpls,0),\r
+   report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+interpret_prob_report(help,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :- !,\r
+   write_all([\r
+     '  The system has proven an instance of your query.',nl,\r
+     '  You can give the following commands:',nl,\r
+     '    more.    for more answers',nl,\r
+     '    ok.      for no more answers',nl,\r
+     '    explanations.     to explore how the goal is proved based ',\r
+     ' sets of assumptions.',nl,\r
+     '    worlds.  to see the worlds where ',G,' is true.']),\r
+   report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+interpret_prob_report(Comm,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :-\r
+   Comm \== more,\r
+   write_all(['Unknown command; ',Comm,'. Type "help." if you need help.']),\r
+   report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+\r
+% show_explanations(Expls,DExpls,G,Pr0,Pr1,Err0,Err1)\r
+show_explanations(Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :-\r
+   print_explanations(Expls,0),\r
+   writel(['  [ok,more,how i,help]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_show_explanations_report(Comm,Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+\r
+% interpret_show_explanations_report(Comm,Expls,DExpls,G,Pr0,Pr1,Err0,Err1)\r
+interpret_show_explanations_report(ok,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :- !,\r
+    report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+interpret_show_explanations_report(more,_,_,_,_,_,_,_) :- !,\r
+   reset_runtime,fail.\r
+interpret_show_explanations_report(how I,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :-\r
+   catch(\r
+     (\r
+        ith(Expls,et(_,Tree),I,0),\r
+       traverse(Tree,_)  % Report is ignored\r
+     ),\r
+     Ex,\r
+     (Ex= outofrange ->\r
+         write_all(['Number out of range: how ',I,'.'])\r
+     ;   write_all(['Argument to how must be an integer: how ',I,'.']) \r
+     )\r
+    ),\r
+    report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+interpret_show_explanations_report(help,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :- !,\r
+    write_all([\r
+          'ok.      go back to answer dialogue',nl,\r
+          'more.    get another answer.',nl,\r
+          'how i.   ask how the ith explanation was proved',nl,\r
+          'help.    print this message']),\r
+    report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+interpret_show_explanations_report(Comm,Expls,DExpls,G,Pr0,Pr1,Err0,Err1) :- !,\r
+    write_all([\r
+          'Unknown command: ',Comm,'. Type "help." for help']),\r
+    report_expls(Expls,DExpls,G,Pr0,Pr1,Err0,Err1).\r
+\r
+% print_explanations(DExpls,Count).\r
+print_explanations([],_).\r
+print_explanations([et(W,_)|R],C) :-\r
+   write_all(['  ',C,': ', W]),\r
+   C1 is C+1,\r
+   print_explanations(R,C1).\r
+\r
+% print_worlds(DExpls,Count).\r
+print_worlds([],_).\r
+print_worlds([W|R],C) :-\r
+   prob_expl(W,1,Pr),\r
+   write_all(['  ',C,': ', W,'  Prob=',Pr]),\r
+   C1 is C+1,\r
+   print_worlds(R,C1).\r
+\r
+% print_observations(Obs,N)\r
+print_observations([],0).\r
+print_observations([O|Os],N1) :-\r
+    print_observations(Os,N),\r
+    N1 is N+1,\r
+    write_all([N1,': ',O]).\r
+\r
+\r
+% extract_expls(L1,L2) L1 is a list of et(ass(_,E,_),_) and L2 is the\r
+% corresponding list of explanations E. \r
+extract_expls([],[]).\r
+extract_expls([et(ass(_,E,_),_)|L],R1) :-\r
+    extract_expls(L,R),\r
+    insert_exp(E,R,R1).\r
+\r
+% make_disjoint(L,SL) is true if L is a list of explanations and SL\r
+% is a lists of Expl such that SL are mutually exclusive and cover\r
+% the same worlds as the Expls in L.\r
+% This assumes that L is a minimal set: no member of L is a subset of another.\r
+\r
+make_disjoint([],[]).\r
+make_disjoint([R|L],L2) :-\r
+        % check_sorted(R),\r
+   member(R1,L),\r
+        % check_sorted(R1),\r
+   \+ mutually_incompatible(R,R1),!,\r
+    (member(E,R1), \+ idmember(E,R)   %%% was \+ member(E,R)\r
+      -> true; write_all(['Error in make_disjoint: ',compatible(R,R1)]),fail),\r
+   choice(E,_,NE),\r
+   split([E|NE],R,L,L1),\r
+   make_disjoint(L1,L2).\r
+make_disjoint([E|L1],[E|L2]) :-\r
+   make_disjoint(L1,L2).\r
+\r
+% split(As,R,L0,L1) splits R on As, added to L0 produces L1\r
+split([],_,L,L).\r
+split([A|As],E,L0,L2) :-\r
+   insert_into_sorted_list(A,E,E1),\r
+   insert_exp(E1,L0,L1),\r
+   split(As,E,L1,L2).\r
+\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            HOW QUESTIONS\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% traverse(T,Rep) true if \r
+%   T is a tree being traversed\r
+%   Rep is the reply it is one of {up,top,retry,prompt}\r
+%     up means go up in the tree \r
+%     top means go to the top of the tree (where traverse was called).\r
+%     retry means find another proof tree\r
+%     prompt means go to the top level prompt\r
+traverse((A&B),Rep) :-\r
+   traverse(if(yes,(A&B)),Rep).\r
+traverse(if(H,true),up) :- !,\r
+    write_all(['   ',H,' is a fact']).\r
+traverse(if(H,builtin),up) :- !,\r
+    write_all(['   ',H,' is built-in.']).\r
+traverse(if(H,asked),up) :- !,\r
+    write_all(['   You told me ',H,' is true.']).\r
+traverse(if(H,assumed),up) :- !,\r
+    write_all(['   ',H,' is assumed.']).\r
+traverse(if(~G,nafproof(_,[])),Rep) :- !,\r
+   write_all(['   ',G,' finitely failed. You can examine the search space.']),\r
+   depth_bound(DB),\r
+   whynotb(G,DB,Rep,ass([],[],1),_).\r
+traverse(if(~G,nafproof(Expl,ETs)),Rep) :- !,\r
+   write_all(['   ',~G,' succeeded assuming ',Expl]),\r
+   write_all(['   ',G,' succeeded with the following explanations:']),\r
+   print_explanations(ETs,0),\r
+   writel(['  [up,top,retry,prompt,how i,help,whynot]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_naf_how(Comm,ETs,Rep0),\r
+   (Rep0=repeat ->\r
+       traverse(if(~G,nafproof(Expl,ETs)),Rep)\r
+   ; Rep=Rep0\r
+   ).\r
+traverse(null,top) :- !,\r
+   write_all(['   There was nothing to be proved.']).\r
+traverse(if(H,B),Rep) :-\r
+    write_all(['   ',H,' <-']),\r
+    print_tree_body(B,1,Max),\r
+    writel(['   How? [Number,up,retry,ok,prompt,help]: ']),\r
+    flush_and_read(Comm),\r
+    interpretcommand(Comm,B,Max,if(H,B),Rep).\r
+\r
+% print_tree_body(B,N) is true if B is a body to be printed and N is the \r
+% count of atoms before B was called.\r
+print_tree_body(true,N,N).\r
+print_tree_body((A&B),N0,N2) :-\r
+   print_tree_body(A,N0,N1),\r
+   print_tree_body(B,N1,N2).\r
+print_tree_body(if(H,_),N,N1) :-\r
+   write_all(['      ',N,': ',H]),\r
+   N1 is N+1.\r
+\r
+% interpretcommand(Comm,B,Max,Goal,Reply) interprets the command Comm on body B\r
+interpretcommand(help,_,Max,G,Rep) :- !,\r
+   write_all([\r
+     '     Give either (end each command with a period):',nl,\r
+     '       how i.       explain how subgoal i (i<',Max,') was proved.',nl,\r
+     '       up.          go up the proof tree one level.',nl,\r
+     '       retry.       find another proof.',nl,\r
+     '       ok.          stop traversing the proof tree.',nl,\r
+     '       prompt.      return to the ailog prompt.',nl,\r
+     '       help.        to print this message.']),\r
+   traverse(G,Rep).\r
+interpretcommand((how N),B,Max,G,Rep) :-\r
+   integer(N),\r
+   interpretcommand(N,B,Max,G,Rep).\r
+interpretcommand(N,B,Max,G,Rep) :-\r
+   integer(N),\r
+   N > 0,\r
+   N < Max,!,\r
+   nth(B,1,_,N,E),\r
+   traverse(E,Rep1),\r
+   ( Rep1= up\r
+   -> traverse(G,Rep)\r
+   ; Rep=Rep1\r
+   ).\r
+interpretcommand(N,_,Max,G,Rep) :-\r
+   integer(N),!,\r
+   % (N < 1 ; N >= Max,Rep),\r
+   M1 is Max-1,\r
+   write_all(['Number out of range: ',N,'. Use number in range: [1,',M1,'].']),\r
+   traverse(G,Rep).\r
+interpretcommand(up,_,_,_,up) :-!.\r
+interpretcommand(why,_,_,_,up) :-!.\r
+interpretcommand(ok,_,_,_,top) :-!.\r
+interpretcommand(prompt,_,_,_,_) :-!,\r
+   throw(prompt).\r
+interpretcommand(retry,_,_,_,retry) :-!.\r
+interpretcommand(end_of_file,_,_,_,prompt) :-!,\r
+   write_all(['^D']).\r
+interpretcommand(C,_,_,G,Rep) :-\r
+   write_all(['Illegal Command: ',C,'   Type "help." for help.']),\r
+   traverse(G,Rep).\r
+\r
+% nth(S,N0,N1,N,E) is true if E is the N-th element of structure S\r
+nth((A&B),N0,N2,N,E) :- !,\r
+   nth(A,N0,N1,N,E),\r
+   nth(B,N1,N2,N,E).\r
+nth(true,N0,N0,_,_) :- !.\r
+nth(A,N,N1,N,A) :- !,\r
+   N1 is N+1.\r
+nth(_,N0,N1,_,_) :-\r
+   N1 is N0+1.\r
+\r
+% interpret_naf_how(Comm,ETs,Report)\r
+%  Report is either up, or repeat or whatever travese can report\r
+interpret_naf_how(ok,_,up).\r
+interpret_naf_how(more,_,_) :- !,\r
+   reset_runtime,fail.\r
+interpret_naf_how(how I,Expls,Report) :-\r
+   catch(\r
+     (\r
+        ith(Expls,et(_,Tree),I,0),\r
+       traverse(Tree,Report)\r
+     ),\r
+     Ex,\r
+     ((Ex= outofrange ->\r
+         write_all(['Number out of range: how ',I,'.'])\r
+     ;   write_all(['Argument to how must be an integer: how ',I,'.']) \r
+     ),\r
+        Report=repeat)\r
+    ).\r
+interpret_naf_how(help,_,repeat) :- !,\r
+    write_all([\r
+          'ok.      go back to answer dialogue',nl,\r
+          'more.    get another answer.',nl,\r
+          'how i.   ask how the ith explanation was proved',nl,\r
+          'help.    print this message']).\r
+interpret_naf_how(Comm,_,repeat) :- !,\r
+    write_all([\r
+          'Unknown command: ',Comm,'. Type "help." for help']).\r
+\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            WHY NOT QUESTIONS for FAILING QUERIES\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% determine why an answer to body Q was not found.\r
+% whynotb(+Q,+DB,-Rep,+Ass0,-Ass1) determine why body Q, with depth-bound DB\r
+% and Ass0 did not find an expected answer\r
+%   Rep is the reply it is one of {up,top,retry,prompt}\r
+%     up means go up in the tree \r
+%     top means go to the top of the tree (where traverse was called).\r
+%     retry means find another proof tree\r
+%     prompt means go to the top level prompt\r
+\r
+whynotb((A & B),DB,Rep,Ass0,Ass2) :- \r
+   retractall(failed(_)),\r
+   assert(failed(naturally)),\r
+   solve(A,DB,Res,[whynot],Ass0,Ass1),\r
+   report_whynot_conj(A,Res,B,DB,Rep,Ass0,Ass1,Ass2).\r
+whynotb((A & _),DB,Rep,Ass0,Ass1) :- !,\r
+   whynotb(A,DB,Rep,Ass0,Ass1).\r
+\r
+whynotb(call(A),DB,Rep,Ass0,Ass1) :- !,\r
+   whynotb(A,DB,Rep,Ass0,Ass1).\r
+\r
+whynotb((~ A),DB,Rep,Ass0,Ass1) :-\r
+   ground(A), !,\r
+   retractall(failed(_)),\r
+   assert(failed(naturally)),\r
+   findall(et(Ass,T),solve(A,DB,T,[whynot],Ass0,Ass),ETs),\r
+   (\r
+     member(et(Ass0,T),ETs)\r
+   ->    % found a proof with no assumables\r
+     write_all(['    ',~A,' failed as ',A,' suceeded. Here is how:']),\r
+     traverse(T,Rep)\r
+   ; (ETs=[], failed(naturally)) ->\r
+     write_all(['    ',~A,' succeeds, as ',A,' finitely fails.']),\r
+     whynotb(A,DB,Rep,Ass0,_),\r
+     Ass1=Ass0\r
+   ; failed(unnaturally) ->\r
+     write_all(['    ',~A,' failed because of the depth-bound.']),\r
+     whynotb(A,DB,Rep,Ass0,_)\r
+   ;\r
+     whynotb_expls(A,ETs,Rep)\r
+   ).\r
+\r
+\r
+whynotb((~ A),_,up,Ass0,Ass0) :- !,\r
+   write_all(['   Error: ',~A,' needs to be ground when called.']).\r
+\r
+whynotb(A,_,up,Ass0,Ass0) :-\r
+   builtin(A,C),!,\r
+   (call(C)\r
+    -> (call(A)\r
+        -> write_all(['   ',A,' is built-in and succeeds.'])\r
+         ; write_all(['   ',A,' is built-in and fails.']))\r
+    ; write_all(['   ',A,' is built-in and is insufficiently instanciated.'])).\r
+\r
+whynotb((A \= B),_,up,Ass0,Ass0) :-\r
+   ?=(A,B),!,\r
+   (A \== B\r
+   -> write_all(['   ',(A \= B),' succeeds as they can never unify.'])\r
+   ; write_all(['   ',(A \= B),' fails as they are identical.'])).\r
+whynotb((A \= B),_,up,Ass0,Ass0) :-\r
+   write_all(['   ',(A \= B),' cannot be resolved. It is delayed.']),\r
+   when(?=(A,B),\r
+     (A \== B\r
+      -> write_all(['   Resolving delayed ',(A \= B),'. It succeeded.'])\r
+      ; write_all(['   Failure due to delayed constraint, ',(A \= B),'.']),\r
+        fail)).\r
+whynotb((A #= B),_,up,Ass0,Ass0) :-\r
+   (\+(A = B)\r
+   -> write_all(['   ',(A #= B),' succeeds as they can never unify.'])\r
+   ; write_all(['   ',(A #= B),' fails as they can unify.'])).\r
+\r
+\r
+whynotb(Q,_,up,ass(A0,PAs,P),ass(A1,PAs,P)) :-\r
+    assumabl(Q),!,\r
+    (idmember(Q,A0)\r
+     ->\r
+     write_all(['   ',Q,' has already been assumed. It succeeds.']),\r
+     A1=A0\r
+     ;\r
+     good(Q,A0)\r
+    ->\r
+     write_all(['   ',Q,' is consistently assumed.']),\r
+    A1=[Q|A0]\r
+    ;\r
+      write_all(['   ',Q,' is inconsistent with other assumables.']),\r
+     A1=A0\r
+    ).\r
+\r
+whynotb(Q,_,up,ass(A0,PAs0,P0),ass(A0,PAs1,P1)) :-\r
+   choice(Q,P,A),!,\r
+%    (ground(Q) -> true\r
+%    ; write_all(['   Error: assumable ',Q,' needs to be ground when called.'])),\r
+   (consistent(PAs0,A)\r
+   ->\r
+    insertUpdateProbs(PAs0,P0,Q,P,PAs1,P1),\r
+    prob_threshold(Bound),\r
+    ((P1 < Bound)\r
+    ->\r
+     retract(pruned_prob(PP)),\r
+     PP1 is PP+P1,\r
+     asserta(pruned_prob(PP1)),\r
+     write_all(['   ',Q,' fails as the probability (',P1,') is too small'])\r
+    ;\r
+     write_all(['   ',Q,' suceeds as it can be assumed'])\r
+    )\r
+   ;\r
+    write_all(['   ',Q,' fails as it is inconsistent with other assumpions'])\r
+   \r
+   ).\r
+\r
+whynotb(G=V,_,up,ass(A0,PAs,P),ass(A1,PAs,P)) :-\r
+    arbit(G,V),!,\r
+   (member((G=V1),A0)\r
+   ->\r
+    (V=V1 ->\r
+      write_all(['   ',G=V,' is has already been assumed.'])\r
+    ; write_all(['   arbitrary ',G,' has value ',V1,', so ',G=V,' fails.'])\r
+     ),\r
+    A1=A0\r
+   ;\r
+    write_all(['   ',G=V,' is consistently assumed.']),\r
+    A1=[G=V|A0]\r
+   ).\r
+\r
+\r
+whynotb(Q,0,up,Ass0,Ass0) :- !,\r
+   write_all(['   ',Q,' fails because of the depth-bound.']).\r
+\r
+% whynotb(Q,DB,up,Ass0,Ass0) :-\r
+%    DB > 0,\r
+%    (Q <- true),!,\r
+%    write_all(['   ',Q,' is a fact. It doesn''t fail.']).\r
+\r
+whynotb(Q,DB,Rep,Ass0,Ass1) :-\r
+   DB > 0,\r
+   (Q <- B),\r
+   whynotrule(Q,B,DB,Rep,Ass0,Ass1).\r
+whynotb(Q,_,up,Ass0,Ass0) :-\r
+   write_all(['  There is no applicable rule for ',Q,'.']).\r
+\r
+whynotrule(Q,B,DB,Rep,Ass0,Ass1) :-\r
+   (B=true\r
+     ->\r
+    write_all(['  ',Q,'.']);\r
+    write_all(['  ',Q,' <- ',B,'.'])\r
+   ),\r
+   writel(['    Trace this rule? [yes,no,up,help]: ']),\r
+   flush_and_read(Comm),\r
+   whynotruleinterpret(Comm,Q,B,DB,Rep,Ass0,Ass1).\r
+\r
+whynotruleinterpret(yes,Q,B,DB,Rep,Ass0,Ass1) :- !,\r
+   DB1 is DB-1,\r
+   whynotb(B,DB1,Rep1,Ass0,Ass1),\r
+   (Rep1 = up\r
+   -> whynotrule(Q,B,DB,Rep,Ass0,Ass1)\r
+   ;  Rep=Rep1).\r
+whynotruleinterpret(no,_,_,_,_,_,_) :- !,\r
+   fail.\r
+whynotruleinterpret(up,_,_,_,up,Ass0,Ass0) :- !.\r
+whynotruleinterpret(end_of_file,_,_,_,prompt,_,_) :- !,\r
+   write_all(['^D']).\r
+whynotruleinterpret(ok,_,_,_,prompt,_,_) :- !.\r
+whynotruleinterpret(help,Q,B,DB,Rep,Ass0,Ass1) :- !,\r
+   write_all([\r
+     '     Do you want to examine why this rule failed?',nl,\r
+     '        yes.    look at this rule',nl,\r
+     '        no.     try another rule',nl,\r
+     '        up.     go back to the rule this rule was called from',nl,\r
+     '        ok.     go to top-level prompt']),\r
+   whynotrule(Q,B,DB,Rep,Ass0,Ass1).\r
+whynotruleinterpret(Comm,Q,B,DB,Rep,Ass0,Ass1) :-\r
+   write_all(['     Unknown command: ',Comm,'. Type "help." for help.']),\r
+   whynotrule(Q,B,DB,Rep,Ass0,Ass1).\r
+\r
+\r
+report_whynot_conj(A,Res,B,DB,Rep,Ass0,Ass1,Ass2) :-\r
+   write_all(['  The proof for ',A,' succeeded.']),\r
+   (Ass0 \== Ass1 ->\r
+        write_all(['     assuming ',Ass1])\r
+   ; true\r
+   ),\r
+   writel(['   Is this the appropriate answer? [yes,no,debug,help]: ']),\r
+   flush_and_read(Comm),\r
+   why_not_conj_interpret(Comm,A,Res,B,DB,Rep,Ass1,Ass2).\r
+\r
+why_not_conj_interpret(debug,A,Res,B,DB,Rep,Ass0,Ass1) :- !,\r
+     traverse(Res,Rep1),\r
+     (Rep1 = up\r
+     -> report_whynot_conj(A,Res,B,DB,Rep,Ass0,Ass1)\r
+     ; Rep=Rep1).\r
+why_not_conj_interpret(yes,_,_,B,DB,Rep,Ass0,Ass1) :- !,\r
+     whynotb(B,DB,Rep,Ass0,Ass1).\r
+why_not_conj_interpret(no,_,_,_,_,_,_,_) :- !,\r
+   fail.      % find another proof for A\r
+\r
+why_not_conj_interpret(end_of_file,_,_,_,_,prompt,_,_) :- !,\r
+     write_all(['^D']).\r
+why_not_conj_interpret(ok,_,_,_,_,prompt,_,_) :- !,\r
+     write_all(['^D']).\r
+why_not_conj_interpret(help,A,Res,B,DB,Rep,Ass0,Ass1) :- !,\r
+    write_all([\r
+    '     yes.        this instance should have made the body succeed.',nl,\r
+    '     no.         this instance should lead to a failure of the body.',nl,\r
+    '     debug.      this instance is false, debug it.',nl,\r
+    '     ok.         I''ve had enough. Go to the prompt.',nl,\r
+    '     help.       print this message.']),\r
+    report_whynot_conj(A,Res,B,DB,Rep,Ass0,Ass1).\r
+why_not_conj_interpret(Comm,A,Res,B,DB,Rep,Ass0,Ass1) :-\r
+    write_all([' Unknown command: ',Comm,'. Type "help." for help.']),\r
+    report_whynot_conj(A,Res,B,DB,Rep,Ass0,Ass1).\r
+\r
+whynotb_expls(A,ETs,Rep) :-\r
+     write_all(['    ',~A,' succeeds, as ',A,' has the explanations: ']),\r
+     print_explanations(ETs,0),\r
+        writel(['  [up,top,retry,prompt,how i,help,whynot]: ']),\r
+   flush_and_read(Comm),\r
+   interpret_naf_how(Comm,ETs,Rep0),\r
+   (Rep0=repeat ->\r
+       whynotb_expls(A,ETs,Rep)\r
+   ;   Rep=Rep0\r
+   ).\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            FILE INTERACTION\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+flush_and_read(T) :-\r
+   flush_output,\r
+   (read(T) -> true ; flush_and_read(T)).  % reads until no error.\r
+\r
+ci_load(File) :-\r
+   current_input(OldFile),\r
+   open(File,read,Input),\r
+   set_input(Input),\r
+   flush_and_read(T),\r
+   read_all(T),\r
+   set_input(OldFile),\r
+   write_all(['AILog theory ',File,' loaded.']).\r
+\r
+read_all(C) :-\r
+   file_or_command(C,file),\r
+   flush_and_read(T2),!,\r
+   read_all(T2).\r
+\r
+read_all(end_of_file) :- !.\r
+read_all((H :- B)) :- !,\r
+   write_all(['Error: Illegal Implication: ',H,' :- ',B,'. Use <- or prload.']).\r
+read_all(T) :-\r
+   tell_clause(T),\r
+   flush_and_read(T2),!,\r
+   read_all(T2).\r
+read_all(_).\r
+\r
+prolog_load(File) :-\r
+   current_input(OldFile),\r
+   open(File,read,Input),\r
+   set_input(Input),\r
+   flush_and_read(T),\r
+   prread_all(T),\r
+   set_input(OldFile),\r
+   write_all(['AILog theory ',File,' consulted.']).\r
+\r
+\r
+prread_all(T) :-\r
+   file_or_command(T,file),\r
+   flush_and_read(T2),\r
+   prread_all(T2).\r
+prread_all(end_of_file) :- !.\r
+prread_all(T) :- \r
+   prillegal(T,Mesg),!,\r
+   write_all(Mesg).\r
+prread_all(T) :-\r
+   prtell(T),\r
+   flush_and_read(T2),\r
+   prread_all(T2).\r
+\r
+% prillegal(R,Mesg) is true if R is illegal Prolog rule. \r
+%    Mesg is the corresponding error message.\r
+prillegal((H <- B),['Error. Illegal Implication: ',H,' <- ',B,\r
+                    '. Use :- in prload.']) :- !.\r
+prillegal((:- B),['Error. Commands not allowed. ":- ',B,'."']) :- !.\r
+prillegal((_ :- B),Mesg) :- !,\r
+   prillbody(B,Mesg).\r
+prillbody((A,_),Mesg) :-\r
+   prillbody(A,Mesg).\r
+prillbody((_,B),Mesg) :-\r
+   prillbody(B,Mesg).\r
+prillbody((_;_),['Prolog rules assume disjunction ";". Define it before loading.']) :-\r
+   \+ ((_;_) <- _).\r
+prillbody((A;_),Mesg) :-\r
+   prillbody(A,Mesg).\r
+prillbody((_;B),Mesg) :-\r
+   prillbody(B,Mesg).\r
+prillbody((_&_),['Error. Illegal conjunction in Prolog rules: &']):- !.\r
+prillbody(!,['Error. Cut (!) not allowed.']) :- !.\r
+prillbody((_ -> _ ; _),['Error. "->" is not implemented.']) :- !.\r
+prillbody((_ -> _ ),['Error. "->" is not implemented.']) :- !.\r
+\r
+% prtell(Cl) tells the prolog clause Cl\r
+prtell((H :- B)) :- !,\r
+   convert_body(B,B1),\r
+   assertz((H <- B1)).\r
+prtell(H) :-\r
+   assertz((H <- true)).\r
+\r
+% convert_body(PB,CB) converts Prolog body PB to ailog body CB\r
+convert_body((A,B),(A1&B1)) :- !,\r
+   convert_body(A,A1),\r
+   convert_body(B,B1).\r
+convert_body((A;B),(A1;B1)) :- !,\r
+   convert_body(A,A1),\r
+   convert_body(B,B1).\r
+convert_body((\+ A),(~ A1)) :- !,\r
+   convert_body(A,A1).\r
+convert_body(A,A).\r
+\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            MAIN LOOP\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+start :-\r
+   ailog_version(V,Y),\r
+   write_all([nl,\r
+     'AILog Version ',V,'. Copyright ',Y,', David Poole.',nl,\r
+     'AILog comes with absolutely no warranty.',nl,\r
+     'All inputs end with a period. Type "help." for help.']),\r
+   start1.\r
+\r
+start1 :-\r
+   catch(go,Exc,handle_exception(Exc)). \r
+\r
+go :-\r
+   writel(['ailog: ']), \r
+   flush_and_read(T),\r
+   (T == prolog ->\r
+        write_all(['Returning to Prolog. Type "start." to start ailog.'])\r
+   ; T == end_of_file ->\r
+        write_all(['^D']),\r
+        write_all(['Returning to Prolog. Type "start." to start ailog.'])\r
+   ; interpret(T),\r
+     !,\r
+     go).\r
+\r
+handle_exception(prompt) :- !, start1.\r
+handle_exception(quit) :- halt.\r
+handle_exception(Exc) :-\r
+   write_all(['Error: ',Exc]),\r
+   start1.\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            CHECKING the KB\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% check searches through the knowledge base looking for a rule\r
+% containing an atom in the body which doesn't have a corresponding\r
+% definition (i.e., a clause with it at the head).\r
+check :-\r
+   (H <- B),\r
+   body_elt_undefined(B,H,B).\r
+check.\r
+\r
+check :-\r
+   (H <- _),\r
+   choice(H,_,_),\r
+   write_all([H,' should not be defined in a rule and as a probability.']),\r
+   fail.\r
+\r
+body_elt_undefined(true,_,_) :- !,fail.\r
+body_elt_undefined((A&_),H,B) :-\r
+   body_elt_undefined(A,H,B).\r
+body_elt_undefined((_&A),H,B) :- !,\r
+   body_elt_undefined(A,H,B).\r
+body_elt_undefined((~ A),H,B) :- !,\r
+   body_elt_undefined(A,H,B).\r
+body_elt_undefined((A;_),H,B) :-\r
+   body_elt_undefined(A,H,B).\r
+body_elt_undefined((_;A),H,B) :- !,\r
+   body_elt_undefined(A,H,B).\r
+body_elt_undefined(call(A),H,B) :- !,\r
+   body_elt_undefined(A,H,B).\r
+body_elt_undefined(_ \= _,_,_) :- !,fail.\r
+body_elt_undefined(_ #= _,_,_) :- !,fail.\r
+body_elt_undefined(A,_,_) :-\r
+   askabl(A),!,fail.\r
+body_elt_undefined(A,_,_) :-\r
+   assumabl(A),!,fail.\r
+body_elt_undefined(A,_,_) :-\r
+   choice(A,_,_),!,fail.\r
+body_elt_undefined(X=V,_,_) :-\r
+   arbit(X,V),!,fail.\r
+body_elt_undefined(A,_,_) :-\r
+   builtin(A,_),!,fail.\r
+body_elt_undefined(A,_,_) :-\r
+   (A <- _),!,fail.\r
+body_elt_undefined(A,H,B) :-\r
+   write_all(['Warning: no clauses for ',A,' in rule ',(H <- B),'.']),!,fail.\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            STATS\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% uncomment the next line to make runtime checking the default\r
+%checking_runtime.\r
+\r
+% stats_command(Cmd) means "stats Cmd" was given as a command.\r
+stats_command(runtime) :- !,\r
+   retractall(checking_runtime),\r
+   asserta(checking_runtime),\r
+   write_all(['Runtime report turned on. Type "stats none." to turn it off.']).\r
+stats_command(none) :- !,\r
+   retractall(checking_runtime).\r
+stats_command(_) :-\r
+   write_all(['The stats commands implemented are:']),\r
+   write_all(['    stats runtime.        turn on report of runtime.']),\r
+   write_all(['    stats none.           turn off report of runtime.']).\r
+\r
+% reset_runtime means that we are storing the current valuse of\r
+% runtime.  This means that we are leaving out much of the ailog\r
+% overhead from the calcluation.\r
+\r
+reset_runtime :-\r
+   checking_runtime,\r
+   retractall(lastruntime(_)),\r
+   get_runtime(T,_),\r
+   asserta(lastruntime(T)),!.\r
+reset_runtime :-\r
+   checking_runtime ->\r
+       write_all([' Problem with runtime checking.'])\r
+    ;  true.\r
+\r
+report_runtime :-\r
+   checking_runtime,\r
+   lastruntime(T),\r
+   get_runtime(T1,Units),\r
+   RT is T1 - T,\r
+   write_all([' Runtime since last report: ',RT,' ',Units,'.']),!.\r
+report_runtime :-\r
+   checking_runtime ->\r
+   write_all([' Problem with runtime reporting.'])\r
+    ;  true.\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            NOGOOD Handling\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+% A nogood is a set of assumables that is inconsistent\r
+construct_nogoods(DB) :-\r
+   depth_bound(DB),\r
+   retractall(failed(_)),\r
+   assert(failed(naturally)),\r
+   reset_runtime,\r
+   solve(false,DB,PfTree,[wrule(yes,true,false,true)],ass([],[],1),ass(Ass,_,_)),\r
+   assert(nogood(Ass,PfTree)),\r
+   assert_each_nogood(Ass,[]),\r
+   fail.\r
+construct_nogoods(DB) :-\r
+   failed(naturally)\r
+      -> write_all(['Nogoods recorded. Type "nogoods." to see them.'])\r
+      ;  write_all(['Nogoods recorded, but depth-bound ',DB,' reached. Type "nogoods." to see them.']).\r
+\r
+assert_each_nogood([],[]).\r
+assert_each_nogood([H|NotDone],Done) :-\r
+       append(NotDone,Done,Rest),\r
+       assert(anogood(H,Rest)),\r
+       assert_each_nogood(NotDone,[H|Done]).\r
+\r
+list_nogoods :-\r
+        nogood(NG,_),\r
+       write_all(['Nogood: ',NG,'.']), fail.\r
+list_nogoods.\r
+\r
+good(A,E) :-\r
+       \+ bad(A,E).\r
+bad(A,E) :-\r
+       ground((A,E)),\r
+       anogood(A,N),\r
+       subset(N,E).\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+%%            HELPERS\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+% write_all(L) writes each element of list L, ends with new line\r
+write_all(L) :-\r
+   \+ \+ (mynumbervars(L,0,_),writel0(L)),\r
+   nl.\r
+% writel(L) writes each element of list L\r
+writel(L) :-\r
+   \+ \+ (mynumbervars(L,0,_),writel0(L)).\r
+\r
+% writel0(L) writes each element of list L\r
+writel0([]) :- !.\r
+writel0([nl|T]) :- !,\r
+   nl,\r
+   writel0(T).\r
+writel0([H|T]) :-\r
+   mywrite(H),\r
+   writel0(T).\r
+\r
+% writeAllDelim(L,D) writes the elements of L using delimiter D\r
+writeAllDelim(L,D) :-\r
+   \+ \+ (mynumbervars(L,0,_),writeAllDelim0(L,D)).\r
+\r
+writeAllDelim0([],_) :-!.\r
+writeAllDelim0([E],_) :- !, mywrite(E).\r
+writeAllDelim0([H|T],nl) :- !, mywrite(H),nl,writeAllDelim0(T,nl).\r
+writeAllDelim0([H|T],D) :- mywrite(H),mywrite(D),writeAllDelim0(T,D).\r
+\r
+% mywrite(T) writes term T\r
+mywrite(T) :-\r
+   write_term(T,[numbervars(true),portray(true)]).\r
+\r
+portray(A&B) :- mywrite(A),mywrite(' & '),mywrite(B).\r
+\r
+% insert_into_sorted_list(E,L,R) inserts E into sorted list L producing R\r
+insert_into_sorted_list(A,[],[A]).\r
+insert_into_sorted_list(A,[A1|R],[A|R]) :- A == A1,!.\r
+insert_into_sorted_list(A,[A1|R],[A,A1|R]) :- A @< A1, !.\r
+insert_into_sorted_list(A,[B|R],[B|R1]) :-\r
+   insert_into_sorted_list(A,R,R1).\r
+\r
+% insertUpdateProbs(E,L) inserts E into sorted list L\r
+insertUpdateProbs(A,[],[A]).\r
+insertUpdateProbs(A,[A1|R],[A|R]) :- A == A1,!.\r
+insertUpdateProbs(A,[A1|R],[A,A1|R]) :- A @< A1, !.\r
+insertUpdateProbs(A,[B|R],[B|R1]) :-\r
+   insertUpdateProbs(A,R,R1).\r
+\r
+% consistent(L1,L2) is true if L1 & L2 are sorted lists with no\r
+% elements in common. \r
+consistent([],_) :- !.\r
+consistent(_,[]) :- !.\r
+consistent([A1|R1],[A2|R2]) :-\r
+   A1 @< A2, !,\r
+   consistent(R1,[A2|R2]).\r
+consistent([A1|R1],[A2|R2]) :-\r
+   A1 @> A2, !,\r
+   consistent([A1|R1],R2).\r
+\r
+% remove(E,L,L1) removes E from list L producing L1\r
+remove(E,[E|L],L).\r
+remove(E,[A|L],[A|R]) :-\r
+   remove(E,L,R).\r
+\r
+\r
+% subset_sorted(L1,L2) is true if list L1 is a subset of L2\r
+% all lists are assumed to be ground and sorted.\r
+subset_sorted([],_) :- !.\r
+subset_sorted([A|L1],[A|L2]) :- !,\r
+  subset_sorted(L1,L2).\r
+subset_sorted([A1|L1],[A2|L2]) :-\r
+  A2 @< A1,\r
+  subset_sorted([A1|L1],L2).\r
+\r
+% setDiff(S1,S2,S3) S3 = S1-S2. All lists are sorted.\r
+\r
+setDiff([],_,[]) :- !.\r
+setDiff(S,[],S) :- !.\r
+setDiff([A|L1],[A|L2],R) :- !,\r
+   setDiff(L1,L2,R).\r
+setDiff([A1|L1],[A2|L2],[A1|R]) :-\r
+   A1 @< A2, !,\r
+   setDiff(L1,[A2|L2],R).\r
+setDiff(L1,[_|L2],R) :-\r
+   setDiff(L1,L2,R).\r
+\r
+% mywhen(C,G) replaces "when". It does not delay, but instead gives an\r
+% error. This is now redundant as SWI has "when".\r
+mywhen(C,G) :-\r
+   C -> G \r
+   ;\r
+    write_all(['Warning: ',C,' failing. Delaying not implemented.']),\r
+    fail.\r
+\r
+% ith(L,E,I,I0) is true if E is the Ith element of list L, starting to\r
+% count from I0\r
+ith([],_,_,_) :-\r
+   throw(outofrange).\r
+ith([H|_],H,I,I) :- !.\r
+ith([_|T],E,I,I0) :-\r
+   I>I0, !,\r
+   I1 is I0+1,\r
+   ith(T,E,I,I1).\r
+ith(_,_,_,_) :-\r
+   throw(outofrange).\r
+\r
+idmember(A,[A1|_]) :- A==A1,!.\r
+idmember(A,[_|L]) :- idmember(A,L).\r
+\r
+mynumbervars(Term, From, To) :-\r
+       numbervars(Term, From, To, [attvar(bind)]).\r
+\r
+issorted([]).\r
+issorted([_]).\r
+issorted([E1,E2|R]) :-\r
+       E1 @< E2,\r
+       issorted([E2|R]).\r
+\r
+check_sorted(L) :-\r
+       issorted(L),!.\r
+check_sorted(L) :-\r
+       write_all(['Warning: not sorted: ',L]).\r
+\r
+% Run "start" at initialization\r
+:- initialization(start).
\ No newline at end of file
diff --git a/pl-ail-files/exercise0.pl b/pl-ail-files/exercise0.pl
new file mode 100644 (file)
index 0000000..7b5771f
--- /dev/null
@@ -0,0 +1,44 @@
+/* The facts about the Dutch Royal Family */
+
+mother(wilhelmina, juliana).
+mother(juliana, beatrix).
+mother(juliana, christina).
+mother(juliana, irene).
+mother(juliana, margriet).
+mother(beatrix, friso).
+mother(beatrix, alexander).
+mother(beatrix, constantijn).
+mother(emma, wilhelmina).
+
+father(hendrik, juliana).
+father(bernard, beatrix).
+father(bernard, christina).
+father(bernard, irene).
+father(bernard, margriet).
+father(claus, friso).
+father(claus, alexander).
+father(claus, constantijn).
+father(willem, wilhelmina).
+
+queen(beatrix).
+queen(juliana).
+queen(wilhelmina).
+queen(emma).
+king(willem).
+
+/* rules */
+
+parent(X, Y) :- mother(X, Y).
+parent(X, Y) :- father(X, Y).
+
+ruler(X) :- queen(X).
+ruler(X) :- king(X).
+
+predecessor(X, Y) :-
+   parent(X, Y),
+   ruler(X),
+   ruler(Y).
+predecessor(X, Y) :-
+   ruler(X),
+   parent(X, Z),
+   predecessor(Z, Y).
diff --git a/pl-ail-files/exercise10.ail b/pl-ail-files/exercise10.ail
new file mode 100644 (file)
index 0000000..3ad7a0c
--- /dev/null
@@ -0,0 +1,44 @@
+/* The facts about the Dutch Royal Family */
+
+mother(wilhelmina, juliana).
+mother(juliana, beatrix).
+mother(juliana, christina).
+mother(juliana, irene).
+mother(juliana, margriet).
+mother(beatrix, friso).
+mother(beatrix, alexander).
+mother(beatrix, constantijn).
+mother(emma, wilhelmina).
+father(hendrik, juliana).
+father(bernard, beatrix).
+father(bernard, christina).
+father(bernard, irene).
+father(bernard, margriet).
+father(claus, friso).
+father(claus, alexander).
+father(claus, constantijn).
+father(willem, wilhelmina).
+queen(beatrix).
+queen(juliana).
+queen(wilhelmina).
+queen(emma).
+king(willem).
+/* rules */
+
+parent(X, Y) <- mother(X, Y).
+parent(X, Y) <- father(X, Y).
+ruler(X) <- queen(X).
+ruler(X) <- king(X).
+
+predecessor(X, Y) <-
+        predecessor(Z, Y) &
+        ruler(X) &
+        parent(X, Z).
+predecessor(X, Y) <-
+       parent(X, Y) &
+        ruler(X) &
+        ruler(Y).
diff --git a/pl-ail-files/exmbr.ail b/pl-ail-files/exmbr.ail
new file mode 100644 (file)
index 0000000..7ea73b4
--- /dev/null
@@ -0,0 +1,16 @@
+assumable a1.
+assumable a2.
+assumable fever.
+assumable flu.
+assumable sport.
+
+chills  <- fever & a1.
+fever   <- flu.
+thirst  <- fever.
+myalgia <- flu & a2.
+myalgia <- sport.
+
+false <- chills.
+create_nogoods.
+
+
diff --git a/pl-ail-files/heart.ail b/pl-ail-files/heart.ail
new file mode 100644 (file)
index 0000000..ef92128
--- /dev/null
@@ -0,0 +1,141 @@
+% Subset of the knowledge base put together by a cardiologist
+% of AMC Amsterdam for the 112 alarm service.
+% Idea was that centralists (people answering the phone) should
+% be given assistance in posing the right questions to people
+% calling 112 for cardiac problems. In some cases, when there
+% was an emergency, an ambulance needs to be send, where in
+% others it would save money to send the person to general care.
+% So the essential question is: is there an emergency situation
+% or not.
+
+askable age(Patient) = V.
+askable duration(Patient,heart,pain) = V.
+askable diabetic(Patient).
+askable smoking(Patient).
+askable pain(Patient).
+askable similar_symptoms(Patient,angina_pectoris).
+askable similar_symptoms(Patient,myocardial_infarction).
+askable pattern(Patient,pain,retrosternal).
+askable pattern(Patient,pain,left_lateral_thoracic).
+askable pattern(Patient,pain,right_lateral_thoracic).
+askable provocation(Patient,pain,emotions).
+askable provocation(Patient,pain,food_consumption).
+askable provocation(Patient,pain,physical_exertion).
+askable provocation(Patient,pain,warmth_to_cold_change).
+
+sclerotic_arteries(Patient) <-
+ age(Patient) = A &
+ A > 50.
+
+sclerotic_arteries(Patient) <-
+  diabetic(Patient);
+  smoking(Patient).
+
+known_disease(Patient,angina_pectoris) <-
+  pain(Patient) &
+  similar_symptoms(Patient,angina_pectoris).
+
+known_disease(Patient,myocardial_infarction) <-
+  pain(Patient) &
+  similar_symptoms(Patient,myocardial_infarction).
+
+state(Patient,atherosclerosis) <-
+  sclerotic_arteries(Patient);
+  known_disease(Patient,myocardial_infarction);
+  known_disease(Patient,angina_pectoris).
+
+ischaemia(Patient,heart) <-
+  pain(Patient) &
+  pattern(Patient,pain,retrosternal).
+
+ischaemia(Patient,heart) <-
+  pain(Patient) &
+  pattern(Patient,pain,left_lateral_thoracic).
+
+ischaemia(Patient,heart) <-
+  pain(Patient) &
+  pattern(Patient,pain,right_lateral_thoracic).
+
+state(Patient,coronary_vasodilatation) <-
+  pain(Patient) &
+  present_treatment(Patient,anti_anginal) &
+  cardiac_pain(Patient,gone).
+
+pain(Patient,clear_provocation) <-
+  pain(Patient) &
+  provocation(Patient,pain,emotion).
+
+pain(Patient,clear_provocation) <-
+  pain(Patient) &
+   provocation(Patient,pain,food_consumption).
+
+pain(Patient,clear_provocation) <-
+  pain(Patient) &
+  provocation(Patient,pain,physical_exertion).
+
+pain(Patient,clear_provocation) <-
+  pain(Patient) &
+  provocation(Patient,pain,warmth_to_cold_change).
+
+o2_demand(Patient,heart,increased) <-
+  pain(Patient,clear_provocation).
+
+o2_demand(Patient,heart,normal) <-
+  ~pain(Patient,clear_provocation).
+
+ischaemia(Patient,heart) <-
+  pain(Patient) &
+  state(Patient,atherosclerosis).
+
+state(Patient,heart,necrosis) <-
+  state(Patient,ischaemia,irreversible).
+
+o2_supply(Patient,heart,decreased) <-
+  ischaemia(Patient,heart) &
+  o2_demand(Patient,heart,normal).
+
+state(Patient,ischaemia,irreversible) <-
+  ischaemia(Patient,heart) &
+  duration(Patient,heart,pain) = D &
+  D > 30 &
+  ~state(Patient,coronary_vasodilatation).
+
+state(Patient,ischaemia,reversible) <-
+  ischaemia(Patient,heart) &
+  duration(Patient,heart,pain) = D &
+  D < 30.
+
+state(Patient,ischaemia,reversible) <-
+  ischaemia(Patient,heart) &
+  state(Patient,coronary_vasodilatation).
+
+disorder(Patient,myocardial_infarction) <-
+  state(Patient,heart,necrosis) &
+  state(Patient,atherosclerosis).
+
+disorder(Patient,unstable_angina_pectoris) <-
+  o2_demand(Patient,heart,normal) &
+  state(Patient,ischaemia,irreversible) &
+  state(Patient,atherosclerosis).
+
+disorder(Patient,stable_angina_pectoris) <-
+  state(Patient,atherosclerosis) &
+  state(Patient,ischaemia,reversible) &
+  o2_demand(Patient,heart,increased).
+
+disorder(Patient,variant_angina_pectoris) <-
+  ~state(Patient,atherosclerosis) &
+  state(Patient,ischaemia,reversible) &
+  o2_supply(Patient,heart,decreased).
+
+condition(Patient,emergency) <-
+  disorder(Patient,unstable_angina_pectoris).
+
+condition(Patient,emergency) <-
+  disorder(Patient,myocardial_infarction).
+
+condition(Patient,no_emergency) <-
+  disorder(Patient,stable_angina_pectoris).
+
+condition(Patient,no_emergency) <-
+  disorder(Patient,variant_angina_pectoris).
diff --git a/report/report.tex b/report/report.tex
new file mode 100644 (file)
index 0000000..e69de29