Tag: create allomorphs - adamb924/mortal-engine GitHub Wiki

It is often helpful to create allomorphs automatically. One reason to do this would be that you're pulling allomorphs out of the lexicon, and you don't want to have to manually specify each allomorph for each stem. Another reason is that multiple morphemes participate in the same process, and you don't want to have to enter in those allomorphs manually.

When working with this tag, you're going to want to be able to inspect the model, so make sure you're familiar with how to use the command line utility to do that. When I work with this tag, I find it easier to focus on analyzing the allomorphs that are created, by inspecting the model, than to judge by what tests succeed or fail. (The latter is just two many steps for me to do in my head.)

Creating allomorphs within stem tags

The snippet below is from examples/23-Create-Stem-Allomorphs-1.xml. The toy alternation for this example is that [t] becomes [d] before [u].

In this example, inside the <stem-list> tag there is a <create-allomorphs> tag. But before we get into what the <create-allomorphs> tag does, let's consider what the model output would be if there wasn't one. If we were to remove the <create-allomorphs> tag and do a model dump, we would see lexical stems like the following, each with one allomorph:

LexicalStem(1 allomorph(s),
	Allomorph(Original, 1 form(s),
		 Use in generations: true,
		(wk-LA, sit)
		Tags: noun
		Constraints ( none )
	)
	No glosses
)

The purpose of the <create-allomorphs> tag is to create more allomorphs. If we include the <create-allomorphs> tag from the example, we get the following output:

LexicalStem(2 allomorph(s),
	Allomorph(Original, 1 form(s),
		 Use in generations: true,
		(wk-LA, sit)
		Tags: noun
		Constraints (1:
			NotCondition (
				FollowingPhonologicalCondition (1: ^u (wk-LA))
			)
		)
	)
	Allomorph(Derived, 1 form(s),
		 Use in generations: true,
		(wk-LA, sid)
		Tags: noun
		Constraints (1:
			FollowingPhonologicalCondition (1: ^u (wk-LA))
		)
	)
	No glosses
)

We now have one “Original” allomorph and one “Derived” allomorph. The derived allomorph was added automatically by the <create-allomorphs> tag. The derived allomorph has the form [sid], and occurs when there is a following [u]. The original allomorph has the form [sit], and occurs when there is not a following [u]. (The result will be, you get forms like [sit] and [sidu], but not *[situ].)

This is what the <create-allomorphs> tag looks like:

<stem-list label="Stem">
	<filename>12-stems.xml</filename>
	<matching-tag>noun</matching-tag>
	<!-- this tag will create new allomorphs, based on the conditions below -->
	<create-allomorphs>
		<!-- in this example, there is a single case (and an implied 'otherwise' case) -->
		<case>
			<!-- 'when there is a following u' -->
			<when>
				<phonological-condition type="following">
					<match-expression lang="wk-LA">^u</match-expression>
				</phonological-condition>
			</when>
			<!-- 'then replace stem-final t with d' -->
			<then>
				<replace-this>
					<form lang="wk-LA">t$</form>
				</replace-this>
				<with-this>
					<form lang="wk-LA">d</form>
				</with-this>
			</then>
		</case>
	</create-allomorphs>
</stem-list>

The tag is a bit verbose, but hopefully semantically meaningful. The <create-allomorphs> tag has at least one <case> tag. The <case> tag has <when> and <then> tags: when this, then do this. The <when> tag will contain constraints. When those constraints are met, a new allomorph will be generated using the replacements in the <then> tag. The <then> tag has at least one <replace-this> and <with-this> pair. (It can have more than one as well.) This replacement will be used to generate the new allomorph.

This tag has a declarative presentation rather than a procedural one. But if you wanted to describe it procedurally, you could say, “Create a new allomorph with the constraints in <when>. Its forms should based on the original allomorph, but performing the replacements in <then>.”

There is a further twist here. The “original” allomorph is considered to be the “otherwise” allomorph, i.e., the allomorph that should be used if none of the other conditions are met. In the example above, the derived allomorph is given the constraint

<phonological-condition type="following">
	<match-expression lang="wk-LA">^u</match-expression>
</phonological-condition>

And the “original” allomorph is automatically given the condition:

<not>
	<phonological-condition type="following">
		<match-expression lang="wk-LA">^u</match-expression>
	</phonological-condition>
</not>

It's automatic: you don't have to specify that the original morpheme is the otherwise morpheme.

For another example of <create-allomorphs> in a <stem-list> tag, see examples/17-Create-Allomorphs-4.xml.

'Otherwise' alternatives

As described above, you get the ‘otherwise’ morpheme automatically. To be painfully clear: it will be not( or( any of the conditions in the cases ) ).

If you do not there to be an otherwise morpheme, you can include the <no-otherwise/> tag after your <case> tags. You might want to do that, for example, the original form was an abstract form that never actually surfaced in the language (an abstract underlying form, or an archiphoneme, etc.). Example code:

<create-allomorphs>
	<!-- in this example, there is a single case (and an implied 'otherwise' case) -->
	<case>
		<!-- 'when there is a following u' -->
		<when>
			<phonological-condition type="following">
				<match-expression lang="wk-LA">^u</match-expression>
			</phonological-condition>
		</when>
		<!-- 'then replace stem-final t with d' -->
		<then>
			<replace-this>
				<form lang="wk-LA">t$</form>
			</replace-this>
			<with-this>
				<form lang="wk-LA">d</form>
			</with-this>
		</then>
	</case>
	<no-otherwise/>
</create-allomorphs>

If for some reason you wish to specify your own constraints for the otherwise morpheme, you can include the <override-otherwise> tag after your <case> tags. The following would be equivalent to the automatically-generated otherwise condition (and perhaps somewhat more efficient):

<create-allomorphs>
	<!-- in this example, there is a single case (and an implied 'otherwise' case) -->
	<case>
		<!-- 'when there is a following u' -->
		<when>
			<phonological-condition type="following">
				<match-expression lang="wk-LA">^u</match-expression>
			</phonological-condition>
		</when>
		<!-- 'then replace stem-final t with d' -->
		<then>
			<replace-this>
				<form lang="wk-LA">t$</form>
			</replace-this>
			<with-this>
				<form lang="wk-LA">d</form>
			</with-this>
		</then>
	</case>
	<override-otherwise>
		<phonological-condition type="following">
			<match-expression lang="wk-LA">^[^u]</match-expression>
		</phonological-condition>
	</override-otherwise>
</create-allomorphs>

Multiple cases

An example with multiple <case> tags is given in examples/24-Create-Stem-Allomorphs-2.xml. In this example, there are two stem alternations: [t] becomes [d] before [u], and nasals become [ŋ] before [k]. There isn't really anything more conceptually difficult than that, so I won't paste the code here.

Shared create allomorphs

Inasmuch as languages tend to use the same natural classes over and over, you're going to want to reuse your <create-allomorphs> tags. This is just like using shared constraints, but with the following differences:

  • Shared <create-allomorphs> tags are placed in the <shared-create-allomorphs> tag up top.
  • You refer to the shared tag with <add-allomorphs>, e.g., <add-allomorphs with="harmony" />.
  • In a stem tag, you can use either <create-allomorphs> or <add-allomorphs>. But...
  • In a morpheme tag, you can only use <add-allomorphs>.

An example of the use of <shared-create-allomorphs> is given in examples/14-Create-Allomorphs.xml. (This example behaves identically to examples/13-Shared-Conditions.xml.) Once the <create-allomorphs> tags are defined up above, it's easy to make them apply to any morpheme we want:

<morpheme label="Classifier">
	<allomorph>
		<form lang="wk-LA">e</form>
	</allomorph>
	<add-allomorphs with="harmony" />
</morpheme>
<morpheme label="Plural">
	<optional/>
	<allomorph>
		<form lang="wk-LA">no</form>
	</allomorph>
	<add-allomorphs with="harmony" />
</morpheme>

More complex situations

Multiple <create-allomorphs> tags

You can have more than one <add-allomorphs> tag in a morpheme. For instance, examples/15-Create-Allomorphs-2.xml has an example of a language with both vowel harmony and nasal place assimilation. These two patterns are defined in <shared-create-allomorphs>, and then applied to the same morpheme:

<morpheme label="Plural">
	<optional/>
	<allomorph>
		<form lang="wk-LA">non</form>
	</allomorph>
	<!-- these two <add-allomorphs> will add all of the combinations of morphemes automatically -->
	<add-allomorphs with="harmony" />
	<add-allomorphs with="nasal-assimilation" />
</morpheme>

Each of the <add-allomorphs> tags has two cases: an explictly defined case and an implied otherwise case. Consequently, the resulting morpheme has four allomorphs:

MorphemeNode(
	Label: Plural
	ID: 
	Type: morpheme
	Optional: true
	Has optional completion path: false
	4 allomorph(s),
	Allomorph(Derived, 1 form(s),
		 Use in generations: true,
		(wk-LA, noŋ)
		Tags: 
		Constraints (2:
			NotCondition (
				Pointer to non-atr-harmony: FollowingPhonologicalCondition (1: .*[ɪɛɔ] (wk-LA))
			)
			FollowingPhonologicalCondition (1: ^[kg] (wk-LA))
		)
	)
	Allomorph(Original, 1 form(s),
		 Use in generations: true,
		(wk-LA, non)
		Tags: 
		Constraints (2:
			NotCondition (
				Pointer to non-atr-harmony: FollowingPhonologicalCondition (1: .*[ɪɛɔ] (wk-LA))
			)
			NotCondition (
				AndCondition (
					NotCondition (
						Pointer to non-atr-harmony: FollowingPhonologicalCondition (1: .*[ɪɛɔ] (wk-LA))
					)
					FollowingPhonologicalCondition (1: ^[kg] (wk-LA))
				)
			)
		)
	)
	Allomorph(Derived, 1 form(s),
		 Use in generations: true,
		(wk-LA, nɔn)
		Tags: 
		Constraints (2:
			NotCondition (
				AndCondition (
					Pointer to non-atr-harmony: FollowingPhonologicalCondition (1: .*[ɪɛɔ] (wk-LA))
					FollowingPhonologicalCondition (1: ^[kg] (wk-LA))
				)
			)
			Pointer to non-atr-harmony: FollowingPhonologicalCondition (1: .*[ɪɛɔ] (wk-LA))
		)
	)
	Allomorph(Derived, 1 form(s),
		 Use in generations: true,
		(wk-LA, nɔŋ)
		Tags: 
		Constraints (2:
			Pointer to non-atr-harmony: FollowingPhonologicalCondition (1: .*[ɪɛɔ] (wk-LA))
			FollowingPhonologicalCondition (1: ^[kg] (wk-LA))
		)
	)
)

A closely related example is examples/16-Create-Allomorphs-3.xml. This is the same as the previous example, except that labial assimilation is added in as well.

Multiple writing systems

The nasal place assimilation examples used above are expanded in examples/25-Create-Allomorphs-7.xml, to show what happens when you have multiple alphabets. The toy problem is this: in the Latin orthography for Kiwakanda, nasal place assimilation is represented, but in the Arabic orthography, there is no special symbol for a velar nasal; the letter for [n] is used.

Here is a regular lexical entry:

<stem>
	<form lang="wk-LA">sit</form>
	<form lang="wk-AR">سیت</form>
	<tag>noun</tag>
</stem>

Here we see that the velar nasal doesn't get a special letter:

<stem>
	<form lang="wk-LA">kɔŋ</form>
	<form lang="wk-AR">کون</form>
	<tag>noun</tag>
</stem>

Accordingly, in our <create-allomorphs> tag for nasal place assimilation, we have one <case> that handles labial place assimilation for both writing systems, and one <case> that handles velar place assimilation only for the Latin alphabet:

<create-allomorphs id="nasal-assimilation">
	<!-- velar assimilation only takes place in the Latin writing system -->
	<case>
		<when>
			<phonological-condition type="following">
				<match-expression lang="wk-LA">^[kg]</match-expression>
			</phonological-condition>
		</when>
		<then>
			<replace-this>
				<form lang="wk-LA">n$</form>
			</replace-this>
			<with-this>
				<form lang="wk-LA">ŋ</form>
			</with-this>
		</then>
	</case>
	<!-- labial assimilation takes place in both writing systems -->
	<case>
		<when>
			<phonological-condition type="following">
				<match-expression lang="wk-LA">^[pmb]</match-expression>
				<match-expression lang="wk-AR">^[پمب]</match-expression>
			</phonological-condition>
		</when>
		<then>
			<replace-this>
				<form lang="wk-LA">n$</form>
				<form lang="wk-AR">ن$</form>
			</replace-this>
			<with-this>
				<form lang="wk-LA">m</form>
				<form lang="wk-AR">م</form>
			</with-this>
		</then>
	</case>
</create-allomorphs>

In the model dump, we see that we create three allomorphs, one with (wk-AR, نون),(wk-LA, non), one with (wk-AR, نون), (wk-LA, noŋ) (NB the Arabic is not different here), and one with (wk-AR, نوم), (wk-LA, nom):

MorphemeNode(
	Label: Plural
	ID: 
	Type: morpheme
	Optional: true
	Has optional completion path: false
	3 allomorph(s),
	Allomorph(Original, 2 form(s), Use in generations: true,
		(wk-AR, نون)
		(wk-LA, non)
		Tags: 
		Constraints (1:
			NotCondition (
				OrCondition (
					FollowingPhonologicalCondition (2: ^[پمب] (wk-AR); ^[pmb] (wk-LA))
					FollowingPhonologicalCondition (1: ^[kg] (wk-LA))
				)
			)
		)
	)
	Allomorph(Derived, 2 form(s), Use in generations: true,
		(wk-AR, نون)
		(wk-LA, noŋ)
		Tags: 
		Constraints (1:
			FollowingPhonologicalCondition (1: ^[kg] (wk-LA))
		)
	)
	Allomorph(Derived, 2 form(s), Use in generations: true,
		(wk-AR, نوم)
		(wk-LA, nom)
		Tags: 
		Constraints (1:
			FollowingPhonologicalCondition (2: ^[پمب] (wk-AR); ^[pmb] (wk-LA))
		)
	)
)

Including only changed morphemes

In the example above, we saw that a morpheme was generated with forms (wk-AR, نون) and (wk-LA, noŋ). If for some reason you wanted an allomorph with only the Latin orthography, then instead of <case> you would use <case mode="include-only-changed-forms">. This puts only those forms into an allomorph that were changed by the replacements. So we would get get:

Allomorph(Derived, 1 form(s), Use in generations: true,
	(wk-LA, noŋ)
	Tags: 
	Constraints (1:
		FollowingPhonologicalCondition (1: ^[kg] (wk-LA))
	)
)

In allomorph above, a form in the Arabic writing system was not included, because the replacement rules did not change that form.

Creating duplicate allomorphs

By default, if the replacements do not change at least one of the forms of the original allomorph, no additional allomorph will be created. If for some reason you an allomorph with the same form(s) as the original allomorph, then you simply use <case tolerate-duplicates="true">. This can be useful in cases where an allomorph appears in several different contexts, and you want to see each context in a separate allomorph.

The attribute tolerate-duplicates="true" can be used with or without the mode="include-only-changed-forms" attribute.

⚠️ **GitHub.com Fallback** ⚠️