%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                      %
%   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):-
  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,
	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):-
	search_clause(Done,Example,Cl),
	write('Found clause: '),write(Cl),nl,
	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.

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.

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).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

