@stevenvo780/autologic 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/atoms/index.d.ts +1 -1
- package/dist/atoms/index.d.ts.map +1 -1
- package/dist/atoms/index.js +91 -3
- package/dist/atoms/index.js.map +1 -1
- package/dist/atoms/keyword-extractor.d.ts +9 -0
- package/dist/atoms/keyword-extractor.d.ts.map +1 -1
- package/dist/atoms/keyword-extractor.js +64 -2
- package/dist/atoms/keyword-extractor.js.map +1 -1
- package/dist/atoms/math-parser.d.ts +11 -0
- package/dist/atoms/math-parser.d.ts.map +1 -0
- package/dist/atoms/math-parser.js +44 -0
- package/dist/atoms/math-parser.js.map +1 -0
- package/dist/compiler-frontend.d.ts +9 -0
- package/dist/compiler-frontend.d.ts.map +1 -0
- package/dist/compiler-frontend.js +142 -0
- package/dist/compiler-frontend.js.map +1 -0
- package/dist/context/discourse-state.d.ts +10 -0
- package/dist/context/discourse-state.d.ts.map +1 -0
- package/dist/context/discourse-state.js +26 -0
- package/dist/context/discourse-state.js.map +1 -0
- package/dist/discourse/markers-es.d.ts.map +1 -1
- package/dist/discourse/markers-es.js +23 -0
- package/dist/discourse/markers-es.js.map +1 -1
- package/dist/discourse/pattern-detector.d.ts.map +1 -1
- package/dist/discourse/pattern-detector.js +2 -1
- package/dist/discourse/pattern-detector.js.map +1 -1
- package/dist/discourse/role-classifier.js +38 -6
- package/dist/discourse/role-classifier.js.map +1 -1
- package/dist/formalize.d.ts +16 -0
- package/dist/formalize.d.ts.map +1 -1
- package/dist/formalize.js +128 -0
- package/dist/formalize.js.map +1 -1
- package/dist/formula/argument-builder.d.ts.map +1 -1
- package/dist/formula/argument-builder.js +124 -15
- package/dist/formula/argument-builder.js.map +1 -1
- package/dist/formula/ast-compiler.d.ts +6 -0
- package/dist/formula/ast-compiler.d.ts.map +1 -0
- package/dist/formula/ast-compiler.js +105 -0
- package/dist/formula/ast-compiler.js.map +1 -0
- package/dist/formula/ast.d.ts +81 -0
- package/dist/formula/ast.d.ts.map +1 -0
- package/dist/formula/ast.js +52 -0
- package/dist/formula/ast.js.map +1 -0
- package/dist/formula/connectors.js +1 -1
- package/dist/formula/connectors.js.map +1 -1
- package/dist/formula/first-order.js +74 -7
- package/dist/formula/first-order.js.map +1 -1
- package/dist/formula/helpers.d.ts +8 -0
- package/dist/formula/helpers.d.ts.map +1 -0
- package/dist/formula/helpers.js +166 -0
- package/dist/formula/helpers.js.map +1 -0
- package/dist/formula/index.d.ts +1 -0
- package/dist/formula/index.d.ts.map +1 -1
- package/dist/formula/index.js +5 -3
- package/dist/formula/index.js.map +1 -1
- package/dist/formula/modal.d.ts.map +1 -1
- package/dist/formula/modal.js +56 -67
- package/dist/formula/modal.js.map +1 -1
- package/dist/formula/probabilistic.d.ts +3 -0
- package/dist/formula/probabilistic.d.ts.map +1 -0
- package/dist/formula/probabilistic.js +55 -0
- package/dist/formula/probabilistic.js.map +1 -0
- package/dist/formula/propositional.d.ts +2 -2
- package/dist/formula/propositional.d.ts.map +1 -1
- package/dist/formula/propositional.js +99 -88
- package/dist/formula/propositional.js.map +1 -1
- package/dist/formula/temporal.d.ts.map +1 -1
- package/dist/formula/temporal.js +87 -62
- package/dist/formula/temporal.js.map +1 -1
- package/dist/generator/validator.d.ts +20 -0
- package/dist/generator/validator.d.ts.map +1 -1
- package/dist/generator/validator.js +112 -0
- package/dist/generator/validator.js.map +1 -1
- package/dist/index.d.ts +6 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -17
- package/dist/index.js.map +1 -1
- package/dist/llm-parser.d.ts +29 -0
- package/dist/llm-parser.d.ts.map +1 -0
- package/dist/llm-parser.js +122 -0
- package/dist/llm-parser.js.map +1 -0
- package/dist/local-slm-web.d.ts +8 -0
- package/dist/local-slm-web.d.ts.map +1 -0
- package/dist/local-slm-web.js +87 -0
- package/dist/local-slm-web.js.map +1 -0
- package/dist/nl-linter/index.d.ts +10 -0
- package/dist/nl-linter/index.d.ts.map +1 -0
- package/dist/nl-linter/index.js +45 -0
- package/dist/nl-linter/index.js.map +1 -0
- package/dist/nl-linter/rules.d.ts +6 -0
- package/dist/nl-linter/rules.d.ts.map +1 -0
- package/dist/nl-linter/rules.js +93 -0
- package/dist/nl-linter/rules.js.map +1 -0
- package/dist/nl-linter/types.d.ts +14 -0
- package/dist/nl-linter/types.d.ts.map +1 -0
- package/dist/nl-linter/types.js +3 -0
- package/dist/nl-linter/types.js.map +1 -0
- package/dist/segmenter/clause-splitter.d.ts.map +1 -1
- package/dist/segmenter/clause-splitter.js +208 -10
- package/dist/segmenter/clause-splitter.js.map +1 -1
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +14 -3
- package/readme.md +666 -1
package/readme.md
CHANGED
|
@@ -1 +1,666 @@
|
|
|
1
|
-
|
|
1
|
+
# autologic
|
|
2
|
+
|
|
3
|
+
> Formalizador automático de texto natural a lógica formal ST, sin IA obligatoria.
|
|
4
|
+
|
|
5
|
+
`@stevenvo780/autologic` toma texto en lenguaje natural y produce código ST válido y ejecutable. Soporta **dos modos**:
|
|
6
|
+
|
|
7
|
+
- **Modo reglas** (sin IA): NLP basado en marcadores discursivos, stemming y coreferencia.
|
|
8
|
+
- **Modo LLM/SLM**: extracción semántica vía OpenAI, Ollama o modelo local ONNX.
|
|
9
|
+
|
|
10
|
+
En ambos casos el pipeline incluye pre-validación con el **NL Linter** y genera código ST compatible con `@stevenvo780/st-lang`.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Texto Natural
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
NL Linter ──(errores)──▶ Abortar con diagnóstico
|
|
17
|
+
│
|
|
18
|
+
▼ (texto válido)
|
|
19
|
+
┌─────────────────────────────────────────┐
|
|
20
|
+
│ Modo reglas │ Modo LLM/SLM │
|
|
21
|
+
│ (NLP determinista) │ (OpenAI/Ollama/ │
|
|
22
|
+
│ │ SLM local) │
|
|
23
|
+
└──────────┬───────────┴──────┬───────────┘
|
|
24
|
+
│ │
|
|
25
|
+
▼ ▼
|
|
26
|
+
Pipeline NLP AST JSON → compileAST()
|
|
27
|
+
│ │
|
|
28
|
+
└──────────┬───────┘
|
|
29
|
+
▼
|
|
30
|
+
ST Generator (emitST)
|
|
31
|
+
│
|
|
32
|
+
▼
|
|
33
|
+
Validación + Ejecución (st-lang)
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
FormalizationResult
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Instalación
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @stevenvo780/autologic
|
|
45
|
+
# peerDep requerida:
|
|
46
|
+
npm install @stevenvo780/st-lang
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Uso rápido — Modo reglas
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { formalize } from '@stevenvo780/autologic';
|
|
55
|
+
|
|
56
|
+
const result = formalize(
|
|
57
|
+
"Si llueve, entonces la calle se moja. Dado que está lloviendo, la calle está mojada.",
|
|
58
|
+
{ profile: 'classical.propositional', language: 'es' }
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
console.log(result.ok); // true
|
|
62
|
+
console.log(result.stCode); // código ST completo
|
|
63
|
+
console.log(result.analysis.detectedPatterns); // ["modus_ponens"]
|
|
64
|
+
console.log(result.stExecution?.ok); // true (ejecutado con st-lang)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Uso con LLM — Modo inferencia
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { formalizeWithLLM } from '@stevenvo780/autologic';
|
|
71
|
+
|
|
72
|
+
const result = await formalizeWithLLM(
|
|
73
|
+
"Es obligatorio pagar impuestos. Si pagas impuestos está permitido votar.",
|
|
74
|
+
{
|
|
75
|
+
profile: 'deontic.standard',
|
|
76
|
+
language: 'es',
|
|
77
|
+
llmConfig: { provider: 'openai', apiKey: process.env.OPENAI_KEY! }
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// result.linterDiagnostics — pre-validación NL Linter
|
|
82
|
+
// result.llmRawAst — AST JSON crudo devuelto por el LLM
|
|
83
|
+
// result.stCode — código ST generado
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Uso con modelo local ONNX (sin API externa)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const result = await formalizeWithLLM(text, {
|
|
90
|
+
profile: 'classical.propositional',
|
|
91
|
+
llmConfig: {
|
|
92
|
+
provider: 'web-distilled',
|
|
93
|
+
apiKey: '',
|
|
94
|
+
// Si se omite endpoint, descarga stevenvo780/autologic-slm-onnx de HuggingFace (~2.4 GB)
|
|
95
|
+
endpoint: '/models/autologic-slm' // ruta local opcional
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
El modelo local usa `@huggingface/transformers` con ONNX runtime en el browser o Node. El modelo `stevenvo780/autologic-slm-onnx` es un Qwen2.5-0.5B fine-tuneado para traducir texto a AST JSON.
|
|
101
|
+
|
|
102
|
+
## Clase con estado
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { Autologic } from '@stevenvo780/autologic';
|
|
106
|
+
|
|
107
|
+
const al = new Autologic({ language: 'es', defaultProfile: 'classical.propositional' });
|
|
108
|
+
|
|
109
|
+
const r1 = al.formalize("Todo humano es mortal. Sócrates es humano.");
|
|
110
|
+
const analysis = al.analyze("Si P entonces Q, pero no Q, luego no P.");
|
|
111
|
+
const validation = al.validate("logic classical.propositional\ncheck valid (P -> P)");
|
|
112
|
+
al.addMarker({ text: 'se sigue que', role: 'conclusion', language: 'es' });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## API pública
|
|
118
|
+
|
|
119
|
+
### `formalize(text, options?): FormalizationResult`
|
|
120
|
+
|
|
121
|
+
Función stateless — modo reglas NLP.
|
|
122
|
+
|
|
123
|
+
| Opción | Tipo | Default | Descripción |
|
|
124
|
+
|---|---|---|---|
|
|
125
|
+
| `profile` | `LogicProfile` | `'classical.propositional'` | Perfil lógico ST |
|
|
126
|
+
| `language` | `'es' \| 'en'` | `'es'` | Idioma del texto |
|
|
127
|
+
| `atomStyle` | `'keywords' \| 'letters' \| 'numbered'` | `'keywords'` | Nombres para átomos |
|
|
128
|
+
| `includeComments` | `boolean` | `true` | Comentarios de trazabilidad |
|
|
129
|
+
| `validateOutput` | `boolean` | `true` | Valida y ejecuta con st-lang |
|
|
130
|
+
| `maxClauseDepth` | `number` | `3` | Profundidad máxima de cláusulas |
|
|
131
|
+
|
|
132
|
+
### `formalizeWithLLM(text, options): Promise<FormalizationLLMResult>`
|
|
133
|
+
|
|
134
|
+
Modo doble capa: NL Linter → LLM/SLM → AST → ST.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
interface FormalizeWithLLMOptions extends FormalizeOptions {
|
|
138
|
+
llmConfig: LLMConfig;
|
|
139
|
+
abortOnLinterErrors?: boolean; // default: true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface FormalizationLLMResult extends FormalizationResult {
|
|
143
|
+
linterDiagnostics: NLLinterDiagnostic[];
|
|
144
|
+
llmRawAst?: LLMParsedResult;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `lintNaturalLanguage(text, rules?): NLLinterDiagnostic[]`
|
|
149
|
+
|
|
150
|
+
Valida texto natural antes de formalizar. Detecta problemas que reducen la calidad de la formalización.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { lintNaturalLanguage } from '@stevenvo780/autologic';
|
|
154
|
+
|
|
155
|
+
const diags = lintNaturalLanguage("Frecuentemente, este caso produce errores.");
|
|
156
|
+
// [
|
|
157
|
+
// { id: 'nl-fuzzy-quantifier', severity: 'error', message: "Término difuso 'Frecuentemente'...", start: 0, end: 13 },
|
|
158
|
+
// { id: 'nl-anaphoric-ambiguity', severity: 'warning', message: "El pronombre 'este'...", start: 15, end: 19 }
|
|
159
|
+
// ]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `parseTextWithLLM(text, profile, config): Promise<LLMParsedResult>`
|
|
163
|
+
|
|
164
|
+
Llama directamente a la API del LLM y retorna el AST JSON crudo.
|
|
165
|
+
|
|
166
|
+
### `llmResultToST(result): { formula, type }[]`
|
|
167
|
+
|
|
168
|
+
Convierte el AST JSON del LLM a líneas de código ST.
|
|
169
|
+
|
|
170
|
+
### Resultado completo
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
interface FormalizationResult {
|
|
174
|
+
ok: boolean;
|
|
175
|
+
stCode: string;
|
|
176
|
+
analysis: DiscourseAnalysis;
|
|
177
|
+
atoms: Map<string, string>; // atomId → texto original
|
|
178
|
+
formulas: FormulaEntry[];
|
|
179
|
+
diagnostics: Diagnostic[];
|
|
180
|
+
stValidation?: { ok: boolean; errors: string[] };
|
|
181
|
+
stExecution?: STExecutionResult; // resultado real de ejecutar con st-lang
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
interface STExecutionResult {
|
|
185
|
+
ok: boolean;
|
|
186
|
+
exitCode: number;
|
|
187
|
+
timedOut: boolean;
|
|
188
|
+
durationMs: number;
|
|
189
|
+
errors: string[];
|
|
190
|
+
resultStatuses: string[]; // ["valid", "derivable", ...]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## NL Linter
|
|
197
|
+
|
|
198
|
+
El NL Linter es una capa de pre-validación que analiza el texto natural antes de enviarlo a formalización. Se ejecuta automáticamente en `formalizeWithLLM()` y puede usarse de forma independiente.
|
|
199
|
+
|
|
200
|
+
Cuatro reglas integradas (`DEFAULT_RULES`):
|
|
201
|
+
|
|
202
|
+
| ID | Severidad | Qué detecta |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `nl-anaphoric-ambiguity` | warning | Pronombres anafóricos: "este", "ese", "lo anterior", "su" — ambigüedad referencial |
|
|
205
|
+
| `nl-cognitive-density` | warning | Oraciones de más de 40 palabras — el contexto semántico pierde precisión |
|
|
206
|
+
| `nl-fuzzy-quantifier` | **error** | Cuantificadores difusos: "frecuentemente", "la mayoría", "a veces", "probablemente" |
|
|
207
|
+
| `nl-missing-relations` | warning | Textos > 60 chars sin conectores de inferencia ("si... entonces", "por lo tanto") |
|
|
208
|
+
|
|
209
|
+
Los errores de severidad `error` abortan `formalizeWithLLM` por defecto (configurable con `abortOnLinterErrors: false`).
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { lintNaturalLanguage, DEFAULT_RULES, anaphoricRule } from '@stevenvo780/autologic';
|
|
213
|
+
|
|
214
|
+
// Usar solo reglas específicas:
|
|
215
|
+
const diags = lintNaturalLanguage(text, [anaphoricRule]);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Cada `NLLinterDiagnostic` incluye `{ id, severity, message, start, end }` con la posición exacta en el texto.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Configuración del LLM
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
interface LLMConfig {
|
|
226
|
+
provider: 'openai' | 'anthropic' | 'gemini' | 'custom' | 'ollama' | 'web-distilled';
|
|
227
|
+
apiKey: string;
|
|
228
|
+
endpoint?: string; // URL personalizada
|
|
229
|
+
model?: string; // modelo específico
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
| Provider | Descripción | Default model |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| `openai` | API OpenAI (fetch isomórfico) | `gpt-4o` |
|
|
236
|
+
| `ollama` | Servidor Ollama local con GPU | `qwen2.5:7b` |
|
|
237
|
+
| `web-distilled` | Modelo ONNX local vía @huggingface/transformers | `stevenvo780/autologic-slm-onnx` |
|
|
238
|
+
|
|
239
|
+
El LLM recibe un **system prompt** que le instruye a actuar como parser AST situado. No debe resolver la lógica, solo extraer claims y relaciones. Devuelve un JSON con la interfaz `LLMParsedResult`:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
interface LLMParsedResult {
|
|
243
|
+
axioms: Array<{ name: string; formulaJSON: LogicNode }>;
|
|
244
|
+
conclusions: Array<{ formulaJSON: LogicNode }>;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Sistema AST
|
|
251
|
+
|
|
252
|
+
autologic incluye un sistema de tipos AST completo para representar fórmulas lógicas de forma programática, independiente del texto.
|
|
253
|
+
|
|
254
|
+
### Nodos disponibles
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// Átomos proposicionales
|
|
258
|
+
AST.atom('LLUEVE', 'llueve')
|
|
259
|
+
|
|
260
|
+
// Conectivos
|
|
261
|
+
AST.and(left, right)
|
|
262
|
+
AST.or(left, right)
|
|
263
|
+
AST.implies(left, right)
|
|
264
|
+
AST.not(child)
|
|
265
|
+
|
|
266
|
+
// Cuantificadores
|
|
267
|
+
AST.forall(['x'], child)
|
|
268
|
+
AST.exists(['x'], child)
|
|
269
|
+
AST.exactlyN(['x', 'y'], 2, child) // Exactamente N instancias
|
|
270
|
+
|
|
271
|
+
// Modales (con soporte multi-agente)
|
|
272
|
+
AST.modal('K', child, 'Diego') // K_Diego(child)
|
|
273
|
+
AST.modal('B', child) // Belief
|
|
274
|
+
AST.modal('O', child) // Obligation
|
|
275
|
+
AST.modal('P', child) // Permission
|
|
276
|
+
AST.modal('F', child) // Forbidden
|
|
277
|
+
AST.modal('BOX', child) // Necesidad
|
|
278
|
+
AST.modal('DIA', child) // Posibilidad
|
|
279
|
+
AST.modal('EVENTUALLY', child) // Temporal F
|
|
280
|
+
AST.modal('NEXT', child) // Temporal X
|
|
281
|
+
|
|
282
|
+
// Temporal binario
|
|
283
|
+
AST.temporalUntil(left, right) // left U right
|
|
284
|
+
|
|
285
|
+
// Primer orden
|
|
286
|
+
AST.predicate('Humano', [AST.obj('x')])
|
|
287
|
+
AST.forall(['x'], AST.implies(AST.predicate('Humano', [AST.obj('x')]), ...))
|
|
288
|
+
|
|
289
|
+
// Matemáticas
|
|
290
|
+
AST.math('ADD', AST.obj('x'), AST.obj('y'))
|
|
291
|
+
AST.math('LT', left, AST.obj('100'))
|
|
292
|
+
|
|
293
|
+
// Probabilidad
|
|
294
|
+
AST.probability(0.755, child) // Pr(child) = 0.755
|
|
295
|
+
|
|
296
|
+
// DRT - referencias
|
|
297
|
+
AST.ref('s1') // Referencia a enunciado anterior (DRT)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Compilar AST a ST
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { compileAST, AST } from '@stevenvo780/autologic/formula/ast-compiler';
|
|
304
|
+
|
|
305
|
+
const ast = AST.implies(
|
|
306
|
+
AST.predicate('Humano', [AST.obj('x')]),
|
|
307
|
+
AST.predicate('Mortal', [AST.obj('x')])
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
compileAST(ast); // "Humano(x) -> Mortal(x)"
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## DRT — Discourse Reference Theory
|
|
316
|
+
|
|
317
|
+
`DiscourseState` mantiene un registro de enunciados en orden para resolver referencias anafóricas complejas (pronombres como "esto", "lo anterior").
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { globalDrt } from '@stevenvo780/autologic/context/discourse-state';
|
|
321
|
+
|
|
322
|
+
// El estado global registra cada enunciado formalizado
|
|
323
|
+
const id = globalDrt.registerStatement(astNode); // "s1", "s2", ...
|
|
324
|
+
globalDrt.resolvePronoun('esto'); // → "s1" (último enunciado)
|
|
325
|
+
globalDrt.resolvePronoun('lo anterior'); // → "s1"
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Se usa internamente en `compiler-frontend.ts` para casos como:
|
|
329
|
+
- "Ana aprueba el balance. Diego **sabe esto**." → K_Diego(ANA_APRUEBA_BALANCE)
|
|
330
|
+
- "El servidor colapsó. El administrador sabe esto. El CEO cree que **lo ignora**."
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Compiler Frontend
|
|
335
|
+
|
|
336
|
+
`compileComplexLogic()` es un compilador especializado para textos con estructura lógica compleja que el pipeline NLP genérico no puede manejar. Cubre casos extremos por perfil:
|
|
337
|
+
|
|
338
|
+
| Caso | Perfil | Ejemplo |
|
|
339
|
+
|---|---|---|
|
|
340
|
+
| "Ningún X es Y, excepto Z" | `aristotelian` | `forall x (M(x) -> !H(x)) & H(Ornitorrinco)` |
|
|
341
|
+
| "Exactamente N..." | `classical.first_order` | Cuantificación exacta con desigualdades |
|
|
342
|
+
| Expresiones matemáticas | `arithmetic` | Delega a `extractMath()` |
|
|
343
|
+
| Obligación con excepción | `deontic.standard` | `SystemaFalla -> (O(Reiniciar) & (Prohibe -> F(Reiniciar)))` |
|
|
344
|
+
| Conocimiento multi-agente | `epistemic.s5` | `K_Diego(P) & B_Carlos(!K_Diego(P))` |
|
|
345
|
+
| Contradicción explícita | `paraconsistent` | `Recibido() & !Recibido()` |
|
|
346
|
+
| Probabilidad numérica | `probabilistic` | `Pr(FallaMecanica) = 0.755` |
|
|
347
|
+
| Doble negación | `intuitionistic` | `!!TenemosSoluciones` |
|
|
348
|
+
| Eventualmente / Until | `temporal` | `F_temp(Alarma) & (Alarma U Pin)` |
|
|
349
|
+
|
|
350
|
+
Devuelve `null` si el texto no corresponde a ningún caso extremo conocido, dejando que el pipeline normal continúe.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Math Parser
|
|
355
|
+
|
|
356
|
+
`extractMath()` detecta y extrae expresiones matemáticas del texto, protegiéndolas para que el pipeline NLP no las interprete como proposiciones.
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import { extractMath } from '@stevenvo780/autologic/atoms/math-parser';
|
|
360
|
+
|
|
361
|
+
const { nodes, shieldedText } = extractMath(
|
|
362
|
+
"Si al cuadrado de X le sumas la variable Y, el resultado será siempre menor a 100."
|
|
363
|
+
);
|
|
364
|
+
// nodes: Map { "__MATH_1__" → AST.math('LT', ADD(MUL(X,X), Y), 100) }
|
|
365
|
+
// shieldedText: "Si __MATH_1__, ..."
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Soporta:
|
|
369
|
+
- Expresiones algebraicas verbales ("al cuadrado de X le sumas Y")
|
|
370
|
+
- Ecuaciones simples (`x = y + 2`, `x = y - 3`)
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Perfiles lógicos
|
|
375
|
+
|
|
376
|
+
| Perfil | Caso de uso |
|
|
377
|
+
|---|---|
|
|
378
|
+
| `classical.propositional` | Conectores básicos (→, ∧, ∨, ¬). Default. |
|
|
379
|
+
| `classical.first_order` | Cuantificadores ∀x, ∃x, predicados |
|
|
380
|
+
| `modal.k` | Necesidad (`[]`), posibilidad (`<>`) |
|
|
381
|
+
| `deontic.standard` | Obligación (O), permiso (P), prohibición (F) |
|
|
382
|
+
| `epistemic.s5` | Conocimiento (K), creencia (B), multi-agente |
|
|
383
|
+
| `intuitionistic.propositional` | Sin tercero excluido |
|
|
384
|
+
| `temporal.ltl` | `next`, `until`, `G`, `F` |
|
|
385
|
+
| `paraconsistent.belnap` | Tolerante a contradicciones |
|
|
386
|
+
| `aristotelian.syllogistic` | Silogística clásica |
|
|
387
|
+
| `probabilistic.basic` | `Pr(X) = 0.75` |
|
|
388
|
+
| `arithmetic` | Operaciones aritméticas explicadas |
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Ejemplos por perfil
|
|
393
|
+
|
|
394
|
+
### `classical.propositional` — Modus Ponens
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
"Si los precios suben, la demanda baja. Los precios están subiendo. Por lo tanto, la demanda bajará."
|
|
398
|
+
```
|
|
399
|
+
```st
|
|
400
|
+
logic classical.propositional
|
|
401
|
+
interpret "los precios suben" as PRECIOS_SUBEN
|
|
402
|
+
interpret "la demanda baja" as DEMANDA_BAJA
|
|
403
|
+
axiom regla : PRECIOS_SUBEN -> DEMANDA_BAJA
|
|
404
|
+
axiom hecho : PRECIOS_SUBEN
|
|
405
|
+
derive DEMANDA_BAJA from {regla, hecho}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### `classical.first_order` — Silogismo
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
"Todo humano es mortal. Sócrates es humano. Por tanto, Sócrates es mortal."
|
|
412
|
+
```
|
|
413
|
+
```st
|
|
414
|
+
logic classical.first_order
|
|
415
|
+
axiom a1 : forall x (Humano(x) -> Mortal(x))
|
|
416
|
+
axiom a2 : Humano(socrates)
|
|
417
|
+
derive Mortal(socrates) from {a1, a2}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### `deontic.standard` — Normas
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
"Es obligatorio pagar impuestos. Si pagas impuestos, está permitido votar."
|
|
424
|
+
```
|
|
425
|
+
```st
|
|
426
|
+
logic deontic.standard
|
|
427
|
+
axiom obligacion : [](PAGAR_IMPUESTOS)
|
|
428
|
+
axiom permiso : PAGAR_IMPUESTOS -> <>(VOTAR)
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### `epistemic.s5` — Conocimiento multi-agente (LLM)
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
"Ana aprueba el balance. Diego sabe esto. Carlos duda de lo anterior."
|
|
435
|
+
```
|
|
436
|
+
```st
|
|
437
|
+
logic epistemic.s5
|
|
438
|
+
axiom a1 : ANA_APRUEBA_BALANCE & K_Diego(ANA_APRUEBA_BALANCE) & B_Carlos(!K_Diego(ANA_APRUEBA_BALANCE))
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### `probabilistic.basic`
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
"Existe exactamente un 75.5% de probabilidad de que el disco sufra una falla mecánica."
|
|
445
|
+
```
|
|
446
|
+
```st
|
|
447
|
+
logic probabilistic.basic
|
|
448
|
+
axiom a1 : Pr(FallaMecanica) = 0.755
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Pipeline interno (modo reglas)
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
1. Segmenter Divide texto en oraciones y cláusulas
|
|
457
|
+
(puntuación + marcadores discursivos)
|
|
458
|
+
2. Discourse Clasifica roles: premisa, conclusión,
|
|
459
|
+
Analyzer condición, consecuente
|
|
460
|
+
Detecta negaciones y cuantificadores
|
|
461
|
+
3. Atom Extractor Extrae proposiciones atómicas → IDs
|
|
462
|
+
Correferencia léxica básica (Dice/Jaccard)
|
|
463
|
+
4. Formula Builder Construye fórmulas por perfil
|
|
464
|
+
(A->B, forall x, []A, next A...)
|
|
465
|
+
5. ST Generator Emite código ST con trazabilidad
|
|
466
|
+
6. Validator valida parse + ejecuta con st-lang
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Marcadores discursivos (~200 bilingüe)
|
|
470
|
+
|
|
471
|
+
| Categoría | Español | English | Rol lógico |
|
|
472
|
+
|---|---|---|---|
|
|
473
|
+
| Condicional | si, siempre que, en caso de | if, whenever, provided that | `condition` |
|
|
474
|
+
| Consecuente | entonces, por lo tanto, luego | then, therefore, hence | `consequent` |
|
|
475
|
+
| Premisa | dado que, puesto que, ya que | since, because, given that | `premise` |
|
|
476
|
+
| Conjunción | y, además, también | and, moreover, furthermore | `and` |
|
|
477
|
+
| Disyunción | o, o bien | or, either...or | `or` |
|
|
478
|
+
| Adversativa | pero, sin embargo, aunque | but, however, although | `adversative` |
|
|
479
|
+
| Negación | no, nunca, ningún | not, never, neither | `negation` |
|
|
480
|
+
| Universal | todo, cada, cualquier | all, every, each | `universal` |
|
|
481
|
+
| Existencial | algún, existe, hay | some, there exists | `existential` |
|
|
482
|
+
| Modal-necesidad | necesariamente, debe | necessarily, must | `necessity` |
|
|
483
|
+
| Modal-posibilidad | posiblemente, puede | possibly, may | `possibility` |
|
|
484
|
+
| Bicondicional | si y solo si | if and only if | `biconditional` |
|
|
485
|
+
| Temporal | después, antes, hasta que | after, before, until | `temporal` |
|
|
486
|
+
|
|
487
|
+
### Patrones argumentales detectados
|
|
488
|
+
|
|
489
|
+
| Patrón | Condición |
|
|
490
|
+
|---|---|
|
|
491
|
+
| `modus_ponens` | (A→B) + A → B |
|
|
492
|
+
| `modus_tollens` | (A→B) + ¬B → ¬A |
|
|
493
|
+
| `hypothetical_syllogism` | A→B + B→C → A→C |
|
|
494
|
+
| `disjunctive_syllogism` | A∨B + ¬A → B |
|
|
495
|
+
| `constructive_dilemma` | (A→B) & (C→D) + (A∨C) → (B∨D) |
|
|
496
|
+
| `conditional_chain` | Serie de condicionales encadenados |
|
|
497
|
+
| `universal_generalization` | Múltiples instancias del mismo patrón |
|
|
498
|
+
| `conjunction_introduction` | Varias premisas aisladas |
|
|
499
|
+
| `biconditional_introduction` | A si y solo si B |
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## Estructura del proyecto
|
|
504
|
+
|
|
505
|
+
```
|
|
506
|
+
autologic/
|
|
507
|
+
├── src/
|
|
508
|
+
│ ├── index.ts # Exports públicos (API completa)
|
|
509
|
+
│ ├── autologic.ts # Clase Autologic con estado
|
|
510
|
+
│ ├── formalize.ts # formalize() y formalizeWithLLM()
|
|
511
|
+
│ ├── types.ts # Todos los tipos
|
|
512
|
+
│ ├── compiler-frontend.ts # Casos extremos por perfil (AST directo)
|
|
513
|
+
│ ├── llm-parser.ts # Parser LLM (OpenAI/Ollama/web-distilled)
|
|
514
|
+
│ ├── local-slm-web.ts # Inferencia ONNX local (@huggingface/transformers)
|
|
515
|
+
│ │
|
|
516
|
+
│ ├── nl-linter/
|
|
517
|
+
│ │ ├── index.ts # lintNaturalLanguage() + DEFAULT_RULES
|
|
518
|
+
│ │ ├── rules.ts # 4 reglas: anaphoric, density, fuzzy, completeness
|
|
519
|
+
│ │ └── types.ts # NLLinterDiagnostic, NLRule
|
|
520
|
+
│ │
|
|
521
|
+
│ ├── context/
|
|
522
|
+
│ │ └── discourse-state.ts # DRT: DiscourseState + globalDrt
|
|
523
|
+
│ │
|
|
524
|
+
│ ├── formula/
|
|
525
|
+
│ │ ├── ast.ts # Tipos AST + factory AST.*
|
|
526
|
+
│ │ ├── ast-compiler.ts # compileAST() → código ST
|
|
527
|
+
│ │ ├── argument-builder.ts # Constructor de argumentos
|
|
528
|
+
│ │ ├── connectors.ts # Mapa marcador → operador ST
|
|
529
|
+
│ │ ├── first-order.ts # Builder FOL
|
|
530
|
+
│ │ ├── modal.ts # Builder modal
|
|
531
|
+
│ │ ├── propositional.ts # Builder proposicional
|
|
532
|
+
│ │ ├── temporal.ts # Builder temporal
|
|
533
|
+
│ │ ├── probabilistic.ts # Builder probabilístico
|
|
534
|
+
│ │ ├── helpers.ts # Utilidades
|
|
535
|
+
│ │ └── index.ts # buildFormulas()
|
|
536
|
+
│ │
|
|
537
|
+
│ ├── atoms/
|
|
538
|
+
│ │ ├── index.ts # extractAtoms()
|
|
539
|
+
│ │ ├── coreference.ts # Resolución de correferencia
|
|
540
|
+
│ │ ├── identifier-gen.ts # Generador de IDs ST válidos
|
|
541
|
+
│ │ ├── keyword-extractor.ts # Extracción de palabras clave
|
|
542
|
+
│ │ └── math-parser.ts # extractMath() — escudo matemático
|
|
543
|
+
│ │
|
|
544
|
+
│ ├── segmenter/
|
|
545
|
+
│ │ ├── index.ts # segment()
|
|
546
|
+
│ │ ├── sentence-splitter.ts # Split por puntuación
|
|
547
|
+
│ │ └── clause-splitter.ts # Split de cláusulas internas
|
|
548
|
+
│ │
|
|
549
|
+
│ ├── discourse/
|
|
550
|
+
│ │ ├── index.ts # analyzeDiscourse()
|
|
551
|
+
│ │ ├── markers-es.ts # ~100 marcadores español
|
|
552
|
+
│ │ ├── markers-en.ts # ~100 marcadores inglés
|
|
553
|
+
│ │ ├── role-classifier.ts # Asigna roles a cláusulas
|
|
554
|
+
│ │ └── pattern-detector.ts # Detecta patrones argumentales
|
|
555
|
+
│ │
|
|
556
|
+
│ ├── generator/
|
|
557
|
+
│ │ ├── index.ts
|
|
558
|
+
│ │ ├── st-emitter.ts # emitST() — código ST con comentarios
|
|
559
|
+
│ │ └── validator.ts # validateST(), executeST()
|
|
560
|
+
│ │
|
|
561
|
+
│ └── nlp/
|
|
562
|
+
│ ├── index.ts
|
|
563
|
+
│ ├── tokenizer.ts
|
|
564
|
+
│ ├── stemmer-es.ts # Snowball español
|
|
565
|
+
│ ├── stemmer-en.ts # Snowball inglés
|
|
566
|
+
│ └── stopwords.ts
|
|
567
|
+
│
|
|
568
|
+
└── tests/
|
|
569
|
+
├── segmenter.test.ts
|
|
570
|
+
├── discourse.test.ts
|
|
571
|
+
├── atoms.test.ts
|
|
572
|
+
├── formula.test.ts
|
|
573
|
+
├── patterns.test.ts
|
|
574
|
+
└── profiles.test.ts
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## Exports públicos (`index.ts`)
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
// Funciones principales
|
|
583
|
+
export { formalize } from './formalize';
|
|
584
|
+
export { formalizeWithLLM } from './formalize';
|
|
585
|
+
export type { FormalizeWithLLMOptions, FormalizationLLMResult } from './formalize';
|
|
586
|
+
|
|
587
|
+
// NL Linter
|
|
588
|
+
export { lintNaturalLanguage, DEFAULT_RULES } from './nl-linter';
|
|
589
|
+
export type { NLLinterDiagnostic, NLRule } from './nl-linter';
|
|
590
|
+
|
|
591
|
+
// Clase con estado
|
|
592
|
+
export { Autologic } from './autologic';
|
|
593
|
+
|
|
594
|
+
// LLM
|
|
595
|
+
export { parseTextWithLLM, llmResultToST } from './llm-parser';
|
|
596
|
+
export type { LLMConfig, LLMParsedResult } from './llm-parser';
|
|
597
|
+
|
|
598
|
+
// Pipeline interno (uso avanzado)
|
|
599
|
+
export { segment } from './segmenter';
|
|
600
|
+
export { analyzeDiscourse } from './discourse';
|
|
601
|
+
export { extractAtoms } from './atoms';
|
|
602
|
+
export { buildFormulas } from './formula';
|
|
603
|
+
export { emitST } from './generator/st-emitter';
|
|
604
|
+
export { validateST } from './generator/validator';
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## Dependencias
|
|
610
|
+
|
|
611
|
+
**Runtime**: ninguna (0 dependencias).
|
|
612
|
+
|
|
613
|
+
**peerDependencies**: `@stevenvo780/st-lang >= 3.0.0`
|
|
614
|
+
|
|
615
|
+
**devDependencies**: `typescript`, `vitest`, `@stevenvo780/st-lang`
|
|
616
|
+
|
|
617
|
+
**Opcional (LLM web)**: `@huggingface/transformers` — se importa dinámicamente solo si se usa el provider `web-distilled`.
|
|
618
|
+
|
|
619
|
+
NLP propio (sin compromise.js ni spaCy):
|
|
620
|
+
- Stemmer Snowball ES/EN (~200 líneas)
|
|
621
|
+
- Stopwords curadas (~150 palabras/idioma)
|
|
622
|
+
- Marcadores discursivos (~200 entradas)
|
|
623
|
+
- Tokenizador regex
|
|
624
|
+
|
|
625
|
+
Tamaño: ~30 KB minificado (sin el modelo ONNX).
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## Tests
|
|
630
|
+
|
|
631
|
+
```bash
|
|
632
|
+
npm test # vitest
|
|
633
|
+
npm run test:coverage # con reporte en coverage/
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
## Decisiones de diseño
|
|
639
|
+
|
|
640
|
+
| Decisión | Razón |
|
|
641
|
+
|---|---|
|
|
642
|
+
| Modo reglas SIN IA por defecto | Determinismo, reproducibilidad, latencia cero, costo cero |
|
|
643
|
+
| Modo LLM opcional | Para textos legales/técnicos complejos que el pipeline NLP no maneja |
|
|
644
|
+
| NL Linter como puerta de entrada | Previene formalización de textos ambiguos que producirían ASTs incorrectos |
|
|
645
|
+
| AST tipado en TypeScript | El LLM devuelve JSON; compileAST() lo transforma a ST sin riesgo de inyección |
|
|
646
|
+
| DRT para correferencia | Resolución de pronombres anafóricos en lógicas epistémicas y modales multi-agente |
|
|
647
|
+
| compiler-frontend para casos extremos | Algunos patrones (cuantificación exacta, probabilidades) requieren construcción AST directa |
|
|
648
|
+
| 0 deps runtime | Librería ultraligera, sin supply-chain risk |
|
|
649
|
+
| st-lang como peerDep | El consumidor ya la tiene; evita duplicación |
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Integración con EducacionCooperativa
|
|
654
|
+
|
|
655
|
+
La plataforma usa autologic en dos puntos:
|
|
656
|
+
|
|
657
|
+
1. **`src/lib/buildSTFromSemantic.ts`** — genera automáticamente el archivo `.st` companion para cada documento de la Mesa Semántica.
|
|
658
|
+
2. **`src/components/FormalizerPlayground.tsx`** — interfaz interactiva para formalizar texto con selección de perfil, historial y ejecución en tiempo real.
|
|
659
|
+
|
|
660
|
+
Ver `docs/formalizacion-automatica.md` en EducacionCooperativa para el flujo completo.
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
## Licencia
|
|
665
|
+
|
|
666
|
+
Ver [LICENSE](LICENSE).
|