File size: 6,572 Bytes
5c1d1c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c81be24
 
 
 
5c1d1c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
072f358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5c1d1c7
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
"""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