%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                      %
%   Prolog programs from Chapter 4 of the book         %
%   SIMPLY LOGICAL: Intelligent reasoning by example   %
%   (c) Peter A. Flach/John Wiley & Sons, 1994.        %
%                                                      %
%   Predicates: term_tree/3                            %
%               term_root/2                            %
%               term_subtree/2                         %
%               term_arc/2                             %
%               term_path/2                            %
%               term_write/1                           %
%               arc/2                                  %
%               path/1                                 %
%               path_leaf/2                            %
%               leaf/1                                 %
%               resolve/3                              %
%               properties/2                           %
%               properties_sn/2                        %
%               inherit_sn/3                           %
%               override/3                             %
%               properties_fr/2                        %
%               inherit_fr/3                           %
%                                                      %
%   NB. This file needs predicates defined in          %
%   the file 'library'.                                %
%                                                      %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


:-consult(library).


%%% 4.1  Representing structured knowledge %%%

% term_tree(T,R,S) <- term T represents a tree with root R 
%                     and list of subtrees S
term_tree(Tree,Root,Subtrees):-
	Tree=..[Root|Subtrees].

% term_root(T,R) <- R is the root of tree T
term_root(Tree,Root):-
	term_tree(Tree,Root,S).

% term_subtree(T,S) <- S is a subtree of tree T
term_subtree(Tree,Subtree):-
	term_tree(Tree,R,S),
	element(Subtree,S).

% term_arc(T,A) <- T is a tree, and A is an arc in T
term_arc(Tree,[Root,SR]):-	% Arc from Root to Subtree
	term_root(Tree,Root),
	term_subtree(Tree,Subtree),
	term_root(Subtree,SR).
term_arc(Tree,Arc):-	% Arc in Subtree
	term_subtree(Tree,Subtree),
	term_arc(Subtree,Arc).

% term_path(T,P) <- T is a tree, and P is a path in T
term_path(Tree,Arc):-	% consisting of one arc
	term_arc(Tree,Arc).
term_path(Tree,[Node1,Node2|Nodes]):-	% several arcs
	term_arc(Tree,[Node1,Node2]),
	term_path(Tree,[Node2|Nodes]).

term_write(Tree):-
	term_write(0,Tree),nl.

% write a Tree at position Pos
term_write(Pos,Tree):-
	term_tree(Tree,Root,Subtrees),	% decompose Tree
	term_write_node(Pos,Pos2,Root),	% write Root
	term_writes(Pos2,Subtrees).	% new position 

% write a list of trees at position Pos
term_writes(Pos,[]).
term_writes(Pos,[Tree]):-!,	% no newline here
	term_write(Pos,Tree).
term_writes(Pos,[Tree|Subtrees]):-
	term_write(Pos,Tree),
	nl,tab(Pos),	% skip to position Pos
	term_writes(Pos,Subtrees).

% write a Node from Begin to End
term_write_node(Begin,End,Node):-
	name(Node,L),length(L,N),	% N is length of Nodename
	End is Begin+10,
	N1 is End-Begin-N,	% N1 is length of line
	write_line(N1),
	write(Node).

% write a line of given length
write_line(0).
write_line(N):-
	N>0,N1 is N-1,
	write('-'),
	write_line(N1).


%%% 4.2  Graphs generated by a predicate %%%

/*
arc(1,2).
arc(1,3).
arc(2,4).
arc(2,5).
arc(2,6).
arc(5,7).
arc(3,8).
arc(3,9).
arc(9,10).
*/

% path(P) <- P is a path in the graph given by arc/2
path([Node1,Node2]):-
	arc(Node1,Node2).
path([Node1,Node2|Nodes]):-
	arc(Node1,Node2),
	path([Node2|Nodes]).

% path_leaf(N,P) <- P is a path starting at node N, ending 
%                   in a leaf in the graph given by arc/2
path_leaf(Leaf,[Leaf]):-
	leaf(Leaf).
path_leaf(Node1,[Node1|Nodes]):-
	arc(Node1,Node2),
	path_leaf(Node2,Nodes).

leaf(Leaf):-
	not arc(Leaf,SomeNode).

arc(A,B):-
	resolve(A,(br(X,Y):-[br(X,Z),br(Z,Y)]),B).
arc(A,B):-
	resolve(A,(br(paul,peter):-[]),B).

% resolve(G,C,NewG) <- the goal G (a list of atoms) 
%                      resolves with the clause C (body 
%                      is a list) to yield the goal NewG
resolve([H1|T],(H2:-Body),B):-
	H1=H2,  % literal in goal unifies with head of clause
	append(Body,T,B).
resolve([H|T],Clause,[H|B]):-
	resolve(T,Clause,B).	% try next literal


%%% 4.3  Inheritance hierarchies %%%

%% Logical representation %%

% Classes
instrument(X):-wind(X).
instrument(X):-string(X).
instrument(X):-percussion(X).
wind(X):-woodwind(X).
wind(X):-brass(X).
string(X):-plucked(X).
string(X):-bowed(X).
string(X):-keyboard(X).
percussion(X):-tuned(X).
percussion(X):-untuned(X).

% Instances
woodwind(recorder).
woodwind(flute).
woodwind(oboe).
woodwind(saxophone).
brass(trumpet).
brass(trombone).
brass(horn).
plucked(guitar).
plucked(lute).
plucked(harp).
bowed(violin).
bowed(cello).
keyboard(harpsichord).
keyboard(piano).
tuned(triangle).
tuned(kettledrum).
untuned(cymbal).
untuned(snaredrum).

% Properties
function(X,musical):-instrument(X).

material(flute,metal).
material(saxophone,metal).
material(X,wood):-woodwind(X).
material(X,metal):-brass(X).
material(X,wood):-string(X).
material(X,metal):-percussion(X).

action(oboe,reed(double)).
action(saxophone,reed(single)).
action(harpsichord,plucked).
action(piano,hammered).
action(X,reed(lip)):-brass(X).
action(X,plucked):-plucked(X).
action(X,bowed):-bowed(X).
action(X,hammered):-percussion(X).


%%% Inference %%%

properties(Inst,Props):-
	attributes(Attrs),
	properties(Attrs,Inst,Props).

properties([],Inst,[]).
properties([Attr|Attrs],Inst,[Attr=Value|Props]):-
	get_value(Attr,Inst,Value),!,	% only first answer
	properties(Attrs,Inst,Props).

attributes([function,material,action]).

get_value(A,B,C):-
	Goal =.. [A,B,C],
	call(Goal).


%% Semantic network %%

% Classes
isa(instrument,top).
isa(wind,instrument).
isa(string,instrument).
isa(percussion,instrument).
isa(woodwind,wind).
isa(brass,wind).
isa(plucked,string).
isa(bowed,string).
isa(keyboard,string).
isa(tuned,percussion).
isa(untuned,percussion).

% Instances
inst(recorder,woodwind).
inst(flute,woodwind).
inst(oboe,woodwind).
inst(saxophone,woodwind).
inst(trumpet,brass).
inst(trombone,brass).
inst(horn,brass).
inst(guitar,plucked).
inst(lute,plucked).
inst(harp,plucked).
inst(violin,bowed).
inst(cello,bowed).
inst(harpsichord,keyboard).
inst(piano,keyboard).
inst(triangle,tuned).
inst(kettledrum,tuned).
inst(cymbal,untuned).
inst(snaredrum,untuned).

% Class properties
prop(instrument,function,musical).
prop(string,material,wood).
prop(percussion,material,metal).
prop(percussion,action,hammered).
prop(woodwind,material,wood).
prop(brass,material,metal).
prop(brass,action,reed(lip)).
prop(plucked,action,plucked).
prop(bowed,action,bowed).

% Instance properties
prop(flute,material,metal).
prop(oboe,action,reed(double)).
prop(saxophone,material,metal).
prop(saxophone,action,reed(single)).
prop(harpsichord,action,plucked).
prop(piano,action,hammered).


%%% Inference %%%

properties_sn(Inst,Props):-
	props(Inst,InstProps),	% properties of instance
	inst(Inst,Class),
	inherit_sn(Class,InstProps,Props).	% inherit from (super)class

inherit_sn(top,Props,Props).
inherit_sn(Class,SpecificProps,AllProps):-
	props(Class,GeneralProps),	% properties of this class
	override(SpecificProps,GeneralProps,Props),
	isa(Class,SuperClass),	% climb hierarchy
	inherit_sn(SuperClass,Props,AllProps).	% properties of superclasses

override(Props,[],Props).
override(Specific,[Attr=Value|General],Props):-
	element(Attr=V,Specific),	% overriding
	override(Specific,General,Props).
override(Specific,[Attr=Value|General],[Attr=Value|Props]):-
	not element(Attr=V,Specific),	% no overriding
	override(Specific,General,Props).

props(IC,Props):-
	findall(Attr=Value,prop(IC,Attr,Value),Props).


%% Frames %%

% Classes
class(instrument,top,[]).
class(wind,instrument,[function=musical]).
class(string,instrument,[material=wood]).
class(percussion,instrument,[material=metal,action=hammered]).
class(woodwind,wind,[material=wood]).
class(brass,wind,[material=metal,action=reed(lip)]).
class(plucked,string,[action=plucked]).
class(bowed,string,[action=bowed]).
class(keyboard,string,[]).
class(tuned,percussion,[]).
class(untuned,percussion,[]).

% Instances
instance(recorder,woodwind,[]).
instance(flute,woodwind,[material=metal]).
instance(oboe,woodwind,[action=reed(double)]).
instance(saxophone,woodwind,[material=metal,action=reed(single)]).
instance(trumpet,brass,[]).
instance(trombone,brass,[]).
instance(horn,brass,[]).
instance(guitar,plucked,[]).
instance(lute,plucked,[]).
instance(harp,plucked,[]).
instance(violin,bowed,[]).
instance(cello,bowed,[]).
instance(harpsichord,keyboard,[action=plucked]).
instance(piano,keyboard,[action=hammered]).
instance(triangle,tuned,[]).
instance(kettledrum,tuned,[]).
instance(cymbal,untuned,[]).
instance(snaredrum,untuned,[]).


%%% Inference %%%

properties_fr(Inst,Props):-
	instance(Inst,Class,InstProps),
	inherit_fr(Class,InstProps,Props).	% inherit from (super)class

inherit_fr(top,Props,Props).
inherit_fr(Class,SpecificProps,AllProps):-
	class(Class,SuperClass,GeneralProps),	% properties of this class
	override(SpecificProps,GeneralProps,Props),
	inherit_fr(SuperClass,Props,AllProps).	% properties of superclasses



