diff --git a/nisaba/scripts/natural_translit/utils/feature.py b/nisaba/scripts/natural_translit/utils/feature.py index 75231592..d61939e2 100644 --- a/nisaba/scripts/natural_translit/utils/feature.py +++ b/nisaba/scripts/natural_translit/utils/feature.py @@ -284,6 +284,13 @@ def has_feature(self, value: 'Feature.Aspect.VALUES'): return True return any(value in feature.parent_list for feature in self) + def non_generic(self, alias: str = '') -> 'Feature.Set': + """Returns a copy of set without aspect.any and aspect.n_a features.""" + return Feature.Set([ + feature for feature in self + if feature != feature.aspect.any and feature != feature.aspect.n_a + ], alias=(alias if alias else self.alias + '_non_generic')) + class ValueListType(enum.Enum): EQUIDISTANT = 0 LINEAR = 1 @@ -368,8 +375,10 @@ def distance( return Feature.ERROR_DISTANCE delta = self._items.index(values2) - self._items.index(values1) match self.list_type: - case Feature.ValueListType.EQUIDISTANT: return self.step - case Feature.ValueListType.LINEAR: return delta * self.step + case Feature.ValueListType.EQUIDISTANT: + return self.step + case Feature.ValueListType.LINEAR: + return delta * self.step case Feature.ValueListType.CYCLIC: return min(delta, len(self) - delta) * self.step return Feature.ERROR_DISTANCE @@ -591,6 +600,13 @@ def has_feature(self, value: 'VALUES') -> bool: """Checks if the given value or one of its children is in this aspect.""" return value.is_in(self) + def is_applicable(self, profile: 'Feature.Profile') -> bool: + """Checks if this aspect is applicable to the given profile.""" + return ( + profile.inventory == self.inventory + and self.n_a not in profile.get(self) + ) + class Inventory(inventory.Inventory): """An inventory of Aspects and their contrastive features. @@ -683,7 +699,7 @@ def __init__( alias: The alias of the feature profile. *features: Features to be added to the profile. unspecified_aspect_n_a: If true, the default value for an aspect is - n_a (not available) instead of any. + n_a (not_applicable) instead of any. """ super().__init__(alias) self.inventory = feature_inventory @@ -703,6 +719,22 @@ def __str__(self): text += '}\n' return text + def get(self, aspect: 'Feature.Aspect') -> 'Feature.Set': + """Gets the value set for the given aspect.""" + return super().get( + aspect.alias, + Feature.Set( + aspect.n_a, + alias='%s_%s' + % ( + 'missing' + if aspect.inventory == self.inventory + else aspect.inventory.alias, + aspect.alias, + ), + ), + ) + def copy_and_update( self, alias: str, *updates: 'Feature.ITERABLE' @@ -744,7 +776,7 @@ def copy_and_update( new = Feature.Profile(self.inventory, alias, *self) update_dict = Feature.Set.aspect_dict(*updates) for aspect, value in update_dict.items(): - new.get(aspect.alias).update(value) + new.get(aspect).update(value) return new def compare( @@ -779,8 +811,8 @@ def compare( headers = ['aspect', self.text, p.text, 'distance'] table = [] for aspect in aspects: - item1 = self.get(aspect.alias) - item2 = p.get(aspect.alias) + item1 = self.get(aspect) + item2 = p.get(aspect) dist = item1.distance(item2) total_dist += dist max_dist += aspect.max_dist diff --git a/nisaba/scripts/natural_translit/utils/feature_test.py b/nisaba/scripts/natural_translit/utils/feature_test.py index 1f084c07..34850e0b 100644 --- a/nisaba/scripts/natural_translit/utils/feature_test.py +++ b/nisaba/scripts/natural_translit/utils/feature_test.py @@ -210,6 +210,12 @@ def test_has_feature(self): self.assertTrue(_R.room2.has_feature(_R.door.cls)) self.AssertNotHasFeature(_R.room2, _R.door.open) + def test_set_non_generic(self): + non_generic = f.Set( + _R.warmth.cold, _R.lighting.n_a, _R.color.any, alias='set1' + ).non_generic() + self.AssertStrEqual(non_generic, 'set1_non_generic: {cold}') + def test_max_dist(self): self.assertEqual(_R.warmth.max_dist, 3.00) @@ -373,6 +379,17 @@ def test_profile_default_value_n_a(self): '}\n', ) + def test_profile_aspect_applicable(self): + self.assertTrue(_R.color.is_applicable(_R.room1)) + self.assertFalse(_R.color.is_applicable(_R.room2)) + self.assertFalse(_R.color.is_applicable(_A.cat)) + + def test_profile_get(self): + self.AssertStrEqual(_R.room1.get(_R.warmth), 'warmth: {cold}') + self.AssertStrEqual( + _R.room1.get(_A.size), 'animal_features_size: {not_applicable}' + ) + def test_profile_compare_all(self): self.assertEqual( _R.room1.comparison_table(_R.room2),