git » alan.git » master » tree

[master] / semantic.py

"""Semantic utilities for ALAN items."""
from __future__ import annotations

from dataclasses import dataclass
from typing import List


@dataclass(frozen=True)
class NPMeaning:
    noun: str
    feminine: bool
    plural: bool
    adjectives: tuple[str, ...]
    role: str  # AGENT/RECIPIENT/THEME
    use_irregular: bool


@dataclass(frozen=True)
class SentenceMeaning:
    verb: str
    tense: str  # PRES/PAST
    use_irregular_verb: bool
    subj: NPMeaning
    obj1: NPMeaning
    obj2: NPMeaning | None = None


def to_meaning(sf) -> SentenceMeaning:
    """Convert SentenceFeatures to SentenceMeaning."""
    def np_to_meaning(np):
        return NPMeaning(
            noun=np.noun_id,
            feminine=np.feminine,
            plural=np.plural,
            adjectives=tuple(np.adjectives),
            role=np.role,
            use_irregular=np.use_irregular,
        )

    return SentenceMeaning(
        verb=sf.verb_id,
        tense=sf.tense,
        use_irregular_verb=sf.use_irregular_verb,
        subj=np_to_meaning(sf.subject),
        obj1=np_to_meaning(sf.obj1),
        obj2=np_to_meaning(sf.obj2) if sf.obj2 else None,
    )


def meanings_equal(a: SentenceMeaning, b: SentenceMeaning) -> bool:
    return a == b


def semantic_distance(a: SentenceMeaning, b: SentenceMeaning) -> int:
    """Count feature differences between two meanings."""
    dist = 0
    if a.verb != b.verb or a.tense != b.tense or a.use_irregular_verb != b.use_irregular_verb:
        dist += 1
    for np_a, np_b in [(a.subj, b.subj), (a.obj1, b.obj1)]:
        if np_a != np_b:
            dist += 1
    if a.obj2 or b.obj2:
        if (a.obj2 or NPMeaning("", False, False, tuple(), "", False)) != (
            b.obj2 or NPMeaning("", False, False, tuple(), "", False)
        ):
            dist += 1
    return dist