From 0dc794561bb13d860981d32446476cfe5ab92e6c Mon Sep 17 00:00:00 2001 From: Peter Flach Date: Mon, 27 Mar 2017 14:25:39 +0100 Subject: [PATCH] Sections 9.2-3 --- section92.pl | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++ section93.pl | 241 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 542 insertions(+) create mode 100755 section92.pl create mode 100755 section93.pl diff --git a/section92.pl b/section92.pl new file mode 100755 index 0000000..f785509 --- /dev/null +++ b/section92.pl @@ -0,0 +1,301 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% Prolog programs from Section 9.2 of the book % +% SIMPLY LOGICAL: Intelligent reasoning by example % +% (c) Peter A. Flach/John Wiley & Sons, 1994. % +% % +% Predicates: induce_rlgg/2 % +% rlgg/4 % +% % +% NB. This file needs predicates defined in % +% the file 'library'. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%:-consult(library). + + +%%% 9.2 Bottom-up induction %%% + +induce_rlgg(Exs,Clauses):- + writeln('%%% Bottom-up induction %%%'), + writeln('Examples'), + writelns(Exs), + pos_neg(Exs,Poss,Negs), + bg_model(BG), + append(Poss,BG,Model), + induce_rlgg(Poss,Negs,Model,Clauses). + +induce_rlgg(Poss,Negs,Model,Clauses):- + covering(Poss,Negs,Model,[],Clauses). + +% split positive and negative examples +pos_neg([],[],[]). +pos_neg([+E|Exs],[E|Poss],Negs):- + pos_neg(Exs,Poss,Negs). +pos_neg([-E|Exs],Poss,[E|Negs]):- + pos_neg(Exs,Poss,Negs). + +% covering algorithm +covering(Poss,Negs,Model,H0,H):- + construct_hypothesis(Poss,Negs,Model,Hyp),!, + remove_pos(Poss,Model,Hyp,NewPoss), + nl,writeln(' to continue'), + readln(_),nl,nl, + covering(NewPoss,Negs,Model,[Hyp|H0],H). +covering(P,_N,_M,H0,H):- + append(H0,P,H). % add uncovered examples to hypothesis + +% remove covered positive examples +remove_pos([],_M,_H,[]). +remove_pos([P|Ps],Model,Hyp,NewP):- + covers_ex(Hyp,P,Model),!, + write('Covered example: '),write(P),nl, + remove_pos(Ps,Model,Hyp,NewP). +remove_pos([P|Ps],Model,Hyp,[P|NewP]):- + remove_pos(Ps,Model,Hyp,NewP). + + +% extensional coverage, relative to a ground model +covers_ex((Head:-Body),Example,Model):- + try((Head=Example,forall(element(L,Body),element(L,Model)))). + +% construct a clause by means of RLGG +construct_hypothesis([E1,E2|_Es],Negs,Model,Clause):- + write('RLGG of '),write(E1),write(' and '),write(E2),write(' is'), + rlgg(E1,E2,Model,Cl), + reduce(Cl,Negs,Model,Clause),!, + nl,portray_clause(Clause),nl. +construct_hypothesis([_E1,E2|Es],Negs,Model,Clause):- + write(' too general'),nl, + construct_hypothesis([E2|Es],Negs,Model,Clause). + + +% rlgg(E1,E2,M,C) <- C is RLGG of E1 and E2 relative to M +rlgg(E1,E2,M,(H:-B)):- + anti_unify(E1,E2,H,[],S10,[],S20), + varsin(H,V), % determine variables in head of clause + rlgg_bodies(M,M,[],B,S10,_S1,S20,_S2,V). + +rlgg_bodies([],_B2,B,B,S1,S1,S2,S2,_V). +rlgg_bodies([L|B1],B2,B0,B,S10,S1,S20,S2,V):- + rlgg_literal(L,B2,B0,B00,S10,S11,S20,S21,V), + rlgg_bodies(B1,B2,B00,B,S11,S1,S21,S2,V). + +rlgg_literal(_L1,[],B,B,S1,S1,S2,S2,_V). +rlgg_literal(L1,[L2|B2],B0,B,S10,S1,S20,S2,V):- + same_predicate(L1,L2), + anti_unify(L1,L2,L,S10,S11,S20,S21), + varsin(L,Vars),var_proper_subset(Vars,V), % no new variables in literal + !,rlgg_literal(L1,B2,[L|B0],B,S11,S1,S21,S2,V). +rlgg_literal(L1,[_L2|B2],B0,B,S10,S1,S20,S2,V):- + rlgg_literal(L1,B2,B0,B,S10,S1,S20,S2,V). + + +:-op(600,xfx,'<-'). + +anti_unify(Term1,Term2,Term):- + anti_unify(Term1,Term2,Term,[],_S1,[],_S2). + +anti_unify(Term1,Term2,Term1,S1,S1,S2,S2):- + Term1 == Term2,!. +anti_unify(Term1,Term2,V,S1,S1,S2,S2):- + subs_lookup(S1,S2,Term1,Term2,V),!. +anti_unify(Term1,Term2,Term,S10,S1,S20,S2):- + nonvar(Term1),nonvar(Term2), + functor(Term1,F,N),functor(Term2,F,N),!, + functor(Term,F,N), + anti_unify_args(N,Term1,Term2,Term,S10,S1,S20,S2). +anti_unify(Term1,Term2,V,S10,[Term1<-V|S10],S20,[Term2<-V|S20]). + +anti_unify_args(0,_Term1,_Term2,_Term,S1,S1,S2,S2). +anti_unify_args(N,Term1,Term2,Term,S10,S1,S20,S2):- + N>0,N1 is N-1, + arg(N,Term1,Arg1), + arg(N,Term2,Arg2), + arg(N,Term,Arg), + anti_unify(Arg1,Arg2,Arg,S10,S11,S20,S21), + anti_unify_args(N1,Term1,Term2,Term,S11,S1,S21,S2). + +subs_lookup([T1<-V|_Subs1],[T2<-V|_Subs2],Term1,Term2,V):- + T1 == Term1, + T2 == Term2,!. +subs_lookup([_S1|Subs1],[_S2|Subs2],Term1,Term2,V):- + subs_lookup(Subs1,Subs2,Term1,Term2,V). + + +% remove redundant literals +reduce((H:-B0),Negs,M,(H:-B)):- + setof0(L,(element(L,B0),not(var_element(L,M))),B1), + reduce_negs(H,B1,[],B,Negs,M). + +% reduce_negs(H,B1,B0,B,N,M) <- B is a subsequence of B1 +% such that H:-B does not +% cover elements of N +reduce_negs(H,[_L|B0],In,B,Negs,M):- + append(In,B0,Body), + not(covers_neg((H:-Body),Negs,M,_N)),!, + reduce_negs(H,B0,In,B,Negs,M). +reduce_negs(H,[L|B0],In,B,Negs,M):- + reduce_negs(H,B0,[L|In],B,Negs,M). +reduce_negs(H,[],Body,Body,Negs,M):- + not(covers_neg((H:-Body),Negs,M,_N)). + +covers_neg(Clause,Negs,Model,N):- + element(N,Negs), + covers_ex(Clause,N,Model). + + +%%% From library %%% + +%%% Lists and sets + +% element(X,Ys) <- X is an element of the list Ys +element(X,[X|_Ys]). +element(X,[_Y|Ys]):- + element(X,Ys). + +var_element(X,[Y|_Ys]):- + X == Y. % syntactic identity +var_element(X,[_Y|Ys]):- + var_element(X,Ys). + +var_remove_one(X,[Y|Ys],Ys):- + X == Y. % syntactic identity +var_remove_one(X,[Y|Ys],[Y|Zs]):- + var_remove_one(X,Ys,Zs). + +var_proper_subset([],Ys):- + Ys \= []. +var_proper_subset([X|Xs],Ys):- + var_remove_one(X,Ys,Zs), + var_proper_subset(Xs,Zs). + + +% try(Goal) <- Goal succeeds, but variables are not instantiated +try(Goal):- + not(not(Goal)). + + +%%% Various. + +% variant of setof/3 which succeeds with the empty list +% if no solutions can be found +setof0(X,G,L):- + setof(X,G,L),!. +setof0(_X,_G,[]). + +% same_predicate(L1,L2) <- literals L1 and L2 have +% the same predicate and arity +same_predicate(L1,L2):- + functor(L1,P,N),functor(L2,P,N). + +varsin(Term,Vars):- + varsin(Term,[],V), + sort(V,Vars). + +varsin(V,Vars,[V|Vars]):- + var(V),!. +varsin(Term,V0,V):- + functor(Term,_,N), + varsin_args(N,Term,V0,V). + +varsin_args(0,_,Vars,Vars). +varsin_args(N,Term,V0,V):- + N>0, N1 is N-1, + arg(N,Term,ArgN), + varsin(ArgN,V0,V1), + varsin_args(N1,Term,V1,V). + + +%%% For lectures + +writelns(X):- + ( X=[] -> nl + ; X=[H|T] -> writelns(H),writelns(T) + ; otherwise -> write(X),nl + ). + + +%%% Queries %%% + +%%%%%%%%%%%%%%%%%% element/2 %%%%%%%%%%%%%%%%%%%%%%%% + +% bg_model([]). + +query1(Clauses):- + induce_rlgg([+element(b,[b]), + +element(2,[2,3]), + +element(3,[1,2,3]), + +element(b,[a,b]), + +element(3,[2,3]), + +element(3,[3]), + -element(3,[a,b]), + -element(a,[]) + ],Clauses). + +%%%%%%%%%%%%%%%%%% append/3 %%%%%%%%%%%%%%%%%%%%%%% + +% bg_model([]). + +query2(Clauses):- + induce_rlgg([+append([1,2],[3,4],[1,2,3,4]), + +append([a],[],[a]), + +append([],[],[]), + +append([],[1,2,3],[1,2,3]), + +append([2],[3,4],[2,3,4]), + +append([],[3,4],[3,4]), + -append([a],[b],[b]), + -append([c],[b],[c,a]), + -append([1,2],[],[1,3]) + ],Clauses). + +%%%%%%%%%%%%%%%%%% num/2 %%%%%%%%%%%%%%%%%%%%%%% + +bg_model([num(1,one), + num(2,two), + num(3,three), + num(4,four), + num(5,five) + ]). + +query3(Clauses):- + induce_rlgg([+listnum([],[]), + +listnum([2,three,4],[two,3,four]), + +listnum([4],[four]), + +listnum([three,4],[3,four]), + +listnum([two],[2]), + -listnum([1,4],[1,four]), + -listnum([2,three,4],[two]), + -listnum([five],[5,5]) + ],Clauses). + +%%%%%%%%%%%%%%%%%% names/2 %%%%%%%%%%%%%%%%%%%%%%% + +/* +bg_model([person(mick,jagger), + person(david,bowie), + person(tina,turner), + person(johann,sebastian), + person(ludwig,van) + ]). +*/ + +query4(Clauses):- + induce_rlgg([+names([],[]), + +names([david,turner,johann],[p(david,bowie),p(tina,turner),p(johann,sebastian)]), + +names([johann],[p(johann,sebastian)]), + +names([turner,johann],[p(tina,turner),p(johann,sebastian)]), + +names([bowie],[p(david,bowie)]), + -names([mick,johann],[p(mick,mick),p(johann,sebastian)]), + -names([david,turner,johann],[p(david,bowie)]), + -names([van],[p(ludwig,van),p(ludwig,van)]) + ],Clauses). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + diff --git a/section93.pl b/section93.pl new file mode 100755 index 0000000..c405210 --- /dev/null +++ b/section93.pl @@ -0,0 +1,241 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% Prolog programs from Section 9.3 of the book % +% SIMPLY LOGICAL: Intelligent reasoning by example % +% (c) Peter A. Flach/John Wiley & Sons, 1994. % +% % +% Predicates: induce_spec/2 % +% % +% NB. This file needs predicates defined in % +% the file 'library'. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +:-consult(library). + + +%%% 9.3 Top-down induction %%% + +induce_spec(Examples,Clauses):- + writeln('%%% Top-down induction %%%'), + writeln('Examples'), + writelns(Examples), + process_examples([],[],Examples,Clauses). + +% process the examples +process_examples(Clauses,Done,[],Clauses). +process_examples(Cls1,Done,[Ex|Exs],Clauses):- + process_example(Cls1,Done,Ex,Cls2), + process_examples(Cls2,[Ex|Done],Exs,Clauses). + +% process one example +process_example(Clauses,Done,+Example,Clauses):- + covers(Clauses,Example). +process_example(Cls,Done,+Example,Clauses):- + not covers(Cls,Example), + generalise(Cls,Done,Example,Clauses). +process_example(Cls,Done,-Example,Clauses):- + covers(Cls,Example), + specialise(Cls,Done,Example,Clauses). +process_example(Clauses,Done,-Example,Clauses):- + not covers(Clauses,Example). + + +% covers(Clauses,Ex) <- Ex can be proved from Clauses and +% background theory in max. 10 steps +covers(Clauses,Example):- + prove_d(10,Clauses,Example). + +prove_d(D,Cls,true):-!. +prove_d(D,Cls,(A,B)):-!, + prove_d(D,Cls,A), + prove_d(D,Cls,B). +prove_d(D,Cls,A):- + D>0,D1 is D-1, + copy_element((A:-B),Cls), % make copy of clause + prove_d(D1,Cls,B). +prove_d(D,Cls,A):- + prove_bg(A). + +prove_bg(true):-!. +prove_bg((A,B)):-!, + prove_bg(A), + prove_bg(B). +prove_bg(A):- + bg((A:-B)), + prove_bg(B). + + +% Specialisation by removing a refuted clause +specialise(Cls,Done,Example,Clauses):- + false_clause(Cls,Done,Example,C), + remove_one(C,Cls,Cls1), + write(' ...refuted: '),write(C),nl,nl, + writeln(' to continue'),readln(_), + process_examples(Cls1,[],[-Example|Done],Clauses). + +% false_clause(Cs,E,E,C) <- C is a false clause in the proof of E (or ok) +false_clause(Cls,Exs,true,ok):-!. +false_clause(Cls,Exs,(A,B),X):-!, + false_clause(Cls,Exs,A,Xa), + ( Xa = ok -> false_clause(Cls,Exs,B,X) + ; otherwise -> X = Xa + ). +false_clause(Cls,Exs,E,ok):- + element(+E,Exs),!. +false_clause(Cls,Exs,A,ok):- + bg((A:-B)),!. +false_clause(Cls,Exs,A,X):- + copy_element((A:-B),Cls), + false_clause(Cls,Exs,B,Xb), + ( Xb \= ok -> X = Xb + ; otherwise -> X = (A:-B) + ). + + +% Generalisation by adding a covering clause +generalise(Cls,Done,Example,Clauses):- + write('Generalising example: '),write(Example),nl, + search_clause(Done,Example,Cl), + writeln('Found clause: '),portray_clause(Cl),nl, + writeln(' to continue'),readln(_), + process_examples([Cl|Cls],[],[+Example|Done],Clauses). + + +% search_clause(Exs,E,C) <- C is a clause covering E and +% not covering negative examples +% (iterative deepening search) +search_clause(Exs,Example,Clause):- + literal(Head,Vars), + try((Head=Example)), + search_clause(3,a((Head:-true),Vars),Exs,Example,Clause). + +search_clause(D,Current,Exs,Example,Clause):- + write(D),write('..'), + search_clause_d(D,Current,Exs,Example,Clause),!. +search_clause(D,Current,Exs,Example,Clause):- + D1 is D+1, + !,search_clause(D1,Current,Exs,Example,Clause). + +search_clause_d(D,a(Clause,Vars),Exs,Example,Clause):- + covers_ex(Clause,Example,Exs), % goal + not((element(-N,Exs),covers_ex(Clause,N,Exs))),!. +search_clause_d(D,Current,Exs,Example,Clause):- + D>0,D1 is D-1, + specialise_clause(Current,Spec), + search_clause_d(D1,Spec,Exs,Example,Clause). + + +% Extensional coverage +covers_ex((Head:-Body),Example,Exs):- + try((Head=Example,covers_ex(Body,Exs))). + +covers_ex(true,Exs):-!. +covers_ex((A,B),Exs):-!, + covers_ex(A,Exs), + covers_ex(B,Exs). +covers_ex(A,Exs):- + element(+A,Exs). +covers_ex(A,Exs):- + prove_bg(A). + + +% specialise_clause(C,S) <- S is a minimal specialisation +% of C under theta-subsumption +specialise_clause(Current,Spec):- + add_literal(Current,Spec). +specialise_clause(Current,Spec):- + apply_subs(Current,Spec). + +add_literal(a((H:-true),Vars),a((H:-L),Vars)):-!, + literal(L,LVars), + proper_subset(LVars,Vars). +add_literal(a((H:-B),Vars),a((H:-L,B),Vars)):- + literal(L,LVars), + proper_subset(LVars,Vars). + +apply_subs(a(Clause,Vars),a(Spec,SVars)):- + copy_term(a(Clause,Vars),a(Spec,Vs)), + apply_subs1(Vs,SVars). + +apply_subs1(Vars,SVars):- + unify_two(Vars,SVars). +apply_subs1(Vars,SVars):- + subs_term(Vars,SVars). + +unify_two([X|Vars],Vars):- + element(Y,Vars), + X=Y. +unify_two([X|Vars],[X|SVars]):- + unify_two(Vars,SVars). + +subs_term(Vars,SVars):- + remove_one(X,Vars,Vs), + term(Term,TVars), + X=Term, + append(Vs,TVars,SVars). + + +%%% Queries %%% + +term(list([]),[]). +term(list([X|Y]),[item(X),list(Y)]). + +%%%%%%%%%%%%%%%%%% element/2 %%%%%%%%%%%%%%%%%%%%%%%% + +/* +literal(element(X,Y),[item(X),list(Y)]). + +bg(true). +*/ + +query1(Clauses):- + induce_spec([+element(a,[a,b]), + -element(x,[a,b]), + +element(b,[b]), + +element(b,[a,b]) + ],Clauses). + + +%%%%%%%%%%%%%%%%%% append/3 %%%%%%%%%%%%%%%%%%%%%%% + +/* +literal(append(X,Y,Z),[list(X),list(Y),list(Z)]). + +bg(true). +*/ + +query2(Clauses):- + induce_spec([+append([],[b,c],[b,c]), + -append([],[a,b],[c,d]), + -append([a,b],[c,d],[c,d]), + -append([a],[b,c],[d,b,c]), + -append([a],[b,c],[a,d,e]), + +append([a],[b,c],[a,b,c]) + ],Clauses). + +%%%%%%%%%%%%%%%%%% listnum/2 %%%%%%%%%%%%%%%%%%%%%%% + + +literal(listnum(X,Y),[list(X),list(Y)]). +literal(num(X,Y),[item(X),item(Y)]). + +bg((num(1,one):-true)). +bg((num(2,two):-true)). +bg((num(3,three):-true)). +bg((num(4,four):-true)). +bg((num(5,five):-true)). + + +query3(Clauses):- + induce_spec([+listnum([],[]), + -listnum([one],[one]), + -listnum([1,two],[one,two]), + +listnum([1],[one]), + -listnum([five,two],[5,two]), + +listnum([five],[5]) + ],Clauses). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +