| """ |
| CAMADA L3 — Avaliação Paraconsistente |
| ====================================== |
| Implementa a Lógica Anotada de Evidências (LAE / PAL2v) de da Costa & Abe. |
| |
| Cada proposição recebe um par de anotações: |
| μ ∈ [0,1] — grau de evidência FAVORÁVEL |
| λ ∈ [0,1] — grau de evidência CONTRÁRIA |
| |
| Estados resultantes: |
| ┌──────────────────────────────────────────────────┐ |
| │ Verdadeiro : μ alto, λ baixo │ |
| │ Falso : μ baixo, λ alto │ |
| │ Inconsistente : μ alto, λ alto (contradição) │ |
| │ Indeterminado : μ baixo, λ baixo │ |
| │ Intermediário : valores médios (morno, etc.) │ |
| └──────────────────────────────────────────────────┘ |
| |
| Princípio central: |
| "Contradição Local + Consistência Global ≠ Trivialização" |
| |
| A explosão é GENTIL: uma contradição local (quente e frio) não |
| trivializa o sistema — produz o estado "Intermediário" (morno). |
| """ |
|
|
| from __future__ import annotations |
| from dataclasses import dataclass |
| from typing import Dict, List, Tuple, Optional |
| import math |
|
|
| import torch |
|
|
| try: |
| from paraconsistent_rules import ( |
| state_from_rules, |
| state_12_to_simple, |
| load_rules_from_fuzzy_file, |
| ParaconsistentRules, |
| ) |
| except Exception: |
| state_from_rules = None |
| state_12_to_simple = None |
| load_rules_from_fuzzy_file = None |
| ParaconsistentRules = None |
|
|
| try: |
| |
| from neural_truth_model import TruthScoringModel, load_tokenizer, neural_annotations |
| except Exception: |
| TruthScoringModel = None |
| load_tokenizer = None |
| neural_annotations = None |
|
|
|
|
| |
| |
| |
| THRESHOLD_TRUE = 0.7 |
| THRESHOLD_FALSE = 0.3 |
| THRESHOLD_INCONSISTENT = 0.6 |
| THRESHOLD_INDETERMINATE= 0.4 |
|
|
|
|
| @dataclass |
| class ParaconsistentValue: |
| """ |
| Valor-verdade paraconsistente para uma proposição. |
| Baseado na Lógica Anotada de Evidências (LAE). |
| """ |
| proposition: str |
| mu: float |
| lam: float |
|
|
| |
| @property |
| def certainty(self) -> float: |
| """Grau de certeza: Gc = μ − λ ∈ [−1, 1]""" |
| return self.mu - self.lam |
|
|
| @property |
| def contradiction(self) -> float: |
| """Grau de contradição: Gct = μ + λ − 1 ∈ [−1, 1]""" |
| return self.mu + self.lam - 1.0 |
|
|
| @property |
| def state(self) -> str: |
| """Estado lógico qualitativo. Usa regras do Fuzzy.txt se disponíveis.""" |
| if state_from_rules is not None and state_12_to_simple is not None: |
| state_12 = state_from_rules(self.mu, self.lam) |
| return state_12_to_simple(state_12) |
| |
| if self.mu >= THRESHOLD_TRUE and self.lam <= (1 - THRESHOLD_TRUE): |
| return "Verdadeiro" |
| if self.mu <= THRESHOLD_FALSE and self.lam >= (1 - THRESHOLD_FALSE): |
| return "Falso" |
| if self.mu >= THRESHOLD_INCONSISTENT and self.lam >= THRESHOLD_INCONSISTENT: |
| return "Inconsistente_local" |
| if self.mu <= THRESHOLD_INDETERMINATE and self.lam <= THRESHOLD_INDETERMINATE: |
| return "Indeterminado" |
| return "Intermediário" |
|
|
| @property |
| def state_12(self) -> Optional[str]: |
| """Estado lógico de 12 valores (reticulado) conforme Fuzzy.txt, se regras carregadas.""" |
| if state_from_rules is not None: |
| return state_from_rules(self.mu, self.lam) |
| return None |
|
|
| @property |
| def truth_value(self) -> float: |
| """Valor-verdade escalar normalizado para saída final.""" |
| return round((self.mu + (1 - self.lam)) / 2.0, 4) |
|
|
| def __str__(self) -> str: |
| return ( |
| f" μ={self.mu:.3f} λ={self.lam:.3f} " |
| f"Gc={self.certainty:+.3f} Gct={self.contradiction:+.3f} " |
| f"v={self.truth_value:.3f} [{self.state}]\n" |
| f" \"{self.proposition}\"" |
| ) |
|
|
|
|
| |
| |
| |
|
|
| class ParaconsistentEngine: |
| """ |
| Avalia as hipóteses kantiana (L2) e atribui valores-verdade |
| paraconsistentes a cada uma. |
| |
| Pode operar em dois modos: |
| - Modo heurístico (padrão): usa apenas o banco de conhecimento. |
| - Modo neural: se um TruthScoringModel for fornecido, usa o modelo |
| para calcular (μ, λ) compatíveis com a Lógica Anotada. |
| """ |
|
|
| def __init__( |
| self, |
| neural_model: Optional["TruthScoringModel"] = None, |
| neural_tokenizer=None, |
| device: Optional[torch.device] = None, |
| ) -> None: |
| self.neural_model = neural_model |
| self.neural_tokenizer = neural_tokenizer |
| self.device = device or torch.device("cuda" if torch.cuda.is_available() else "cpu") |
|
|
| def evaluate( |
| self, |
| propositions: List[Tuple[str, float]], |
| knowledge_base: Dict[str, float], |
| ) -> List[ParaconsistentValue]: |
| """ |
| Para cada proposição: |
| μ = evidência favorável extraída do banco de dados |
| λ = evidência contrária = 1 − f(compatibilidade) |
| """ |
| results: List[ParaconsistentValue] = [] |
| for prop_text, l2_priority in propositions: |
| mu, lam = self._compute_annotations(prop_text, l2_priority, knowledge_base) |
| pv = ParaconsistentValue(proposition=prop_text, mu=mu, lam=lam) |
| results.append(pv) |
|
|
| |
| results.sort(key=lambda pv: pv.truth_value, reverse=True) |
| return results |
|
|
| |
| |
| |
|
|
| def _compute_annotations( |
| self, |
| text: str, |
| l2_priority: float, |
| kb: Dict[str, float], |
| ) -> Tuple[float, float]: |
| """ |
| Calcula (μ, λ) para uma proposição. |
| |
| Se um modelo neural estiver disponível, usa-o para obter anotações |
| compatíveis com L3. Caso contrário, volta para a heurística original |
| baseada apenas no banco de conhecimento e em contradições locais. |
| """ |
| if self.neural_model is not None and self.neural_tokenizer is not None and neural_annotations is not None: |
| mu, lam, _, _ = neural_annotations(self.neural_model.to(self.device), self.neural_tokenizer, text) |
| |
| mu = min(1.0, mu * (0.5 + 0.5 * l2_priority)) |
| lam = max(0.0, lam * (1.0 - 0.3 * l2_priority)) |
| return round(mu, 4), round(lam, 4) |
|
|
| import re |
| tokens = set(re.findall(r"[a-záàãâéêíóôõúüç]+", text.lower())) |
|
|
| kb_scores = [kb.get(t, 0.0) for t in tokens if kb.get(t, 0.0) > 0] |
| mu_kb = sum(kb_scores) / len(kb_scores) if kb_scores else 0.3 |
|
|
| contradiction_detected = self._has_antonym_pair(tokens, kb) |
| lam_base = 0.8 if contradiction_detected else (1.0 - mu_kb) |
|
|
| mu = min(1.0, mu_kb * (0.5 + 0.5 * l2_priority)) |
| lam = max(0.0, lam_base * (1.0 - 0.3 * l2_priority)) |
|
|
| return round(mu, 4), round(lam, 4) |
|
|
| ANTONYM_PAIRS = [ |
| ("quente", "frio"), ("quente", "gelado"), |
| ("verdadeiro", "falso"), ("real", "fictício"), |
| ("afirmativo", "negativo"), ("possível", "impossível"), |
| ] |
|
|
| def _has_antonym_pair(self, tokens: set, kb: Dict[str, float]) -> bool: |
| for a, b in self.ANTONYM_PAIRS: |
| if a in tokens and b in tokens: |
| return True |
| return False |
|
|
| |
| |
| |
|
|
| @staticmethod |
| def check_global_consistency(values: List[ParaconsistentValue]) -> bool: |
| """ |
| Retorna True se o sistema é globalmente consistente |
| (nenhuma trivialização — todos os estados válidos). |
| Uma trivialização ocorre se TODAS as proposições são |
| 'Inconsistente_local' sem nenhum 'Verdadeiro' ou 'Intermediário'. |
| """ |
| states = {pv.state for pv in values} |
| if states == {"Inconsistente_local"}: |
| return False |
| return True |
|
|