/*
This file is part of NSM-DALIA, an extensible parser and generator
for NSM grammars.
Copyright (C) 2009 Francesco Zamblera.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
:- module(dg,[
dg_parse/3,
dg_gen/3,
dg_gen_tagm/3,
dg_parse_text_level/3,
dg_gen_text_level/3
]).
/** Dependency grammar
This module contains the routines for syntactic parsing and
generation with NSM-DALIA dependency grammars.
@tbd dg_parse_text_level/3 and dg_gen_text_level/3 implementation.
*/
:- include('operators.pl').
:- use_module(messages).
:- use_module(checkers).
:- use_module(grammar).
:- use_module(word_scanner).
:- use_module(morph_parse).
:- use_module(morph_gen).
/* SYNTACTICAL DEPENDENCY PARSER */
%% dg_parse(+Lang,+Sentence:string,-Parse) is det
%
% Parses a sentence written in language Lang according
% to the active transcription table (see module transcr.pl)
% and returns the parse in the third argument.
%
% The first word is parsed, calling
% morph_parse:generic_parse_word/7. Then, the internal
% procedure parse_dg/5 does the job.
dg_parse(Lang,Sent,ct(CT,Parse)) :-
generic_parse_word(Lang,Sent,"##",Word,[],Rest,Stack),
parse_dg(Lang,Word,Rest,Stack,ct(CT,Parse1)),
explain_idiom(Lang,Parse1,Parse),
!.
dg_parse(_,Sent,noparse(Sent)).
parse_dg(Lang,_PrevWord,[],Stack,Parse) :-
% !,
try_reduce(Lang,1,Stack,NewStack,yes),
reduce_all(Lang,1,NewStack,Parse).
parse_dg(Lang,PrevWord,Sent,Stack,Parse) :-
generic_parse_word(Lang,Sent,PrevWord,Word,Stack,Rest,Stack1),
notify_shift(Stack1),
try_reduce(Lang,1,Stack1,Stack2,no),
parse_dg(Lang,Word,Rest,Stack2,Parse).
try_reduce(Lang,Level,[W1,W2,W3,W4|Stack],NewStack,B) :-
dbl_dependency(Lang,Level,W2,W3,W4,W5,Degree),
no_dependency(Lang,Level,W1,W2,Degree),
notify_reduce(Degree,W2+W3+W4==>W5,[W1,W5|Stack]),
try_reduce(Lang,Level,[W1,W5|Stack],NewStack,B).
try_reduce(Lang,Level,[W1,W2,W3|Stack],NewStack,B) :-
dependency(Lang,Level,W2,W3,W4,Degree),
no_dependency(Lang,Level,W1,W2,Degree),
no_dbl_dependency(Lang,Level,W1,W2,W3,Degree),
notify_reduce(Degree,W3+W2==>W4,[W1,W4|Stack]),
try_reduce(Lang,Level,[W1,W4|Stack],NewStack,B).
try_reduce(Lang,Level,[W1,W2|Stack],NewStack,yes) :- %yes
dependency(Lang,Level,W1,W2,W3,Degree),
notify_reduce(Degree,W2+W1==>W3,[W3|Stack]),
try_reduce(Lang,Level,[W3|Stack],NewStack,yes).
try_reduce(Lang,Level,[W1,W2,W3|Stack],NewStack,yes) :- %yes
dbl_dependency(Lang,Level,W1,W2,W3,W5,Degree),
notify_reduce(Degree,W3+W2+W1==>W5,[W5|Stack]),
try_reduce(Lang,Level,[W5|Stack],NewStack,yes).
try_reduce(_Lang,_Level,Stack,Stack,_).
reduce_all(_Lang,_Level,[Parse],Parse) :- !.
reduce_all(Lang,Level,Stack,Parse) :-
grammar:max_dep_threshold(Lang,L),
Level < L,
NewLevel is Level + 1,
reverse(Stack,NewStack),
reparse(Lang,NewLevel,NewStack,[],Parse).
reparse(_Lang,_Level,[],[Parse],Parse) :- !.
reparse(Lang,Level,[],Stack,Parse) :-
reduce_all(Lang,Level,Stack,Parse),!.
reparse(Lang,Level,[W],Stack,Parse) :-
!,
try_reduce(Lang,Level,[W|Stack],Stack1,no),
try_reduce(Lang,Level,Stack1,Stack2,yes),
reduce_all(Lang,Level,Stack2,Parse).
reparse(Lang,Level,[W|Sent],Stack,Parse) :-
try_reduce(Lang,Level,[W|Stack],Stack1,no),
reparse(Lang,Level,Sent,Stack1,Parse).
dependency(Lang,Level,W2,W1,W3,Deg) :-
grammar:dep(Lang,Deg,W1+W2 ==> W3,C),
grammar:dep_threshold(Lang,Level,X),
Deg < X,
check_cond_list(Lang,C).
dbl_dependency(Lang,Level,W3,W2,W1,W4,Deg) :-
grammar:dep(Lang,Deg,W1+W2+W3 ==> W4,C),
grammar:dep_threshold(Lang,Level,X),
Deg < X,
check_cond_list(Lang,C).
no_dependency(Lang,_Level,W2,W1,Deg) :-
dependency(Lang,_Level1,W2,W1,_,Deg1),
!,
Deg < Deg1.
no_dependency(_,_,_,_,_).
no_dbl_dependency(Lang,Level,W3,W2,W1,Deg) :-
dbl_dependency(Lang,Level,W1,W2,W3,_W4,Deg1),
!,
Deg < Deg1.
no_dbl_dependency(_Lang,_Level,_W3,_W2,_W1,_Deg).
explain_back_idiom(Lang,ct(Cat,Parse1),ct(Cat,Parse)) :-
explain_idiom(Lang,Parse,Parse1).
explain_idiom(Lang,Parse,Parse1) :-
grammar:idiom(Lang,Parse,Parse1),
!.
explain_idiom(Lang,if(S1,S2),if(S1a,S2a)) :-
explain_idiom(Lang,S1,S1a),
explain_idiom(Lang,S2,S2a).
explain_idiom(Lang,when(S1,S2),when(S1a,S2a)) :-
explain_idiom(Lang,S1,S1a),
explain_idiom(Lang,S2,S2a).
explain_idiom(Lang,because(S1,S2),because(S1a,S2a)) :-
explain_idiom(Lang,S1,S1a),
explain_idiom(Lang,S2,S2a).
explain_idiom(Lang,like(S1,S2),like(S1a,S2a)) :-
explain_idiom(Lang,S1,S1a),
explain_idiom(Lang,S2,S2a).
explain_idiom(Lang,s(A,B,C,D,E,p(P,[R:S,prop:PROP|REST]),F,G),
s(A,B,C,D,E,p(P,[R:S,prop:PROP1|REST]),F,G)) :-
explain_idiom(Lang,PROP,PROP1).
explain_idiom(_Lang,Parse,Parse).
%% dg_parse_text_level(+Lang,-Parse,+NewParse) is det
%
% Scans a parse result for _|text-level dependencies|_.
% To be done.
%
dg_parse_text_level(_,T,T).
/*
dg_parse_text_level(Lang,T,T) :-
max_dep_threshold(Lang,Threshold),
actual_max_dep(Lang,MaxDep),
MaxDep < Threshold,
!.
dg_parse_text_level(Lang,T1,T2) :-
max_dep_threshold(Lang,Threshold),
dg_parse_text_level_aux(Lang,Threshold,T1,T2).
dg_parse_text_level_aux(Lang,Level,[S1,S2|T1],[S3,S4|T2]) :-
text_dependency(Lang,Level,S1,S2,S3+S4),
!,
dg_parse_text_level_aux(Lang,Level,T1,T2).
dg_parse_text_level_aux(Lang,Level,[S1,S2|T1],[S3|T2]) :-
text_dependency(Lang,Level,S1,S2,S3),
!,
dg_parse_text_level_aux(Lang,Level,T1,T2).
dg_parse_text_level_aux(Lang,Level,[S1|T1],[S1|T2]) :-
dg_parse_text_level_aux(Lang,Level,T1,T2).
dg_parse_text_level_aux(_,_,[],[]).
*/
/* MORPHOLOGICAL DEPENDENCY PARSER */
/* DEPENDENCY GENERATOR (MORPHOLOGICAL AND SYNTACTICAL) */
%% dg_gen(+Lang,+LF,-PF) is det
%
% Generates a sentence into language Lang, from the
% semantic representation contained in LF, and unifies the
% third argument with the generated sentence.
%
% Procedure dg_gen_aux/3 generates the sentence as a sequence
% of morphemes, which is then turned into a string by
% procedure lex_to_surf/3.
dg_gen(Lang,LF,PF) :-
explain_back_idiom(Lang,LF,LF1),
dg_gen_aux(Lang,LF1,Lex),
lex_to_surf(Lang,Lex,PF).
dg_gen_aux(Lang,ct(Cat,LF),PF) :-
lex(Lang,Cat,PF,LF),
notify_gen_found(PF),
!.
dg_gen_aux(Lang,LF,PF) :-
grammar:dep(Lang,Deg,A+B+D ==> LF,C),
check_cond_list_reverse(Lang,C),
notify_gen_pushdown(Deg,A+B+D ==> LF,C),
dg_gen_aux(Lang,A,PF1),
dg_gen_aux(Lang,B,PF2),
dg_gen_aux(Lang,D,PF3),
find_correct_boundary(Lang,Deg,A,B,Boundary1),
find_correct_boundary(Lang,Deg,B,D,Boundary2),
append(PF1,[Boundary1],NewPF1),
append(NewPF1,PF2,NewPF2),
append(NewPF2,[Boundary2],NewPF3),
append(NewPF3,PF3,PF),
notify_gen_sofar(PF).
dg_gen_aux(Lang,LF,PF) :-
grammar:dep(Lang,Deg,A+B ==> LF,C),
check_cond_list_reverse(Lang,C),
notify_gen_pushdown(Deg,A+B ==> LF,C),
dg_gen_aux(Lang,A,PF1),
dg_gen_aux(Lang,B,PF2),
find_correct_boundary(Lang,Deg,A,B,Boundary),
append(PF1,[Boundary],NewPF1),
append(NewPF1,PF2,PF),
notify_gen_sofar(PF).
/*
find_correct_boundary(Lang,_Deg,ct(Cat1,_LF1),ct(Cat2,_LF2),45) :-
grammar:arc(Lang,Cat1,Cat2),!.
*/
find_correct_boundary(Lang,Deg,_A,_B,45) :-
grammar:morph_threshold(Lang,Deg1),
Deg < Deg1,
!.
find_correct_boundary(_Lang,_Deg,_A,_B,32).
lex_to_surf(Lang,Lex,PF) :-
lex_to_surf(Lang,Lex,[],PF),!.
lex_to_surf(_Lang,[],PF,PF).
lex_to_surf(Lang,Lex,PF,ResultPF) :-
dg_get_next_word(Lex,Word,NewLex),
scan_phonemes(Lang,Word,NewWord),
append(PF,[32|NewWord],PF1),
lex_to_surf(Lang,NewLex,PF1,ResultPF).
dg_get_next_word([32|Lex],[],Lex) :- !.
dg_get_next_word([],[],[]).
dg_get_next_word([C|Lex],[C|Word],Rest) :-
dg_get_next_word(Lex,Word,Rest).
lex(Lang,Cat,PF,LF) :-
grammar:m(Lang,Cat,PF,LF),!.
lex(Lang,Cat,PF,LF) :-
grammar:dg_class_macro(Lang,Cat,Exp,LF),
grammar:m(Lang,Cat,PF,Exp).
lex(_Lang,group,[],_).
% TEXT LEVEL DEPENDENCIES (funzionano solo con traduzione, parse text,
% gen text)
%% dg_gen_text_level(+Lang,+NSMFormulas,-NewNSMFormulas) is det
%
% Scans a formula for _|text-level dependencies|_ before generation.
% To be done.
%
dg_gen_text_level(_,T,T).
/*
% prima clausola: so non ho dipendenze di livello testo,
% inutile fare lo scanning
dg_gen_text_level(Lang,T,T) :-
max_dep_threshold(Lang,Threshold),
actual_max_dep(Lang,MaxDep),
MaxDep < Threshold,
!.
dg_gen_text_level(Lang,T1,T2) :-
max_dep_threshold(Lang,Threshold),
dg_gen_text_level_aux(Lang,Threshold,T1,T2).
dg_gen_text_level_aux(Lang,Level,[S1,S2|T1],[S3,S4|T2]) :-
text_dependency(Lang,Level,S3,S4,S1+S2),
!,
dg_gen_text_level_aux(Lang,Level,T1,T2).
dg_gen_text_level_aux(Lang,Level,[S3|T1],[S1,S2|T2]) :-
text_dependency(Lang,Level,S1,S2,S3),
!,
dg_gen_text_level_aux(Lang,Level,T1,T2).
dg_gen_text_level_aux(Lang,Level,[S1|T1],[S1|T2]) :-
dg_gen_text_level_aux(Lang,Level,T1,T2).
dg_gen_text_level_aux(_,_,[],[]).
*/
text_dependency(Lang,Level,S1,S2,S3) :-
grammar:dep(Lang,Deg,S1+S2==>S3,C),
check_cond_list(Lang,C),
Deg >= Level.
/* SYNTACTICAL DEPENDENCY GENERATOR for MORPHOLOGICAL TAGMEMIC GRAMMAR */
%% dg_gen_tagm(+Lang,+LF,-PF) is det
%
% Syntactic generator for tagmemic grammars.
% To be revised.
%
dg_gen_tagm(Lang,LF,PF) :-
dg_gen_tagm_aux(Lang,LF,Lex),
tm_morph_gen_sent(Lang,Lex,PF).
dg_gen_tagm_aux(Lang,ct(Cat,LF),[m(Cat,LF)]) :-
grammar:morph_synt(Lang,Cat,_Tagmeme,LF,_C),
!.
dg_gen_tagm_aux(Lang,LF,Lex) :-
grammar:dep(Lang,_Deg,A+B ==> LF,C),
check_cond_list_reverse(Lang,C),
dg_gen_tagm_aux(Lang,A,Lex1),
dg_gen_tagm_aux(Lang,B,Lex2),
append(Lex1,Lex2,Lex).