
max(X,Y,X) :- X >= Y, !.
max(X,Y,Y) :- X < Y.

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

sano(X) :- felice(X).
sano(X) :- ha_anticorpi(X).

%%felice(X) :- canta(X), !, balla(X).
felice(X) :- canta(X), balla(X).
felice(X) :- stupido(X).

ha_anticorpi(maria).
canta(linda).  %% invertire
canta(gianni). %% queste due clausole
stupido(gianni).
balla(linda).

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

%gentile(X) :- parigino(X), !, fail.
%gentile(X) :- francese(X).

%gentile(X) :- francese(X), not(parigino(X)).
gentile(X) :- not(parigino(X)), francese(X).
francese(antoine).
francese(charles).
parigino(antoine).

/* merge di liste ordinate */
merge(X,[],X).
merge([],X,X).
merge([X|R1],[Y|R2],[X,Y|R]) :-
	X=Y, !,
merge(R1,R2,R).
merge([X|R1],[Y|R2],[X|R]) :-
	X<Y, !,
merge(R1,[Y|R2],R).
merge([X|R1],[Y|R2],[Y|R]) :-
	X>Y,
merge([X|R1],R2,R).

/* intersezione insiemistica */
intersect(_,[],[]).
intersect([],_,[]).
intersect([X|Rest],Y,[X|R]) :-
        member(X,Y), !,
        intersect(Rest,Y,R).
intersect([_|Rest],Y,R) :-
	 intersect(Rest,Y,R).

/* different */
different(X,X) :- !, fail.
different(_,_).

%%%%%%%%%%%%%%%%%%%%
number_of_parents(adam,0) :- !.
number_of_parents(eve,0) :- !.
number_of_parents(_,2).

%%%%%%%%%%%%%
% rappresentazione alberi nari
% radice => lista non vuota di sottoalberi, oppure
% foglia (qualsiasi termine che non abbia => come funtore principale)

?- op(600,xfx,=>).
 
binario(a => [b=> [c => [d,e]], f => [g => [h],i]]).
ternario(a => [b=> [c => [d,e]],q(x),f => [g => [h],i,m=>[n,p,q]]]).

is_ntree(_ => Tlist) :-
	!, length(Tlist,N), N>0, %% almeno un sottoalbero
        is_ntreelist(Tlist).
is_ntree(_).  % caso foglia

is_ntreelist([]).
is_ntreelist([T|Tlist]) :-
        is_ntree(T),
        is_ntreelist(Tlist).

is_leaf(Leaf) :- Leaf \= _ => _.

/* Se si vogliono trattare gli alberi n-ari come tipo astratto, si
   definiscono anche i selettori */
/* root(+Tree,?Label) true se Label è l’etichetta della radice di Tree */
root(X => _, X) :- !.
root(X,X).

/* left(+Tree,?Left) true se Left è il primo sottoalbero di Tree. Fallisce se
   Tree è una foglia. */
left(_ => [Left|_], Left).
/* treerest(+Tree,?Rest) true se Rest è l’albero che si ottiene da Tree
   eliminandone il primo sottoalbero. Fallisce se Tree è una foglia. */
treerest(X=> [_], X).		% se c'e' un unico sottoalbero,
                                % si ottiene una foglia
treerest(X =>[_|Rest], X=>Rest).



/* branching_factor(+T,?N) = N e' il fattore di ramificazione di T */
%% Versione 1
branching_factor(_ => Tlist,B) :- !,
	length(Tlist,N),
	max_bf(Tlist,Blist),
%	(N >= Blist, B=N ; N < Blist, B=Blist).
%%%     oppure:
	B is max(N,Blist).
%%	max_list([N|Blist],B).
branching_factor(_,0).

max_bf([T],B) :- !,
	branching_factor(T,B).
max_bf([T|Rest],B) :-
	branching_factor(T,BT),
	max_bf(Rest,Brest),
	B is max(BT,Brest).

%%%%% Versione 2: utilizzando i selettori
branching_factor2(T,B) :-
	T = _ => Tlist, !,
	left(T,Left), 
	length(Tlist,N),
	branching_factor2(Left,BLeft),
	treerest(T,Rest),
	branching_factor2(Rest,BRest),
	max_list([N,BLeft,BRest],B).
branching_factor2(_,0).


%%%%%%%% ricerca di un ramo
% ramo(+T,?Leaf,?Ramo) = Ramo e' una lista che rappresenta un ramo in T
%        dalla radice a una foglia etichettata da Leaf
% ramo(+Tlist,?Leaf,?Ramo) = Ramo e' un ramo in uno degli alberi in Tlist
%        dalla radice a una foglia etichettata da Leaf
ramo(Root => Tlist,Leaf,[Root|Rest]) :- !,
	ramo_in_lista(Tlist,Leaf,Rest).
ramo(Leaf,Leaf,[Leaf]).

ramo_in_lista([T|_],Leaf,Ramo) :-
	ramo(T,Leaf,Ramo).
ramo_in_lista([_|Rest],Leaf,Ramo) :-
	ramo_in_lista(Rest,Leaf,Ramo).

%%%%%%% versione 2
ramo2(T,Leaf,[Root|Ramo]) :-
	left(T,Left),
	root(T,Root),
	ramo(Left,Leaf,Ramo).
ramo2(T,Leaf,Ramo) :-
	treerest(T,Rest), !,
	ramo(Rest,Leaf,Ramo).
ramo2(Leaf,Leaf,[Leaf]).

	