| %****************************************************************************** | |
| % COPTIC_DEPENDENCY_RULES.PL - Prolog Dependency Grammar for Coptic | |
| %****************************************************************************** | |
| % | |
| % This module demonstrates the adaptation from DCG (DETECT5.PRO style) | |
| % to modern dependency grammar formalism. | |
| % | |
| % PARADIGM SHIFT: | |
| % DCG: sentence --> NP, VP. (hierarchical constituents) | |
| % Dependency: dep(verb, subject, nsubj). (head-dependent relations) | |
| % | |
| % Based on Universal Dependencies annotation scheme adapted for Coptic | |
| % linguistic patterns (VSO word order, tripartite sentences, etc.) | |
| % | |
| % Author: Adapted from DETECT5.PRO (André Linden, 1989-91) | |
| % Date: 2025 | |
| % | |
| %****************************************************************************** | |
| :- module(coptic_dependency_rules, [ | |
| dependency_pattern/3, | |
| validate_dependency/4, | |
| suggest_parse/3, | |
| apply_dependency_rules/3 | |
| ]). | |
| :- ensure_loaded(coptic_lexicon). | |
| %****************************************************************************** | |
| % CORE DEPENDENCY PATTERNS | |
| %****************************************************************************** | |
| % Pattern 1: VSO Transitive Sentence | |
| % Example: ⲥⲱⲧⲙ ⲡⲣⲱⲙⲉ ⲡϣⲁϫⲉ (hear the-man the-word = "The man hears the word") | |
| % | |
| % Dependency structure: | |
| % ⲥⲱⲧⲙ (VERB, root) | |
| % ├── ⲡⲣⲱⲙⲉ (NOUN, nsubj) | |
| % └── ⲡϣⲁϫⲉ (NOUN, obj) | |
| % | |
| dependency_pattern(vso_transitive, | |
| Words, | |
| [dep(Subj, SubjPOS, SIdx, Verb, VIdx, nsubj), | |
| dep(Obj, ObjPOS, OIdx, Verb, VIdx, obj)]) :- | |
| % Verb at position VIdx | |
| nth1(VIdx, Words, word(Verb, VerbPOS, _)), | |
| member(VerbPOS, ['VERB', 'AUX']), | |
| % Subject at position SIdx | |
| nth1(SIdx, Words, word(Subj, SubjPOS, _)), | |
| member(SubjPOS, ['NOUN', 'PRON', 'PROPN']), | |
| % Object at position OIdx | |
| nth1(OIdx, Words, word(Obj, ObjPOS, _)), | |
| member(ObjPOS, ['NOUN', 'PRON', 'PROPN']), | |
| % VSO word order constraint (crucial for Coptic!) | |
| VIdx < SIdx, | |
| SIdx < OIdx, | |
| % Verify verb is transitive | |
| is_transitive(Verb). | |
| % Pattern 2: VS Intransitive Sentence | |
| % Example: ⲃⲱⲕ ⲡⲣⲱⲙⲉ (go the-man = "The man goes") | |
| % | |
| dependency_pattern(vs_intransitive, | |
| Words, | |
| [dep(Subj, SubjPOS, SIdx, Verb, VIdx, nsubj)]) :- | |
| % Verb | |
| nth1(VIdx, Words, word(Verb, VerbPOS, _)), | |
| member(VerbPOS, ['VERB', 'AUX']), | |
| % Subject | |
| nth1(SIdx, Words, word(Subj, SubjPOS, _)), | |
| member(SubjPOS, ['NOUN', 'PRON', 'PROPN']), | |
| % VS word order | |
| VIdx < SIdx, | |
| % Verify verb is intransitive | |
| is_intransitive(Verb). | |
| % Pattern 3: Tripartite Nominal Sentence | |
| % Example: ⲁⲛⲟⲕ ⲡⲉ ⲡⲛⲟⲩⲧⲉ (I am the-god = "I am God") | |
| % | |
| % Structure: Subject + Copula + Predicate | |
| % In UD: Predicate is head, Subject and Copula depend on it | |
| % | |
| % ⲡⲛⲟⲩⲧⲉ (NOUN, root) | |
| % ├── ⲁⲛⲟⲕ (PRON, nsubj) | |
| % └── ⲡⲉ (AUX, cop) | |
| % | |
| dependency_pattern(tripartite, | |
| Words, | |
| [dep(Subj, SubjPOS, SIdx, Pred, PIdx, nsubj), | |
| dep(Cop, 'AUX', CIdx, Pred, PIdx, cop)]) :- | |
| % Subject (first position, typically) | |
| nth1(SIdx, Words, word(Subj, SubjPOS, _)), | |
| member(SubjPOS, ['NOUN', 'PRON', 'PROPN']), | |
| % Copula (ⲡⲉ, ⲧⲉ, ⲛⲉ) | |
| nth1(CIdx, Words, word(Cop, 'AUX', _)), | |
| member(Cop, ['ⲡⲉ', 'ⲧⲉ', 'ⲛⲉ']), | |
| % Predicate (nominal or adjectival) | |
| nth1(PIdx, Words, word(Pred, PredPOS, _)), | |
| member(PredPOS, ['NOUN', 'ADJ', 'PROPN']), | |
| % Typical order: S - Cop - Pred (but can vary) | |
| SIdx < PIdx, | |
| % Gender/number agreement between copula and predicate | |
| copula_agrees_with_predicate(Cop, Pred). | |
| % Pattern 4: Converted Tripartite (Predicate-Subject-Copula) | |
| % Example: ⲡⲛⲟⲩⲧⲉ ⲁⲛⲟⲕ ⲡⲉ (God I am = "I am God" - emphatic) | |
| % | |
| dependency_pattern(tripartite_converted, | |
| Words, | |
| [dep(Subj, SubjPOS, SIdx, Pred, PIdx, nsubj), | |
| dep(Cop, 'AUX', CIdx, Pred, PIdx, cop)]) :- | |
| nth1(PIdx, Words, word(Pred, PredPOS, _)), | |
| member(PredPOS, ['NOUN', 'ADJ', 'PROPN']), | |
| nth1(SIdx, Words, word(Subj, SubjPOS, _)), | |
| member(SubjPOS, ['NOUN', 'PRON', 'PROPN']), | |
| nth1(CIdx, Words, word(Cop, 'AUX', _)), | |
| member(Cop, ['ⲡⲉ', 'ⲧⲉ', 'ⲛⲉ']), | |
| % Converted order: Pred before Subj | |
| PIdx < SIdx, | |
| copula_agrees_with_predicate(Cop, Pred). | |
| % Pattern 5: Determiner + Noun | |
| % Example: ⲡⲣⲱⲙⲉ (the-man) | |
| % | |
| % In Coptic, articles often attach as prefixes, but in tokenized form: | |
| % ⲡⲣⲱⲙⲉ | |
| % ├── ⲡ (DET, det) | |
| % | |
| dependency_pattern(determiner_noun, | |
| Words, | |
| [dep(Det, 'DET', DIdx, Noun, NIdx, det)]) :- | |
| nth1(DIdx, Words, word(Det, 'DET', _)), | |
| nth1(NIdx, Words, word(Noun, 'NOUN', _)), | |
| % Determiner precedes noun in Coptic | |
| DIdx < NIdx, | |
| % Adjacent or nearly adjacent | |
| NIdx - DIdx =< 2, | |
| % Gender agreement | |
| determiner_gender_agrees(Det, Noun). | |
| % Pattern 6: Adjective Modification | |
| % Example: ⲡⲣⲱⲙⲉ ⲛⲁⲛⲟⲩϥ (the-man good = "the good man") | |
| % | |
| % In Coptic, adjectives typically follow nouns | |
| % ⲣⲱⲙⲉ (NOUN) | |
| % └── ⲛⲁⲛⲟⲩϥ (ADJ, amod) | |
| % | |
| dependency_pattern(noun_adjective, | |
| Words, | |
| [dep(Adj, 'ADJ', AIdx, Noun, NIdx, amod)]) :- | |
| nth1(NIdx, Words, word(Noun, 'NOUN', _)), | |
| nth1(AIdx, Words, word(Adj, 'ADJ', _)), | |
| % Coptic: Adjective follows noun (typically) | |
| NIdx < AIdx, | |
| % Should be adjacent or nearly so | |
| AIdx - NIdx =< 2, | |
| % Gender/number agreement | |
| adjective_agrees(Adj, Noun). | |
| % Pattern 7: Prepositional Phrase | |
| % Example: ϩⲛ ⲧⲡⲟⲗⲓⲥ (in the-city) | |
| % | |
| % ⲧⲡⲟⲗⲓⲥ (NOUN, head in larger structure) | |
| % ├── ϩⲛ (ADP, case) | |
| % | |
| dependency_pattern(prepositional_phrase, | |
| Words, | |
| [dep(Prep, 'ADP', PIdx, Noun, NIdx, case)]) :- | |
| nth1(PIdx, Words, word(Prep, 'ADP', _)), | |
| nth1(NIdx, Words, word(Noun, NounPOS, _)), | |
| member(NounPOS, ['NOUN', 'PRON', 'PROPN']), | |
| % Preposition before noun | |
| PIdx < NIdx, | |
| % Adjacent | |
| NIdx - PIdx =< 2. | |
| % Pattern 8: Conjunction | |
| % Example: ⲡⲣⲱⲙⲉ ⲙⲛ ⲧⲉϣⲓⲙⲉ (the-man and the-woman) | |
| % | |
| dependency_pattern(coordination, | |
| Words, | |
| [dep(Conj, 'CCONJ', CIdx, Head, HIdx, cc), | |
| dep(Coord2, Coord2POS, C2Idx, Head, HIdx, conj)]) :- | |
| nth1(HIdx, Words, word(Head, HeadPOS, _)), | |
| member(HeadPOS, ['NOUN', 'VERB', 'ADJ']), | |
| nth1(CIdx, Words, word(Conj, 'CCONJ', _)), | |
| nth1(C2Idx, Words, word(Coord2, Coord2POS, _)), | |
| Coord2POS = HeadPOS, % Same POS as head | |
| % Order: Head < Conj < Coord2 | |
| HIdx < CIdx, | |
| CIdx < C2Idx. | |
| %****************************************************************************** | |
| % CONSTRAINT CHECKING | |
| %****************************************************************************** | |
| % Check if verb is transitive (requires object) | |
| is_transitive(Verb) :- | |
| coptic_verb(Verb, Features), | |
| member(transitive, Features), !. | |
| is_transitive(_). % Default: assume transitive if unknown | |
| % Check if verb is intransitive (no object) | |
| is_intransitive(Verb) :- | |
| coptic_verb(Verb, Features), | |
| member(intransitive, Features), !. | |
| is_intransitive(_). % Default: allow intransitive | |
| % Copula-predicate agreement | |
| copula_agrees_with_predicate(Cop, Pred) :- | |
| coptic_noun(Pred, Gender, Number), !, | |
| copula_form(Cop, Gender, Number). | |
| copula_agrees_with_predicate(_, _). % Allow if not in lexicon | |
| copula_form('ⲡⲉ', masc, sing). | |
| copula_form('ⲧⲉ', fem, sing). | |
| copula_form('ⲛⲉ', _, plur). | |
| copula_form('ⲛⲉ', masc, plur). | |
| copula_form('ⲛⲉ', fem, plur). | |
| % Determiner-noun gender agreement | |
| determiner_gender_agrees(Det, Noun) :- | |
| coptic_noun(Noun, Gender, Number), !, | |
| determiner_form(Det, Gender, Number). | |
| determiner_gender_agrees(_, _). % Allow if not in lexicon | |
| determiner_form('ⲡ', masc, sing). | |
| determiner_form('ⲧ', fem, sing). | |
| determiner_form('ⲛ', _, plur). | |
| determiner_form('ⲟⲩ', _, _). % Indefinite: any gender/number | |
| % Adjective-noun agreement | |
| adjective_agrees(Adj, Noun) :- | |
| coptic_noun(Noun, Gender, Number), | |
| coptic_adjective(Adj, Gender, Number), !. | |
| adjective_agrees(_, _). % Allow if not in lexicon | |
| %****************************************************************************** | |
| % VALIDATION AND ERROR DETECTION | |
| %****************************************************************************** | |
| % validate_dependency(+Token, +Head, +Relation, +Words) | |
| % Check if a proposed dependency is valid according to Coptic grammar | |
| validate_dependency(Token, Head, Relation, Words) :- | |
| % Find positions | |
| nth1(TokenIdx, Words, word(Token, TokenPOS, _)), | |
| nth1(HeadIdx, Words, word(Head, HeadPOS, _)), | |
| % Check if relation is valid for this POS pair | |
| valid_relation(TokenPOS, HeadPOS, Relation), | |
| % Check linguistic constraints | |
| check_constraints(Token, TokenPOS, TokenIdx, Head, HeadPOS, HeadIdx, Relation, Words). | |
| % Valid dependency relations (simplified from UD) | |
| valid_relation('NOUN', 'VERB', nsubj). | |
| valid_relation('PRON', 'VERB', nsubj). | |
| valid_relation('PROPN', 'VERB', nsubj). | |
| valid_relation('NOUN', 'VERB', obj). | |
| valid_relation('PRON', 'VERB', obj). | |
| valid_relation('NOUN', 'NOUN', nmod). | |
| valid_relation('ADJ', 'NOUN', amod). | |
| valid_relation('DET', 'NOUN', det). | |
| valid_relation('ADP', 'NOUN', case). | |
| valid_relation('ADP', 'PRON', case). | |
| valid_relation('AUX', 'NOUN', cop). | |
| valid_relation('AUX', 'ADJ', cop). | |
| valid_relation('CCONJ', 'NOUN', cc). | |
| valid_relation('CCONJ', 'VERB', cc). | |
| valid_relation(_, _, root). % Root can be anything | |
| % Constraint checking | |
| check_constraints(_Token, _TokenPOS, TokenIdx, _Head, HeadPOS, HeadIdx, Relation, _Words) :- | |
| % Word order constraints | |
| ( Relation = nsubj, | |
| member(HeadPOS, ['VERB', 'AUX']) | |
| -> % In VSO, subject follows verb | |
| TokenIdx > HeadIdx | |
| ; true | |
| ), | |
| ( Relation = obj, | |
| HeadPOS = 'VERB' | |
| -> % Object follows subject in VSO | |
| TokenIdx > HeadIdx | |
| ; true | |
| ), | |
| ( Relation = det | |
| -> % Determiner precedes noun | |
| TokenIdx < HeadIdx | |
| ; true | |
| ), | |
| ( Relation = amod | |
| -> % Adjective typically follows noun in Coptic | |
| TokenIdx > HeadIdx | |
| ; true | |
| ). | |
| %****************************************************************************** | |
| % PARSING WITH DEPENDENCY RULES | |
| %****************************************************************************** | |
| % suggest_parse(+Words, +POSTags, -Dependencies) | |
| % Use dependency rules to suggest a parse | |
| suggest_parse(Words, POSTags, Dependencies) :- | |
| % Build word structures | |
| length(Words, N), | |
| build_word_list(Words, POSTags, 1, N, WordList), | |
| % Try to match patterns | |
| findall(Deps, dependency_pattern(_, WordList, Deps), AllDeps), | |
| % Combine non-overlapping dependencies | |
| flatten(AllDeps, FlatDeps), | |
| sort(FlatDeps, Dependencies). | |
| build_word_list([], [], _, _, []). | |
| build_word_list([W|Ws], [P|Ps], Idx, N, [word(W, P, Idx)|Rest]) :- | |
| NextIdx is Idx + 1, | |
| build_word_list(Ws, Ps, NextIdx, N, Rest). | |
| % apply_dependency_rules(+Tokens, +POSTags, -ParseTree) | |
| % Full parsing using dependency rules | |
| apply_dependency_rules(Tokens, POSTags, ParseTree) :- | |
| suggest_parse(Tokens, POSTags, Dependencies), | |
| % Find root | |
| ( select(dep(Root, RootPOS, RootIdx, _, 0, root), Dependencies, OtherDeps) | |
| -> true | |
| ; % No root found - pick first verb or noun | |
| nth1(RootIdx, POSTags, RootPOS), | |
| member(RootPOS, ['VERB', 'NOUN', 'AUX']), | |
| nth1(RootIdx, Tokens, Root), | |
| OtherDeps = Dependencies | |
| ), | |
| ParseTree = dep_tree{ | |
| root: Root, | |
| root_pos: RootPOS, | |
| root_index: RootIdx, | |
| dependencies: OtherDeps, | |
| parser: 'Dependency Rules' | |
| }. | |
| %****************************************************************************** | |
| % COMPARISON: DCG vs DEPENDENCY | |
| %****************************************************************************** | |
| % EXAMPLE: How DETECT5.PRO might have encoded a rule | |
| % | |
| % DCG Style (old): | |
| % sentence --> verb_phrase. | |
| % verb_phrase --> verb(V, trans), noun_phrase(Subj), noun_phrase(Obj), | |
| % {vso_order(V, Subj, Obj)}. | |
| % noun_phrase --> determiner(D), noun(N), {gender_agrees(D, N)}. | |
| % | |
| % Dependency Style (new): | |
| % dependency_pattern(vso, | |
| % [verb(V, VIdx), noun(S, SIdx), noun(O, OIdx)], | |
| % [dep(S, SIdx, V, VIdx, nsubj), | |
| % dep(O, OIdx, V, VIdx, obj)]) :- | |
| % VIdx < SIdx, SIdx < OIdx. | |
| % | |
| % KEY DIFFERENCES: | |
| % 1. DCG builds hierarchical structure (VP contains NPs) | |
| % 2. Dependency expresses direct relations (verb governs subject) | |
| % 3. Dependency is more flexible for free word order | |
| % 4. Dependency better matches modern neural parser output | |
| %****************************************************************************** | |
| % END OF MODULE | |
| %****************************************************************************** | |