Skip to content

Commit

Permalink
Add Feature pairing to Symbol.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 634099532
  • Loading branch information
isingoo authored and copybara-github committed May 15, 2024
1 parent 8a5ac5e commit 98747b1
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 10 deletions.
29 changes: 24 additions & 5 deletions nisaba/scripts/natural_translit/script/inventories/latn.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,44 @@ def _build_inventory() -> grapheme.Grapheme.Inventory:
g = grapheme.Grapheme
grf = g.GR_FEATURES
inventory = g.Inventory(g.GR_FEATURES.script.latn)
lowercase_features = f.Set(
grf.script.latn,
grf.case.lower,
)
lowercase_args = [
['a', grf.ph_class.vwl],
['b', grf.ph_class.cons],
['c', grf.ph_class.cons],
['d', grf.ph_class.cons],
['e', grf.ph_class.vwl],
['f', grf.ph_class.cons],
['g', grf.ph_class.cons],
['h', grf.ph_class.cons],
['i', grf.ph_class.vwl],
['j', grf.ph_class.cons],
['k', grf.ph_class.cons],
['l', grf.ph_class.cons],
['m', grf.ph_class.cons],
['n', grf.ph_class.cons],
['o', grf.ph_class.vwl],
['p', grf.ph_class.cons],
['q', grf.ph_class.cons],
['r', grf.ph_class.cons],
['s', grf.ph_class.cons],
['t', grf.ph_class.cons],
['u', grf.ph_class.vwl],
['v', grf.ph_class.cons],
['w', grf.ph_class.cons],
['x', grf.ph_class.cons],
['y', [grf.ph_class.cons, grf.ph_class.vwl]],
['z', grf.ph_class.cons],
]
inventory.add_graphemes(
*[
g.from_char(char, char, f.Set(lowercase_features, features))
g.from_char(char, char, f.Set(grf.script.latn, features))
for char, features in lowercase_args
],
list_alias='lower',
)
for lower in inventory.lower:
upper = g.from_char(lower.raw.upper(), lower.alias + '_uc', lower.features)
inventory.add_pairs(grf.case.lower, grf.case.upper, (lower, upper))
return inventory

graphemes = _build_inventory()
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,11 @@ def test_in_raw_dict(self):
def test_lowercase_list(self):
self.assertIn(_latn.a, _latn.lower)

def test_uppercase(self):
self.assertEqual(_latn.text_lookup('A'), _latn.a_uc)
self.assertEqual(_latn.a.upper, _latn.a_uc)
self.assertEqual(_latn.a_uc.lower, _latn.a)
self.assertIn(_latn.a_uc, _latn.upper)

if __name__ == '__main__':
absltest.main()
9 changes: 5 additions & 4 deletions nisaba/scripts/natural_translit/utils/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,15 @@ def aspect_dict(
distances.update({feature.aspect: value_set.add(feature)})
return distances

def remove(self, *features) -> 'Feature.Set':
def remove(self, *features: 'Feature.ITERABLE') -> 'Feature.Set':
for feature in Feature.Set(*features):
self._item_set().discard(feature)
return self

def replace(
self, old: tuple['Feature.ITERABLE', ...],
new: tuple['Feature.ITERABLE', ...]
self,
old: 'Feature.ITERABLE',
new: 'Feature.ITERABLE',
) -> 'Feature.Set':
for feature in Feature.Set(old):
self.remove(feature)
Expand Down Expand Up @@ -329,7 +330,7 @@ class ValueList(ty.IterableThing):
isoceles: 0.00
round: 1.00
}
resulting in all troangular rooms to match in terms of shape, but
resulting in all triangular rooms to match in terms of shape, but
there can be different rules for the precise shapes eg.
if room.has_feature(equilateral): do x
Expand Down
66 changes: 65 additions & 1 deletion nisaba/scripts/natural_translit/utils/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class Symbol(ty.Thing):
value of the inventory is Symbol.Inventory.EMPTY.
"""

OR_NOTHING = Union['Symbol', ty.Nothing]
SYM_FEATURES = _symbol_features()

class ReservedIndex(enum.IntEnum):
Expand Down Expand Up @@ -142,6 +143,33 @@ def descriptions(
+ '\n'
)

# Stub functions to avoid rewrites when symbol features are profiles instead
# of sets.
def has_feature(self, feature: ft.Feature) -> bool:
return feature in self.features

def add_features(self, *features: ft.Feature.ITERABLE) -> None:
self.features.add(features)

def remove_features(self, *features: ft.Feature.ITERABLE) -> None:
self.features.remove(features)

def replace_features(
self, old: ft.Feature.ITERABLE, new: ft.Feature.ITERABLE
) -> None:
self.features.replace(old, new)

def pair(
self,
from_feature: ft.Feature,
to_feature: ft.Feature,
symbol: 'Symbol',
) -> None:
setattr(self, to_feature.text, symbol)
setattr(symbol, from_feature.text, self)
self.replace_features(to_feature, from_feature)
symbol.replace_features(from_feature, to_feature)

class Inventory(inventory.Inventory):
"""Symbol inventory.
Expand Down Expand Up @@ -237,7 +265,7 @@ def lookup(
self,
key: ...,
source_dict: Union[dict[Any, 'Symbol'], str],
default: Union['Symbol', ty.Nothing] = ty.UNSPECIFIED,
default: 'Symbol.OR_NOTHING' = ty.UNSPECIFIED,
) -> 'Symbol':
"""Get symbol by key from source_dict.
Expand Down Expand Up @@ -272,6 +300,42 @@ def text_lookup(self, text: str) -> 'Symbol':
"""Get symbol by its text field."""
return log.dbg_return(self.lookup(text, self.text_dict))

def add_pairs(
self,
from_feature: ft.Feature,
to_feature: ft.Feature,
*pairs: tuple['Symbol', 'Symbol'],
) -> None:
self.make_suppl(from_feature.alias, [])
self.make_suppl(to_feature.alias, [])
from_list = self.get(from_feature.alias)
to_list = self.get(to_feature.alias)
for sym1, sym2 in pairs:
self.add_symbols(sym1, sym2)
sym1.pair(from_feature, to_feature, sym2)
if sym1 not in from_list:
from_list.append(sym1)
if sym2 not in to_list:
to_list.append(sym2)

def pair_lookup(self, symbol: 'Symbol', feature: ft.Feature) -> 'Symbol':
"""Gets feature pair of a symbol.
Args:
symbol: The symbol whose pair is being looked up.
feature: The opposing feature that the target symbol differs from the
given symbol.
Returns:
The symbol that is paired with the given symbol and feature. If no pair
is found, returns the symbol itself.
"""
if hasattr(symbol, feature.text):
pair = getattr(symbol, feature.text)
if isinstance(pair, Symbol):
return pair
return symbol

def raw_from_unknown(self, raw: str = '') -> 'Symbol':
"""Makes and adds a new raw symbol to the inventory from a string."""
self.unknown_count += 1
Expand Down

0 comments on commit 98747b1

Please sign in to comment.