jdmagent / src /jdm_agent /inference /constants.py
expAge
refactor(inference): désactiver les patrons de synonymie
c81be24
"""Constantes du moteur d'inférence JDM (Phase 11).
Cartes dérivées de `relation_definitions.md` et du moteur PHP `infer_answer`.
Aucune dépendance runtime au markdown — littéraux testables hors-ligne.
"""
from __future__ import annotations
# --- Relations inverses -----------------------------------------------------
#: Couples (relation, inverse). On construit la carte bidirectionnelle ensuite.
_INVERSE_PAIRS: list[tuple[str, str]] = [
("r_isa", "r_hypo"),
("r_has_part", "r_holo"),
("r_carac", "r_carac-1"),
("r_agent", "r_agent-1"),
("r_patient", "r_patient-1"),
("r_instr", "r_instr-1"),
("r_lieu", "r_lieu-1"),
("r_domain", "r_domain-1"),
("r_has_prop", "r_has_prop-1"),
("r_promote", "r_promote-1"),
("r_against", "r_against-1"),
("r_but", "r_but-1"),
("r_sentiment", "r_sentiment-1"),
("r_can_eat", "r_can_eat-1"),
("r_make_use_of", "r_make_use_of-1"),
("r_own", "r_own-1"),
("r_object>mater", "r_mater>object"),
("r_set>item", "r_item>set"),
("r_processus>agent", "r_processus>agent-1"),
("r_processus>patient", "r_processus>patient-1"),
("r_processus>instr", "r_processus>instr-1"),
]
#: Relations symétriques : leur inverse est elles-mêmes.
_SYMMETRIC: tuple[str, ...] = ("r_syn", "r_anto", "r_associated", "r_similar")
#: Carte bidirectionnelle nom de relation → nom de la relation inverse.
INVERSE_RELATIONS: dict[str, str] = {}
for _a, _b in _INVERSE_PAIRS:
INVERSE_RELATIONS[_a] = _b
INVERSE_RELATIONS[_b] = _a
for _s in _SYMMETRIC:
INVERSE_RELATIONS[_s] = _s
# --- Relations transitives --------------------------------------------------
#: Relations où A R X ∧ X R B ⟹ A R B.
TRANSITIVE_RELATIONS: frozenset[str] = frozenset({
"r_isa", "r_hypo", "r_has_part", "r_holo",
"r_lieu", "r_lieu-1", "r_has_conseq", "r_syn",
})
# --- Implication ------------------------------------------------------------
#: La relation demandée (clé) est IMPLIQUÉE si l'une des relations de la
#: liste tient entre les mêmes termes (R' plus spécifique ⟹ R).
IMPLICATION_MAP: dict[str, list[str]] = {
"r_lieu-1": ["r_has_part"],
"r_lieu": ["r_holo"],
"r_interact_with": ["r_can_eat", "r_against", "r_promote", "r_make_use_of"],
"r_has_conseq": ["r_sentiment"],
}
# --- Composition (effort 2) -------------------------------------------------
#: R demandée ⟸ il existe C tel que `A R2 C` ∧ `C R3 B`. Cartes (R2, R3).
COMPOSITION_MAP: dict[str, list[tuple[str, str]]] = {
"r_lieu": [("r_holo", "r_lieu")],
"r_agent-1": [("r_make_use_of", "r_instr-1"), ("r_has_part", "r_instr-1")],
"r_interact_with": [("r_agent-1", "r_patient"), ("r_instr-1", "r_patient")],
}
# --- Génériques & classes ---------------------------------------------------
#: Relations « génériques » : du terme vers ses sur-ensembles (déduction-ISA).
#: La synonymie a été retirée volontairement : `A r_syn B` ne signifie pas que
#: A et B sont substituables dans tous les contextes (souvent une hyperonymie
#: déguisée). La garder ici introduisait trop de faux positifs.
GENERIC_RELATIONS: tuple[str, ...] = ("r_isa",)
#: Grandes classes pour le schéma d'élimination par classe.
ELIMINATION_CLASSES: tuple[str, ...] = (
"être vivant", "être humain", "animal", "plante", "végétal",
"objet", "artéfact", "substance", "matière",
"oiseau", "poisson", "insecte", "mammifère", "reptile",
"arbre", "personne", "aliment", "véhicule", "lieu",
)
# --- Calibration & défauts --------------------------------------------------
#: Facteur d'échelle pour normaliser la confiance via `tanh(|w| / W)`.
#: Pas un seuil de filtrage — un facteur d'échelle.
STRONG_SUPPORT_W: float = 100.0
DEFAULT_MAX_DEPTH: int = 2
DEFAULT_TOP_K: int = 8
# --- Rendu en langage naturel ----------------------------------------------
#: Traduction d'une relation JDM en locution française, pour rendre les
#: chaînes d'inférence lisibles (« le moineau est un type d'oiseau ») plutôt
#: que codées (« moineau r_isa oiseau »).
RELATION_PHRASES: dict[str, str] = {
"r_isa": "est un type de",
"r_hypo": "a pour exemple",
"r_syn": "est synonyme de",
"r_anto": "est le contraire de",
"r_has_part": "a pour partie",
"r_holo": "fait partie de",
"r_carac": "a pour caractéristique",
"r_carac-1": "caractérise",
"r_lieu": "se situe dans",
"r_lieu-1": "est un lieu pour",
"r_can_eat": "peut manger",
"r_agent": "fait l'action de",
"r_agent-1": "est fait par",
"r_patient": "s'applique à",
"r_patient-1": "subit l'action de",
"r_instr": "utilise comme instrument",
"r_instr-1": "est l'instrument de",
"r_telic_role": "sert à",
"r_domain": "relève du domaine de",
"r_domain-1": "a pour terme du domaine",
"r_has_conseq": "a pour conséquence",
"r_has_causatif": "a pour cause",
"r_associated": "est associé à",
"r_isa-incompatible": "est incompatible avec",
"r_has_color": "a pour couleur",
"r_make": "produit",
"r_but": "a pour but",
"r_sentiment": "évoque le sentiment de",
}
#: Étiquette humaine du schéma d'inférence (au lieu du code interne).
SCHEMA_LABELS: dict[str, str] = {
"tautology": "trivialement",
"contradiction": "par contradiction",
"inverse": "par la relation inverse",
"implication": "par implication",
"synonym_equiv": "via un synonyme",
"isa_incompatible": "par incompatibilité de catégorie",
"class_elimination": "par héritage de catégorie",
"deduction_isa": "par généralisation",
"transitivity": "par transitivité",
"geo_propagation": "par contenance géographique",
"hyponym_propagation": "par cas particulier",
"composition": "par composition de relations",
"target_generic": "via un générique de la cible",
"double_isa": "par double généralisation",
"prefix": "par préfixe lexical",
"antonym_contrast": "par contraste antonymique",
"cohyponym": "par cohyponymie",
}
#: Budget d'appels HTTP par inférence, selon l'effort. Généreux mais borné :
#: tous les appels passent par le cache disque de JDMClient — la 1re inférence
#: sur un terme froid prend quelques secondes, les suivantes sont instantanées.
BUDGET_BY_EFFORT: dict[int, int] = {1: 70, 2: 150}
#: Nb d'hyperonymes scrutés par les schémas de réfutation (isa_incompatible,
#: class_elim). Le vrai générique peut être noyé loin dans le bruit JDM
#: (baleine → mammifère vers le rang 25).
REFUTATION_SCAN: int = 25