Difference between revisions of "Ambiguity resolution"

From LING073
Jump to: navigation, search
(→‎Calculating ambiguity)
(→‎The structure of lrx files)
Line 197: Line 197:
 
An <code>lrx</code> file is written in xml.  It consists of a list of rules surrounded by {{tag|rules}}<code>...</code>{{tag|/rules}}.  Each {{tag|rule}}<code>...</code>{{tag|rule}} block contains some combination of {{tag|match}}{{tag|select ... /}}{{tag|/match}} blocks and {{tag|match .../}} blocks.  {{tag|match ...}} tags can contain attributes like <code>lemma=""</code> and <code>tags=""</code>.  Multiple {{tag|match .../}} blocks may be included within {{tag|or}}<code>...</code>{{tag|/or}} so that multiple rules don't have to be written in cases of multiple matching criteria.
 
An <code>lrx</code> file is written in xml.  It consists of a list of rules surrounded by {{tag|rules}}<code>...</code>{{tag|/rules}}.  Each {{tag|rule}}<code>...</code>{{tag|rule}} block contains some combination of {{tag|match}}{{tag|select ... /}}{{tag|/match}} blocks and {{tag|match .../}} blocks.  {{tag|match ...}} tags can contain attributes like <code>lemma=""</code> and <code>tags=""</code>.  Multiple {{tag|match .../}} blocks may be included within {{tag|or}}<code>...</code>{{tag|/or}} so that multiple rules don't have to be written in cases of multiple matching criteria.
  
−
Besides the additional documentation linked to above, countless examples can be found in the [https://github.com/apertium/ Apertium codebase], and some examples from class will also [https://github.swarthmore.edu/Ling073-sp26/ling073-kir-eng be posted].
+
Besides the additional documentation linked to above, countless examples can be found in the [https://github.com/apertium/ Apertium codebase], and the below example from class will also be posted.
  
 
Here is an '''example''' to try in class:
 
Here is an '''example''' to try in class:
 
* Көзүнөн жаш акты.
 
* Көзүнөн жаш акты.
 
* Анын жашын билбейм.
 
* Анын жашын билбейм.
 +
 +
'''[https://github.swarthmore.edu/Ling073-sp26/ling073-kir-eng/blob/master/apertium-kir-eng.kir-eng.lrx Here is the solution] to this in-class example.'''
  
 
=== Additional guidelines ===
 
=== Additional guidelines ===

Revision as of 15:20, 26 March 2026

There are two primary types of ambiguity that an Apertium pipeline can deal with:

  • Morphological ambiguity — when a single form has multiple analyses. The solution to this is #Morphological disambiguation.
  • Lexical ambiguity — when a single lexical item (lemma+POS+subcategory) has multiple translations. The solution to this is #Lexical selection.

Distinguishing between the two

Morphological ambiguity

Imagine you have a word that has two different tagsets, e.g.

^houses/house<n><pl>/house<v><tv><p3><sg>$
^this/this<det><dem><sg>/this<prn><dem><sg>$

Normally your analyser will randomly output ("choose") one of these. Now imagine you have a sentence where the wrong analysis is "chosen" (in this case, twice!):

^The/The<det><def>$ ^motel/motel<n><sg>$ ^houses/house<n><pl>$ ^this/this<prn><dem><sg>$ ^dog/dog<n><sg>$^./.<sent>$

In both of these examples, there is a different lemma+POS+subcategory. However, the following is also an example of morphological ambiguity:

^deer/deer<n><sg>/deer<n><pl>$

As with the previous examples, both analyses are correct output from the transducer, but which one is correct in a given context will vary. (The assumption is that one and only one analysis will be correct for a given context.)

The goal of morphological disambiguation is to choose the correct analysis in cases like these based on the surrounding words.

Lexical ambiguity

An example of lexical ambiguity is the following:

  • yard (a unit of length)
  • yard (an enclosed area)

What's different about these words? Spelling, pronunciation, part of speech? What [different] contexts might each occur in?

Can we decide which translation is right from the surrounding words?

In both cases, these two words would receive the same analysis: ^yard/yard<n><sg>$. There would likely even be only one entry in a transducer that covers both nouns. But in a bilingual dictionary, depending on the target language, you could easily need two different entries to translate these correctly. Without further mechanisms, one of the options would be "chosen" randomly during translation.

To demonstrate this point, let's take an example from Spanish-to-English translation ("Estoy en la estación de tren" = "I'm at the train station"):

^Estar<vblex><pri><p1><sg>/Be<vbser><pri><p1><sg>$ ^en<pr>/in<pr>/at<pr>/on<pr>$ ^el<det><def><f><sg>/the<det><def><f><sg>$ ^estación<n><f><sg>/season<n><sg>/station<n><sg>$ ^de<pr>/of<pr>/from<pr>$ ^tren<n><m><sg>/train<n><sg>$^.<sent>/.<sent>$

Given the output of the bilingual dictionary, this sentence could end up translated as "I'm in the train season". Given the surrounding context, however, it is possilbe to decide the correct translation alternatives.

There are two main scenarios when lexical ambiguity may occur:

  • There are two words in Language A that happen to have the same lemma and POS tags
    • (kir) жаш → (eng) age; tear (eye water)
    • (kir) ат → (eng) horse; name
    • (eng) right → (kir) оң (side); туура (correct)
    • (eng) lie → (kir) жат (lie down); калп айт (state a falsehood)
    • (eng) bat → (kir) жарганат (animal); таякча (stick for hitting a ball)
    • (eng) bank → (kir) банк (financial institution); жээк (shore)
  • There is a semantic distinction in Language B that is not expressed in Language A
    • (kir) кол → (eng) hand; arm
    • (kir) күн → (eng) sun; day
    • (kir) бир → (eng) one; a/an
    • (kir) кара → (eng) look at; watch
    • (eng) paper → (kir) кагаз (material); доклад (written work)
    • (eng) horse → (kir) ат (for riding, working); жылкы (for herding, eating)
    • (eng) sister → (kir) сиңди (younger, of female); карындаш (younger, of male); эже (older)
    • (eng) move → (kir) жыл/жылдыр (location iv/tv); кыймылда/кыймылдат (movement iv/tv); көч/көчүр (residence, files iv/tv)
    • (eng) fall → (kir) түш (drop from a height / fall down); кула (to the side / fall over); жыгыл (due to loss of footing)

Choosing between the two

Based on the above, which problem does each of the following example represent?

  1. (eng) tear → (kir) жаш (eye water); айыр (rip)
  2. (eng) plant → (kir) өсүмдүк (growing thing); отургуз (put in the ground to grow)
  3. (eng) fall → (kir) күз (season, <n>); күзгү (relating to the season, <adj>); [the verbs above]
  4. (kir) күзгү → (eng) fall (<adj>), mirror
  5. (kir) өч → (eng) revenge; be extinguished
  6. (kir) кыл → (eng) strand of hair; string (of instrument); do; make
  7. (kir) кара → (eng) black; look at; watch
  8. (kir) жыл → (eng) year; move

Morphological disambiguation

The goal of a morphological disambiguator is to choose the correct analysis based on the surrounding words.

Constraint Grammar (CG) is a formalism that can be used to formalise context-sensitive constraints to select or remove analyses from the list of possible analyses.

The structure of a CG file

At the top you define delimiters. You can then add lists (which are kind of like sets in twol). After that you can have any number of constraints. You can also put lists and constraints in sections. In the original specification for constraint grammar, all the constraints in each section are applied simultaneously, but the sections are applied in order and lists are always global. In the version we use (VISL CG3), the constraints are applied in strict order within the sections.

Constraints

Think of constraints as a series of heuristics to whittle down the number of analyses until you have as little ambiguity as possible.

The most commonly used constraints are to either remove a reading under a certain condition or select a reading under a certain condition. The syntax is e.g., REMOVE <target> [contextual tests] ;.

Targets can be defined as list names—like Nominals—or individual tag names, in parentheses—e.g., (n pl). This target identifies the reading to select or remove.

Contextual tests come together in ()s. All tests must match in order for the constraint to apply. Inside the parentheses, the first definition is a position: 0 means the current cohort, -1 means the previous cohort, etc. The rest of the test is what should be matched. If you want to match any member of the Nominals set in the previous position, it would be (-1 Nominals) You can match tag sequences by adding an extra set of parentheses, e.g. (1 (n pl)) would match a plural noun in the following position. You can match specific baseforms with quotation marks, e.g. (1 ("house" n)) would match any form of the noun "house" in the following position.

Classroom activity: implement "houses this" example (at top of page). Solution to this in-class example.

Useful commands

The file that your disambiguation constraints are defined in is the apertium-xyz.xyz.rlx file.

Getting output before disambiguation

example command:

echo "The motel houses this dog" | apertium -d . eng-morph

example output:

^The/the<det><def>$ ^motel/motel<n><sg>$ ^houses/house<n><pl>/house<v><tv><p3><sg>$ ^this/this<det><dem><sg>/this<prn><dem><sg>$ ^dog/dog<n><sg>$^./.<sent>$

Getting output after disambiguation

example command:

echo "The motel houses this dog" | apertium -d . eng-tagger

example output:

^The<det><def>$ ^motel<n><sg>$ ^house<v><tv><p3><sg>$ ^this<det><dem><sg>$ ^dog<n><sg>$^.<sent>$

Seeing which constraints are doing what

example command:

echo "The motel houses this dog" | apertium -d . eng-disam

example output:

"<The>"
	"the" det def
"<motel>"
	"motel" n sg
"<houses>"
	"house" v tv pres p3 sg
;	"house" n pl REMOVE:26
"<this>"
	"this" det dem sg
;	"this" prn dem sg REMOVE:29
"<dog>"
	"dog" n sg
"<.>"
	"." sent

Calculating ambiguity

Note: `lt-proc` and `.bin` can be replaced with `hfst-proc` and `.hfst` throughout if there are problems with tokenisation or similar

The ambiguity of a corpus is the average number of analyses provided per token. You can get the number of tokens like this:

cat corpus.txt | apertium-destxt | lt-proc /path/to/xyz.automorf.bin | apertium-retxt | sed 's/$\W*\^/$\n^/g' | wc -l

You can get the total number of analyses in your corpus like this:

cat corpus.txt | apertium-destxt | lt-proc /path/to/xyz.automorf.bin | apertium-retxt | sed 's/$\W*\^/$\n^/g' | cut -f2- -d'/' | sed 's/\//\n/g' | wc -l

You can get the total number of analyses in your corpus after disambiguation like this:

cat corpus.txt | apertium-destxt | lt-proc /path/to/xyz.automorf.bin | apertium-retxt | cg-proc /path/to/xyz.rlx.bin | sed 's/$\W*\^/$\n^/g' | cut -f2- -d'/' | sed 's/\//\n/g' | wc -l

The commands apertium-destxt and apertium-retxt strip and readd (respectively) characters that could be parsed in problematic ways.

Automating it a little further, you can put something like the following in a file and run it as a shell script. Note that the coverage-hfst script already implements most of this. The first three lines need to be replaced with the path to your corpus, your compiled analyser, and your compiled disambiguator, respectively.

CORPUS=/path/to/xyz.corpus.txt
MORPH=/path/to/xyz.automorf.bin
RLX=/path/to/xyz.rlx.bin # you might need to remove ".bin"
TOKENS=`apertium-destxt ${CORPUS} | lt-proc ${MORPH} | apertium-retxt | sed 's/$\W*\^/$\n^/g' | wc -l`
ANALYSES=`apertium-destxt ${CORPUS} | lt-proc ${MORPH} | apertium-retxt | sed 's/$\W*\^/$\n^/g' | cut -f2- -d'/' | sed 's/\//\n/g' | wc -l`
DISAMB=`apertium-destxt ${CORPUS} | lt-proc ${MORPH} | cg-proc ${RLX} | apertium-retxt | sed 's/$\W*\^/$\n^/g' | cut -f2- -d'/' | sed 's/\//\n/g' | wc -l`
AMBIGPRE=`calc $ANALYSES/$TOKENS`
AMBIGPOST=`calc $DISAMB/$TOKENS`
echo "Ambiguity before disambiguation: ${AMBIGPRE}"
echo "Ambiguity after disambiguation: ${AMBIGPOST}"

It's recommended that you put this script in tests/ and name it disambiguation-test.sh. Don't forget to git add it, git commit, and git push.

Checking what forms are ambiguous in the corpus and transducer

You can get all of the words in the corpus along with their analyses (or lack thereof) like this:

cat corpus.txt | apertium-destxt | lt-proc /path/to/xyz.automorf.bin | apertium-retxt | sed 's/$\W*\^/$\n^/g'

You can get all of the words in the corpus that have more than one analysis like this:

cat corpus.txt | apertium-destxt | lt-proc /path/to/xyz.automorf.bin | apertium-retxt | sed 's/$\W*\^/$\n^/g' | grep '\/.*\/'

You can find all forms in your transducer like this:

hfst-expand -c0 xyz.automorf.hfst

You can count ambiguity in your transducer by comparing the number of all forms to the number of unique forms.

Number of all forms:

hfst-expand -c0 xyz.automorf.hfst | wc -l

Number of unique forms:

hfst-expand -c0 xyz.automorf.hfst | cut -f1 -d':' | sort -u | wc -l

If the number's different you'll want to compare the lists:

hfst-expand -c0 xyz.automorf.hfst | cut -f1 -d':' | sort > /tmp/totalforms
hfst-expand -c0 xyz.automorf.hfst | cut -f1 -d':' | sort -u > /tmp/uniqforms
diff /tmp/totalforms /tmp/uniqforms

Then you'll want to see what the multiple analyses are of any forms that show up there.

More resources

Lexical selection

Lexical selection rules are in the apertium-xyz-abc.xyz-abc.lrx file in your language pair. You can find information about and examples of the formalism on the Apertium wiki: constraint-based lexical selection module, how to get started with lexical selection rules.

In short, you use the surrounding words (with morphological analyses) as context to decide which translation is the correct one.

The structure of lrx files

An lrx file is written in xml. It consists of a list of rules surrounded by <rules>...</rules>. Each <rule>...<rule> block contains some combination of <match><select ... /></match> blocks and <match .../> blocks. <match ...> tags can contain attributes like lemma="" and tags="". Multiple <match .../> blocks may be included within <or>...</or> so that multiple rules don't have to be written in cases of multiple matching criteria.

Besides the additional documentation linked to above, countless examples can be found in the Apertium codebase, and the below example from class will also be posted.

Here is an example to try in class:

  • Көзүнөн жаш акты.
  • Анын жашын билбейм.

Here is the solution to this in-class example.

Additional guidelines

You may wish to make a "default" translation and then some more specific rules. Because of how lrx-proc works, the less specific rule (the "default") may override any more specific rules.

Currently, the best way to get the less specific rule to be the default seems to be with weights—i.e., give a lower weight to the rule you wish to be default than to the specific ones (e.g., by just giving a weight above 1 to the specific rule).

More resources

The assignment

This assignment is generally due at the end of the day on Friday of the 10th week of class (this semester, 23:59, Friday, April 3rd, 2026).

The assignment is to identify two or three instances of ambiguity and write code to resolve them.

  • You only need to identify two instances of ambiguity if one requires morphological disambiguation to solve and the other requires lexical selection
  • If you only identify examples for morphological disambiguation or lexical selection, then you will need three instances of ambiguity.

Prepping

  1. If you're still working on your generator, finish that first.
  2. Commit and push your transducer at this point, and then add a tag "generator":
    • git tag generator
    • Then push the tag to the repo: git push origin generator
  3. If you're still working on lexical transfer, finish that too.
  4. Commit and push your language pair at this point, and then add a tag "lexical-transfer":
    • git tag lexical-transfer
    • Then push the tag to the repo: git push origin lexical-transfer

Initial Documentation

  1. Make a new page on the wiki, Language1_and_Language2/Ambiguity resolution, linking to it from the main page for your language pair, and adding it to the category Category:Sp26_AmbiguityResolution and the categories for the two languages.
  2. Add a section xyz for your language and xyz → abc for your language pair.
  3. In the xyz section, document your initial evaluation of ambiguity over two corpora in a bullet point (or similar) with this name
    1. Find the "xyz-tagger" section of your modes.xml file. Change cg-proc -w to cg-proc -1 -n -w (but not in the "xyz-disam" section!). Recompile, commit, push.
    2. Add some of the most common stems identified by a coverage test of your parallel sentences corpus (xyz.sentences.txt) to your transducer.
    3. Measure the level of ambiguity on your parallel sentences corpus and the largest monolingual corpus in your corpus repository. (See above; the coverage-hfst script will also return coverage.)

Morphological ambiguity

Identifying and documenting

  • If ambiguity is 1 (i.e., there is no ambiguity), then find any form in the language that can have more than one analysis. Check a grammar book and dictionary and think creatively. For example, demonstratives are ambiguous in many languages between determiners and pronouns, colour and material terms can often be ambiguous between adjectives and nouns, etc.
    • Implement this into your transducer.
    • Recompile, and measure level of ambiguity again.
  • If ambiguity is greater than 1 (i.e., there are at least some ambiguous forms), then figure out what form is ambiguous. Once you get ambiguity of this sort, update your initial evaluation of ambiguity to reflect this.
  • Find two sentences for two possible readings of any ambiguous term. Make sure all the words are in your transducer with correct analyses. Put them in the xyz section on the wiki page, in a subsection called "Identified ambiguity" (or similar), highlighting the correct reading of the ambiguous form in each sentence. For example, if the word was "this", examples might be:
    • ^This/this<det><dem><sg>/this<prn><dem><sg>$ ^is/be<v><iv><pres><p3><sg>$ ^a/a<det><ind>$ ^dog/dog<n><sg>$^./.<sent>$
    • ^I/I<prn><pers><p1><sg><sbj>$ ^saw/see<v><tv><past>$ ^this/this<det><dem><sg>/this<prn><dem><sg>$ ^dog/dog<n><sg>$^./.<sent>$
    • Note that it's best to use real sentences, e.g. from your corpus (or any of the sources that went into the corpus). If you absolutely must, you may create examples, but make note of this!

Implementing

  1. Once you have identified examples of ambiguity, come up with prose forms of the constraints you'll need to write to get the correct form in each of the two sentences.
    • Be as linguistically sound as you can, so that the constraints will apply in the broadest possible range of scenarios.
  2. Put the prose forms of the constraints as comments in your code.
  3. Using them as guidance, implement CG versions of the constraints.
    • Be sure to define any sets/lists you might need.

Finish up

  1. Once you get your disambiguator working as expected, commit your code
  2. Also, add a link to the git repository on in the xyz section of the wiki page, and vice versa (i.e., a link to the wiki page as a comment in the .rlx file in the git repo)
  3. Measure ambiguity again and add that number to the wiki page under something like "final evaluation of ambiguity".

Lexical selection

  1. Find and document at least one case of a one-to-many mapping for translation.
    • First check any dictionary resources you have for words with multiple translations. Things like lacking a hand/arm or sun/day or moon/month distinction in the source language but having it in the target language are potentially good places to start.
    • If you're translating to English and are having trouble coming up with examples for this assignment, consider words in English that are used in lexically specific ways, like in/on/at (e.g., one rides in a car but one rides on a bus) or watch/look at or say/tell.
    • See more examples under the second bullet point above where the need for lexical selection is discussed ("There are two main scenarios when lexical ambiguity may occur").
  2. For each ambiguous translation you work on, determine some generalisation for how to decide which translation is right, documenting these generalisations on the wiki in the xyz → abc section.
    • It may be that there is no obvious generalisation that can be made for a given lexical selection problem; in this case, choose a default form to select and find some other one-to-many translation that can be solved with lexical selection. You must have at least one [mostly] solvable problem.
  3. For each translation of the word, add an example sentence (or phrase if necessary—but check with me) where the meaning is unambiguous (minimum: two sentences).
  4. In the appropriate lrx file (for the xyz-abc direction), set up any necessary default translations, and at least one set of lexical selection rules (at least two rules) for one solvable lexical selection problem. Add the example sentences/phrases in a comment before the relevant rule.
  5. Compile and test that the sentences are translated with the correct stem.
  6. Commit and push your code!