%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                                                                                              %
%                                                              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...                                                          %
%                                                                                                                                              %
%         Fabrizio Larosa                                                                                                                      %
%                                                                                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

:- use_module(library(lists)).


%%%%%%%%%%%%%%%%%%%%%%%%%%% Settings %%%%%%%%%%%%%%%%%%%%%%%%%%%

relations_limit(3).


%%%%%%%%%%%%%%%%%%%%%%%%%% Parameters %%%%%%%%%%%%%%%%%%%%%%%%%%

boolean(true).
boolean(false).
relation(hyponymy).
relation(hypernymy).
relation(meronymy).
relation(holonymy).
relation(similarity).


%%%%%%%%%%%%%%%%%%%%%%%%%% Predicates %%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%% assert(+List)
%%%%%%%%% Asserisce ogni elemento della lista List assicurandosi che l'elemento non sia già asserito.
assert_list([Head|Tail]) :-
     clause(Head, _),                %controlla l'esistenza di una clausola che unifichi con Head per evitare errori di esistenza
     Head,                           %già asserito? va avanti senza fare niente
     !,                              %taglia
     assert_list(Tail).              %va avanti
assert_list([Head|Tail]) :-          %qui, grazie all'operatore cut, sa che Head non è già asserito
     assert(Head),                   %asserisce
     assert_list(Tail).              %va avanti
assert_list([]).
     

%%%%%%%%% get_last(+List, ?Elem)
%%%%%%%%% Unifica la variabile Elem con l'ultimo elemento della lista List.
get_last([Head], Head) :-            %se è la lista formata da un solo elemento 
     !.                              %taglia, ha finito
get_last([_|Tail], List) :-          %altrimenti
     get_last(Tail, List).           %va avanti calcolando l'ultimo elemento della sottolista Tail
     

%%%%%%%%% get_semantic_portion(+T)
%%%%%%%%% Asserisce la rete semantica diretta delle parole nella lista T.
get_semantic_portion(T) :- 
     clean,                                                    
     load_wn(s),                                                               %carica 'wn_s.pl'
     recognize_words(T, N),                                                    %effettua il riconoscimento di plurali e verbi coniugati
     remove_duplicates(N, R),                                                  %rimuove le parole doppie
     load_wn(hyp),                                                             %carica 'wn_hyp.pl'
     extract_r_hypernym(R),                                                    %asserisce gli iperonimi diretti come predicati 'ext_hyp/2'
     extract_r_hyponym(R),                                                     %asserisce gli iponimi diretti come predicati 'ext_hyp/2'
     unload_wn(hyp),                                                           %toglie dalla tabella degli atomi i predicati 'hyp/2' del file 'wn_hyp.pl'
     rename_assertions(ext_hyp, hyp, 2),                                       %rinomina i predicati 'ext_hyp/2' in 'hyp/2'
     load_wn(mm),                                                              %carica 'wn_mm.pl'
     extract_r_meronym(R),                                                     %asserisce i meronimi diretti come predicati 'ext_mm/2'
     extract_r_holonym(R),                                                     %asserisce gli olonimi diretti come predicati 'ext_mm/2'
     unload_wn(mm),                                                            %toglie dalla tabella degli atomi i predicati 'mm/2' del file 'wn_mm.pl'
     rename_assertions(ext_mm, mm, 2),                                         %rinomina i predicati 'ext_mm/2' in 'mm/2'
     load_wn(sim),                                                             %carica 'wn_sim.pl'
     extract_r_similars(R),                                                    %asserisce i simili diretti come predicati 'ext_sim/2'
     unload_wn(sim),                                                           %toglie dalla tabella degli atomi i predicati 'sim/2' del file 'wn_sim.pl'
     rename_assertions(ext_sim, sim, 2),                                       %rinomina i predicati 'ext_sim/2' in 'sim/2'
     extract_s(R, [hypernymy,hyponymy,meronymy,holonymy,similarity]),          %asserisce i synset delle parole e delle loro relazioni come predicati 'ext_s/6'
     unload_wn(s),                                                             %toglie dalla tabella degli atomi i predicati 's/6' del file 'wn_s.pl'
     rename_assertions(ext_s, s, 6),                                           %rinomina i predicati 'ext_s/6' in 's/6'
     load_wn(g),                                                               %carica 'wn_g.pl'
     extract_g,                                                                %asserisce i gloss dei synset presenti nei predicati 's/6' della tabella degli atomi come predicati 'ext_g/2'
     unload_wn(g),                                                             %toglie dalla tabella degli atomi i predicati 'g/2' del file 'wn_g.pl'
     rename_assertions(ext_g, g, 2).                                           %rinomina i predicati 'ext_g/2' in 'g/2'
     

clean :-
        unload_wn(g), 
        retractall(g(_, _)),
        retractall(ext_g(_, _)),
	unload_wn(s),
	retractall(s(_, _, _, _, _, _)),
	retractall(ext_s(_, _, _, _, _, _)),
	unload_wn(hyp),
	retractall(hyp(_, _)),
	retractall(ext_hyp(_, _)),
	unload_wn(mm),
	retractall(mm(_, _)),  
	retractall(ext_mm(_, _)),
	unload_wn(sim),
	retractall(sim(_, _)),
	retractall(ext_sim(_, _)),
	garbage_collect_atoms. 
	
     
%%%%%%%%% extract_g
%%%%%%%%% Estrae come una serie di predicati 'ext_g/2' i gloss dei synset presenti nella tabella degli atomi.
extract_g :-
     write('-- Extracting glosses... '),                             %stampa informazione
     nl,                                                             %nuova linea
     findall(ext_g(S,G), (s(S, _, _, _, _, _), g(S,G)), L),          %crea la lista di predicati 'ext_g/2' a partire dai synset presenti
     assert_list(L).                                                 %la asserisce
     

%%%%%%%%% extract_r_holonym(+List)
%%%%%%%%% Estrae gli olonimi come una serie di predicati 'ext_mm/2' a partire dalla lista List di parole.
extract_r_holonym(List) :- 
     write('-- Extracting holonyms... '),                                                                 %stampa informazione                                                  
     nl,                                                                                                  %nuova linea
     extract_r_holonym_(List).                                                                            %predicato ausiliario
extract_r_holonym_([Head|Tail]) :-
     findall(ext_mm(Mero, Holo), (s(Mero, _, Head, _, _, _), mm(Mero, Holo), limiter(Mero)), L),          %crea la lista di predicati 'ext_mm/2' con eventuale limite di numerosità
     retractall(counter(_, _)),                                                                           %resetta il limitatore
     assert_list(L),                                                                                      %asserisce la lista
     extract_r_holonym_(Tail).                                                                            %va avanti
extract_r_holonym_([]).


%%%%%%%%% extract_r_hypernym(+List)
%%%%%%%%% Estrae gli iperonimi come una serie di predicati 'ext_hyp/2' a partire dalla lista List di parole.
extract_r_hypernym(List) :- 
     write('-- Extracting hypernyms... '),                                                                 %stampa informazione
     nl,                                                                                                   %nuova linea
     extract_r_hypernym_(List).                                                                            %predicato ausiliario
extract_r_hypernym_([Head|Tail]) :-
     findall(ext_hyp(Hypo, Hype),(s(Hypo, _, Head, _, _, _), hyp(Hypo, Hype), limiter(Hypo)), L),          %crea la lista di predicati 'ext_hyp/2' con eventuale limite di numerosità
     retractall(counter(_, _)),                                                                            %resetta il limitatore
     assert_list(L),                                                                                       %asserisce la lista
     extract_r_hypernym_(Tail).                                                                            %va avanti
extract_r_hypernym_([]).


%%%%%%%%% extract_r_hyponym(+List)
%%%%%%%%% Estrae gli iponimi come una serie di predicati 'ext_hyp/2' a partire dalla lista List di parole.
extract_r_hyponym(List) :- 
     write('-- Extracting hyponyms... '),                                                                   %stampa informazione
     nl,                                                                                                    %nuova linea
     extract_r_hyponym_(List).                                                                              %predicato ausiliario
extract_r_hyponym_([Head|Tail]) :-
     findall(ext_hyp(Hypo, Hype), (s(Hype, _, Head, _, _, _), hyp(Hypo, Hype), limiter(Hype)), L),          %crea la lista di predicati 'ext_hyp/2' con eventuale limite di numerosità
     retractall(counter(_, _)),                                                                             %resetta il limitatore
     assert_list(L),                                                                                        %asserisce la lista
     extract_r_hyponym_(Tail).                                                                              %va avanti
extract_r_hyponym_([]).


%%%%%%%%% extract_r_meronym(+List)
%%%%%%%%% Estrae i meronimi come una serie di predicati 'ext_mm/2' a partire dalla lista List di parole.
extract_r_meronym(List) :- 
     write('-- Extracting meronyms... '),                                                                 %stampa informazione
     nl,                                                                                                  %nuova linea
     extract_r_meronym_(List).                                                                            %predicato ausiliario
extract_r_meronym_([Head|Tail]) :-
     findall(ext_mm(Mero, Holo), (s(Holo, _, Head, _, _, _), mm(Mero, Holo), limiter(Holo)), L),          %crea la lista di predicati 'ext_mm/2' con eventuale limite di numerosità
     retractall(counter(_, _)),                                                                           %resetta il limitatore
     assert_list(L),                                                                                      %asserisce la lista
     extract_r_meronym_(Tail).                                                                            %va avanti
extract_r_meronym_([]).


%%%%%%%%% extract_r_similars(+List)
%%%%%%%%% Estrae i simili come una serie di predicati 'ext_sim/2' a partire dalla lista List di parole.
extract_r_similars(List) :-
     write('-- Extracting similars... '),                                                                   %stampa informazione
     nl,                                                                                                    %nuova linea
     extract_r_similars_(List).                                                                             %predicato ausiliario
extract_r_similars_([Head|Tail]) :-
     findall(ext_sim(Sim1, Sim2), (s(Sim1, _, Head, _, _, _), sim(Sim1, Sim2), limiter(Sim1)), L),          %crea la lista di predicati 'ext_sim/2' con eventuale limite di numerosità
     retractall(counter(_, _)),                                                                             %resetta il limitatore
     assert_list(L),                                                                                        %asserisce la lista
     extract_r_similars_(Tail).                                                                             %va avanti
extract_r_similars_([]).


%%%%%%%%% extract_s(+WordList, +RelationList)
%%%%%%%%% Estrae i synset come una serie di predicati 'ext_s/6' a partire dalla lista di parole WordList e la lista di relazioni RelationList.
extract_s(WordList, RelationList) :-
     write('-- Extracting synsets from words '),          %stampo informazione
     print_list(WordList),                                %stampo lista di parole
     write(' and from relations '),                       %stampo informazione
     print_list(RelationList),                            %stampo lista di relazioni
     write('...'),                                        %stampo informazione
     nl,                                                  %nuova linea
     extract_s_wl(WordList),                              %estrae i synsets delle parole
     extract_s_rl(RelationList).                          %estrae i synsets delle parole in relazione
     
     
%%%%%%%%% extract_s_r(holonymy)
%%%%%%%%% Estrae i synset dei sensi in relazione di olonimia con i synset presenti nella tabella degli atomi.
extract_s_r(holonymy) :-
     findall(ext_s(Holo,P2,P3,P4,P5,P6), (mm(_, Holo), s(Holo,P2,P3,P4,P5,P6)), L),          %crea la lista di predicati 'ext_s/6'
     assert_list(L).                                                                         %la asserisce
     
     
%%%%%%%%% extract_s_r(hypernymy)
%%%%%%%%% Estrae i synset dei sensi in relazione di iperonimia con i synset presenti nella tabella degli atomi.
extract_s_r(hypernymy) :-
     findall(ext_s(Hype,P2,P3,P4,P5,P6), (hyp(_, Hype), s(Hype,P2,P3,P4,P5,P6)), L),          %crea la lista di predicati 'ext_s/6'
     assert_list(L).                                                                          %la asserisce
     
     
%%%%%%%%% extract_s_r(hyponymy)
%%%%%%%%% Estrae i synset dei sensi in relazione di iponimia con i synset presenti nella tabella degli atomi.
extract_s_r(hyponymy) :-
     findall(ext_s(Hypo,P2,P3,P4,P5,P6), (hyp(Hypo, _), s(Hypo,P2,P3,P4,P5,P6)), L),          %crea la lista di predicati 'ext_s/6'
     assert_list(L).                                                                          %la asserisce

     
%%%%%%%%% extract_s_r(meronymy)
%%%%%%%%% Estrae i synset dei sensi in relazione di meronimia con i synset presenti nella tabella degli atomi.
extract_s_r(meronymy) :-
     findall(ext_s(Mero,P2,P3,P4,P5,P6), (mm(Mero, _), s(Mero,P2,P3,P4,P5,P6)), L),          %crea la lista di predicati 'ext_s/6'
     assert_list(L).                                                                         %la asserisce

     
%%%%%%%%% extract_s_r(similarity)
%%%%%%%%% Estrae i synset dei sensi in relazione di similarità con i synset presenti nella tabella degli atomi.
extract_s_r(similarity) :-
     findall(ext_s(Sim,P2,P3,P4,P5,P6), (sim(_, Sim), s(Sim,P2,P3,P4,P5,P6)), L),          %crea la lista di predicati 'ext_s/6'
     assert_list(L).                                                                       %la asserisce

     
%%%%%%%%% extract_s_rl(+List)
%%%%%%%%% Estrae i synset per le relazioni elencate nella lista List dei synset presenti nella tabella degli atomi.
extract_s_rl([Head|Tail]) :-
     relation(Head),              %controlla che sia un parametro valido
     extract_s_r(Head),           %estrae per la relazione Head
     extract_s_rl(Tail).          %va avanti
extract_s_rl([]).


%%%%%%%%% extract_s_wl(+List)      
%%%%%%%%% Estrae i synset dei sensi delle parole della lista List.
extract_s_wl([Head|Tail]) :-
     findall(ext_s(P1, P2, Head, P4, P5, P6), s(P1, P2, Head, P4, P5, P6), L),          %crea la lista di predicati 'ext_s/6'
     assert_list(L),                                                                    %la asserisce
     extract_s_wl(Tail).                                                                %va avanti
extract_s_wl([]).


%%%%%%%%% extract_word(+List, ?Word, ?Rest)
%%%%%%%%% Unifica la variabile Word con la prima parola estratta dalla stringa List in lowercase e la variabile Rest con la lista rimanente.
extract_word([Head|Tail], [], Tail) :-  
     Head < "A",                           %non è un carattere alfabetico
     !.                                    %taglia e unifica Word con la lista vuota e Rest con il resto della stringa
extract_word([Head|Tail], [], Tail) :-
     Head > "z",                           %non è un carattere alfabetico
     !.                                    %taglia e unifica Word con la lista vuota e Rest con il resto della stringa
extract_word([Head|Tail], [], Tail) :-
     Head > "Z",
     Head < "a",                           %non è un carattere alfabetico
     !.                                    %taglia e unifica Word con la lista vuota e Rest con il resto della stringa
extract_word([Head|Tail], Word, Rest) :-
     Head >= "A",
     Head =< "Z",                          %è un carattere alfabetico maiuscolo
     L is Head+"a"-"A",                    %rende minuscolo
     extract_word(Tail, P, Rest),          %estrae il resto della parola
     append([L], P, Word),                 %concatena il carattere con il resto della parola
     !.                                    %taglia e unifica Word con la parola trovata e Rest con la stringa senza più la parola estratta
extract_word([Head|Tail], Word, Rest) :-
     Head >= "a",
     Head =< "z",                          %è un carattere alfabetico minuscolo
     extract_word(Tail, P, Rest),          %estrae il resto della parola
     append([Head], P, Word).              %concatena il carattere con il resto della parola e unifica Word con la parola trovata e Rest con la stringa senza più la parola estratta
extract_word([], [], []).


%%%%%%%%% limiter(+Synset)
%%%%%%%%% Implementa il limitatore per il numero di relazioni asserite.
limiter(_) :-
     relations_limit(none),                         %il limite è settato a 'none'
     !.                                             %taglia, ha finito qui
limiter(Synset) :-
     clause(counter(Synset, counting), _),          %controlla che il conto sia già iniziato
     counter(Synset, N),                            %a che punto è con il conto?
     integer(N),                                    %è un intero e sto quindi ancora contando?
     N > 0,                                         %è maggiore di 0?
     !,                                             %taglia
     retract(counter(Synset, N)),                   %elimina valore precedente
     M is N - 1,                                    %decrementa
     assert(counter(Synset, M)).                    %asserisce nuovo valore decrementato
limiter(Synset) :-
     counter(Synset, 0),                            %il conto è giunto al termine
     !,                                             %taglia
     fail.                                          %fallisce il goal per questo valore di Synset
limiter(Synset) :-
     retractall(counter(_, _)),                  %nuovo Synset, elimina il conto per il Synset precedente
     relations_limit(L),                         %prende il parametro impostato dall'utente
     N is L - 1,                                 %decrementa
     assert(counter(Synset, N)),                 %salva il valore nuovo per il contatore
     assert(counter(Synset, counting)).          %inizia a contare
     

%%%%%%%%% load_wn(+Name)
%%%%%%%%% Carica il file di WordNet che contiene i predicati specificati dalla variabile Name.
load_wn(Name) :- 
     atom_codes('wn_', P1),                                  %trasforma in una lista di codici di caratteri
     atom_codes(Name, P2),                                   %trasforma in una lista di codici di caratteri                             
     atom_codes('.pl', P3),                                  %trasforma in una lista di codici di caratteri
     append(P1, P2, L1), 
     append(L1, P3, L2),                                     %costruisce il nome come lista di codici di caratteri
     atom_codes(N, L2),                                      %trasforma la lista nel nome del file come atomo
     write('-- Loading '),                                   %stampa informazione
     write(N),                                               %stampa informazione
     write('...'),                                           %stampa informazione
     nl,                                                     %nuova linea
     load_files(N, [compilation_mode(assert_all)]).          %carica il file in modalità 'assert_all' per poter cancellare successivamente i predicati


%%%%%%%%% print_list(+List)
%%%%%%%%% Stampa la lista List.
print_list(List) :-
     write('['),                 %stampa parentesi aperta
     print_list_(List),          %stampa lista con predicato ausiliario
     write(']').                 %stampa parentesi chiusa
print_list_([Head]) :-           %un solo elemento
     !,                          %taglia
     write(Head).                %lo stampa
print_list_([Head|Tail]) :-      %più elementi
     write(Head),                %stampa il primo
     write(', '),                %stampa virgola
     print_list_(Tail).          %stampa il resto della lista
print_list_([]).


%%%%%%%%% recognize_words(+Words, ?List)
%%%%%%%%% Unifica la variabile List con la lista dei singolari e dei verbi al futuro delle parole della lista Words.
recognize_words(Words, List) :-
     write('-- Recognizing words...'),          %stampa informazione
     nl,                                        %nuova linea
     recognize_words_(Words, List).             %predicato ausiliario
recognize_words_([Head|Tail], [Word|List]) :-
     word_recognition(Head, Word),              %trasforma la parola Head nel corrispondente contenuto in WordNet
     recognize_words_(Tail, List).              %va avanti
recognize_words_([], []).


%%%%%%%%% remove_last(+List, ?Result)
%%%%%%%%% Unifica la variabile Result con la lista List senza l'ultimo elemento.
remove_last([H|T], [H|L]) :-
     remove_last(T, L).          %va avanti
remove_last([_], []).            %ultimo elemento, lo scarta
     

%%%%%%%%% rename_assertions(+OldName, +NewName, +Arity)
%%%%%%%%% Rinomina tutti i predicati OldName/Arity in NewName/Arity.
rename_assertions(OldName, NewName, Arity) :- 
     write('-- Renaming '),                                %stampa informazione
     write(OldName),                                       %stampa informazione
     write('/'),                                           %stampa informazione
     write(Arity),                                         %stampa informazione
     write(' to '),                                        %stampa informazione
     write(NewName),                                       %stampa informazione
     write('/'),                                           %stampa informazione
     write(Arity),                                         %stampa informazione
     write('...'),                                         %stampa informazione
     nl,                                                   %nuova linea
     rename_assertions_(OldName, NewName, Arity).          %predicato ausiliario
rename_assertions_(OldName, NewName, Arity) :-
     functor(Test, OldName, Arity),                        %crea un termine di test con funtore OldName e arità Arity
     clause(Test, _),                                      %controlla se almeno un predicato OldName/Arity è stato asserito, se non esiste viene utilizzata l'altra regola e niente viene rinominato.
     !,                                                    %taglia
     functor(Term1, OldName, Arity),                       %crea un termine OldName/Arity
     functor(Term2, NewName, Arity),                       %crea un termine NewName/Arity
     unify_variables(Term1, Term2, Arity),                 %unifica gli argomenti dei due termini
     findall(Term2, Term1, L),                             %crea la lista dei termini rinominati
     assert_list(L),                                       %la asserisce
     retractall(Term1),                                    %cancella i termini vecchi
     garbage_collect_atoms.                                %forza pulitura della tabella degli atomi
rename_assertions_(_, _, _).

     
%%%%%%%%% set_relations_limit(+Limit)
%%%%%%%%% Imposta a Limit il valore per il limitatore di relazioni.
set_relations_limit(none) :-                  %se il valore è 'none'
     !,                                       %taglia   
     retractall(relations_limit(_)),          %elimina l'impostazione precedente
     assert(relations_limit(none)).           %imposta il nuovo valore a 'none'
set_relations_limit(Int) :-                   %se non è 'none'
     integer(Int),                            %deve essere un intero
     retractall(relations_limit(_)),          %elimina l'impostazione precedente
     assert(relations_limit(Int)).            %imposta il nuovo valore
     
     
%%%%%%%%% unify_variables(+Term1, +Term2, +Arity)
%%%%%%%%% Unifica il parametro p1[i] di Term1 con il parametro p2[i] Term2 per 1<=i<=Arity.
unify_variables(Term1, Term2, Arity) :- 
     unify_variables_(Term1, Term2, Arity, 1).             %predicato ausiliario
unify_variables_(Term1, Term2, Arity, Index) :- 
     Index =< Arity,                                       %se non ha finito
     !,                                                    %taglia                                                     
     arg(Index, Term1, Arg),                                     
     arg(Index, Term2, Arg),                               %unifica i due parametri 
     Next is Index+1,                                      %calcola l'indice successivo
     unify_variables_(Term1, Term2, Arity, Next).          %va avanti                    
unify_variables_(_,_, Arity, Index) :-
     Index > Arity.                                        %ha finito
     
     
%%%%%%%%% tokenize(+Text, ?List)
%%%%%%%%% Unifica la variabile List con la lista di parole estratte dalla lista di caratteri Text.
tokenize([Head|Tail], List) :-
     extract_word([Head|Tail], [], R),          %se estrae una lista di caratteri vuota
     !,                                         %taglia
     tokenize(R, List).                         %va avanti
tokenize([Head|Tail], [Word|List]) :-
     extract_word([Head|Tail], A, R),           %se estrae una lista di caratteri non vuota
     atom_codes(Word, A),                       %crea l'atomo a partire dalla lista di caratteri
     tokenize(R, List).                         %va avanti aggiungendo in testa al risultato la parola estratta
tokenize([], []).


%%%%%%%%% unload_wn(+Name)
%%%%%%%%% Elimina dalla tabella degli atomi i predicati WordNet aventi come nome del funtore l'argomento Name.
unload_wn(s) :-
     unload_wn_(s, 6).                 %predicato ausiliario
unload_wn(hyp) :-
     unload_wn_(hyp, 2).               %predicato ausiliario
unload_wn(mm) :-
     unload_wn_(mm, 2).                %predicato ausiliario
unload_wn(sim) :-
     unload_wn_(sim, 2).               %predicato ausiliario
unload_wn(g) :-
     unload_wn_(g, 2).                 %predicato ausiliario
unload_wn_(Name, Arity) :-
     write('-- Retracting '),          %stampa informazione
     write(Name),                      %stampa informazione
     write('/'),                       %stampa informazione
     write(Arity),                     %stampa informazione
     write('...'),                     %stampa informazione
     nl,                               %nuova linea
     functor(Term, Name, Arity),       %crea un termine con nome del funtore Name e airtà Arity
     retractall(Term),                 %cancella ogni termine che unifica con esso
     garbage_collect_atoms.		 %forza pulitura della tabella degli atomi
              


%%%%%%%%% word_recognition(+Word1, ?Word2)
%%%%%%%%% Unifica la variabile Word2 con il singolare o la coniugazione al futuro della parola lowercase Word1.
word_recognition(Word, Word) :-
     s(_,_,Word,_,_,_),                %la parola è già in WordNet
     !.                                %taglia, finito
word_recognition(Word, S) :-           %la parola non è in WordNet, termina in 'es', viene tagliato tale suffisso
     atom_chars(Word, C),              %trasforma l'atomo in una lista di codici di caratteri
     char_code(s, Code1),              %ottiene il codice del carattere 's'
     get_last(C, Code1),               %l'ultima lettera è 's'
     remove_last(C, R1),               %la toglie
     char_code(e, Code2),              %ottiene il codice del carattere 'e'
     get_last(R1, Code2),              %l'ultima lettera è 'e'
     remove_last(R1, R2),              %la toglie
     atom_chars(S, R2),                %ricostruisce l'atomo a partire dalla lista modificata
     s(_,_,S,_,_,_),                   %la nuova parola è in WordNet?
     !.                                %taglia, la nuova parola è presente in WordNet
word_recognition(Word, S) :-           %il tentativo precedente non ha avuto successo, termina in 's', viene tagliato tale suffisso
     atom_chars(Word, C),              %trasforma l'atomo in una lista di codici di caratteri
     char_code(s, Code1),              %ottiene il codice del carattere 's'
     get_last(C, Code1),               %l'ultima lettera è 's'
     remove_last(C, R1),               %la toglie
     atom_chars(S, R1),                %ricostruisce l'atomo a partire dalla lista modificata
     s(_,_,S,_,_,_),                   %la nuova parola è in WordNet?
     !.                                %taglia, la nuova parola è presente in WordNet
word_recognition(Word, S) :-           %il tentativo precedente non ha avuto successo, termina in 'ies', viene tagliato tale suffisso ed aggiunto 'y' in fondo
     atom_chars(Word, C),              %trasforma l'atomo in una lista di codici di caratteri
     char_code(s, Code1),              %ottiene il codice del carattere 's'
     get_last(C, Code1),               %l'ultima lettera è 's'
     remove_last(C, R1),               %la toglie
     char_code(e, Code2),              %ottiene il codice del carattere 'e'
     get_last(R1, Code2),              %l'ultima lettera è 'e'
     remove_last(R1, R2),              %la toglie
     char_code(i, Code3),              %ottiene il codice del carattere 'i'
     get_last(R2, Code3),              %l'ultima lettera è 'i'
     remove_last(R2, R3),              %la toglie
     char_code(y, Code4),              %ottiene il codice del carattere 'y'
     append(R3, [Code4], L),           %lo aggiunge in fondo
     atom_chars(S, L),                 %ricostruisce l'atomo a partire dalla lista modificata
     s(_,_,S,_,_,_),                   %la nuova parola è in WordNet?
     !.                                %taglia, la nuova parola è presente in WordNet
word_recognition(Word, S) :-           %il tentativo precedente non ha avuto successo, termina in 'ed', viene tagliato tale suffisso
     atom_chars(Word, C),              %trasforma l'atomo in una lista di codici di caratteri
     char_code(d, Code1),              %ottiene il codice del carattere 'd'
     get_last(C, Code1),               %l'ultima lettera è 'd'
     remove_last(C, R1),               %la toglie
     char_code(e, Code2),              %ottiene il codice del carattere 'e'
     get_last(R1, Code2),              %l'ultima lettera è 'e'
     remove_last(R1, R2),              %la toglie
     atom_chars(S, R2),                %ricostruisce l'atomo a partire dalla lista modificata
     s(_,_,S,_,_,_),                   %la nuova parola è in WordNet?
     !.                                %taglia, la nuova parola è presente in WordNet
word_recognition(Word, S) :-           %il tentativo precedente non ha avuto successo, termina in 'ied', viene tagliato tale suffisso ed aggiunto 'y' in fondo
     atom_chars(Word, C),              %trasforma l'atomo in una lista di codici di caratteri
     char_code(d, Code1),              %ottiene il codice del carattere 'd'
     get_last(C, Code1),               %l'ultima lettera è 'd'
     remove_last(C, R1),               %la toglie
     char_code(e, Code2),              %ottiene il codice del carattere 'e'
     get_last(R1, Code2),              %l'ultima lettera è 'e'
     remove_last(R1, R2),              %la toglie
     char_code(i, Code3),              %ottiene il codice del carattere 'i'
     get_last(R2, Code3),              %l'ultima lettera è 'i'
     remove_last(R2, R3),              %la toglie
     char_code(y, Code4),              %ottiene il codice del carattere 'y'
     append(R3, [Code4], L),           %lo aggiunge in fondo
     atom_chars(S, L),                 %ricostruisce l'atomo a partire dalla lista modificata
     s(_,_,S,_,_,_),                   %la nuova parola è in WordNet?
     !.                                %taglia, la nuova parola è presente in WordNet
word_recognition(Word, S) :-           %il tentativo precedente non ha avuto successo, termina in 'd', viene tagliato tale suffisso      
     atom_chars(Word, C),              %trasforma l'atomo in una lista di codici di caratteri
     char_code(d, Code1),              %ottiene il codice del carattere 'd'
     get_last(C, Code1),               %l'ultima lettera è 'd'
     remove_last(C, R1),               %la toglie
     atom_chars(S, R1),                %ricostruisce l'atomo a partire dalla lista modificata
     s(_,_,S,_,_,_),                   %la nuova parola è in WordNet?
     !.                                %taglia, la nuova parola è presente in WordNet
word_recognition(Word, Word).          %non è stato possibile riconoscere la parola, unifica con la parola non modificata
