/*************************************************************************

         name: cllsLib.pl
      version: March 13, 2002
  description: Additional predicates for working with clls USRs
      authors: Stephan Walter, Aljoscha Burchardt
 
*************************************************************************/

:- module(cllsLib,[mergeUSR/2,usr2LambdaList/2,idom/3,root/2,hasCycle/1,reachable/3]).
		
:- ensure_loaded(comsemOperators).

:- use_module(comsemLib,[compose/3]).
:- use_module(signature,[newvar/1]).

/*========================================================================
   Merge for Underspecified Semantic Representations
========================================================================*/

mergeUSR(usr(N,L,D,B),usr(N,L,D,B)).

mergeUSR(merge(U1,U2),usr(N3,L3,D3,B3)):-
   mergeUSR(U1,usr(N1,L1,D1,B1)),
   mergeUSR(U2,usr(N2,L2,D2,B2)),
   append(N1,N2,N3),
   append(L1,L2,L3),
   append(D1,D2,D3),
   append(B1,B2,B3).


/*========================================================================
   Constraint Tree Predicats
========================================================================*/

%% The root node

% a root node has no incoming edges 
% (is not dominated by anyone)
root(Root,Usr) :-
	Usr = usr(Ns,_,_,_),
	member(Root,Ns),
	\+ dom(_,Root,Usr).

%% Dominance

% X immediately dominates Y via a dominance constraint
cdom(X,Y,Usr) :-
	Usr =  usr(_,_,DCs,_),
	member(dom(X,Y),DCs).

% X is Ys father
idom(X,Y,Usr) :-
	Usr = usr(_,LCs,_,_),
	member(X:Label,LCs),
	compose(Label,_,Args),
	member(Y,Args).

% X dominates Y by a constraint or is Y's father
dom(X,Y,Usr) :- cdom(X,Y,Usr).
dom(X,Y,Usr) :- idom(X,Y,Usr).

%% Reachability

% N1 is reachable from N2 if N2 dominates N1 or
reachable(N1,N2,Usr) :- 
	dom(N2,N1,Usr),!.

% if there is a node N3 that is dominates N1 and 
% N3 can be reached from N2
reachable(N1,N2,Usr) :-
	dom(N3,N1,Usr),
	reachable(N3,N2,Usr).


%% Test for Cycles

% if there are nodes, but there is no root node,
% there must be a cycle
hasCycle(Usr) :-
	Usr = usr(Ns,_,_,_),
	length(Ns,Length),
	Length > 0,
	\+ root(_,Usr).

% if there is a root node,
% look for cycles from the root node upwards
hasCycle(Usr) :-
	root(Root,Usr),
	hasCycleRec(Root,[],Usr).

% if a node is reached the second time, the Usr has a cycle
hasCycleRec(N,SoFar,_) :-
	member(N,SoFar). 

hasCycleRec(N,SoFar,Usr) :-	
	reachable(N2,N,Usr),
	hasCycleRec(N2,[N|SoFar],Usr).


/*========================================================================
  Translation of Solved Underspecified Representations to Lambda Terms
========================================================================*/

usr2LambdaList([],_).

usr2LambdaList([Usr|Usrs],[LT1|LTs]) :-
	usr2Lambda(Usr,LT1),
	usr2LambdaList(Usrs,LTs).

% translate from from root node upwards	
usr2Lambda(Usr,LT) :-
	root(Root,Usr),
	translate(Root,LT,[],Usr).


% binary operators: @, & ,v,>,< >: recursive translation of both children
translate(N,OutTerm,Bindings,Usr) :-
	Usr = usr(_,LCs,_,_),
	member(N:Term,LCs),
	compose(Term,Functor,[N1,N2]),
	member(Functor,['@','&','v','>','< >']),
	translate(N1,LT1,Bindings,Usr),
	translate(N2,LT2,Bindings,Usr),
	compose(OutTerm,Functor,[LT1,LT2]).


% N is labled Binder(N1), introduce new Var,
% add the binding N:Var to Bindings
% continue translation at node N1
translate(N,OutTerm,Bindings,Usr) :-
	Usr = usr(_,LCs,_,_),
	member(N:Term,LCs),
	compose(Term,Functor,[N1]),
	member(Functor,[lambda,exists,forall]),
	newvar(NewVar),
	translate(N1,LT,[N:NewVar|Bindings],Usr),
	compose(OutTerm,Functor,[NewVar,LT]). 


% var translates to a variable according to Bindings
translate(N,Var,Bindings,Usr) :-
	Usr = usr(_,LCs,_,BCs),
	member(N:var,LCs),
	member(bind(N,BinderNode),BCs),
	member(BinderNode:Var,Bindings).


% dom(N1,N2): continue translation at N2
translate(N1,LT,Bindings,Usr) :-
	Usr = usr(_,_,DCs,_),
	member(dom(N1,N2),DCs),
	translate(N2,LT,Bindings,Usr).
	

% basic case: labled nodes translate to the label
translate(N,Label,_,Usr) :-
	Usr = usr(_,LCs,_,_),
	member(N:Label,LCs).
