%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                                                                                              %
%                                                              Disclaimer                                                                      %
%                                                                                                                                              %
% This Prolog program is no more than a prototype used for demonstrating the feasibility of some ideas we had for obtaining ontology           %
% alignments with good precision and recall.                                                                                                   %
%                                                                                                                                              % 
% The program may have bugs, it has neither inline documentation (apart form some comments in Italian), nor a manual of use.                   %
% A more solid version is under development.                                                                                                   %
%                                                                                                                                              %
% Although good results are obtained under very restrictive conditions (in particular, all the concepts of the ontologies to match must belong %
% to WordNet), when input ontologies have the right form, we may obtain imressive results.                                                     %      
%                                                                                                                                              %
% You may download and use this program under LGPL, but you do it at your own risk...                                                          %
%                                                                                                                                              %
%         Viviana Mascardi and Fabrizio Larosa                                                                                                 %
%                                                                                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

:- use_module('wn_tools.pl').



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                                                                                              %
%                                                 SUPERVISED MAPPING REFINER                                                                   %
%                                                                                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

stand_alone_supervised_map_refine(OntoName1, OntoName2, OntoFile, MappingFile, RefinedMappingFile, LogFile):-
	compile(OntoFile), 
	compile(MappingFile),
	create_mappings(MappingList), 
	open(RefinedMappingFile,write,RefinedMappingStream),
	open(LogFile,write,LogStream),
	consistency_check(OntoName1, OntoName2, MappingList, RefinedMappingStream, LogStream), 
	close(RefinedMappingStream), 
	close(LogStream).


create_mappings(MappingList) :-
	findall(map(C1, C2, Conf), map(C1, C2, Conf), MappingList).


consistency_check(_, _, [], _, _).
	consistency_check(Onto1, Onto2, [map(C1, C2, Conf)|List], RefinedMappingStream, LogStream):-
	nl, 
	write('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'), 
	nl, 
	nl, 
	write('Checking the consistency of  ('), write(C1), write(' in '), write(Onto1), write(','), 
	write(C2), write(' in '), write(Onto2), write(') with confidence '), write(Conf),  nl, nl,  
	nl(LogStream),
	write(LogStream, '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'), 
	nl(LogStream),
	nl(LogStream),
	write(LogStream, 'Checking the consistency of  ('), write(LogStream, C1), write(LogStream, ' in '), write(LogStream, Onto1), write(LogStream, ','), 
	write(LogStream, C2), write(LogStream, ' in '), write(LogStream, Onto2), write(LogStream, ') with confidence '), 
	write(LogStream, Conf), nl(LogStream), nl(LogStream),
	get_inconsistencies(Onto1, Onto2, C1, C2, Inconsistencies),
	keep_or_discard_consistency(Onto1, Onto2, map(C1, C2, Conf),  Inconsistencies, List, RefinedMappingStream, LogStream).


keep_or_discard_consistency(Onto1, Onto2, map(C1, C2, Conf),  [], List, RefinedMappingStream, LogStream):-
     write('No semantic inconsistencies found: mapping kept'), nl,  
     write(LogStream, 'No semantic inconsistencies found: mapping kept'), nl(LogStream), 
     write(RefinedMappingStream, 'map(\''), write(RefinedMappingStream, C1), write(RefinedMappingStream, '\', \''), write(RefinedMappingStream, C2), 
     write(RefinedMappingStream, '\', '), write(RefinedMappingStream, Conf), write(RefinedMappingStream, ').'), 
     nl(RefinedMappingStream),  
     consistency_check(Onto1, Onto2, List, RefinedMappingStream, LogStream), 
     !. 
      
keep_or_discard_consistency(Onto1, Onto2, map(C1, C2, Conf),  InconsistencyList, List, RefinedMappingStream, LogStream) :-
    query_the_user(Onto1, Onto2, map(C1, C2, Conf),  InconsistencyList, RefinedMappingStream, LogStream), 
    consistency_check(Onto1, Onto2, List, RefinedMappingStream, LogStream).


query_the_user(_, _, _,  [], _, _).
 
query_the_user(Onto1, Onto2, map(C1, C2, Conf),  [Head|Tail], RefinedMappingStream, LogStream):-
      query(Head, RefinedMappingStream, LogStream),   
      query_the_user(Onto1, Onto2, map(C1, C2, Conf),  Tail, RefinedMappingStream, LogStream). 


query(inconsistency(
		transitive_closure_is_a(Onto1, C1, SuperC1),
		transitive_closure_is_a(Onto2, C2, SuperC2),
		map(MapInO1, MapInO2, Con), 
		disjoint(Onto, Disj1, Disj2)), RefinedMappingStream, LogStream) :-
	nl(LogStream), write(LogStream, 'The following request has been posed to the user:'), nl(LogStream), 
	nl, write('Concept '), write(C1), write(' in '), write(Onto1), write(' descends from concept '), write(SuperC1), nl, 
	write('Concept '), write(C2), write(' in '), write(Onto2), write(' descends from concept '), write(SuperC2), nl,
	write('Concept '), write(MapInO1), write(' in '), write(Onto1), write(' is equivalent to concept '), write(MapInO2), write(' in '), write(Onto2),
	write(' with confidence '), write(Con), nl,
	write('Concepts '), write(Disj1), write(' and '), write(Disj2), write(' are disjoint in '), write(Onto), nl, nl, 
	write('This raises an inconsistency. What should I do with the checked mapping?'), nl,   
	write('Press k for keep and d for discard'), nl, 
	nl(LogStream), write(LogStream, 'Concept '), write(LogStream, C1), write(LogStream, ' in '), write(LogStream, Onto1), 
	write(LogStream, ' descends from concept '), write(LogStream, SuperC1), nl(LogStream), 
	write(LogStream, 'Concept '), write(LogStream, C2), write(LogStream, ' in '), write(LogStream, Onto2), 
	write(LogStream, ' descends from concept '), write(LogStream, SuperC2), nl(LogStream),
	write(LogStream, 'Concept '), write(LogStream, MapInO1), write(LogStream, ' in '), write(LogStream, Onto1), 
	write(LogStream, ' is equivalent to concept '), write(LogStream, MapInO2), write(LogStream, ' in '), write(LogStream, Onto2),
	write(LogStream, ' with confidence '), write(LogStream, Con), nl(LogStream),
	write(LogStream, 'Concepts '), write(LogStream, Disj1), write(LogStream, ' and '), write(LogStream, Disj2), 
	write(LogStream, ' are disjoint in '), write(LogStream, Onto), nl(LogStream), nl(LogStream), 
	write(LogStream, 'This raises an inconsistency. What should I do with the checked mapping?'), nl(LogStream),   
	write(LogStream, 'Press k for keep and d for discard (remember to type a dot after your choice)'), nl(LogStream), nl(LogStream), 
	read(Decision), 
	k_or_d(C1, C2, Decision, RefinedMappingStream, LogStream). 


k_or_d(C1, C2, k, MappingStream, LogStream):-
	map(C1, C2, Conf), 
 	write(MappingStream, 'map(\''), write(MappingStream, C1), write(MappingStream, '\', \''), write(MappingStream, C2), write(MappingStream, '\','),
 	write(MappingStream, Conf), write(MappingStream, ').'), nl(MappingStream), 
 	write('The user typed k: mapping kept'), nl, 
 	write(LogStream, 'The user typed k: mapping kept'), nl(LogStream), 
 	!.
			 
k_or_d(_, _, d, _, LogStream):-
 	write('The user typed d: mapping discarded'), nl, 
	write(LogStream, 'The user typed d: mapping discarded'), nl(LogStream), 
 	!.
 
k_or_d(C1, C2, _, MappingStream, LogStream):-
	write('Please, type either k or d!!!'), nl, 
	read(Decision),
	k_or_d(C1, C2, Decision, MappingStream, LogStream).
 

disjoint(O, C1, C2) :- 
	disjointWith(O, C1, C2). 

disjoint(O, C1, C2) :- 
	disjointWith(O, C2, C1). 

   
transitive_closure_is_a(_, C, C). 

transitive_closure_is_a(Onto, C, SuperC):-
	is_a(Onto, C, Super), 
	transitive_closure_is_a(Onto, Super, SuperC). 


get_inconsistencies(Onto1, Onto2, C1, C2, Inconsistencies) :-
	
	findall(inconsistency(
			transitive_closure_is_a(Onto1, C1, SuperC1),
			transitive_closure_is_a(Onto2, C2, SuperC2),
			map(SuperC1, MapSuperC1, Con), 
			disjoint(Onto2, MapSuperC1, SuperC2)),  
		(map(C1, C2, Confidence), 
		transitive_closure_is_a(Onto1, C1, SuperC1),
		transitive_closure_is_a(Onto2, C2, SuperC2),
		map(SuperC1, MapSuperC1, Con), 
		disjoint(Onto2, MapSuperC1, SuperC2)),
		List1), 
		
	findall(inconsistency(
			transitive_closure_is_a(Onto1, C1, SuperC1),
			transitive_closure_is_a(Onto2, C2, SuperC2),
			map(InverseMapSuperC2, SuperC2, Con), 
			disjoint(Onto1, InverseMapSuperC2, SuperC1)),  
		(map(C1, C2, Confidence), 
		transitive_closure_is_a(Onto1, C1, SuperC1),
		transitive_closure_is_a(Onto2, C2, SuperC2),
		map(InverseMapSuperC2, SuperC2, Con), 
		disjoint(Onto1, InverseMapSuperC2, SuperC1)),
		List2),
		
	append(List1, List2, Inconsistencies). 	
   


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                                                                                              %
%                                                          LESK MATCHER                                                                        %
%                                                                                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 


lesk_match(OntoName1, OntoName2, OntoFile, MappingFile, LogFile):-
	compile(OntoFile), 
	create_concepts_list(OntoName1, OntoName2, ConceptList),
	get_semantic_portion(ConceptList),
	create_mappings(OntoName1, OntoName2, MappingList), 
	open(MappingFile,write,MappingStream),
	open(LogFile,write,LogStream),
	check(OntoName1, OntoName2, MappingList, MappingStream, LogStream), 
	close(MappingStream), 
	close(LogStream),
	clean.


create_concepts_list(OntoName1, OntoName2, ConceptList):-
	findall(C1, is_a(OntoName1, C1, _),  ConceptList1),  
	findall(C2, is_a(OntoName2, C2, _),  ConceptList2),
	append(ConceptList1, ConceptList2, ConceptList).


create_mappings(OntoName1, OntoName2, MappingList):-
	findall(map(C1, C2), (is_a(OntoName1, C1, _),  is_a(OntoName2, C2, _)), MappingList). 


check(_, _, [],  _, _).

check(Onto1, Onto2, [map(C1, C2)|List], MappingStream, LogStream):-
	nl, 
	write('Processing the mapping ('), write(C1), write(' in '), write(Onto1), write(','), write(C2), write(' in '), write(Onto2), write(')'), nl, 
	nl(LogStream),
	write(LogStream, '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'), 
	nl(LogStream),
	write(LogStream, 'Processing the mapping ('), write(LogStream, C1), write(LogStream, ' in '), write(LogStream, Onto1), write(LogStream, ','), 
	write(LogStream, C2), write(LogStream, ' in '), write(LogStream, Onto2), write(LogStream, ')'), nl(LogStream), 
	get_concept_context(C1, Onto1, Context1), 
	get_concept_context(C2, Onto2, Context2),
	disambiguate_concept(C1, Context1, Sense1, Gloss1, _), 
	disambiguate_concept(C2, Context2, Sense2, Gloss2, _),
	write('The sense of '), write(C1), write(' after disambiguation in the context '), write(Context1), write(' is '), write(Sense1), 
	write(' meaning '), write(Gloss1), nl, 
	write('The sense of '), write(C2), write(' after disambiguation in the context '), write(Context2), write(' is '), 
	write(Sense2), write(' meaning '), write(Gloss2), nl, 
	write(LogStream, 'The sense of '), write(LogStream, C1), write(LogStream, ' after disambiguation in the context '), 
	write(LogStream, Context1), write(LogStream, ' is '), write(LogStream, Sense1), write(LogStream, ' meaning '), write(LogStream, Gloss1), nl(LogStream), 
	write(LogStream, 'The sense of '), write(LogStream, C2), write(LogStream, ' after disambiguation in the context '), 
	write(LogStream, Context2), write(LogStream, ' is '), write(LogStream, Sense2), write(LogStream, ' meaning '), write(LogStream, Gloss2), nl(LogStream), 
	keep_or_discard(Onto1, C1,  Sense1, Onto2, C2,  Sense2,  List, MappingStream, LogStream).

keep_or_discard(Onto1, C1,  Sense,  Onto2, C2,  Sense, List, MappingStream, LogStream):-
     	write('The sense is the same: mapping ('), write(C1), write(' in '), write(Onto1), write(','), write(C2), write(' in '), 
     	write(Onto2), write(') kept with confidence 1'), 
    	nl, 
     	write(LogStream, 'The sense is the same: mapping ('), write(LogStream, C1), write(LogStream, ' in '), 
     	write(LogStream, Onto1), write(LogStream, ','), write(LogStream, C2), write(LogStream, ' in '), 
     	write(LogStream, Onto2), write(LogStream, ') kept with confidence 1'), 
     	nl(LogStream), 
     	write(MappingStream, 'map(\''), write(MappingStream, C1), write(MappingStream, '\', \''), write(MappingStream, C2), write(MappingStream, '\', 1).'), 
     	nl(MappingStream),  
     	check(Onto1, Onto2, List, MappingStream, LogStream), 
     	!. 
      
keep_or_discard(Onto1, C1,  _, Onto2, C2,  _, List, MappingStream, LogStream) :-
    	write('The sense is different: mapping ('), write(C1), write(' in '), write(Onto1), write(','), write(C2), write(' in '), write(Onto2), write(') discarded'), nl, 
    	write(LogStream, 'The sense is different: mapping ('), write(LogStream, C1), write(LogStream, ' in '), write(LogStream, Onto1), write(LogStream, ','), 
    	write(LogStream, C2), write(LogStream, ' in '), write(LogStream, Onto2), write(LogStream, ') discarded'), nl(LogStream), 
    	check(Onto1, Onto2, List, MappingStream, LogStream).


get_concept_context(C, Onto, Context):-
	findall(Concept, is_a(Onto, C, Concept), List1), 
	findall(Concept, is_a(Onto, Concept, C), List2),
	findall(Concept, rel(Onto, _, C, Concept), List3),
	findall(Concept, rel(Onto, _, Concept, C), List4),
	append(List1, List2, List12), 
	append(List12, List3, List123), 
	append(List123, List4, Context). 
    
    
writeList([]). 

writeList([H|T]) :- 
	write(H), write('  '), writeList(T).    


writeList([], _). 

writeList([H|T], Stream) :- 
	write(H, Stream), write('  ', Stream), writeList(T, Stream).   


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%% From now on: Fabrizio Larosa's predicates (somewhere adapted by Viviana Mascardi) %%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%% Parameters %%%%%%%%%%%%%%%%%%%%%%%%%%

context_window(8).             %8
min_length(4).                 %4
wg_into_cg_weight(1).          %1
c_into_wg_weight(50).          %50
wg_into_t_weight(25).          %25


%%%%%%%%%%%%%%%%%%%%%%%%%% Predicates %%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%% count_occurrences(+Word, +List, ?Count)
%%%%%%%%% Unifica la variabile Count con il numero di occorrenze dell'atomo Word nella lista List.
count_occurrences(Word, [Word|Tail], Count) :-          %Word è il primo elemento di List
     !,                                                 %taglia
     count_occurrences(Word, Tail, C),                  %conta le occorrenze nella coda
     Count is C + 1.                                    %incrementa il risultato
count_occurrences(Word, [_|Tail], Count) :-             %Word non è il primo elemento di List
     count_occurrences(Word, Tail, Count).              %conta le occorrenze nella coda
count_occurrences(_, [], 0).



%%%%%%%%% disambiguate_concept(+Word, +Context, ?Gloss, ?PartOfSpeech) :-
%%%%%%%%% Unifica la variabile Gloss con la definizione del senso per la parola Word nella lista Context e la variabile PartOfSpeech con la relativa parte del discorso.
disambiguate_concept(Word, _, none, '*** WORD NOT PRESENT IN WORDNET ***', none) :-
     not(s(_,_,Word,_,_,_)),                                                                    %la parola non è presente in WordNet
     !. 
     											%taglia
disambiguate_concept(Word, Context, S1, Gloss, PartOfSpeech) :-                                    %la parola è presente in  WordNet
     get_glosses_from_context(Context, L),                                                      %calcola le definizioni delle parole del contesto
     min_length(Min),                                                                           %recupera il settaggio della lunghezza minima
     filter_min_length(L, Min, [Word], C),                                                      %filtra le definizioni per lunghezza minima delle parole con eccezione della parola da disambiguare
     write('disambiguate_concept 1'), nl, 
     findall(score(S, V), (s(S, _, Word, _, _, _), get_glosses_from_s(S, G),
          filter_min_length(G, Min, [Word], F), score(F, Context, C, V), 
          write('sense '), write(S), write(';'), nl, write('gloss '), write(G), write(';'), nl, write('score '), write(V), nl, nl), M),             %calcola la lista dei sensi associati ad un valore di valutazione
     write('disambiguate_concept 2'), nl,
     max_score(M, S1, _),         
     write('disambiguate_concept 3'), nl,                                                              %calcola il senso con valutazione massima
     part_of_speech(S1, PartOfSpeech),                                                          %recupera l'identificativo della parte del discorso associata al senso
     g(S1, Gloss).                                                                              %recupera la definizione del senso


%%%%%%%%% filter_min_length(+List, +Min, +ExcList, ?Filtered) :-
%%%%%%%%% Unifica la variabile Filtered con la lista delle parole della lista List di lunghezza maggiore o uguale a Min con le eccezioni della lista ExcList.
filter_min_length([Head|Tail], Min, ExcList, [Head|List]) :-
     atom_length(Head, N),                                 %calcola la lunghezza dell'atomo
     N >= Min,                                             %la lunghezza è maggiore o uguale a Min
     !,                                                    %taglia
     filter_min_length(Tail, Min, ExcList, List).          %va avanti
filter_min_length([Head|Tail], Min, ExcList, [Head|List]) :-
     member(Head, ExcList),                                %è un'eccezione
     !,                                                    %taglia
     filter_min_length(Tail, Min, ExcList, List).          %va avanti
filter_min_length([_|Tail], Min, ExcList, List) :-
     filter_min_length(Tail, Min, ExcList, List).          %nessuno dei due casi, non include l'atomo e va avanti
filter_min_length([], _, _, []).


%%%%%%%%% flatten(+List, ?Flattened)
%%%%%%%%% Unifica la variabile Flattened con la lista List appiattita.
flatten(List, Flattened) :- 
     flatten_(List, [], Flattened).           %predicato ausiliario
flatten_([Head|Tail], Accumulator, Flattened) :-
     flatten_(Tail, Accumulator, A),          %appiattisce la coda della lista
     flatten_(Head, A, Flattened).            %appiattisce il primo elemento
flatten_(Head, Tail, [Head|Tail]) :-          %aggiungo alla lista appiattita se
     integer(Head).                           %Head non è una lista ma un intero
flatten_(Head, Tail, [Head|Tail]) :-
     atom(Head),                              %oppure un atomo
     Head\=[].                                %diverso dalla lista vuota
flatten_([], Flattened, Flattened).



%%%%%%%%% get_glosses_from_context(+Context, ?List)
%%%%%%%%% Unifica la variabile List con la concatenazione delle definizioni dei sensi delle parole contenute nella lista Context.
get_glosses_from_context([Head|Tail], List) :-
     get_glosses_from_w(Head, G),                 %trova le definizioni della parola
     get_glosses_from_context(Tail, L1),          %calcola le definizioni della coda
     append(G, L1, List).                         %concatena la definizione con quelle della coda
get_glosses_from_context([], []).


%%%%%%%%% get_glosses_from_s(+Synset, ?Glosses)
%%%%%%%%% Unifica la variabie Glosses con la concatenazione delle definizioni del synset Synset e delle definizioni dei synset in relazione ad esso.
get_glosses_from_s(Synset, Glosses) :-
     g(Synset, G),                                                                                 %recupera la definizione del synset
     atom_codes(G, L),                                                                             %trasforma la definizione in una lista di caratteri
     tokenize(L, LG),                                                                              %trasforma la lista di caratteri in una lista di parole
     findall(T1, (hyp(Synset, H1), g(H1, G1), atom_codes(G1, A1), tokenize(A1, T1)), L1),          %recupera le definizioni degli iperonimi
     findall(T2, (hyp(H2, Synset), g(H2, G2), atom_codes(G2, A2), tokenize(A2, T2)), L2),          %recupera le definizioni degli iponimi
     findall(T3, (mm(Synset, M1), g(M1, G3), atom_codes(G3, A3), tokenize(A3, T3)), L3),           %recupera le definizioni degli olonimi
     findall(T4, (mm(M2, Synset), g(M2, G4), atom_codes(G4, A4), tokenize(A4, T4)), L4),           %recupera le definizioni degli meronimi
     findall(T5, (sim(Synset, S1), g(S1, G5), atom_codes(G5, A5), tokenize(A5, T5)), L5),          %recupera le definizioni dei simili
     flatten([LG,L1,L2,L3,L4,L5], Glosses).                                                        %concatena tutte le definizioni                                                          


%%%%%%%%% get_glosses_from_w(+Word, ?Glosses)
%%%%%%%%% Unifica la variabile Glosses con la concatenazione dell'insieme delle definizioni per la parola Word.
get_glosses_from_w(Word, Glosses) :-
     findall(G, (s(S,_,Word,_,_,_), get_glosses_from_s(S, G)), L),          %recupera le definizioni della parola
     flatten(L, Glosses).                                                   %appiattisce la lista


%%%%%%%%% max_score(+List, ?Synset, ?Value)
%%%%%%%%% Unifica la variabile Value con il valore massimo della lista di risultati List e Synset con il synset associato.
max_score(List, Synset, Value) :-
     max_score_(0, 0, List, Synset, Value).                                         %predicato ausiliario
max_score_(OldSynset, OldValue, [score(_, Value)], OldSynset, OldValue) :-          %ultimo elemento
     OldValue > Value,                                                              %il valore precedente è maggiore di quello dell'elemento attuale della lista
     !.                                                                             %taglia, mantiene il valore precedente
max_score_(_, OldValue, [score(Synset, Value)], Synset, Value) :-                   %ultimo elemento
     OldValue =< Value,                                                             %il valore precedente è minore o uguale a quello dell'elemento attuale della lista
     !.                                                                             %taglia, accetta il valore attuale
max_score_(OldSynset, OldValue, [score(_, Value)|Tail], Synset2, Value2) :-         %più elementi nella lista
     OldValue > Value,                                                              %il valore precedente è maggiore di quello dell'elemento attuale della lista
     max_score_(OldSynset, OldValue, Tail, Synset2, Value2),                        %va avanti con il valore precedente
     !.                                                                             %taglia
max_score_(_, OldValue, [score(Synset, Value)|Tail], Synset2, Value2) :-            %più elementi nella lista
     OldValue =< Value,                                                             %il valore precedente è minore o uguale a quello dell'elemento attuale della lista
     max_score_(Synset, Value, Tail, Synset2, Value2).                              %va avanti con il valore attuale
     
     
%%%%%%%%% not(+Goal)
%%%%%%%%% Implementa la negazione.
not(Goal) :-
     Goal,           %il goal esiste?
     !,              %taglia
     fail.           %fallisce
not(_).              %se non esiste, allora il predicato ha successo


%%%%%%%%% part_of_speech(+Synset, ?Pos)
%%%%%%%%% Unifica la variabile Pos con l'indicazione della parte del discorso relativa al synset Synset.
part_of_speech(Synset, noun) :-
     number_codes(Synset, [H|_]),          %recupera il primo carattere del numero di synset
     1 is H - "0",                         %è un 1
     !.                                    %taglia, è un sostantivo
part_of_speech(Synset, verb) :-
     number_codes(Synset, [H|_]),          %recupera il primo carattere del numero di synset
     2 is H - "0",                         %è un 2
     !.                                    %taglia, è un verbo
part_of_speech(Synset, adjective) :-
     number_codes(Synset, [H|_]),          %recupera il primo carattere del numero di synset
     3 is H - "0",                         %è un 3
     !.                                    %taglia, è un aggettivo
part_of_speech(Synset, adverb) :-
     number_codes(Synset, [H|_]),          %recupera il primo carattere del numero di synset
     4 is H - "0",                         %è un 4
     !.                                    %taglia, è un avverbio


%%%%%%%%% present_synsets_list(+List, ?Present)
%%%%%%%%% Unifica la variabile Present con la lista delle parole presenti in WordNet.
present_synsets_list([Head|Tail], [Head|List]) :-
     s(_,_,Head,_,_,_),                         %la parola è presente
     !,                                         %taglia
     present_synsets_list(Tail, List).          %va avanti aggiungendo la parola al risultato
present_synsets_list([_|Tail], List) :-
     present_synsets_list(Tail, List).          %non è presente, va avanti senza includere la parola nel risultato
present_synsets_list([], []).


%%%%%%%%% score(+WordGloss, +Context, +ContextGlosses, +Text, ?Value)
%%%%%%%%% Calcola in Value il valore di bontà di un senso a partire dalla sua definizione, il suo contesto, le definizioni del contesto e il testo.
score(WordGloss, Context, ContextGlosses, Value) :-
     score_(WordGloss, ContextGlosses, V1),          %conta quante parole della definizione della parola da disambiguare stanno nelle definizioni delle parole del contesto
     score_(Context, WordGloss, V2),                 %conta quante parole del contesto stanno nella definizione della parola da disambiguare
     wg_into_cg_weight(F1),                          %recupera il settaggio del primo coefficiente
     c_into_wg_weight(F2),                           %recupera il settaggio del secondo coefficiente
     Value is V1*F1 + V2*F2.                         %calcola il valore finale
score_([Head|Tail], List, Value) :- 
     score_(Tail, List, V1),                         %conta le occorrenze degli atomi di Tail nella lista List
     count_occurrences(Head, List, V2),              %conta le occorrenze del primo elemento nella lista List
     Value is V1 + V2.                               %somma i due valori
score_([], _, 0).


%%%%%%%%% set_c_into_wg_weight(+Num)
%%%%%%%%% Imposta a Num il coefficiente del secondo criterio di valutazione del predicato score/5.
set_c_into_wg_weight(Num) :-
     number(Num),                              %deve essere un numero
     retractall(c_into_wg_weight(_)),          %elimina l'impostazione precedente
     assert(c_into_wg_weight(Num)).            %imposta il nuovo valore


%%%%%%%%% set_context_window(+Int)
%%%%%%%%% Imposta ad Int la finestra di contesto per la disambiguazione.
set_context_window(Int) :-
     integer(Int),                           %deve essere un intero
     retractall(context_window(_)),          %elimina l'impostazione precedente
     assert(context_window(Int)).            %imposta il nuovo valore


%%%%%%%%% set_min_length(+Int)
%%%%%%%%% Imposta ad Int la lunghezza minima delle parole nella disambiguazione.
set_min_length(Int) :-
     integer(Int),                       %deve essere un intero
     retractall(min_length(_)),          %elimina l'impostazione precedente
     assert(min_length(Int)).            %imposta il nuovo valore


%%%%%%%%% set_wg_into_cg_weight(+Num)
%%%%%%%%% Imposta a Num il coefficiente del primo criterio di valutazione del predicato score/5.
set_wg_into_cg_weight(Num) :-
     number(Num),                               %deve essere un numero
     retractall(wg_into_cg_weight(_)),          %elimina l'impostazione precedente
     assert(wg_into_cg_weight(Num)).            %imposta il nuovo valore


%%%%%%%%% set_wg_into_t_weight(+Num)
%%%%%%%%% Imposta a Num il coefficiente del terzo criterio di valutazione del predicato score/5.
set_wg_into_t_weight(Num) :-
     number(Num),                              %deve essere un numero
     retractall(wg_into_t_weight(_)),          %elimina l'impostazione precedente
     assert(wg_into_t_weight(Num)).            %imposta il nuovo valore
